Commit 585a44a0 authored by Craig Silverstein's avatar Craig Silverstein

Thu Oct 18 11:33:20 2007 Google Inc. <opensource@google.com>

	* google-gflags: version 0.7
	* Deal even more correctly with libpthread not linked in (csilvers)
	* Add STRIP_LOG, an improved DO_NOT_SHOW_COMMANDLINE_HELP (sioffe)
	* Be more accurate printing default flag values in --help (dsturtevant)
	* Reduce .o file size a bit by using shorter namespace names (jeff)
	* Use relative install path, so 'setup.py --home' works (csilvers)
	* Notice when a boolean flag has a non-boolean default (bnmouli)
	* Broaden --helpshort to match foo-main.cc and foo_main.cc (hendrie)
	* Fix "no modules match" message for --helpshort, etc (hendrie)


git-svn-id: https://gflags.googlecode.com/svn/trunk@19 6586e3c6-dcc4-952a-343f-ff74eb82781d
parent eb208399
Thu Oct 18 11:33:20 2007 Google Inc. <opensource@google.com>
* google-gflags: version 0.7
* Deal even more correctly with libpthread not linked in (csilvers)
* Add STRIP_LOG, an improved DO_NOT_SHOW_COMMANDLINE_HELP (sioffe)
* Be more accurate printing default flag values in --help (dsturtevant)
* Reduce .o file size a bit by using shorter namespace names (jeff)
* Use relative install path, so 'setup.py --home' works (csilvers)
* Notice when a boolean flag has a non-boolean default (bnmouli)
* Broaden --helpshort to match foo-main.cc and foo_main.cc (hendrie)
* Fix "no modules match" message for --helpshort, etc (hendrie)
Wed Aug 15 07:35:51 2007 Google Inc. <opensource@google.com> Wed Aug 15 07:35:51 2007 Google Inc. <opensource@google.com>
* google-gflags: version 0.6 * google-gflags: version 0.6
......
...@@ -35,7 +35,8 @@ TESTS_ENVIRONMENT = SRCDIR="$(top_srcdir)" ...@@ -35,7 +35,8 @@ TESTS_ENVIRONMENT = SRCDIR="$(top_srcdir)"
check_SCRIPTS = check_SCRIPTS =
# Every time you add a unittest to check_SCRIPTS, add it here too # Every time you add a unittest to check_SCRIPTS, add it here too
noinst_SCRIPTS = noinst_SCRIPTS =
# Used for auto-generated source files
CLEANFILES =
## vvvv RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS ## vvvv RULES TO MAKE THE LIBRARIES, BINARIES, AND UNITTESTS
...@@ -58,10 +59,32 @@ TESTS += gflags_nothreads_unittest ...@@ -58,10 +59,32 @@ TESTS += gflags_nothreads_unittest
gflags_nothreads_unittest_SOURCES = $(gflags_unittest_SOURCES) gflags_nothreads_unittest_SOURCES = $(gflags_unittest_SOURCES)
gflags_nothreads_unittest_LDADD = libgflags.la gflags_nothreads_unittest_LDADD = libgflags.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
gflags_unittest2_SOURCES = $(googleinclude_HEADERS) src/config.h \
src/gflags_unittest-main.cc
gflags_unittest2_LDADD = libgflags.la
src/gflags_unittest-main.cc: src/gflags_unittest.cc
rm -f src/gflags_unittest-main.cc
cp -p src/gflags_unittest.cc src/gflags_unittest-main.cc
CLEANFILES += src/gflags_unittest-main.cc
TESTS += gflags_unittest3
gflags_unittest3_SOURCES = $(googleinclude_HEADERS) src/config.h \
src/gflags_unittest_main.cc
gflags_unittest3_LDADD = libgflags.la
src/gflags_unittest_main.cc: src/gflags_unittest.cc
rm -f src/gflags_unittest_main.cc
cp -p src/gflags_unittest.cc src/gflags_unittest_main.cc
CLEANFILES += src/gflags_unittest_main.cc
check_SCRIPTS += gflags_unittest_sh check_SCRIPTS += gflags_unittest_sh
noinst_SCRIPTS += src/gflags_unittest.sh noinst_SCRIPTS += src/gflags_unittest.sh
dist_noinst_DATA = $(top_srcdir)/src/gflags_unittest_flagfile dist_noinst_DATA = $(top_srcdir)/src/gflags_unittest_flagfile
gflags_unittest_sh: gflags_unittest gflags_unittest_sh: gflags_unittest gflags_unittest2 gflags_unittest3
$(top_srcdir)/src/gflags_unittest.sh $(PWD)/$< $(top_srcdir) $(top_srcdir)/src/gflags_unittest.sh $(PWD)/$< $(top_srcdir)
# These aren't part of the c++ source, but we want them to be distributed # These aren't part of the c++ source, but we want them to be distributed
......
This diff is collapsed.
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59 for gflags 0.6. # Generated by GNU Autoconf 2.59 for gflags 0.7.
# #
# Report bugs to <opensource@google.com>. # Report bugs to <opensource@google.com>.
# #
...@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} ...@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package. # Identity of this package.
PACKAGE_NAME='gflags' PACKAGE_NAME='gflags'
PACKAGE_TARNAME='gflags' PACKAGE_TARNAME='gflags'
PACKAGE_VERSION='0.6' PACKAGE_VERSION='0.7'
PACKAGE_STRING='gflags 0.6' PACKAGE_STRING='gflags 0.7'
PACKAGE_BUGREPORT='opensource@google.com' PACKAGE_BUGREPORT='opensource@google.com'
ac_unique_file="README" ac_unique_file="README"
...@@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then ...@@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures gflags 0.6 to adapt to many kinds of systems. \`configure' configures gflags 0.7 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
...@@ -1020,7 +1020,7 @@ fi ...@@ -1020,7 +1020,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of gflags 0.6:";; short | recursive ) echo "Configuration of gflags 0.7:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
...@@ -1163,7 +1163,7 @@ fi ...@@ -1163,7 +1163,7 @@ fi
test -n "$ac_init_help" && exit 0 test -n "$ac_init_help" && exit 0
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
gflags configure 0.6 gflags configure 0.7
generated by GNU Autoconf 2.59 generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc. Copyright (C) 2003 Free Software Foundation, Inc.
...@@ -1177,7 +1177,7 @@ cat >&5 <<_ACEOF ...@@ -1177,7 +1177,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by gflags $as_me 0.6, which was It was created by gflags $as_me 0.7, which was
generated by GNU Autoconf 2.59. Invocation command line was generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@ $ $0 $@
...@@ -1823,7 +1823,7 @@ fi ...@@ -1823,7 +1823,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='gflags' PACKAGE='gflags'
VERSION='0.6' VERSION='0.7'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
...@@ -20943,7 +20943,7 @@ _ASBOX ...@@ -20943,7 +20943,7 @@ _ASBOX
} >&5 } >&5
cat >&5 <<_CSEOF cat >&5 <<_CSEOF
This file was extended by gflags $as_me 0.6, which was This file was extended by gflags $as_me 0.7, which was
generated by GNU Autoconf 2.59. Invocation command line was generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
...@@ -21006,7 +21006,7 @@ _ACEOF ...@@ -21006,7 +21006,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\ ac_cs_version="\\
gflags config.status 0.6 gflags config.status 0.7
configured by $0, generated by GNU Autoconf 2.59, configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# make sure we're interpreted by some minimal autoconf # make sure we're interpreted by some minimal autoconf
AC_PREREQ(2.57) AC_PREREQ(2.57)
AC_INIT(gflags, 0.6, opensource@google.com) AC_INIT(gflags, 0.7, opensource@google.com)
# The argument here is just something that should be in the current directory # The argument here is just something that should be in the current directory
# (for sanity checking) # (for sanity checking)
AC_CONFIG_SRCDIR(README) AC_CONFIG_SRCDIR(README)
......
...@@ -434,6 +434,19 @@ name (<code>argv[0]</code>).</p> ...@@ -434,6 +434,19 @@ name (<code>argv[0]</code>).</p>
methods such as <code>google::SetUsageMessage</code>, see methods such as <code>google::SetUsageMessage</code>, see
<code>gflags.h</code>.</p> <code>gflags.h</code>.</p>
<h2> <A name="misc">Miscellaneous Notes</code> </h2>
<p>If your application has code like this:</p>
<pre>
#define STRIP_FLAG_HELP 1 // this must go before the #include!
#include &lt;google/gflags.h&gt;
</pre>
<p>we will remove the help messages from the compiled source. This can
reduce the size of the resulting binary somewhat, and may also be
useful for security reasons.</p>
<hr> <hr>
<address> <address>
Craig Silverstein<br> Craig Silverstein<br>
......
This diff is collapsed.
This diff is collapsed.
google-gflags (0.7-1) unstable; urgency=low
* New upstream release.
-- Google Inc. <opensource@google.com> Thu, 18 Oct 2007 11:33:20 -0700
google-gflags (0.6-2) unstable; urgency=low google-gflags (0.6-2) unstable; urgency=low
* Somehow 0.6-1 was missing the lib* control files, so the .deb produced * Somehow 0.6-1 was missing the lib* control files, so the .deb produced
......
...@@ -171,7 +171,7 @@ EXAMPLE USAGE: ...@@ -171,7 +171,7 @@ EXAMPLE USAGE:
sys.exit(1) sys.exit(1)
if FLAGS.debug: print 'non-flag arguments:', argv if FLAGS.debug: print 'non-flag arguments:', argv
print 'Happy Birthday', FLAGS.name print 'Happy Birthday', FLAGS.name
if FLAGS.age != None: if FLAGS.age is not None:
print "You are a %s, who is %d years old" % (FLAGS.gender, FLAGS.age) print "You are a %s, who is %d years old" % (FLAGS.gender, FLAGS.age)
if __name__ == '__main__': main(sys.argv) if __name__ == '__main__': main(sys.argv)
......
#!/usr/bin/python2.2 #!/usr/bin/env python
# Copyright (c) 2007, Google Inc. # Copyright (c) 2007, Google Inc.
# All rights reserved. # All rights reserved.
...@@ -39,4 +39,4 @@ setup(name='gflags', ...@@ -39,4 +39,4 @@ setup(name='gflags',
author_email='opensource@google.com', author_email='opensource@google.com',
url='http://code.google.com/p/google-gflags', url='http://code.google.com/p/google-gflags',
py_modules=["gflags"], py_modules=["gflags"],
data_files=[("/usr/local/bin", ["gflags2man.py"])]) data_files=[("bin", ["gflags2man.py"])])
...@@ -93,6 +93,13 @@ _START_GOOGLE_NAMESPACE_ ...@@ -93,6 +93,13 @@ _START_GOOGLE_NAMESPACE_
static const char kError[] = "ERROR: "; static const char kError[] = "ERROR: ";
// The help message indicating that the commandline flag has been
// 'stripped'. It will not show up when doing "-help" and its
// variants. The flag is stripped if STRIP_FLAG_HELP is set to 1
// before including base/commandlineflags.h (or in
// base/global_strip_options.h).
const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
// Indicates that undefined options are to be ignored. // Indicates that undefined options are to be ignored.
// Enables deferred processing of flags in dynamically loaded libraries. // Enables deferred processing of flags in dynamically loaded libraries.
...@@ -637,7 +644,20 @@ void FlagRegistry::InitGlobalRegistry() { ...@@ -637,7 +644,20 @@ void FlagRegistry::InitGlobalRegistry() {
} }
// We want to use pthread_once here, for safety, but have to worry about // We want to use pthread_once here, for safety, but have to worry about
// whether libpthread is linked in or not. // whether libpthread is linked in or not. We declare a weak version of
// the function, so we'll always compile (if the weak version is the only
// one that ends up existing, then pthread_once will be equal to NULL).
#ifdef HAVE___ATTRIBUTE__
// __THROW is defined in glibc systems. It means, counter-intuitively,
// "This function will never throw an exception." It's an optional
// optimization tool, but we may need to use it to match glibc prototypes.
# ifndef __THROW // I guess we're not on a glibc system
# define __THROW // __THROW is just an optimization, so ok to make it ""
# endif
extern "C" int pthread_once(pthread_once_t *, void (*)(void))
__THROW __attribute__((weak));
#endif
FlagRegistry* FlagRegistry::GlobalRegistry() { FlagRegistry* FlagRegistry::GlobalRegistry() {
if (pthread_once) { // means we're running with pthreads if (pthread_once) { // means we're running with pthreads
pthread_once(&global_registry_once_, &FlagRegistry::InitGlobalRegistry); pthread_once(&global_registry_once_, &FlagRegistry::InitGlobalRegistry);
...@@ -648,6 +668,14 @@ FlagRegistry* FlagRegistry::GlobalRegistry() { ...@@ -648,6 +668,14 @@ FlagRegistry* FlagRegistry::GlobalRegistry() {
return global_registry_; return global_registry_;
} }
void FlagsTypeWarn(const char *name) {
fprintf(stderr, "ERROR: Flag %s is of type bool, "
"but its default value is not a boolean.\n", name);
// This can (and one day should) become a compilations error
//commandlineflags_exitfunc(1); // almost certainly exit()
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// FlagRegisterer // FlagRegisterer
// This class exists merely to have a global constructor (the // This class exists merely to have a global constructor (the
......
...@@ -158,12 +158,22 @@ static string DescribeOneFlag(const CommandLineFlagInfo& flag) { ...@@ -158,12 +158,22 @@ static string DescribeOneFlag(const CommandLineFlagInfo& flag) {
// Append data type // Append data type
AddString(string("type: ") + flag.type, &final_string, &chars_in_line); AddString(string("type: ") + flag.type, &final_string, &chars_in_line);
// Append default value // Append the effective default value (i.e., the value that the flag
// will have after the command line is parsed if the flag is not
// specified on the command line), which may be different from the
// stored default value. This would happen if the value of the flag
// was modified before the command line was parsed. (Unless the
// value was modified using SetCommandLineOptionWithMode() with mode
// SET_FLAGS_DEFAULT.)
// Note that we are assuming this code is being executed because a help
// request was just parsed from the command line, in which case the
// printed value is indeed the effective default, as long as no value
// for the flag was parsed from the command line before "--help".
if (strcmp(flag.type.c_str(), "string") == 0) { // add quotes for strings if (strcmp(flag.type.c_str(), "string") == 0) { // add quotes for strings
AddString(string("default: \"") + flag.default_value + string("\""), AddString(string("default: \"") + flag.current_value + string("\""),
&final_string, &chars_in_line); &final_string, &chars_in_line);
} else { } else {
AddString(string("default: ") + flag.default_value, AddString(string("default: ") + flag.current_value,
&final_string, &chars_in_line); &final_string, &chars_in_line);
} }
...@@ -217,24 +227,42 @@ static string Dirname(const string& filename) { ...@@ -217,24 +227,42 @@ static string Dirname(const string& filename) {
return filename.substr(0, (sep == string::npos) ? 0 : sep); return filename.substr(0, (sep == string::npos) ? 0 : sep);
} }
void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict) { // Test whether a filename contains at least one of the substrings.
#ifndef DO_NOT_SHOW_COMMANDLINE_HELP static bool FileMatchesSubstring(const string& filename,
const vector<string>& substrings) {
for (vector<string>::const_iterator target = substrings.begin();
target != substrings.end();
++target) {
if (strstr(filename.c_str(), target->c_str()) != NULL) {
return true;
}
}
return false;
}
// Show help for every filename which matches any of the target substrings.
// If substrings is empty, shows help for every file. If a flag's help message
// has been stripped (e.g. by adding '#define STRIP_FLAG_HELP 1' to
// base/global_strip_options.h), then this flag will not be displayed by
// '--help' and its variants.
static void ShowUsageWithFlagsMatching(const char *argv0,
const vector<string> &substrings) {
fprintf(stdout, "%s: %s\n", Basename(argv0), ProgramUsage()); fprintf(stdout, "%s: %s\n", Basename(argv0), ProgramUsage());
vector<CommandLineFlagInfo> flags; vector<CommandLineFlagInfo> flags;
GetAllFlags(&flags); // flags are sorted by filename, then flagname GetAllFlags(&flags); // flags are sorted by filename, then flagname
const bool have_restrict = (restrict != NULL) && (*restrict != '\0');
string last_filename = ""; // so we know when we're at a new file string last_filename = ""; // so we know when we're at a new file
bool first_directory = true; // controls blank lines between dirs bool first_directory = true; // controls blank lines between dirs
bool found_match = false; // stays false iff no dir matches restrict bool found_match = false; // stays false iff no dir matches restrict
for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin(); for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin();
flag != flags.end(); flag != flags.end();
++flag) { ++flag) {
if (have_restrict && strstr(flag->filename.c_str(), restrict) == NULL) { if (substrings.empty() ||
continue; // this flag doesn't pass the restrict FileMatchesSubstring(flag->filename, substrings)) {
} // If the flag has been stripped, pretend that it doesn't exist.
found_match = true; // this flag passed the restrict! if (flag->description == kStrippedFlagHelp) continue;
found_match = true; // this flag passed the match!
if (flag->filename != last_filename) { // new file if (flag->filename != last_filename) { // new file
if (Dirname(flag->filename) != Dirname(last_filename)) { // new dir! if (Dirname(flag->filename) != Dirname(last_filename)) { // new dir!
if (!first_directory) if (!first_directory)
...@@ -247,11 +275,18 @@ void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict) { ...@@ -247,11 +275,18 @@ void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict) {
// Now print this flag // Now print this flag
fprintf(stdout, "%s", DescribeOneFlag(*flag).c_str()); fprintf(stdout, "%s", DescribeOneFlag(*flag).c_str());
} }
if (!found_match && restrict == NULL) {
fprintf(stdout, "\n No modules matched program name `%s': use -help\n",
Basename(argv0));
} }
#endif // DO_NOT_SHOW_COMMANDLINE_HELP if (!found_match && !substrings.empty()) {
fprintf(stdout, "\n No modules matched: use -help\n");
}
}
void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict) {
vector<string> substrings;
if (restrict != NULL && *restrict != '\0') {
substrings.push_back(restrict);
}
ShowUsageWithFlagsMatching(argv0, substrings);
} }
void ShowUsageWithFlags(const char *argv0) { void ShowUsageWithFlags(const char *argv0) {
...@@ -276,6 +311,7 @@ static void ShowXMLOfFlags(const char *prog_name) { ...@@ -276,6 +311,7 @@ static void ShowXMLOfFlags(const char *prog_name) {
for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin(); for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin();
flag != flags.end(); flag != flags.end();
++flag) { ++flag) {
if (flag->description != kStrippedFlagHelp)
fprintf(stdout, "%s\n", DescribeOneFlagInXML(*flag).c_str()); fprintf(stdout, "%s\n", DescribeOneFlagInXML(*flag).c_str());
} }
// The end of the document // The end of the document
...@@ -312,8 +348,11 @@ void HandleCommandLineHelpFlags() { ...@@ -312,8 +348,11 @@ void HandleCommandLineHelpFlags() {
if (FLAGS_helpshort) { if (FLAGS_helpshort) {
// show only flags related to this binary: // show only flags related to this binary:
// E.g. for fileutil.cc, want flags containing ... "/fileutil." cc // E.g. for fileutil.cc, want flags containing ... "/fileutil." cc
string restrict = string("/") + progname + "."; vector<string> substrings;
ShowUsageWithFlagsRestrict(progname, restrict.c_str()); substrings.push_back(string("/") + progname + ".");
substrings.push_back(string("/") + progname + "-main.");
substrings.push_back(string("/") + progname + "_main.");
ShowUsageWithFlagsMatching(progname, substrings);
commandlineflags_exitfunc(1); // almost certainly exit() commandlineflags_exitfunc(1); // almost certainly exit()
} else if (FLAGS_help || FLAGS_helpfull) { } else if (FLAGS_help || FLAGS_helpfull) {
...@@ -338,12 +377,15 @@ void HandleCommandLineHelpFlags() { ...@@ -338,12 +377,15 @@ void HandleCommandLineHelpFlags() {
// filename like "/progname.cc", and take the dirname of that. // filename like "/progname.cc", and take the dirname of that.
vector<CommandLineFlagInfo> flags; vector<CommandLineFlagInfo> flags;
GetAllFlags(&flags); GetAllFlags(&flags);
const string restrict = string("/") + progname + "."; vector<string> substrings;
substrings.push_back(string("/") + progname + ".");
substrings.push_back(string("/") + progname + "-main.");
substrings.push_back(string("/") + progname + "_main.");
string last_package = ""; string last_package = "";
for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin(); for (vector<CommandLineFlagInfo>::const_iterator flag = flags.begin();
flag != flags.end(); flag != flags.end();
++flag) { ++flag) {
if (!strstr(flag->filename.c_str(), restrict.c_str())) if (!FileMatchesSubstring(flag->filename, substrings))
continue; continue;
const string package = Dirname(flag->filename) + "/"; const string package = Dirname(flag->filename) + "/";
if (package != last_package) { if (package != last_package) {
......
...@@ -79,6 +79,18 @@ DEFINE_string(test_str3, "initial", ""); ...@@ -79,6 +79,18 @@ DEFINE_string(test_str3, "initial", "");
// This is used to test setting tryfromenv manually // This is used to test setting tryfromenv manually
DEFINE_string(test_tryfromenv, "initial", ""); 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, "");
// These are never used in this unittest, but can be used by // These are never used in this unittest, but can be used by
// commandlineflags_unittest.sh when it needs to specify flags // commandlineflags_unittest.sh when it needs to specify flags
// that are legal for commandlineflags_unittest but don't need to // that are legal for commandlineflags_unittest but don't need to
...@@ -90,6 +102,10 @@ DEFINE_uint64(unused_uint64, 2000, ""); ...@@ -90,6 +102,10 @@ DEFINE_uint64(unused_uint64, 2000, "");
DEFINE_double(unused_double, -1000.0, ""); DEFINE_double(unused_double, -1000.0, "");
DEFINE_string(unused_string, "unused", ""); DEFINE_string(unused_string, "unused", "");
// These flags are used by gflags_unittest.sh
DEFINE_bool(changed_bool1, false, "changed");
DEFINE_bool(changed_bool2, false, "changed");
_START_GOOGLE_NAMESPACE_ _START_GOOGLE_NAMESPACE_
// The following is some bare-bones testing infrastructure // The following is some bare-bones testing infrastructure
...@@ -1110,6 +1126,12 @@ static int Main(int argc, char **argv) { ...@@ -1110,6 +1126,12 @@ static int Main(int argc, char **argv) {
FLAGS_tryfromenv = "test_tryfromenv"; FLAGS_tryfromenv = "test_tryfromenv";
setenv("FLAGS_test_tryfromenv", "pre-set", 1); setenv("FLAGS_test_tryfromenv", "pre-set", 1);
// Modify flag values from declared default value in two ways.
// The recommended way:
SetCommandLineOptionWithMode("changed_bool1", "true", SET_FLAGS_DEFAULT);
// The non-recommended way:
FLAGS_changed_bool2 = true;
SetUsageMessage(usage_message.c_str()); SetUsageMessage(usage_message.c_str());
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
......
...@@ -46,9 +46,16 @@ EXE=$1 ...@@ -46,9 +46,16 @@ EXE=$1
SRCDIR=${2:-./} SRCDIR=${2:-./}
TMPDIR=${3:-/tmp/gflags} TMPDIR=${3:-/tmp/gflags}
# $1: line-number $2: expected return code. $3: substring of expected output. # Executables built with the main source file suffixed with "-main" and "_main".
# $4: a substring you *don't* expect to find in the output. $5+ flags EXE2=${EXE}2 # eg, gflags_unittest2
Expect() { EXE3=${EXE}3 # eg, gflags_unittest3
# $1: executable
# $2: line-number $3: expected return code. $4: substring of expected output.
# $5: a substring you *don't* expect to find in the output. $6+ flags
ExpectExe() {
local executable="$1"
shift
local line_number="$1" local line_number="$1"
shift shift
local expected_rc="$1" local expected_rc="$1"
...@@ -59,7 +66,7 @@ Expect() { ...@@ -59,7 +66,7 @@ Expect() {
shift shift
# We always add --srcdir=$SRCDIR because it's needed for correctness # We always add --srcdir=$SRCDIR because it's needed for correctness
$EXE --srcdir="$SRCDIR" "$@" > "$TMPDIR/test.$line_number" 2>&1 $executable --srcdir="$SRCDIR" "$@" > "$TMPDIR/test.$line_number" 2>&1
local actual_rc=$? local actual_rc=$?
if [ $actual_rc != $expected_rc ]; then if [ $actual_rc != $expected_rc ]; then
echo "Test on line $line_number failed:" \ echo "Test on line $line_number failed:" \
...@@ -67,19 +74,25 @@ Expect() { ...@@ -67,19 +74,25 @@ Expect() {
exit 1; exit 1;
fi fi
if [ -n "$expected_output" ] && if [ -n "$expected_output" ] &&
! fgrep -q "$expected_output" "$TMPDIR/test.$line_number"; then ! fgrep -q -- "$expected_output" "$TMPDIR/test.$line_number"; then
echo "Test on line $line_number failed:" \ echo "Test on line $line_number failed:" \
"did not find expected substring '$expected_output'" "did not find expected substring '$expected_output'"
exit 1; exit 1;
fi fi
if [ -n "$unexpected_output" ] && if [ -n "$unexpected_output" ] &&
fgrep -q "$unexpected_output" "$TMPDIR/test.$line_number"; then fgrep -q -- "$unexpected_output" "$TMPDIR/test.$line_number"; then
echo "Test line $line_number failed:" \ echo "Test line $line_number failed:" \
"found unexpected substring '$unexpected_output'" "found unexpected substring '$unexpected_output'"
exit 1; exit 1;
fi fi
} }
# $1: line-number $2: expected return code. $3: substring of expected output.
# $4: a substring you *don't* expect to find in the output. $5+ flags
Expect() {
ExpectExe $EXE "$@"
}
rm -rf $TMPDIR rm -rf $TMPDIR
mkdir $TMPDIR || exit 2 mkdir $TMPDIR || exit 2
...@@ -101,6 +114,12 @@ Expect $LINENO 0 "PASS" "" ...@@ -101,6 +114,12 @@ Expect $LINENO 0 "PASS" ""
# --help should show all flags, including flags from gflags_reporting.cc # --help should show all flags, including flags from gflags_reporting.cc
Expect $LINENO 1 "/gflags_reporting.cc" "" --help Expect $LINENO 1 "/gflags_reporting.cc" "" --help
# Make sure --help reflects flag changes made before flag-parsing
Expect $LINENO 1 \
"-changed_bool1 (changed) type: bool default: true" "" --help
Expect $LINENO 1 \
"-changed_bool2 (changed) type: bool default: true" "" --help
# --nohelp and --help=false should be as if we didn't say anything # --nohelp and --help=false should be as if we didn't say anything
Expect $LINENO 0 "PASS" "" --nohelp Expect $LINENO 0 "PASS" "" --nohelp
Expect $LINENO 0 "PASS" "" --help=false Expect $LINENO 0 "PASS" "" --help=false
...@@ -111,6 +130,12 @@ Expect $LINENO 1 "/gflags_reporting.cc" "" -helpfull ...@@ -111,6 +130,12 @@ Expect $LINENO 1 "/gflags_reporting.cc" "" -helpfull
# --helpshort should show only flags from the unittest itself # --helpshort should show only flags from the unittest itself
Expect $LINENO 1 "/gflags_unittest.cc" "/gflags_reporting.cc" --helpshort Expect $LINENO 1 "/gflags_unittest.cc" "/gflags_reporting.cc" --helpshort
# --helpshort should work if the main source file is suffixed with [_-]main
ExpectExe $EXE2 $LINENO 1 "/gflags_unittest-main.cc" "/gflags_reporting.cc" \
--helpshort
ExpectExe $EXE3 $LINENO 1 "/gflags_unittest_main.cc" "/gflags_reporting.cc" \
--helpshort
# --helpon needs an argument # --helpon needs an argument
Expect $LINENO 1 "'--helpon' is missing its argument" "" --helpon Expect $LINENO 1 "'--helpon' is missing its argument" "" --helpon
...@@ -130,6 +155,12 @@ Expect $LINENO 1 "/gflags_unittest.cc" "/gflags.cc" \ ...@@ -130,6 +155,12 @@ Expect $LINENO 1 "/gflags_unittest.cc" "/gflags.cc" \
Expect $LINENO 1 "/gflags_unittest.cc" "/gflags.cc" \ Expect $LINENO 1 "/gflags_unittest.cc" "/gflags.cc" \
-helpmatch=unittest -helpmatch=unittest
# if no flags are found with helpmatch or helpon, suggest --help
Expect $LINENO 1 "No modules matched" "/commandlineflags_unittest.cc" \
-helpmatch=nosuchsubstring
Expect $LINENO 1 "No modules matched" "/commandlineflags_unittest.cc" \
-helpon=nosuchmodule
# helppackage shows all the flags in the same dir as this unittest # helppackage shows all the flags in the same dir as this unittest
# --help should show all flags, including flags from google.cc # --help should show all flags, including flags from google.cc
Expect $LINENO 1 "/gflags_reporting.cc" "" --helppackage Expect $LINENO 1 "/gflags_reporting.cc" "" --helppackage
...@@ -176,5 +207,13 @@ Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" \ ...@@ -176,5 +207,13 @@ Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" \
# Make sure -- by itself stops argv processing # Make sure -- by itself stops argv processing
Expect $LINENO 0 "PASS" "" -- --help 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."
echo "PASS" echo "PASS"
exit 0 exit 0
...@@ -293,6 +293,27 @@ extern void AllowCommandLineReparsing(); ...@@ -293,6 +293,27 @@ extern void AllowCommandLineReparsing();
extern uint32 ReparseCommandLineNonHelpFlags(); extern uint32 ReparseCommandLineNonHelpFlags();
// The following code is added to check if proper value types are passed to
// flags. Specially for boolean flags. Since almost anything can be implicitly
// casted to boolean many copy-paste type of errors got through and they are
// there in code now. As of now, flags_safe_cast is written such a way that
// it raises only warning for type mismatches.
//
// TODO(who?): This needs to be changed to give compilation error if type
// does not match.
extern void FlagsTypeWarn(const char *name);
template<typename From>
inline bool flags_safe_bool(From from, const char *name) {
FlagsTypeWarn(name);
return from;
}
inline bool flags_safe_bool(bool from, const char *name) {
return from;
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Now come the command line flag declaration/definition macros that // Now come the command line flag declaration/definition macros that
// will actually be used. They're kind of hairy. A major reason // will actually be used. They're kind of hairy. A major reason
...@@ -340,46 +361,66 @@ class FlagRegisterer { ...@@ -340,46 +361,66 @@ class FlagRegisterer {
}; };
// namespc should be 'std::', and type 'string', for a var of type 'std::string' // namespc should be 'std::', and type 'string', for a var of type 'std::string'
#define DECLARE_VARIABLE(namespc, type, name) \ #define DECLARE_VARIABLE(namespc, type, shorttype, name) \
namespace Flag_Names_##type { \ namespace fL##shorttype { \
extern namespc type& FLAGS_##name; \ extern namespc type& FLAGS_##name; \
} \ } \
using Flag_Names_##type::FLAGS_##name using fL##shorttype::FLAGS_##name
#define DEFINE_VARIABLE(namespc, type, name, value, help) \ // If your application #defines STRIP_FLAG_HELP to a non-zero value
namespace Flag_Names_##type { \ // before #including this file, we remove the help message from the
static union { void* align; char store[sizeof(namespc type)]; } cur_##name;\ // binary file. This can reduce the size of the resulting binary
static union { void* align; char store[sizeof(namespc type)]; } dfl_##name;\ // somewhat, and may also be useful for security reasons.
static @ac_google_namespace@::FlagRegisterer object_##name( \
#name, #type, help, __FILE__, \ extern const char kStrippedFlagHelp[];
new (cur_##name.store) namespc type(value), \
new (dfl_##name.store) namespc type(value)); \ #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)
#else
#define MAYBE_STRIPPED_HELP(txt) txt
#endif
// Each command-line flag defines an internal array of two elements
// of the appropriate time (each element is actually a union to get
// the values to be aligned on larger-than-byte boundaries). Element
// 0 of the s_##name array holds the current value, and element 1
// holds the default value.
#define DEFINE_VARIABLE(namespc, type, shorttype, name, value, help) \
namespace fL##shorttype { \
static union { void* align; char store[sizeof(namespc type)]; } \
s_##name[2]; \
static @ac_google_namespace@::FlagRegisterer o_##name( \
#name, #type, MAYBE_STRIPPED_HELP(help), __FILE__, \
new (s_##name[0].store) namespc type(value), \
new (s_##name[1].store) namespc type(value)); \
namespc type& FLAGS_##name = \ namespc type& FLAGS_##name = \
*(reinterpret_cast<namespc type*>(cur_##name.store)); \ *(reinterpret_cast<namespc type*>(s_##name[0].store)); \
char FLAGS_no##name @ac_cv___attribute__unused@; \ char FLAGS_no##name @ac_cv___attribute__unused@; \
} \ } \
using Flag_Names_##type::FLAGS_##name using fL##shorttype::FLAGS_##name
#ifndef SWIG // In swig, ignore the main flag declarations #ifndef SWIG // In swig, ignore the main flag declarations
#define DECLARE_bool(name) DECLARE_VARIABLE(, bool, name) #define DECLARE_bool(name) DECLARE_VARIABLE(, bool, B, name)
#define DEFINE_bool(name, val, txt) DEFINE_VARIABLE(, bool, name, val, txt) #define DEFINE_bool(name, val, txt) \
DEFINE_VARIABLE(, bool, B, name, @ac_google_namespace@::flags_safe_bool(val, #name), txt)
#define DECLARE_int32(name) DECLARE_VARIABLE(@ac_google_namespace@::,int32, name) #define DECLARE_int32(name) DECLARE_VARIABLE(@ac_google_namespace@::, int32,I, name)
#define DEFINE_int32(name, val, txt) DEFINE_VARIABLE(@ac_google_namespace@::,int32, name, val, txt) #define DEFINE_int32(name, val,txt) DEFINE_VARIABLE(@ac_google_namespace@::, int32,I, name,val,txt)
#define DECLARE_int64(name) DECLARE_VARIABLE(@ac_google_namespace@::,int64, name) #define DECLARE_int64(name) DECLARE_VARIABLE(@ac_google_namespace@::, int64,I64, name)
#define DEFINE_int64(name, val, txt) DEFINE_VARIABLE(@ac_google_namespace@::,int64, name, val, txt) #define DEFINE_int64(name, val,txt) DEFINE_VARIABLE(@ac_google_namespace@::, int64,I64, name,val,txt)
#define DECLARE_uint64(name) DECLARE_VARIABLE(@ac_google_namespace@::,uint64, name) #define DECLARE_uint64(name) DECLARE_VARIABLE(@ac_google_namespace@::, uint64,U64, name)
#define DEFINE_uint64(name, val, txt) DEFINE_VARIABLE(@ac_google_namespace@::,uint64, name, val, txt) #define DEFINE_uint64(name, val,txt) DEFINE_VARIABLE(@ac_google_namespace@::, uint64,U64,name,val,txt)
#define DECLARE_double(name) DECLARE_VARIABLE(, double, name) #define DECLARE_double(name) DECLARE_VARIABLE(, double,D, name)
#define DEFINE_double(name, val, txt) DEFINE_VARIABLE(, double, name, val, txt) #define DEFINE_double(name, val,txt) DEFINE_VARIABLE(, double,D, name,val,txt)
#define DECLARE_string(name) DECLARE_VARIABLE(std::, string, name) #define DECLARE_string(name) DECLARE_VARIABLE(std::, string,S, name)
#define DEFINE_string(name, val, txt) DEFINE_VARIABLE(std::, string, name, val, txt) #define DEFINE_string(name, val,txt) DEFINE_VARIABLE(std::, string,S, name,val,txt)
#endif // SWIG #endif // SWIG
......
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