google_gflags使用

gflags是google开源的一个解析命令行参数的工具。

最简单的demo

 1 #include <iostream>
 2 #include <gflags/gflags.h>
 3 
 4 using namespace std;
 5 
 6 DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
 7 DEFINE_int32(port, 9090, "program listen port");
 8 DEFINE_bool(daemon, true, "run daemon mode");
 9 
10 int main(int argc, char** argv)
11 {
12   gflags::ParseCommandLineFlags(&argc, &argv, true);
13  
14   cout << "confPath = " << FLAGS_confPath << endl;
15   cout << "port = " << FLAGS_port << endl;
16 
17   if (FLAGS_daemon) {
18     cout << "run background ..." << endl;
19   }
20   else {
21     cout << "run foreground ..." << endl;
22   }
23 
24   cout << "good luck and good bye!" << endl;
25 
26   gflags::ShutDownCommandLineFlags();
27   return 0;
28 }

直接运行结果如下:

[amcool@leoox build]$ ./demo
confPath = ../conf/setup.ini
port = 9090
run background ...
good luck and good bye!

设定命令行参数

前面直接运行我们没有输入参数,所以用的就是上面写的那些默认参数。下面来看一下传入命令行参数的情况,主要有3种情况:

1、设定参数值

i)可以用 –参数名=参数值 或者 -参数名=参数值 的方式来设定参数值。

ii)对于bool类型的参数,除了上述方式外,还可以用 –参数名 的方式设定为true(即不带值), 使用 –no参数名 的方式设定为false。为了统一,建议都使用上面的 第 i 种方法来设定参数。

加入参数值运行一下:

[amcool@leoox build]$ ./demo --port=8888 --confPath=./setup.ini --daemon=true  
confPath = ./setup.ini
port = 8888
run background ...
good luck and good bye!
[amcool@leoox build]$ ./demo -port=8888 -confPath=./setup.ini -daemon=false
confPath = ./setup.ini
port = 8888
run foreground ...
good luck and good bye!
[amcool@leoox build]$ ./demo -port=8888 -confPath=./setup.ini -daemon【对于bool型最好还是和上面统一直接指定值,不要用这种特殊方式】
confPath = ./setup.ini
port = 8888
run background ...
good luck and good bye!
[amcool@leoox build]$ ./demo -port=8888 -confPath=./setup.ini -nodaemon【对于bool型最好还是和上面统一直接指定值,不要用这种特殊方式】
confPath = ./setup.ini
port = 8888
run foreground ...
good luck and good bye!
[amcool@leoox build]$

2、从文件读入“命令行”参数

如果命令行参数很多,可以用 –flagfile=命令行文件 的方式传入命令行文件。

[amcool@leoox build]$ vi param.cmd
--port=8888
--confPath=./setup.ini
--daemon=true
[amcool@leoox build]$ ./demo --flagfile=param.cmd
confPath = ./setup.ini
port = 8888
run background ...
good luck and good bye!
[amcool@leoox build]$

3、从环境变量读入参数值

gflags另外还提供了 –fromenv 和 –tryfromenv 参数,通过这两个参数,程序可以从环境变量中获取到具体的值。

–fromenv 从环境变量读取参数值 –fromenv=port,confPath 表明要从环境变量读取port,confPath两个参数的值。但是当无法从环境变量中获取到的时候,会报错,同时程序退出。【注意:gflags的变量名是 FLAGS_我们定义的参数名】

–tryfromenv 与–fromenv类似,当参数的没有在环境变量定义时,不退出。

这种方式并不太常用,知道就可以了。

[amcool@leoox build]$ ./demo --fromenv=port,confPath
ERROR: FLAGS_confPath not found in environment
ERROR: FLAGS_port not found in environment
[amcool@leoox build]$ ./demo --tryfromenv=port,confPath
confPath = ../conf/setup.ini
port = 9090
run background ...
good luck and good bye!
[amcool@leoox build]$ export FLAGS_confPath=./loveyou.ini
[amcool@leoox build]$ export FLAGS_port=36888   
[amcool@leoox build]$ env | grep FLAGS
FLAGS_port=36888
FLAGS_confPath=./loveyou.ini
[amcool@leoox build]$          
[amcool@leoox build]$ ./demo --fromenv=port,confPath     
confPath = ./loveyou.ini
port = 36888
run background ...
good luck and good bye!
[amcool@leoox build]$

支持的参数类型

使用gflags提供的宏:DEFINE_xxx(变量名,默认值,help_string)。这些变量需要在全局范围内定义。变量支持以下类型:

定义类型
DEFINE_bool 布尔型
DEFINE_int32 32位整形
DEFINE_int64 64位整形
DEFINE_uint64 64位无符号整形
DEFINE_double double型
DEFINE_string C++中string类型

针对定义的宏进行一下参数解释:

1 DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");

第一个字段 confPath就是命令行里要输入的参数名,比如 –confPath=./love.ini

第二个字段”../conf/setup.ini”,就是如果命令行里没指定这个参数,那默认值就是 ../conf/setup.ini

第三个字段”program configure file.”,就是这个参数的帮助说明信息,当用户输入 –hlep 的时候,会显示出来。

然后在代码中使用的变量就是:FLAGS_confPath

解析命令行参数

gflags是使用ParseCommandLineFlags这个方法来完成命令行参数的解析的。具体如下:

1 gflags::ParseCommandLineFlags(&argc, &argv, true);

一目了然,唯一值得注意的就是第三个参数了。如果设置为true,gflags就会移除解析过的参数。即argc, argv就会变了。否则gflags还会保持这些参数继续留在argc,argv中。但是参数的顺序有可能会发生变化。下面来看一个例子就清楚了:

 1 #include <iostream>
 2 #include <gflags/gflags.h>
 3  
 4 using namespace std;
 5  
 6 DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
 7 DEFINE_int32(port, 9090, "program listen port");
 8 DEFINE_bool(daemon, true, "run daemon mode");
 9  
10 int main(int argc, char** argv)
11 {
12   for (int i = 0; i < argc; i++) {
13     printf("argv[%d] = %s
", i, argv[i]);
14   }
15   printf("---------------here--------------
");
16 
17   gflags::SetVersionString("1.0.0.0");
18   gflags::SetUsageMessage("Usage : ./demo ");
19   gflags::ParseCommandLineFlags(&argc, &argv, true);
20  
21   for (int i = 0; i < argc; i++) {
22     printf("argv[%d] = %s
", i, argv[i]);
23   }
24   printf("---------------there--------------
");
25 
26   cout << "confPath = " << FLAGS_confPath << endl;
27   cout << "port = " << FLAGS_port << endl;
28  
29   if (FLAGS_daemon) {
30     cout << "run background ..." << endl;
31   }
32   else {
33     cout << "run foreground ..." << endl;
34   }
35  
36   cout << "good luck and good bye!" << endl;
37  
38   gflags::ShutDownCommandLineFlags();
39   return 0;
40 }

当第三个参数为true时,运行结果如下:

[amcool@leoox build]$ ./demo --port=8888 --confPath=./happy.ini --daemon
argv[0] = ./demo
argv[1] = --port=8888
argv[2] = --confPath=./happy.ini
argv[3] = --daemon
---------------here--------------
argv[0] = ./demo
---------------there--------------
confPath = ./happy.ini
port = 8888
run background ...
good luck and good bye! 

当第三个参数为false时,运行结果如下:

[amcool@leoox build]$ ./demo --port=8888 --confPath=./happy.ini --daemon  
argv[0] = ./demo
argv[1] = --port=8888
argv[2] = --confPath=./happy.ini
argv[3] = --daemon
---------------here--------------
argv[0] = ./demo
argv[1] = --port=8888
argv[2] = --confPath=./happy.ini
argv[3] = --daemon
---------------there--------------
confPath = ./happy.ini
port = 8888
run background ...
good luck and good bye!

参数检查

按照以前的习惯,我们可以获取到所有参数的值后,再在代码里面进行判断这个参数是否是我们想要的。比如,我们需要端口是36800 到 36888之间的,那我们可以这样检查。

1 if (FLAGS_port < 36800 || FLAGS_port > 36888) {
2     printf("port must [36800, 36888]
");
3     return -1;
4 }

gflags里面建议使用 RegisterFlagValidator 这个方法来做参数检查。参数不通过的时候,程序是启动失败的。什么时候会调用这个参数检查函数呢?

如果采用 static 全局变量来确保检查函数会在 main 开始时被注册,可以保证注册会在 ParseCommandLineFlags 函数之前。如果默认值检查失败,那么 ParseCommandLineFlag将会使程序退出。如果之后使用 SetCommandLineOption() 来改变参数的值,那么检查函数也会被调用,但是如果验证失败,只会返回 false,然后参数保持原来的值,程序不会结束。

 1 #include <stdint.h>
 2 #include <stdio.h>
 3 #include <iostream>
 4 
 5 #include <gflags/gflags.h>
 6 
 7 // 定义对 FLAGS_port 的检查函数
 8 static bool ValidatePort(const char* name, int32_t value) {
 9     if (value > 0 && value < 32768) {
10         return true;
11     }
12     printf("Invalid value for --%s: %d
", name, (int)value);
13     return false;
14 }
15 
16 /**
17  *  设置命令行参数变量
18  *  默认的主机地址为 127.0.0.1,变量解释为 'the server host'
19  *  默认的端口为 12306,变量解释为 'the server port'
20  */
21 DEFINE_string(host, "127.0.0.1", "the server host");
22 DEFINE_int32(port, 12306, "the server port");
23 
24 // 使用全局 static 变量来注册函数,static 变量会在 main 函数开始时就调用
25 static const bool port_dummy = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort);
26 
27 int main(int argc, char** argv) {
28     // 解析命令行参数,一般都放在 main 函数中开始位置
29     gflags::ParseCommandLineFlags(&argc, &argv, true);
30     std::cout << "The server host is: " << FLAGS_host
31         << ", the server port is: " << FLAGS_port << std::endl;
32 
33     // 使用 SetCommandLineOption 函数对参数进行设置才会调用检查函数
34     gflags::SetCommandLineOption("port", "-2");
35     std::cout << "The server host is: " << FLAGS_host
36         << ", the server port is: " << FLAGS_port << std::endl;
37     return 0;
38 }

运行结果如下:

#命令行指定非法值,程序解析参数时直接退出
➜  test ./gflags_test -port -2
Invalid value for --port: -2
ERROR: failed validation of new value '-2' for flag 'port'
# 这里参数默认值合法,但是 SetCommandLineOption 指定的值不合法,程序不退出,参数保持原来的值
➜  test ./gflags_test        
The server host is: 127.0.0.1, the server port is: 12306
Invalid value for --port: -2
The server host is: 127.0.0.1, the server port is: 12306

其他代码文件使用参数变量

正常来说,代码可能不只有1个cpp,还会有很多模块。而每个模块可能会使用到不同的参数值。所以我们之前在demo.cpp定义的参数变量(比如FLAGS_port),在其他模块怎么引用和使用呢?so easy,与DEFINE相对应的有DECLARE。声明一下,就可以使用了。

1 DECLARE_bool: boolean
2 DECLARE_int32: 32-bit integer
3 DECLARE_int64: 64-bit integer
4 DECLARE_uint64: unsigned 64-bit integer
5 DECLARE_double: double
6 DECLARE_string: C++ string

判断flags变量是否被用户使用

在gflags.h中,还定义了一些平常用不到的函数和结构体。这里举一个例子,判断参数port有没有被用户设定过

1 google::CommandLineFlagInfo info;
2 if(GetCommandLineFlagInfo("port" ,&info) && info.is_default) {
3     FLAGS_port = 27015;
4 }

版本号和帮助信息

在使用程序的时候,都离不开两个参数 –version 和 –help。来看看上面实现的demo能否支持呢?

[amcool@leoox build]$ ./demo --version
demo
[amcool@leoox build]$ ./demo --help
demo: Warning: SetUsageMessage() never called

 Flags from /home/thrift/program/gflags/demo/demo.cpp:
 -confPath (program configure file.) type: string
 default: "../conf/setup.ini"
 -daemon (run daemon mode) type: bool default: true
 -port (program listen port) type: int32 default: 9090

help支持了,但是version没支持,而且help信息里面还有waring。可以用  SetVersionString() 和 SetUsageMessage() 方法来满足需求。

注意:SetVersionString() 和 SetUsageMessage() 一定要在 ParseCommandLineFlags() 之前设定。

修改后的代码如下:

 1 #include <iostream>
 2 #include <gflags/gflags.h>
 3 
 4 using namespace std;
 5 
 6 DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
 7 DEFINE_int32(port, 9090, "program listen port");
 8 DEFINE_bool(daemon, true, "run daemon mode");
 9 
10 int main(int argc, char** argv)
11 {
12   gflags::SetVersionString("1.0.0.0");
13   gflags::SetUsageMessage("Usage : ./demo ");
14   gflags::ParseCommandLineFlags(&argc, &argv, true);
15  
16   cout << "confPath = " << FLAGS_confPath << endl;
17   cout << "port = " << FLAGS_port << endl;
18 
19   if (FLAGS_daemon) {
20     cout << "run background ..." << endl;
21   }
22   else {
23     cout << "run foreground ..." << endl;
24   }
25 
26   cout << "good luck and good bye!" << endl;
27 
28   gflags::ShutDownCommandLineFlags();
29   return 0;
30 }

运行结果如下:

[amcool@leoox build]$ ./demo --version
demo version 1.0.0.0
[amcool@leoox build]$ ./demo --help
demo: Usage : ./demo

  Flags from /home/amcool/program/gflags/demo/demo.cpp:
    -confPath (program configure file.) type: string
      default: "../conf/setup.ini"
    -daemon (run daemon mode) type: bool default: true
    -port (program listen port) type: int32 default: 9090



  Flags from /home/amcool/soft/gflags-2.1.1/src/gflags.cc:
    -flagfile (load flags from file) type: string default: ""
    -fromenv (set flags from the environment [use 'export FLAGS_flag1=value'])
      type: string default: ""
    -tryfromenv (set flags from the environment if present) type: string
      default: ""
    -undefok (comma-separated list of flag names that it is okay to specify on
      the command line even if the program does not define a flag with that
      name.  IMPORTANT: flags in this list that have arguments MUST use the
      flag=value format) type: string default: ""

  Flags from /home/amcool/soft/gflags-2.1.1/src/gflags_completions.cc:
    -tab_completion_columns (Number of columns to use in output for tab
      completion) type: int32 default: 80
    -tab_completion_word (If non-empty, HandleCommandLineCompletions() will
      hijack the process and attempt to do bash-style command line flag
      completion on this value.) type: string default: ""

  Flags from /home/amcool/soft/gflags-2.1.1/src/gflags_reporting.cc:
    -help (show help on all flags [tip: all flags can have two dashes])
      type: bool default: false currently: true
    -helpfull (show help on all flags -- same as -help) type: bool
      default: false
    -helpmatch (show help on modules whose name contains the specified substr)
      type: string default: ""
    -helpon (show help on the modules named by this flag value) type: string
      default: ""
    -helppackage (show help on all modules in the main package) type: bool
      default: false
    -helpshort (show help on only the main module for this program) type: bool
      default: false
    -helpxml (produce an xml version of help) type: bool default: false
    -version (show version and build info and exit) type: bool default: false
[amcool@leoox build]$

本文参考自:

http://blog.csdn.net/u013407923/article/details/53084076

http://blog.csdn.net/jcjc918/article/details/50876613

http://blog.csdn.net/lezardfu/article/details/23753741

http://www.leoox.com/?p=270

http://www.leoox.com/?p=275

原文地址:https://www.cnblogs.com/abc-begin/p/7895817.html