Commit 688ea02a authored by Craig Silverstein's avatar Craig Silverstein

Thu Sep 10 12:53:04 2009 Google Inc. <opensource@google.com>

	* google-gflags: version 1.2
	* PORTABILITY: can now build and run tests under mingw (csilvers)
	* Using a string arg for a bool flag is a compile-time error (rbayardo)
	* Add --helpxml to gflags.py (salcianu)
	* Protect against a hypothetical global d'tor mutex problem (csilvers)
	* BUGFIX: can now define a flag after 'using namespace google' (hamaji)


git-svn-id: https://gflags.googlecode.com/svn/trunk@32 6586e3c6-dcc4-952a-343f-ff74eb82781d
parent de718176
Thu Sep 10 12:53:04 2009 Google Inc. <opensource@google.com>
* google-gflags: version 1.2
* PORTABILITY: can now build and run tests under mingw (csilvers)
* Using a string arg for a bool flag is a compile-time error (rbayardo)
* Add --helpxml to gflags.py (salcianu)
* Protect against a hypothetical global d'tor mutex problem (csilvers)
* BUGFIX: can now define a flag after 'using namespace google' (hamaji)
Tue Apr 14 12:35:25 2009 Google Inc. <opensource@google.com>
* google-gflags: version 1.1
......
......@@ -67,7 +67,7 @@ lib_LTLIBRARIES += libgflags_nothreads.la
libgflags_nothreads_la_SOURCES = $(GFLAGS_SOURCES)
libgflags_nothreads_la_CXXFLAGS = -DNDEBUG -DNO_THREADS
TESTS += gflags_unittest$(EXEEXT)
TESTS += gflags_unittest
gflags_unittest_SOURCES = $(gflagsinclude_HEADERS) src/config.h \
src/gflags_unittest.cc
gflags_unittest_CXXFLAGS = $(PTHREAD_CFLAGS)
......@@ -75,14 +75,14 @@ gflags_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
gflags_unittest_LDADD = libgflags.la
# Also make sure this works when we don't link in pthreads
TESTS += gflags_nothreads_unittest$(EXEEXT)
TESTS += gflags_nothreads_unittest
gflags_nothreads_unittest_SOURCES = $(gflags_unittest_SOURCES)
gflags_nothreads_unittest_LDADD = libgflags_nothreads.la
# We also want to test that things work properly when the file that
# holds main() has a name ending with -main or _main. To keep the
# Makefile small :-), we test the no-threads version of these.
TESTS += gflags_unittest2$(EXEEXT)
TESTS += gflags_unittest2
gflags_unittest2_SOURCES = $(gflagsinclude_HEADERS) src/config.h \
src/gflags_unittest-main.cc
gflags_unittest2_LDADD = libgflags_nothreads.la
......@@ -91,7 +91,7 @@ src/gflags_unittest-main.cc: src/gflags_unittest.cc
cp -p src/gflags_unittest.cc src/gflags_unittest-main.cc
CLEANFILES += src/gflags_unittest-main.cc
TESTS += gflags_unittest3$(EXEEXT)
TESTS += gflags_unittest3
gflags_unittest3_SOURCES = $(gflagsinclude_HEADERS) src/config.h \
src/gflags_unittest_main.cc
gflags_unittest3_LDADD = libgflags_nothreads.la
......@@ -109,9 +109,32 @@ dist_noinst_DATA = src/gflags_unittest_flagfile
gflags_unittest_sh: gflags_unittest$(EXEEXT) \
gflags_unittest2$(EXEEXT) \
gflags_unittest3$(EXEEXT)
bash --version >/dev/null && export SH=bash || export SH=sh; \
bash --version >/dev/null 2>&1 && export SH=bash || export SH=sh; \
$$SH "$(top_srcdir)/src/gflags_unittest.sh" "$(PWD)/gflags_unittest" \
"$(top_srcdir)"
"$(top_srcdir)" "@TMPDIR@"
# These are negative-compilation tests. We want to make sure these
# erroneous use of the flags macros correctly fail to compile.
# Again, we just bother testing with the no-threads version of the library.
check_SCRIPTS += gflags_nc_test1
gflags_nc_test1: $(gflagsinclude_HEADERS) src/config.h src/gflags_nc.cc
! $(CXX) -DTEST_SWAPPED_ARGS $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gflags_nc_test1.o $(srcdir)/src/gflags_nc.cc && echo "Compile failed, like it was supposed to"
check_SCRIPTS += gflags_nc_test2
gflags_nc_test2: $(gflagsinclude_HEADERS) src/config.h src/gflags_nc.cc
! $(CXX) -DTEST_INT_INSTEAD_OF_BOOL $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gflags_nc_test2.o $(srcdir)/src/gflags_nc.cc && echo "Compile failed, like it was supposed to"
check_SCRIPTS += gflags_nc_test3
gflags_nc_test3: $(gflagsinclude_HEADERS) src/config.h src/gflags_nc.cc
! $(CXX) -DTEST_BOOL_IN_QUOTES $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gflags_nc_test3.o $(srcdir)/src/gflags_nc.cc && echo "Compile failed, like it was supposed to"
# This one, on the other hand, should succeed.
check_SCRIPTS += gflags_nc_test4
gflags_nc_test4: $(gflagsinclude_HEADERS) src/config.h src/gflags_nc.cc
$(CXX) -DSANITY $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gflags_nc_test4.o $(srcdir)/src/gflags_nc.cc && echo "Compile failed, like it was supposed to"
# This file isn't covered under any rule that would cause it to be distributed.
dist_noinst_DATA += src/gflags_nc.cc
# These aren't part of the c++ source, but we want them to be distributed
PYTHON = python/setup.py \
......
......@@ -158,7 +158,7 @@ am__remove_distdir = \
{ test ! -d $(distdir) \
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -fr $(distdir); }; }
DIST_ARCHIVES = $(distdir).tar.gz
DIST_ARCHIVES = $(distdir).tar.gz $(distdir).zip
GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print
distcleancheck_listfiles = find . -type f -print
......@@ -225,6 +225,7 @@ SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
TMPDIR = @TMPDIR@
VERSION = @VERSION@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
......@@ -314,14 +315,21 @@ lib_LTLIBRARIES = libgflags.la libgflags_nothreads.la
# We also want to test that things work properly when the file that
# holds main() has a name ending with -main or _main. To keep the
# Makefile small :-), we test the no-threads version of these.
TESTS = gflags_unittest$(EXEEXT) gflags_nothreads_unittest$(EXEEXT) \
gflags_unittest2$(EXEEXT) gflags_unittest3$(EXEEXT)
TESTS = gflags_unittest gflags_nothreads_unittest gflags_unittest2 \
gflags_unittest3
TESTS_ENVIRONMENT = SRCDIR="$(top_srcdir)"
# Some buggy sh's ignore "" instead of treating it as a positional
# parameter. Since we use "" in this script, we prefer bash if we
# can. If there's no bash, we fall back to sh.
check_SCRIPTS = gflags_unittest_sh
# These are negative-compilation tests. We want to make sure these
# erroneous use of the flags macros correctly fail to compile.
# Again, we just bother testing with the no-threads version of the library.
# This one, on the other hand, should succeed.
check_SCRIPTS = gflags_unittest_sh gflags_nc_test1 gflags_nc_test2 \
gflags_nc_test3 gflags_nc_test4
# Every time you add a unittest to check_SCRIPTS, add it here too
noinst_SCRIPTS = src/gflags_unittest.sh
# Used for auto-generated source files
......@@ -352,7 +360,9 @@ gflags_unittest3_SOURCES = $(gflagsinclude_HEADERS) src/config.h \
src/gflags_unittest_main.cc
gflags_unittest3_LDADD = libgflags_nothreads.la
dist_noinst_DATA = src/gflags_unittest_flagfile
# This file isn't covered under any rule that would cause it to be distributed.
dist_noinst_DATA = src/gflags_unittest_flagfile src/gflags_nc.cc
# These aren't part of the c++ source, but we want them to be distributed
PYTHON = python/setup.py \
......@@ -862,7 +872,6 @@ dist-tarZ: distdir
dist-shar: distdir
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
......@@ -870,6 +879,8 @@ dist-zip: distdir
dist dist-all: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
......@@ -1060,9 +1071,17 @@ src/gflags_unittest_main.cc: src/gflags_unittest.cc
gflags_unittest_sh: gflags_unittest$(EXEEXT) \
gflags_unittest2$(EXEEXT) \
gflags_unittest3$(EXEEXT)
bash --version >/dev/null && export SH=bash || export SH=sh; \
bash --version >/dev/null 2>&1 && export SH=bash || export SH=sh; \
$$SH "$(top_srcdir)/src/gflags_unittest.sh" "$(PWD)/gflags_unittest" \
"$(top_srcdir)"
"$(top_srcdir)" "@TMPDIR@"
gflags_nc_test1: $(gflagsinclude_HEADERS) src/config.h src/gflags_nc.cc
! $(CXX) -DTEST_SWAPPED_ARGS $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gflags_nc_test1.o $(srcdir)/src/gflags_nc.cc && echo "Compile failed, like it was supposed to"
gflags_nc_test2: $(gflagsinclude_HEADERS) src/config.h src/gflags_nc.cc
! $(CXX) -DTEST_INT_INSTEAD_OF_BOOL $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gflags_nc_test2.o $(srcdir)/src/gflags_nc.cc && echo "Compile failed, like it was supposed to"
gflags_nc_test3: $(gflagsinclude_HEADERS) src/config.h src/gflags_nc.cc
! $(CXX) -DTEST_BOOL_IN_QUOTES $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gflags_nc_test3.o $(srcdir)/src/gflags_nc.cc && echo "Compile failed, like it was supposed to"
gflags_nc_test4: $(gflagsinclude_HEADERS) src/config.h src/gflags_nc.cc
$(CXX) -DSANITY $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gflags_nc_test4.o $(srcdir)/src/gflags_nc.cc && echo "Compile failed, like it was supposed to"
rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec
@cd packages && ./rpm.sh ${PACKAGE} ${VERSION}
......
This diff is collapsed.
......@@ -4,11 +4,11 @@
# make sure we're interpreted by some minimal autoconf
AC_PREREQ(2.57)
AC_INIT(gflags, 1.1, opensource@google.com)
AC_INIT(gflags, 1.2, opensource@google.com)
# The argument here is just something that should be in the current directory
# (for sanity checking)
AC_CONFIG_SRCDIR(README)
AM_INIT_AUTOMAKE
AM_INIT_AUTOMAKE([dist-zip])
AM_CONFIG_HEADER(src/config.h)
# Checks for programs.
......@@ -27,11 +27,15 @@ case $host_os in
# MinGW. Using this option means an extra link step is executed during
# "make install".
AC_DISABLE_FAST_INSTALL
# /tmp is a mount-point in mingw, and hard to use. use cwd instead
TMPDIR=gflags_testdir
;;
*)
AC_ENABLE_FAST_INSTALL
TMPDIR=/tmp/gflags
;;
esac
AC_SUBST(TMPDIR)
# Uncomment this if you'll be exporting libraries (.so's)
AC_PROG_LIBTOOL
......@@ -53,6 +57,7 @@ AC_CHECK_TYPE(u_int16_t, ac_cv_have_u_int16_t=1, ac_cv_have_u_int16_t=0)
AC_CHECK_TYPE(__int16, ac_cv_have___int16=1, ac_cv_have___int16=0)
AC_CHECK_FUNCS([strtoll strtoq])
AC_CHECK_FUNCS([setenv putenv]) # MinGW has putenv but not setenv
AX_C___ATTRIBUTE__
# We only care about __attribute__ ((unused))
......
gflags (1.2-1) unstable; urgency=low
* New upstream release.
-- Google Inc. <opensource@google.com> Thu, 10 Sep 2009 12:53:04 -0700
gflags (1.1-1) unstable; urgency=low
* New upstream release.
......
......@@ -47,7 +47,18 @@ mkdir "$RPM_BUILD_DIR"
cp "$archive" "$RPM_SOURCE_DIR"
rpmbuild -bb rpm/rpm.spec \
# rpmbuild -- as far as I can tell -- asks the OS what CPU it has.
# This may differ from what kind of binaries gcc produces. dpkg
# does a better job of this, so if we can run 'dpkg --print-architecture'
# to get the build CPU, we use that in preference of the rpmbuild
# default.
target=`dpkg --print-architecture 2>/dev/null` # "" if dpkg isn't found
if [ -n "$target" ]
then
target=" --target $target"
fi
rpmbuild -bb rpm/rpm.spec $target \
--define "NAME $PACKAGE" \
--define "VERSION $VERSION" \
--define "_sourcedir $RPM_SOURCE_DIR" \
......
......@@ -32,6 +32,15 @@ The %name-devel package contains static and debug libraries and header
files for developing applications that use the %name package.
%changelog
* Thu Sep 10 2009 <opensource@google.com>
- Change from '%configure' to something like it, but without -m32
* Mon Apr 20 2009 <opensource@google.com>
- Change build rule to use '%configure' rather than './configure'
- Change install to use DESTDIR instead of prefix for make install.
- Use wildcards for doc/ and lib/ directories
- Use {_libdir}/{_includedir}/etc instead of {prefix}/lib, etc
* Tue Dec 13 2006 <opensource@google.com>
- First draft
......@@ -39,12 +48,15 @@ files for developing applications that use the %name package.
%setup
%build
./configure
make prefix=%prefix
# I can't use '% configure', because it defines -m32 which breaks the
# build somehow on my system. But I do take as much from % configure
# (in /usr/lib/rpm/macros) as I can.
./configure --prefix=%{_prefix} --exec-prefix=%{_exec_prefix} --bindir=%{_bindir} --sbindir=%{_sbindir} --sysconfdir=%{_sysconfdir} --datadir=%{_datadir} --includedir=%{_includedir} --libdir=%{_libdir} --libexecdir=%{_libexecdir} --localstatedir=%{_localstatedir} --sharedstatedir=%{_sharedstatedir} --mandir=%{_mandir} --infodir=%{_infodir}
make
%install
rm -rf $RPM_BUILD_ROOT
make prefix=$RPM_BUILD_ROOT%{prefix} install
make DESTDIR=$RPM_BUILD_ROOT install
%clean
rm -rf $RPM_BUILD_ROOT
......@@ -52,28 +64,20 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
## Mark all installed files within /usr/share/doc/{package name} as
## documentation. This depends on the following two lines appearing in
## Makefile.am:
## docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
## dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README
%docdir %{prefix}/share/doc/%{NAME}-%{VERSION}
%{prefix}/share/doc/%{NAME}-%{VERSION}/*
%{prefix}/lib/libgflags.so.0
%{prefix}/lib/libgflags.so.0.0.0
%{prefix}/lib/libgflags_nothreads.so.0
%{prefix}/lib/libgflags_nothreads.so.0.0.0
%{prefix}/bin/gflags_completions.sh
%doc AUTHORS COPYING ChangeLog INSTALL NEWS README
%doc doc/*
%{_libdir}/*.so.*
%{_bindir}/gflags_completions.sh
%files devel
%defattr(-,root,root)
%{prefix}/include/google
%{prefix}/include/gflags
%{prefix}/lib/libgflags.a
%{prefix}/lib/libgflags.la
%{prefix}/lib/libgflags.so
%{prefix}/lib/libgflags_nothreads.a
%{prefix}/lib/libgflags_nothreads.la
%{prefix}/lib/libgflags_nothreads.so
%{_includedir}/gflags
%{_includedir}/google
%{_libdir}/*.a
%{_libdir}/*.la
%{_libdir}/*.so
This diff is collapsed.
This diff is collapsed.
......@@ -29,7 +29,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"Unittest for flags.py module"
"Unittest for gflags.py module"
__pychecker__ = "no-local" # for unittest
......@@ -495,7 +495,7 @@ class FlagsUnitTest(unittest.TestCase):
"--testspacelist [] --x 10 "
"--noexec --quack "
"--test1 "
"--testget1 --no? --nodebug --nohelp --nohelpshort "
"--testget1 --no? --nodebug --nohelp --nohelpshort --nohelpxml "
"--noq --notest0 --notestget2 "
"--notestget3 --notestnone")
......@@ -520,7 +520,7 @@ class FlagsUnitTest(unittest.TestCase):
"--testspacelist [] --x 10 "
"--debug --noexec --quack "
"--test1 "
"--testget1 --no? --nohelp --nohelpshort "
"--testget1 --no? --nohelp --nohelpshort --nohelpxml "
"--noq --notest0 --notestget2 "
"--notestget3 --notestnone")
......@@ -535,12 +535,25 @@ class FlagsUnitTest(unittest.TestCase):
except flags.DuplicateFlag, e:
pass
# Duplicate short flag detection
try:
flags.DEFINE_boolean("zoom1", 0, "runhelp z1", short_name='z')
flags.DEFINE_boolean("zoom2", 0, "runhelp z2", short_name='z')
raise AssertionError("duplicate flag detection failed")
raise AssertionError("duplicate short flag detection failed")
except flags.DuplicateFlag, e:
pass
self.assertTrue("The flag 'z' is defined twice. " in e.args[0])
self.assertTrue("First from" in e.args[0])
self.assertTrue(", Second from" in e.args[0])
# Duplicate mixed flag detection
try:
flags.DEFINE_boolean("short1", 0, "runhelp s1", short_name='s')
flags.DEFINE_boolean("s", 0, "runhelp s2")
raise AssertionError("duplicate mixed flag detection failed")
except flags.DuplicateFlag, e:
self.assertTrue("The flag 's' is defined twice. " in e.args[0])
self.assertTrue("First from" in e.args[0])
self.assertTrue(", Second from" in e.args[0])
# Make sure allow_override works
try:
......@@ -1165,6 +1178,7 @@ class FlagsUnitTest(unittest.TestCase):
(default: 'false')
-?,--[no]help: show this help
--[no]helpshort: show usage only for this module
--[no]helpxml: like --help, but generates XML output
--kwery: <who|what|why|where|when>: ?
--l: how long to be
(default: '9223372032559808512')
......@@ -1407,7 +1421,9 @@ class FlagsUnitTest(unittest.TestCase):
try:
help_flag_help = (
" -?,--[no]help: show this help\n"
" --[no]helpshort: show usage only for this module")
" --[no]helpshort: show usage only for this module\n"
" --[no]helpxml: like --help, but generates XML output"
)
expected_help = "\n%s:\n%s" % (sys.argv[0], help_flag_help)
......@@ -1477,18 +1493,18 @@ class FlagsUnitTest(unittest.TestCase):
self.assertEqual(flags._GetCallingModule(), sys.argv[0])
self.assertEqual(
module_foo.GetModuleName(),
'google3.pyglib.tests.flags_modules_for_testing.module_foo')
'test_module_foo')
self.assertEqual(
module_bar.GetModuleName(),
'google3.pyglib.tests.flags_modules_for_testing.module_bar')
'test_module_bar')
# We execute the following exec statements for their side-effect
# (i.e., not raising an error). They emphasize the case that not
# all code resides in one of the imported modules: Python is a
# really dynamic language, where we can dynamically construct some
# code and execute it.
code = ("from google3.pyglib import flags\n"
"module_name = flags._GetCallingModule()")
code = ("import gflags\n"
"module_name = gflags._GetCallingModule()")
exec code
# Next two exec statements executes code with a global environment
......@@ -1517,7 +1533,7 @@ class FlagsUnitTest(unittest.TestCase):
module_bar.ExecuteCode(code, global_dict)
self.assertEqual(
global_dict['module_name'],
'google3.pyglib.tests.flags_modules_for_testing.module_bar')
'test_module_bar')
def main():
......
......@@ -21,6 +21,12 @@
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
......
......@@ -669,7 +669,7 @@ class FlagRegistry {
};
FlagRegistry* FlagRegistry::global_registry_ = NULL;
Mutex FlagRegistry::global_registry_lock_;
Mutex FlagRegistry::global_registry_lock_(Mutex::LINKER_INITIALIZED);
FlagRegistry* FlagRegistry::GlobalRegistry() {
MutexLock acquire_lock(&global_registry_lock_);
......@@ -1037,6 +1037,25 @@ uint32 CommandLineFlagParser::ParseNewCommandLineFlags(int* argc, char*** argv,
break; // we treat this as an unrecoverable error
} else {
value = (*argv)[++i]; // read next arg for value
// Heuristic to detect the case where someone treats a string arg
// like a bool:
// --my_string_var --foo=bar
// We look for a flag of string type, whose value begins with a
// dash, and where the flag-name and value are separated by a
// space rather than an '='.
// To avoid false positives, we also require the word "true"
// or "false" in the help string. Without this, a valid usage
// "-lat -30.5" would trigger the warning. The common cases we
// want to solve talk about true and false as values.
if (value[0] == '-'
&& strcmp(flag->type_name(), "string") == 0
&& (strstr(flag->help(), "true")
|| strstr(flag->help(), "false"))) {
fprintf(stderr, "Did you really mean to set flag '%s'"
" to the value '%s'?\n",
flag->name(), value);
}
}
}
......@@ -1343,15 +1362,6 @@ bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) {
// values in a global destructor.
// --------------------------------------------------------------------
// TODO(csilvers): When we're ready to have this error be a fatal one,
// change this to give a compilation error (via COMPILE_ASSERT(false)).
bool FlagsTypeWarn(const char *name) {
cerr << "Flag " << name << " is of type bool, but its default"
<< " value is not a boolean. NOTE: This will soon be a"
<< " compilations error!";
return false;
}
FlagRegisterer::FlagRegisterer(const char* name, const char* type,
const char* help, const char* filename,
void* current_storage, void* defvalue_storage) {
......@@ -1530,7 +1540,7 @@ bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT) {
CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name) {
CommandLineFlagInfo info;
if (!GetCommandLineFlagInfo(name, &info)) {
fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exit", name);
fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exist\n", name);
commandlineflags_exitfunc(1); // almost certainly exit()
}
return info;
......
......@@ -415,7 +415,7 @@ class FlagRegisterer {
void* current_storage, void* defvalue_storage);
};
#ifndef SWIG // In swig, ignore the main flag declarations
extern bool FlagsTypeWarn(const char *name);
// If your application #defines STRIP_FLAG_HELP to a non-zero value
// before #including this file, we remove the help message from the
......@@ -424,6 +424,10 @@ class FlagRegisterer {
extern const char kStrippedFlagHelp[];
@ac_google_end_namespace@
#ifndef SWIG // In swig, ignore the main flag declarations
#if defined(STRIP_FLAG_HELP) && STRIP_FLAG_HELP > 0
// Need this construct to avoid the 'defined but not used' warning.
#define MAYBE_STRIPPED_HELP(txt) (false ? (txt) : kStrippedFlagHelp)
......@@ -459,26 +463,30 @@ extern const char kStrippedFlagHelp[];
} \
using fL##shorttype::FLAGS_##name
// For boolean flags, we want to do the extra check that the passed-in
// For DEFINE_bool, we want to do the extra check that the passed-in
// value is actually a bool, and not a string or something that can be
// coerced to a bool. These declarations (no definition needed!) will
// help us do that, and never evaluate from, which is important.
// We'll use 'sizeof(IsBool(val))' to distinguish.
// help us do that, and never evaluate From, which is important.
// We'll use 'sizeof(IsBool(val))' to distinguish. This code requires
// that the compiler have different sizes for bool & double. Since
// this is not guaranteed by the standard, we check it with a
// compile-time assert (msg[-1] will give a compile-time error).
namespace fLB {
struct CompileAssert {};
typedef CompileAssert expected_sizeof_double_neq_sizeof_bool[
(sizeof(double) != sizeof(bool)) ? 1 : -1];
template<typename From> double IsBoolFlag(const From& from);
bool IsBoolFlag(bool from);
}
extern bool FlagsTypeWarn(const char *name);
} // namespace fLB
#define DECLARE_bool(name) DECLARE_VARIABLE(bool,B, name)
// We have extra code here to make sure 'val' is actually a boolean.
#define DEFINE_bool(name,val,txt) namespace fLB { \
const bool FLAGS_nonono##name = \
(sizeof(@ac_google_namespace@::fLB::IsBoolFlag(val)) \
== sizeof(double)) \
? @ac_google_namespace@::FlagsTypeWarn(#name) : true; \
} \
DEFINE_VARIABLE(bool,B, name, val, txt)
#define DEFINE_bool(name,val,txt) \
namespace fLB { \
typedef CompileAssert FLAG_##name##_value_is_not_a_bool[ \
(sizeof(::fLB::IsBoolFlag(val)) != sizeof(double)) ? 1 : -1]; \
} \
DEFINE_VARIABLE(bool,B, name, val, txt)
#define DECLARE_int32(name) DECLARE_VARIABLE(@ac_google_namespace@::int32,I, name)
#define DEFINE_int32(name,val,txt) DEFINE_VARIABLE(@ac_google_namespace@::int32,I, name, val, txt)
......@@ -522,6 +530,4 @@ extern bool FlagsTypeWarn(const char *name);
#endif // SWIG
@ac_google_end_namespace@
#endif // GOOGLE_GFLAGS_H_
// Copyright (c) 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
// Author: Roberto Bayardo
//
// A negative compile test for commandlineflags.
#include <gflags/gflags.h>
#if defined(TEST_SWAPPED_ARGS)
DEFINE_bool(some_bool_flag,
"the default value should go here, not the description",
false);
#elif defined(TEST_INT_INSTEAD_OF_BOOL)
DEFINE_bool(some_bool_flag_2,
0,
"should have been an int32 flag but mistakenly used bool instead");
#elif defined(TEST_BOOL_IN_QUOTES)
DEFINE_bool(some_bool_flag_3,
"false",
"false in in quotes, which is wrong");
#elif defined(SANITY)
DEFINE_bool(some_bool_flag_4,
true,
"this is the correct usage of DEFINE_bool");
#endif
......@@ -57,6 +57,28 @@ using GOOGLE_NAMESPACE::FlagRegisterer;
// Returns the number of elements in an array.
#define GET_ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*(arr)))
#if !defined(HAVE_SETENV) && defined(HAVE_PUTENV) // mingw, at least
void setenv(const char* name, const char* value, int) {
// In windows, it's impossible to set a variable to the empty string.
// We handle this by setting it to "0" and the NUL-ing out the \0.
// cf http://svn.apache.org/viewvc/stdcxx/trunk/tests/src/environ.cpp?r1=611451&r2=637508&pathrev=637508
static const char* const kFakeZero = "0";
if (*value == '\0')
value = kFakeZero;
// Apparently the semantics of putenv() is that the input
// must live forever, so we leak memory here. :-(
const int nameval_len = strlen(name) + 1 + strlen(value) + 1;
char* nameval = reinterpret_cast<char*>(malloc(nameval_len));
snprintf(nameval, nameval_len, "%s=%s", name, value);
putenv(nameval);
if (value == kFakeZero) {
nameval[nameval_len - 2] = '\0'; // works when putenv() makes no copy
if (*getenv(name) != '\0')
*getenv(name) = '\0'; // works when putenv() copies nameval
}
}
#endif
DECLARE_string(tryfromenv); // in gflags.cc
DEFINE_string(test_tmpdir, "/tmp/gflags_unittest", "Dir we use for temp files");
......@@ -86,18 +108,6 @@ DEFINE_string(test_str3, "initial", "");
// This is used to test setting tryfromenv manually
DEFINE_string(test_tryfromenv, "initial", "");
// boolean flag assigned correctly with bool
DEFINE_bool(test_bool_bool, true, "");
// boolean flag assigned with string
DEFINE_bool(test_bool_string, "", "");
// boolean flag assigned with float
DEFINE_bool(test_bool_float, 1.0, "");
// boolean flag assigned with int
DEFINE_bool(test_bool_int, 1, "");
// Don't try this at home!
static int changeable_var = 12;
DEFINE_int32(changeable_var, ++changeable_var, "");
......@@ -249,7 +259,11 @@ vector<void (*)()> g_testlist; // the tests to run
#define TEST(a, b) \
struct Test_##a##_##b { \
Test_##a##_##b() { g_testlist.push_back(&Run); } \
static void Run() { FlagSaver fs; RunTest(); } \
static void Run() { \
FlagSaver fs; \
fprintf(stderr, "Running test %s/%s\n", #a, #b); \
RunTest(); \
} \
static void RunTest(); \
}; \
static Test_##a##_##b g_test_##a##_##b; \
......@@ -416,6 +430,7 @@ TEST(FlagFileTest, FilenamesOurfileFirst) {
-1.0);
}
#ifdef HAVE_FNMATCH_H // otherwise glob isn't supported
TEST(FlagFileTest, FilenamesOurfileGlob) {
FLAGS_test_string = "initial";
FLAGS_test_bool = false;
......@@ -467,6 +482,7 @@ TEST(FlagFileTest, FilenamesOurfileInBigList) {
1,
-1.0);
}
#endif
// Tests that a failed flag-from-string read keeps flags at default values
TEST(FlagFileTest, FailReadFlagsFromString) {
......@@ -540,8 +556,11 @@ TEST(SetFlagValueTest, OrdinaryValues) {
// Tests that flags can be set to exceptional values.
// Note: apparently MINGW doesn't parse inf and nan correctly:
// http://www.mail-archive.com/bug-gnulib@gnu.org/msg09573.html
// This url says FreeBSD also has a problem, but I didn't see that.
TEST(SetFlagValueTest, ExceptionalValues) {
#ifdef isinf // on systems without isinf, inf stuff may not work at all
#if defined(isinf) && !defined(__MINGW32__)
EXPECT_EQ("test_double set to inf\n",
SetCommandLineOption("test_double", "inf"));
EXPECT_INF(FLAGS_test_double);
......@@ -558,14 +577,14 @@ TEST(SetFlagValueTest, ExceptionalValues) {
SetCommandLineOption("test_double", " "));
EXPECT_EQ("",
SetCommandLineOption("test_double", ""));
#ifdef isinf
#if defined(isinf) && !defined(__MINGW32__)
EXPECT_EQ("test_double set to -inf\n",
SetCommandLineOption("test_double", "-inf"));
EXPECT_INF(FLAGS_test_double);
EXPECT_GT(0, FLAGS_test_double);
#endif
#ifdef isnan
#if defined(isnan) && !defined(__MINGW32__)
EXPECT_EQ("test_double set to nan\n",
SetCommandLineOption("test_double", "NaN"));
EXPECT_NAN(FLAGS_test_double);
......@@ -1499,7 +1518,13 @@ static int Main(int argc, char **argv) {
SetUsageMessage(usage_message.c_str());
ParseCommandLineFlags(&argc, &argv, true);
#ifdef __MINGW32__
// I had trouble creating a directory in /tmp from mingw
FLAGS_test_tmpdir = "./gflags_unittest_testdir";
mkdir(FLAGS_test_tmpdir.c_str()); // mingw has a weird one-arg mkdir
#else
mkdir(FLAGS_test_tmpdir.c_str(), 0755);
#endif
return RUN_ALL_TESTS();
}
......
......@@ -215,14 +215,6 @@ Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" \
# Make sure -- by itself stops argv processing
Expect $LINENO 0 "PASS" "" -- --help
# Make sure boolean flags gives warning when type of default value is not bool
Expect $LINENO 0 "Flag test_bool_string is of type bool, but its default value is not a boolean." ""
Expect $LINENO 0 "Flag test_bool_float is of type bool, but its default value is not a boolean." ""
Expect $LINENO 0 "Flag test_bool_int is of type bool, but its default value is not a boolean." ""
# Make sure that boolean flags don't give warning when default value is bool
Expect $LINENO 0 "" "Flag test_bool_bool is of type bool, but its default value is not a boolean."
# And we should die if the flag value doesn't pas the validator
Expect $LINENO 1 "ERROR: failed validation of new value 'true' for flag 'always_fail'" "" --always_fail
......
......@@ -38,9 +38,12 @@
// AC_RWLOCK
// The latter is defined in ../autoconf.
//
// This class is meant to be internal-only, so it's defined in the
// global namespace. If you want to expose it, you'll want to move
// it to the Google namespace.
// This class is meant to be internal-only and should be wrapped by an
// internal namespace. Before you use this module, please give the
// name of your internal namespace for this module. Or, if you want
// to expose it, you'll want to move it to the Google namespace. We
// cannot put this class in global namespace because there can be some
// problems when we have multiple versions of Mutex in each shared object.
//
// NOTE: by default, we have #ifdef'ed out the TryLock() method.
// This is for two reasons:
......@@ -95,6 +98,16 @@
// colon-initializer) and set it to true via a function that always
// evaluates to true, but that the compiler can't know always
// evaluates to true. This should be good enough.
//
// A related issue is code that could try to access the mutex
// after it's been destroyed in the global destructors (because
// the Mutex global destructor runs before some other global
// destructor, that tries to acquire the mutex). The way we
// deal with this is by taking a constructor arg that global
// mutexes should pass in, that causes the destructor to do no
// work. We still depend on the compiler not doing anything
// weird to a Mutex's memory after it is destroyed, but for a
// static global variable, that's pretty safe.
#ifndef GOOGLE_MUTEX_H_
#define GOOGLE_MUTEX_H_
......@@ -132,13 +145,26 @@
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif
#include <assert.h>
#include <stdlib.h> // for abort()
#define MUTEX_NAMESPACE gflags_mutex_namespace
namespace MUTEX_NAMESPACE {
class Mutex {
public:
// This is used for the single-arg constructor
enum LinkerInitialized { LINKER_INITIALIZED };
// Create a Mutex that is not held by anybody. This constructor is
// typically used for Mutexes allocated on the heap or the stack.
// See below for a recommendation for constructing global Mutex
// objects.
inline Mutex();
// This constructor should be used for global, static Mutex objects.
// It inhibits work being done by the destructor, which makes it
// safer for code that tries to acqiure this mutex in their global
// destructor.
inline Mutex(LinkerInitialized);
// Destructor
inline ~Mutex();
......@@ -163,6 +189,8 @@ class Mutex {
// when we tell it to, and never makes assumptions is_safe_ is
// always true. volatile is the most reliable way to do that.
volatile bool is_safe_;
// This indicates which constructor was called.
bool destroy_;
inline void SetIsSafe() { is_safe_ = true; }
......@@ -185,9 +213,9 @@ class Mutex {
// In debug mode, we assert these invariants, while in non-debug mode
// we do nothing, for efficiency. That's why everything is in an
// assert.
#include <assert.h>
Mutex::Mutex() : mutex_(0) { }
Mutex::Mutex(Mutex::LinkerInitialized) : mutex_(0) { }
Mutex::~Mutex() { assert(mutex_ == 0); }
void Mutex::Lock() { assert(--mutex_ == -1); }
void Mutex::Unlock() { assert(mutex_++ == -1); }
......@@ -199,8 +227,15 @@ void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
Mutex::Mutex() : destroy_(true) {
InitializeCriticalSection(&mutex_);
SetIsSafe();
}
Mutex::Mutex(LinkerInitialized) : destroy_(false) {
InitializeCriticalSection(&mutex_);
SetIsSafe();
}
Mutex::~Mutex() { if (destroy_) DeleteCriticalSection(&mutex_); }
void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
#ifdef GMUTEX_TRYLOCK
......@@ -212,22 +247,24 @@ void Mutex::ReaderUnlock() { Unlock(); }
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#include <stdlib.h> // for abort()
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
Mutex::Mutex() : destroy_(true) {
SetIsSafe();
if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
}
Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) {
SetIsSafe();
if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_rwlock_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_rwlock_trywrlock(&mutex_) == 0 :
true; }
pthread_rwlock_trywrlock(&mutex_) == 0 : true; }
#endif
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
......@@ -235,16 +272,19 @@ void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#elif defined(HAVE_PTHREAD)
#include <stdlib.h> // for abort()
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
Mutex::Mutex() : destroy_(true) {
SetIsSafe();
if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) {
SetIsSafe();
if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
}
Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_mutex_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
#ifdef GMUTEX_TRYLOCK
......@@ -300,4 +340,10 @@ class WriterMutexLock {
#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
} // namespace MUTEX_NAMESPACE
using namespace MUTEX_NAMESPACE;
#undef MUTEX_NAMESPACE
#endif /* #define GOOGLE_MUTEX_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment