当前位置: 首页 > 工具软件 > Google GFlags > 使用案例 >

C/C++编程: Google命令行工具gflags使用

裴宜春
2023-12-01

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。

  • 比如在foo.cc中DEFINE_string(color, “red”, “the color you want to use”);
  • 如果你需要在foo_test.cc中使用color这个参数,你需要加入DECLARE_string(color, “red”, “the color you want to use”);

参数检查

定义参数后,可以给参数注册一个检查函数(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

特殊参数

  • –help 打印定义过的所有参数的帮助信息
  • –version 打印版本信息 通过google::SetVersionString()指定
  • –nodefok 但命令行中出现没有定义的参数时,并不退出(error-exit)
  • –fromenv 从环境变量读取参数值 --fromenv=foo,bar表明要从环境变量读取foo,bar两个参数的值。通过export FLAGS_foo=xxx; export FLAGS_bar=yyy 程序就可读到foo,bar的值分别为xxx,yyy。
  • –tryfromenv 与–fromenv类似,当参数的没有在环境变量定义时,不退出(fatal-exit)
  • –flagfile 从文件读取参数值,–flagfile=my.conf表明要从my.conf文件读取参数的值。在配置文件中指定参数值与在命令行方式类似,另外在flagfile里可进一步通过–flagfile来包含其他的文件。

举个例子

demo

#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”

 类似资料: