google开源的gflags是一套命令行参数解析工具,比getopt功能更强大,使用起来更加方便,gflags还支持从环境变量、配置文件读取参数(可用gflags代替配置文件)
使用flags需要包含头文件 #include “gflags/gflags.h”
gflags主要支持的参数类型包括bool,int32, int64, uint64, double, string等,定义参数通过DEFINE_type宏实现,如下所示,分别定义了一个bool和一个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");
gflag不支持列表,用户通过灵活借助string参数实现,比如上述的languages参数,可以类型为string,但可看作是以逗号分割的参数列表。
当参数被定义后,通过FLAGS_name就可访问到对应的参数,比如上述定义的big_menu、languages两个参数就可通过FLAGS_big_menu、FLAGS_languages访问。
if (FLAGS_languages.find("english") != string::npos)
HandleEnglish();
以上的访问方式,仅在参数定义和访问在同一个文件(或是通过头文件包含)时,FLAGS_name才能访问到参数,如果要访问其他文件里定义的参数,则需要使用DECLARE_type。
定义参数后,可以给参数注册一个检查函数(validator),当从命令行指定参数或通过SetCommandLineOption()指定参数时,检查函数就会被调用,两个参数分别为命令行参数名,以及设置的参数值。
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);
建议在定义参数后,立即注册检查函数。RegisterFlagValidator()在检查函数注册成功时返回true;如果参数已经注册了检查函数,或者检查函数类型不匹配,返回false。
在引用程序的main()里通过 google::ParseCommandLineFlags(&argc, &argv, true); 即完成对gflags参数的初始,其中第三个参数为remove_flag,如果为true,gflags会移除parse过的参数,否则gflags就会保留这些参数,但可能会对参数顺序进行调整。 比如 “/bin/foo” “arg1” “-q” “arg2” 会被调整为 “/bin/foo”, “-q”, “arg1”, “arg2”,这样更好理解。
#include <iostream>
#include <gflags/gflags.h>
DEFINE_bool(isvip, false, "If Is VIP");
DEFINE_string(ip, "127.0.0.1", "connect ip");
DECLARE_int32(port);
DEFINE_int32(port, 80, "listen port");
int main(int argc, char** argv)
{
google::ParseCommandLineFlags(&argc, &argv, true);
std::cout<<"ip:"<<FLAGS_ip<<std::endl;
std::cout<<"port:"<<FLAGS_port<<std::endl;
if (FLAGS_isvip)
{
std::cout<<"isvip:"<<FLAGS_isvip<<std::endl;
}
google::ShutDownCommandLineFlags();
return 0;
}
比如要在命令行指定languages参数的值,可通过如下4种方式,int32, int64等类型与string类似。
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
#include <iostream>
#include "gflags/gflags.h"
// 定义gflags
DEFINE_bool(foo, false, "a simple gflags named foo, default value is flase, wuruilong, 2018-08-16");
DEFINE_int32(thread_num, 10, "thread number, default value is 10, wuruilong, 2018-08-16");
int main(int argc, char **argv) {
// 解析gflags参数,只需要1行代码
google::ParseCommandLineFlags(&argc, &argv, true);
// 使用gflags
if (FLAGS_foo) {
std::cout << "foo is true" << std::endl;
} else {
std::cout << "foo is false" << std::endl;
}
// 使用gflags
int thread_num = FLAGS_thread_num;
std::cout << "thread number:" << thread_num << std::endl;
return 0;
}
编译:g++ simple_gflags.cpp -I./gflags-2.0/src -L./ -lgflags
运行:
(1)没有参数,./a.out
foo is false
thread number:10
(2)指定参数foo为true,./a.out -foo=true
foo is true
thread number:10
(3)同时指定foo和thread_num,./a.out -foo=true -thread_num=99
foo is true
在工程实践中,有专门定义gflags的文件,通过–flagfile=filename来指定gflags配置文件,其他文件在使用gflags时需要先声明;通常将gflags定义在专门的配置文件中,以方便对程序运行参数管理。
专门定义gflags的头文件gflags_def.cpp
#include "gflags/gflags.h"
// 定义gflags
DEFINE_bool(add_new_feature_x, false, "x feature, gaojingying, 2018-08-16");
DEFINE_bool(add_new_featrue_y, false, "y feature, xiechao, 2018-08-16");
DEFINE_bool(fix_memory_leak_bug, false, "fix memory leak bug, xiechao, 2018-08-16");
DEFINE_bool(fix_cpu_high_bug, false, "fix cpu high bug, xiechao, 2018-08-16");
DEFINE_int32(thread_pool_worker_num, 10, "thread pool worker number, default value is 10, ligang, 2018-08-16");
DEFINE_string(server_ip, "127.0.0.1", "x server's ip address, gaojingying, 2018-08-16");
其他文件中使用gflags之前,需要先通过DECLARE_声明。
#include <iostream>
#include <string>
#include <cstdio>
#include "gflags/gflags.h"
// 声明gflags
DECLARE_bool(add_new_feature_x);
DECLARE_bool(add_new_featrue_y);
DECLARE_bool(fix_memory_leak_bug);
DECLARE_bool(fix_cpu_high_bug);
DECLARE_int32(thread_pool_worker_num);
DECLARE_string(server_ip);
void Work(std::string &name) {
name = "feature";
// 启用x功能
if (FLAGS_add_new_feature_x) {
name += "_x";
}
// 启用y功能
if (FLAGS_add_new_featrue_y) {
name += "_y";
}
char *value = new char[100];
snprintf(value, 100, "thread number: %d", FLAGS_thread_pool_worker_num);
name = name + "," + value + "," + FLAGS_server_ip;
// 留下消缺记录
if (FLAGS_fix_memory_leak_bug) {
delete []value;
}
}
int main(int argc, char **argv) {
google::ParseCommandLineFlags(&argc, &argv, true);
std::string name;
Work(name);
std::cout << name << std::endl;
return 0;
}
编译:g++ main.cpp gflags_def.cpp –I./gflags-2.0/src -L./ -lgflags
gflags配置文件demo_project.gflags
-add_new_feature_x=false
-add_new_featrue_y=true
-fix_memory_leak_bug=true
-fix_cpu_high_bug=false
-thread_pool_worker_num=20
-server_ip="127.0.0.1"
运行。
(1)不指定gflags配置文件,./a.out
feature,thread number: 10,127.0.0.1
(2)指定gflags配置文件,./a.out --flagfile=demo_project.gflags
feature_x,thread number: 20,“127.0.0.1”
有了gflags,测试同学会这样玩:
修改demo_project.gflags,关闭feature_x功能,启用feature_y功能:./a.out --flagfile=demo_project.gflags
feature_y,thread number: 20,“127.0.0.1”