Glags使用
Google Commandline Flags使用说明
命令行flags是在运行命令行时用户指定的标志,在命令fgrep -l -f /var/tmp/foo johannes brahms
中,-l
与-f /var/tmp/foo
为命令行flags,不带横线johannes
与brahms
为命令行参数
Gflags是Google的命令行flags库,与getopt()
不同, 其flag定义可分散在源码中,而不是只能在例如main()
函数中,这意味着一个代码文件中的定义和使用的flags对其他文件也其作用。二和玲姐到该源码文件的应用都能得到flags,glags库会自动地处理flags
这在灵活性方面具有很重要意义,可减少代码的重用。但是,当两个文件都定义了相同flag,当二者链接时会显示错误
定义
定义:对你想要的flag类型使用适当的宏,支持的类型包括:
- DEFINE_bool: boolean
- DEFINE_int32: 32-bit integer
- DEFINE_int64: 64-bit integer
- DEFINE_uint64: unsigned 64-bit integer
- DEFINE_double: double
- DEFINE_string: C++ string
使用方式:
DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");
DEFINE_string(languages, "english,french,german",
"comma-separated list of languages to offer in the 'lang' menu");
没有像目录类似的复杂类型,languages
的flag只是字符串列表,只是定义为字符串。最好只使用简单的类型作为flags
**所有的DEFINE宏都使用相同的三个参数:flag名字,默认值,以及描述其作用的help说明。当用户运行--help flag
时,help字符串内容就会显示
只能定义flag一次,如果想要在多个源码文件中使用flags,则在一个文件中DEFINE,其他文件DECLARE。更好的,可在foo.cc
中定义,foo.h
中声明DECLARE,则所用include其头文件的代码,都可使用其flags
如果想更新库中flags默认值,可使用flag validator
更新无效的默认值
获取Flag
所有已定义的flags对于程序而言只是普通变量而已,使用前缀FLAGS_
。在上述领子中,宏定义了两个变量FLAGS_big_menu
(a bool)与FLAGS_languages
(a C++string)
类似其他变量,读写其他变量:
if (FLAGS_consider_made_up_languages)
FLAGS_languages += ",klingon"; // implied by --consider_made_up_languages
if (FLAGS_languages.find("finnish") != string::npos)
HandleFinnish();
声明:在其他文件中使用Flag
在bar.cc文件中,使用刚才定义的big_menu
变量,即DECLARE_bool(big_menu)
,其与extern FLAGS_big_menu
作用相同
这种外部声明方式表明了二者文件之间的依赖性,但是这种隐含的依赖在大型项目中是很难管理的,因此推荐使用以下方式:如果在foo.cc
中定义了flag,则只在foo.h中DECLARE,或者在紧密相关的测试中DECLARE
RegisterFlagValidator:检查Flag值
在定义了flag之后,可通过flag来register validator函数。当flag从命令行中读取后,无论使用SetCommandLineOption()
改变其值,validator函数可调用作为参数的最新值,如果该flag有效,则返回true,错误则相反。如果这函数对新设置的flag报错,则flag保持当前值
static bool ValidatePort(const char* flagname, int32 value) {
if (value > 0 && value < 32768) // value is ok
return true;
printf("Invalid value for --%s: %d\n", flagname, (int)value);
return false;
}
DEFINE_int32(port, 0, "What port to listen on");
static const bool port_dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort);
在使用全局初始化下register,必须保证在registration完成
合并:怎么是建立Flags
其使用与getopt()
相似,但是更方便。主要使用一个函数 gflags::ParseCommandLineFlags(&argc, &argv, true)
完成命令行参数。第三个参数表示remove_flags
,如果设置为true,则ParseCommandLineFlags
从argv中移除从flags与 其参数,且适当修改argc。在这例子中,在调用函数之后,argv只有命令行参数,没有命令行flag。
另一方面,如果remove_flags
为false,ParseCOmmandLineFlags
会使argc保持不变,但是重新排列在argv中的参数让flags都在开始位置。
命令行设置Flags
创建flag而不是编译时保持不变,是为了让用户在命令行可指定非默认值。有一种非典型的方式设置boolean flag:在其名字之前放置“no”。有许多种方可指定flags:
app_containing_foo --languages="chinese,japanese,korean"
app_containing_foo -languages="chinese,japanese,korean"
app_containing_foo --languages "chinese,japanese,korean"
app_containing_foo -languages "chinese,japanese,korean"
对于boolean flags有一些不同:
app_containing_foo --big_menu
app_containing_foo --nobig_menu
app_containing_foo --big_menu=true
app_containing_foo --big_menu=false
**尽管有许多方式,但是推荐只使用一种形式:非boolean flags--variable=value
与boolean flags--variable/--novariable
。统一性会使代码更可读,且更符合要求
与getopt()
相同,--
会终止flags处理。因此,foo -f 1 -- -f2 2
,f1会被视为flag,而f2不是
如果一个flag在命令行中重复中指定了多次,则只使用最后一个,其他的都被忽略
修改默认Flag值
有时flag在库中被定义,如果想要在一个应用中改变其默认值,但在其他应用中不改变其默认值。只要在main()
中在调用ParseCommmandLineFlags()
之前对其flag赋新值
DECLARE_bool(lib_verbose); // mylib has a lib_verbose flag, default is false
int main(int argc, char** argv) {
FLAGS_lib_verbose = true; // in my app, I want a verbose lib by default
ParseCommandLineFlags(...);
}
在此例中,用户仍然可在命令行中设置flag值,但是如果不设置,则flag默认值为true
特殊Flags
有一些flags在命令行模块中已定义,可对所有应用使用这些commandlineflags,主要有三类。第一类为reporting flags,使应用打印自身相关信息,如--help
,第二类为影响其他flags解析的flags,如--undefok
,第三类为recursive flags,来设置其他flags值,如-fromenv
。