google_gflags使用
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
google_gflags使用的更多相关文章
随机推荐
- Android ANR优化 2
在实际情况中,当Android项目的用户量特别大时候,一些细小的问题也会被放大,ANR问题就是一个典型的例子. 一些ANR问题只会发生在用户实际使用的情景,当系统资源比较紧张等一些特殊情况下才会遇到, ...
- 万里长征第二步——django个人博客(第五步 ——配置后台admin)
在urls.py文件中配置admin路径 from django.conf.urls import url from django.contrib import admin from blog.vie ...
- ElasticSearch调优问题
1. 近期遇到一个ES内存居高不下的问题,查了查,发现ES有个fielddata,当你发起一个查询,分析字符串的聚合将会被加载到 fielddata,如果这些字符串之前没有被加载过.如果结果中 fie ...
- git 超前一个版本 落后一个版本的解决方案
在使用SourceTree的时候经常会遇见超前一个版本,落后N个版本的情况,遇见这种情况应该怎么办呢? 首先打开终端,最好是从SourceTree里面打开,菜单栏有个终端按钮. 然后输入: $ git ...
- iOS7重磅推新--不断尝试与重新设计的过程
来源:GBin1.com iOS7重磅推新--不断尝试与重新设计的过程 或许你心里已经有了关于iPhone最新操作系统的评价,可能你喜欢它,也可能不喜欢,事实上大多数设计者不喜欢.设计界似乎一致认为I ...
- 各种字符编码方式详解及由来(ANSI,UNICODE,UTF-8,GB2312,GBK)
一直对字符的各种编码方式懵懵懂懂,什么ANSI UNICODE UTF-8 GB2312 GBK DBCS UCS……是不是看的很晕,假如您细细的阅读本文你一定可以清晰的理解他们.Let's go! ...
- vue - 条件语句
1.与小程序不同之处一,小程序无论变量还是常亮都可以用双向绑定来解决{{}},而vue一旦双(单)引号包起来以后就失效了. 2.注意一点,切记双引号注意不要混淆哈,这里是一排双引号包单引号,那里是一排 ...
- iOS开发必备指南合集之游戏接入GameCenter 指南
原地址:http://bbs.9ria.com/thread-248408-1-1.html iTunes Connect 设置 首先,申请一个应用程序,不必提交.目地是为了得到Bundle ID. ...
- taro 创建 Tabbar
1.代码 src/app.js import '@tarojs/async-await' import Taro, { Component } from '@tarojs/taro' import H ...
- Visual studio之C#跨线程调用UI控件
背景 当前串口通讯项目,多个线程需要同时利用richTextBoxMsg控件打印信息,直接调用会造成线程不安全,严重的时候会直接导致UI线程挂掉,因此本篇就跨线程调用UI控件做个记录. 正文 定义控件 ...