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

最简单的demo

 #include <iostream>
#include <gflags/gflags.h> using namespace std; DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
DEFINE_int32(port, , "program listen port");
DEFINE_bool(daemon, true, "run daemon mode"); int main(int argc, char** argv)
{
gflags::ParseCommandLineFlags(&argc, &argv, true); cout << "confPath = " << FLAGS_confPath << endl;
cout << "port = " << FLAGS_port << endl; if (FLAGS_daemon) {
cout << "run background ..." << endl;
}
else {
cout << "run foreground ..." << endl;
} cout << "good luck and good bye!" << endl; gflags::ShutDownCommandLineFlags();
return ;
}

直接运行结果如下:

[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类型

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

 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这个方法来完成命令行参数的解析的。具体如下:

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

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

 #include <iostream>
#include <gflags/gflags.h> using namespace std; DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
DEFINE_int32(port, , "program listen port");
DEFINE_bool(daemon, true, "run daemon mode"); int main(int argc, char** argv)
{
for (int i = ; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
printf("---------------here--------------\n"); gflags::SetVersionString("1.0.0.0");
gflags::SetUsageMessage("Usage : ./demo ");
gflags::ParseCommandLineFlags(&argc, &argv, true); for (int i = ; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
printf("---------------there--------------\n"); cout << "confPath = " << FLAGS_confPath << endl;
cout << "port = " << FLAGS_port << endl; if (FLAGS_daemon) {
cout << "run background ..." << endl;
}
else {
cout << "run foreground ..." << endl;
} cout << "good luck and good bye!" << endl; gflags::ShutDownCommandLineFlags();
return ;
}

当第三个参数为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之间的,那我们可以这样检查。

 if (FLAGS_port <  || FLAGS_port > ) {
printf("port must [36800, 36888]\n");
return -;
}

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

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

 #include <stdint.h>
#include <stdio.h>
#include <iostream> #include <gflags/gflags.h> // 定义对 FLAGS_port 的检查函数
static bool ValidatePort(const char* name, int32_t value) {
if (value > && value < ) {
return true;
}
printf("Invalid value for --%s: %d\n", name, (int)value);
return false;
} /**
* 设置命令行参数变量
* 默认的主机地址为 127.0.0.1,变量解释为 'the server host'
* 默认的端口为 12306,变量解释为 'the server port'
*/
DEFINE_string(host, "127.0.0.1", "the server host");
DEFINE_int32(port, , "the server port"); // 使用全局 static 变量来注册函数,static 变量会在 main 函数开始时就调用
static const bool port_dummy = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort); int main(int argc, char** argv) {
// 解析命令行参数,一般都放在 main 函数中开始位置
gflags::ParseCommandLineFlags(&argc, &argv, true);
std::cout << "The server host is: " << FLAGS_host
<< ", the server port is: " << FLAGS_port << std::endl; // 使用 SetCommandLineOption 函数对参数进行设置才会调用检查函数
gflags::SetCommandLineOption("port", "-2");
std::cout << "The server host is: " << FLAGS_host
<< ", the server port is: " << FLAGS_port << std::endl;
return ;
}

运行结果如下:

#命令行指定非法值,程序解析参数时直接退出
➜  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。声明一下,就可以使用了。

 DECLARE_bool: boolean
DECLARE_int32: -bit integer
DECLARE_int64: -bit integer
DECLARE_uint64: unsigned -bit integer
DECLARE_double: double
DECLARE_string: C++ string

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

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

 google::CommandLineFlagInfo info;
if(GetCommandLineFlagInfo("port" ,&info) && info.is_default) {
FLAGS_port = ;
}

版本号和帮助信息

在使用程序的时候,都离不开两个参数 –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() 之前设定。

修改后的代码如下:

 #include <iostream>
#include <gflags/gflags.h> using namespace std; DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
DEFINE_int32(port, , "program listen port");
DEFINE_bool(daemon, true, "run daemon mode"); int main(int argc, char** argv)
{
gflags::SetVersionString("1.0.0.0");
gflags::SetUsageMessage("Usage : ./demo ");
gflags::ParseCommandLineFlags(&argc, &argv, true); cout << "confPath = " << FLAGS_confPath << endl;
cout << "port = " << FLAGS_port << endl; if (FLAGS_daemon) {
cout << "run background ..." << endl;
}
else {
cout << "run foreground ..." << endl;
} cout << "good luck and good bye!" << endl; gflags::ShutDownCommandLineFlags();
return ;
}

运行结果如下:

[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

最新文章

  1. Visual Studio Code 使用 ESLint 增强代码风格检查
  2. 简单SSM配置详解
  3. Python核心编程笔记(类)
  4. 移动页面HTML5自适应手机屏幕宽度
  5. andriod 获得drawable下所有图片
  6. unity c#
  7. nefu 120 梅森素数
  8. tortoisegit 保存用户名密码
  9. 浅谈Hive vs HBase
  10. Duanxx的C++学习: 使用类没有被定义 原因及解决方法
  11. 【数学】HPU--1037 一个简单的数学题
  12. 201521123040《Java程序设计》第12周学习总结
  13. ios自定义数字键盘
  14. ROS机器人程序设计(原书第2版)补充资料 (玖) 第九章 导航功能包集进阶 navigation
  15. Vector的用法
  16. ansible 问题
  17. cpp 区块链模拟示例(五) 序列化
  18. FFmpeg Basic学习笔记(4)
  19. 《剑指offer》第十八题(在O(1)时间删除链表结点)
  20. Q:接口与抽象类

热门文章

  1. android 监控软键盘确定 搜索 按钮并赋予点击事件
  2. Linux驱动mmap内存映射
  3. 流畅的python第三章字典和集合学习记录
  4. CocoSourcesCS 2
  5. [ES6] 11. String Templates
  6. X5平方速算法的证明
  7. 【转】iBatis简单入门教程
  8. 【一步一步走(1)】远程桌面软件VNC的安装与配置
  9. 关于天津中软国际ETC培训中心的见与闻
  10. Load和CPU利用率是如何算出来的 (转发)