目录
一.gflags 介绍
gflags 是 Google 开发的一个开源库,用于 C++ 应用程序中命令行参数的声明、定义和解析。gflags 库提供了一种简单的方式来添加、解析和文档化命令行标志(flags),使得程序可以根据不同的运行时配置进行调整。
它具有如下几个特点:
- 易于使用:gflags 提供了一套简单直观的 API 来定义和解析命令行标志,使得开发者可以轻松地为应用程序添加新的参数;
- 自动帮助和文档:gflags 可以自动生成每个标志的帮助信息和文档,这有助于用户理解如何使用程序及其参数;
- 类型安全:gflags 支持多种数据类型的标志,包括布尔值、整数、字符串等,并且提供了类型检查和转换;
- 多平台支持:gflags 可以在多种操作系统上使用,包括 Windows、Linux 和 macOS;
- 可扩展性:gflags 允许开发者自定义标志的注册和解析逻辑,提供了强大的扩展性。
官方文档:https://gflags.github.io/gflags/
代码仓库:https://github.com/gflags/gflags.git
二.gflags安装
直接命令安装:
sudo apt-get install libgflags-dev
源码安装:
# 下载源码
git clone https://github.com/gflags/gflags.git
# 切换目录
cd gflags/
mkdir build
cd build/
# 生成 Makefile
cmake ..
# 编译代码
make
# 安装
make install
未报错则安装完毕。
三.gflags使用
1.包含头文件
使用 gflags 库来定义/解析命令行参数必须包含如下头文件。
#include <gflags/gflags.h>
2.定义参数
利用 gflag 提供的宏定义来定义参数。该宏的 3 个参数分别为命令行参数名,参数默认值,参数的帮助信息。
DEFINE_bool(reuse_addr, true, "是否开始网络地址重用选项");
DEFINE_int32(log_level, 1, "日志等级:1-DEBUG, 2-WARN, 3-ERROR");
DEFINE_string(log_file, "stdout", "日志输出位置设置,默认为标准输出");
gflags 支持定义多种类型的宏函数:
DEFINE_bool
DEFINE_int32
DEFINE_int64
DEFINE_uint64
DEFINE_double
DEFINE_string
3.访问参数
我们可以在程序中通过 FLAGS_name 像正常变量一样访问标志参数。比如在上面的例子中,我们可以通过 FLAGS_big_menu 和 FLAGS_languages 变量来访问命令行参数。
4.不同文件访问参数
如果想再另外一个文件访问当前文件的参数,以参数 FLAGS_big_menu 为例,我们可以使用用宏 DECLARE_bool(big_menu)来声明引入这个参数。
其实这个宏就相当于做了 extern FLAGS_big_menu, 定义外部链接属性。
5.初始化所有参数
当我们定义好参数后,需要告诉可执行程序去处理解析命令行传入的参数,使得FLAGS_*变量能得到正确赋值。我们需要在 main 函数中,调用下面的函数来解决命令行传入的所有参数。
google::ParseCommandLineFlags(&argc, &argv, true);
- argc 和 argv 就是 main 的入口参数;
- 第三个参数被称为 remove_flags。如果它为 true, 表示ParseCommandLineFlags 会从 argv 中移除标识和它们的参数,相应减少 argc 的值;如果它为 false,ParseCommandLineFlags 会保留 argc 不变,但将会重新调整它们的顺序,使得标识再前面。这里的说明比较晦涩,下面我在Linux上写代码进行输出来演示。
首先是第三个参数设置为false,我在命令行对命令行参数进行设置,而不使用默认值,因为如果使用默认值的话,argc的值在第三个参数设置为true和false的情况下是一样的,就看不出区别。
代码如下:
#include <gflags/gflags.h>
#include <iostream>
DEFINE_string(ip, "127.0.0.1", "这是服务器监听ip地址,格式:127.0.0.1");
DEFINE_int32(port, 8080, "这是服务器监听端口,格式:8080");
DEFINE_bool(enableDebug, true, "是否开启调试模式,格式:true/false");
int main(int argc, char* argv[])
{
google::ParseCommandLineFlags(&argc, &argv, false);
std::cout << "argc的值是:" << argc << std::endl;
std::cout << "FLAGS_作为前缀版本:" << std::endl;
std::cout << FLAGS_ip << std::endl;
std::cout << FLAGS_port << std::endl;
std::cout << FLAGS_enableDebug << std::endl;
std::cout << "argv数组进行访问的版本" << std::endl;
for(int i = 0;i < argc;i++)
{
std::cout << argv[i] << std::endl;
}
return 0;
}
shell命令:
./main --ip="47.235.41.48" --port=9090 --enableDebug=false
输出:
可以看到,argv中包含了完整的命令行参数,包括可执行文件总共四个,下面我们看看第三个参数为true的情况。
代码只是将第三个参数设置为true,其它不变,输出如下:
这时候argv中就只有可执行文件的命令行内容了,argc也相应的变成了1,。也就是说,设置为true的情况下将gflags自定义的命令行参数给删除了,argc也相应减少。设置为true是我个人经常使用和推荐的版本,因为访问gflags命令行参数时,我们直接使用“FLAGS_”作为前缀即可,这样不用自己进行字符串解析,非常的方便。
6.运行参数设置
gflags 为我们提供了多种命令行设置参数的方式。
string 和 int 设置参数
exec --log_file="./main.log"
exec -log_file="./main.log"
exec --log_file "./main.log"
exec -log_file "./main.log"
int版本的设置则是不加双引号,其它没有什么不同。
bool 设置参数
exec --reuse_addr
exec --noreuse_addr
exec --reuse_addr=true
exec --reuse_addr=false
上面命令行中没有声明true或者false的前两行的意思就是设置为true,简化了书写。
另外有一点专门的说明,--单独使用将会终止标识的处理。比如在 exec -f1 1 -- -f2 2 中, f1 被认为是一个标识,但 f2 不会。
7.配置文件的使用
配置文件的使用,其实就是为了让程序的运行参数配置更加标准化,不需要每次运行的时候都手动收入每个参数的数值,而是通过配置文件,一次编写,永久使用。
需要注意的是,配置文件中选项名称必须与代码中定义的选项名称一致。
例子,配置文件main.conf
--ip="222.2.2.2"
--port=7777
--enableDebug=false
命令行
./main --flagfile=./main.conf
这里需要用到--flagfile这个选项来指明配置文件的地址。
输出时则输出配置文件中的内容。
8.特殊参数标识
gflags 也默认为我们提供了几个特殊的标识。
--help # 显示文件中所有标识的帮助信息
--helpfull # 和-help 一样, 帮助信息更全面一些
--helpshort # 只显示当前执行文件里的标志
--helpxml # 以 xml 方式打印,方便处理
--version # 打印版本信息,由 google::SetVersionString()设定
--flagfile -flagfile=f #从文件 f 中读取命令行参数
四.总结
以上就是gflags的使用,非常的简单,并且允许在程序各个地方进行命令行参数的定义,不止在main函数中,但有一个缺点,也就是在两个文件中定义了名字相同的命令行参数,并且这两个文件进行了链接,那么程序就会编译报错,这就要求我们开发人员要格外小心。