最近阅读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_menu
app_containing_foo --nobig_menu
app_containing_foo --big_menu=true
app_containing_foo --big_menu=false
flagfile
如果我们定义了很多参数,那么每次启动时都在命令行指定对应的参数显然是不合理的。
这个时候,可以把 flag 参数和对应的值写在文件中,然后运行时使用 -flagfile
来指定对应的 flag 文件就好