@breakerthb
2016-12-22T05:35:27.000000Z
字数 3845
阅读 3274
C/C++
在Linux平台,一直使用getopt_long来解析命令行参数,同时定义一个全局的struct来保存各个命令行参数的值。虽然用得比较“繁琐”,但也安于现状。
Google早在多年前就开源了一个解析命令行参数的“神器”gflags
https://github.com/gflags/gflags
ref : https://github.com/gflags/gflags/blob/master/INSTALL.md
现在流行cmake的构建方式,gflags的最新版本也改为使用cmake了。
$ unzip gflags-master.zip
$ cd gflags-master
$ mkdir build
$ cd build/
$ cmake ..
$ make
$ make install
gflags不区分‘-’和‘--’
// demo.cpp
#include <iostream>
#include <gflags/gflags.h>
using namespace std;
DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
DEFINE_int32(port, 9090, "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 0;
}
编译:
$ g++ demo.cpp -o demo -lgflags -pthread
$ ./demo
confPath = ../conf/setup.ini
port = 9090
run background ...
good luck and good bye!
直接运行,结果为默认值
为了统一,我建议都使用 上面的 第一种方法来设定参数。
$ ./demo --port=8888 --confPath=./setup.ini --daemon=true
confPath = ./setup.ini
port = 8888
run background ...
good luck and good bye!
$ ./demo -port=8888 -confPath=./setup.ini -daemon=false
confPath = ./setup.ini
port = 8888
run foreground ...
good luck and good bye!
$ ./demo -port=8888 -confPath=./setup.ini -daemon
confPath = ./setup.ini
port = 8888
run background ...
good luck and good bye!
$ ./demo -port=8888 -confPath=./setup.ini -nodaemon
confPath = ./setup.ini
port = 8888
run foreground ...
good luck and good bye!
如果我们的程序比较牛逼,配置项非常多,也就是说命令行参数很多,那你每次启动都要一个一个的输入,那岂不是很麻烦?gflags已经帮我们解决了,用 –flagfile=命令行文件 的方式就可以了。你接着往下看,就明白了。param.cmd就是上面说的命令行文件。
$ vi param.cmd
--port=8888
--confPath=./setup.ini
--daemon=true
$ ./demo --flagfile=param.cmd
confPath = ./setup.ini
port = 8888
run background ...
good luck and good bye!
gflags另外还给我们提供了 –fromenv 和 –tryfromenv 参数,通过这两个参数,我们的程序可以从环境变量中获取到具体的值。两者有什么不一样呢。
–fromenv 从环境变量读取参数值 –fromenv=port,confPath 表明要从环境变量读取port,confPath两个参数的值。但是当无法从环境变量中获取到的时候,会报错,同时程序退出。【注意:gflags的变量名是 FLAGS_我们定义的参数名,开篇的代码里,估计细心的你已经发现了】
–tryfromenv 与–fromenv类似,当参数的没有在环境变量定义时,不退出。
$ ./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!
$ export FLAGS_confPath=./loveyou.ini
$ export FLAGS_port=36888
$ env | grep FLAGS
FLAGS_port=36888
FLAGS_confPath=./loveyou.ini
$ ./demo --fromenv=port,confPath
confPath = ./loveyou.ini
port = 36888
run background ...
good luck and good bye!
我们一般使用程序的时候,都离不开两个参数 –version 和 –help。来看看上面实现的demo能否支持呢?
$ ./demo --version
demo
$ ./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, 9090, "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 0;
}
重新编译执行:
$ ./demo --version
demo version 1.0.0.0
$ ./demo --help
demo: Usage : ./demo