最近阅读yugabyte源码时,看到代码对对gflags的使用,不甚了解,于是去简单查了一下资料学习一下。
简介
GFlags是Google开源的一套命令行参数处理的开源库,包括C++的版本和python 版本。它与其他库(例如getopt())不同之处在于flag可以定义在不同的源代码中,而不仅仅是列在一个地方。一个源码文件可以定义一些对它自己有意义的flag,同时其他任何链接了该文件的应用也都能使用这些flag。
由于这种技术,灵活性和代码重用的简易性有了显着的提高。但是,存在两个文件定义相同标志的危险,当它们链接在一起时会发生错误。
Flags定义
定义一个标志很容易:只需为您希望标志的类型使用适当的宏。 示例:
// foo.cc
#include <gflags/glags.h>
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");
DEFINE_bool定义一个布尔标志。以下是支持的类型:
DEFINE_bool: 布尔值DEFINE_int32: 32 位整数DEFINE_int64: 64 位整数DEFINE_uint64: 无符号 64 位整数DEFINE_double: double浮点数DEFINE_string: C++ 字符串
DEFINE宏包含三个参数:flag名、默认值、描述方法的帮助。帮助会在执行 --help flag时显示。
可以在任何源文件中定义flag,但是每个只能定义一次。如果需要在多处使用,那么在一个文件中 DEFINE ,在其他文件中 DECLARE 。比较好的方法是在 .cc 文件中 DEFINE ,在 .h 文件中 DECLARE ,这样包含头文件即可使用flag了。
Flags声明
如果我们需要在不同的文件中使用同一个flag,而每个flag有只允许定义一次。这个时候就需要用到DECLARE_type
例如我们正在写bar.cc需要访问到上面例子foo.cc中定义的big_menu, 这个时候只用在bar.cc文件的顶部声明即可。
// bar.cc
# include <gflags/glags.h>
DECLARE_bool(big_menu);
但这种声明会在两个文件之间引入依赖关系。在大型项目中,这种隐式依赖可能难以管理。因此,当我们在foo.cc中定义了一个flag时,要么只在紧要的测试中声明它;要么就在foo.h中声明,其他要用到它的文件,只需要引入包含# foo.h即可。
Flags使用
定义的flag可以像正常的变量一样使用,只需在前面加上FLAGS_前缀。如前面例子中的定义了FLAGS_big_menu和FLAGS_languages两个变量。可以像一般变量一样读写:
if (FLAGS_consider_made_up_languages)
FLAGS_languages += ",klingon"; // implied by --consider_made_up_languages
if (FLAGS_languages.find("finnish") != string::npos)
HandleFinnish();
命令行设置flag
对于上面的的flag,我们可以在程序启动时,指定参数:
app_containing_foo --nobig_menu -languages="chinese,japanese,korean" ...
这样当我们的main函数调用:
int main(int argc, char** argv) {
...
google::ParseCommandLineFlags(&argc, &argv, true);
...
}
后,FLAGS_big_menu = false,FLAGS_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"app_containing_foo -languages "chinese,japanese,korean"
对于bool类型:
app_containing_foo --big_menuapp_containing_foo --nobig_menuapp_containing_foo --big_menu=trueapp_containing_foo --big_menu=false
flagfile
如果我们定义了很多参数,那么每次启动时都在命令行指定对应的参数显然是不合理的。
这个时候,可以把 flag 参数和对应的值写在文件中,然后运行时使用 -flagfile来指定对应的 flag 文件就好