gflags学习
2018年12月22日 星期六, 发表于 深圳
如果你对本文有任何的建议或者疑问, 可以在 这里给我提 Issues, 谢谢! :)
gflags库是google开源的一套命令行参数处理库,可以用于便捷的构造一些小工具使用,在学习brpc中看到使用了gflags库,因此再仔细了解一下gfalgs库使用方式
gflags的官方使用文档gflags 使用
本文大部分也是参考该文档,进行实践,开发环境如下;
ubuntu@ubuntu:~/learning/gflags$ gcc -v
gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
step1. 下载安装
gflags库在github上开源,可以直接使用git下载
git clone https://github.com/gflags/gflags.git
下载之后参考上面的官方文档使用cmake安装,在git clone的目录下执行
cmake .
make
make install
执行上面的安装操作后,可以看到gflags将编译好的库拷贝到系统库目录里面
Install the project...
-- Install configuration: "Release"
-- Installing: /usr/local/lib/libgflags.a
-- Installing: /usr/local/lib/libgflags_nothreads.a
-- Installing: /usr/local/include/gflags/gflags.h
-- Installing: /usr/local/include/gflags/gflags_declare.h
-- Installing: /usr/local/include/gflags/gflags_completions.h
-- Installing: /usr/local/include/gflags/gflags_gflags.h
如果没有安装cmake可以先安装cmake,ubuntu系统以root权限执行
apt install cmake
如果使用其他方式安装,可以参考官方文档;
step2. 使用gflags库
在step1中已经编译安装好了gflags库,看一下怎么使用gflags库,依然参考官方文档; 在官方文档中,我们看到使用gflags,需要有几个步骤,首先需要在程序中声明标签,然后在访问标签
step2.1 声明标签
声明标签非常容易,只需要给想用的标签使用合适的宏来声明即可,所有的宏都在 gflags/gflags.h 中声明,例如下面的例子
#include <gflags/gflags.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 定义了一个boolean类型的标签,下面是gflags支持的标签:
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
gflags不支持复杂类型,例如list,在上面的例子中 languages标签,是定义为一个string,而不是 list of string,gfalgs库认为把string的解析放给业务使用者来做更合适
step2.2 访问标签
所有已定义的标签,可以在代码中当成一个正常变量来使用,只需要在前面加上 FLAGS_ 前缀,例如在step2.1中定义了两个标签,在下面的代码中访问
if (FLAGS_consider_made_up_languages)
FLAGS_languages += ",klingon"; // implied by --consider_made_up_languages
if (FLAGS_languages.find("finnish") != string::npos)
HandleFinnish();
也可以通过 gflags.h 文件中定义的函数来获取和修改标签,不过使用的比较少
step2.3 跨文件使用标签
如果需要在其他文件中访问某一个文件中定义的标签,可以使用DECLARE_宏,类似于extern的作用,官方文档有一个建议:
如果在foo.cc中定义了一个标签,要么根本就不要声明它,只在仅需要它的测试案例中声明,要么只在foo.h中声明;
If you DEFINE a flag in foo.cc, either don't DECLARE it at all, only DECLARE it in tightly related tests, or only DECLARE it in foo.h.
step2.4 注册标签校验函数(RegisterFlagValidator)
定义完一个标签之后,可以注册一个标签检验函数(可选的)。如果定义了标签校验函数,当标签从命令行传入,或者任何调用SetCommandLineOption去改变标签值的时候,该函数会被调用,当标签合法的时候,标签函数返回true,更新标签为设置值,如果标签不合法,则标签函数返回false,并且将标签设置为默认值,ParseCommandLineFlags 会退出。
例如:
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");
DEFINE_validator(port, &ValidatePort);
DEFINE_validator 宏调用标签校验函数,当校验函数返回ture,标签才被成功注册,否则标签注册失败;
step2.5 整体流程
参考下面代码
#include <iostream>
#include <gflags/gflags.h>
DEFINE_string(message, "Hello World!", "The message to print");
static bool ValidateMessage(const char* flagname, const std::string &message)
{
return !message.empty();
}
DEFINE_validator(message, ValidateMessage);
int main(int argc, char **argv)
{
gflags::SetUsageMessage("Test CMake configuration of gflags library (gflags-config.cmake)");
gflags::SetVersionString("0.1");
gflags::ParseCommandLineFlags(&argc, &argv, true);
std::cout << FLAGS_message << std::endl;
gflags::ShutDownCommandLineFlags();
return 0;
}
step2.6特殊变量
用到的情况不太多,详情参阅官方文档
--help shows all flags from all files, sorted by file and then by name; shows the flagname, its default value, and its help string
--helpfull same as -help, but unambiguously asks for all flags (in case -help changes in the future)
--helpshort shows only flags for the file with the same name as the executable (usually the one containing main())
--helpxml like --help, but output is in xml for easier parsing
--helpon=FILE shows only flags defined in FILE.*
--helpmatch=S shows only flags defined in *S*.*
--helppackage shows flags defined in files in same directory as main()
--version prints version info for the executable
--fromenv
--tryfromenv
--flagfile