gflags 介绍
# 一、基本介绍
- gflag 是 google 开源的处理命令行参数的库,用 C++ 编写的,同时提供了 Python 接口;
- 其参数定义可以分散在各个文件中,而不是局限于某一个文件,复用性较强;
- 相比于 getopt 应用起来更加灵活与方便,常用于各种开源库中;
- github地址 (opens new window)
- 官方文档 (opens new window)
# 二、安装与编译
# 1,安装二进制包
- 在
Debian/Ubuntu Linux
上,可以使用apt-get
命令安装:
sudo apt-get install libgflags-dev
1
- 在
CentOS Linux
上,可以使用yum
命令安装:
sudo yum install libgflags-dev
1
- 在
macOS
上,使用Homebrew
安装:
brew install gflags
1
# 2,cmake 编译源文件
gflags
的编译要求 CMake 的版本不低于 3.0.2;- 可以从
github
仓库克隆源文件或是直接下载源文件压缩包;
点击查看
git clone https://github.com/gflags/gflags
cd gflags
git checkout v2.2.2 (optional)
mkdir build
cd build
cmake ..
make
make test (optional)
make install (optional)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 三、使用方法
# 1,支持类型
类型 | 描述 |
---|---|
DEFINE_bool | 布尔 |
DEFINE_int32 | 32 位整数 |
DEFINE_int64 | 64 位整数 |
DEFINE_uint64 | 无符号 64 位整数 |
DEFINE_double | 双精度浮点数 |
DEFINE_string | C++字符串 |
# 2,定义方式
- 在某个文件中键入以下代码定义某些标志;
点击查看
// 文件名为:com_flags.cpp
#include <gflags/gflags.h>
// 标志定义
DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");
DEFINE_string(languages, "english,french,german", "comma-separated list of languages to offer in the 'lang' menu");
1
2
3
4
5
6
2
3
4
5
6
- 所有 DEFINE 宏都采用相同的三个参数:标志的名称、其默认值和用法描述;
- 可以在可执行文件中的任何源代码文件中定义标志,并在其他文件中声明它后就可以在该文件使用;
# 3,访问方式
- 所有定义的标志,在程序中都可以想变量一样使用它;
- 对应的变量名为:
FLAGS_
后加上定义的标志名; - 如上面的定义的标志名对应的变量名为:
FLAGS_big_menu, FLAGS_languages
;
# a) 同文件访问
- 同文件直接通过变量名访问;
点击查看
// 文件名为:com_flags.cpp
if (FLAGS_big_menu)
FLAGS_languages += "gflags";
if (FLAGS_languages.find("flag") != string::npos)
HandleFinnish();
1
2
3
4
5
6
2
3
4
5
6
# b) 跨文件访问
- 当需要在其他文件中使用该标志时,需要先声明再访问;
- 声明的方式就是将定义标志的
DEFINE
换成DECLARE
,相当于 C++ 的关键字extern
; - 以上述例子为基础,在
main.cc
文件中访问com_flags.cpp
文件中定义标志; - 需要先在
com_flags.cpp
的头文件com_flags.h
中进行声明,然后在main.cc
文件中包含该头文件既可:点击查看
// 文件名:com_flags.h // 标志的声明 DECLARE_bool(big_menu); DECLARE_string(languages;
1
2
3
4
5// 文件名:main.cc include "com_flags.h" if (FLAGS_big_menu) FLAGS_languages += "gflags"; if (FLAGS_languages.find("flag") != string::npos) HandleFinnish();
1
2
3
4
5
6
7 - 当变量的定义是在命名空间内定义时,声明的时候也需要带上命名空间;
点击查看
// brpc 中的consul服务的标志定义 namespace brpc { namespace policy { DEFINE_string(consul_agent_addr, "http://127.0.0.1:8500", "The query string of request consul for discovering service."); DEFINE_string(consul_service_discovery_url, "/v1/health/service/", "The url of consul for discovering service."); } }
1
2
3
4
5
6
7
8
9
10
11// 文件名:main.cc // 在其他文件中声明标志时带上命名空间 namespace brpc { namespace policy { DECLARE_string(consul_agent_addr,); DECLARE_string(consul_service_discovery_url); // ...... } }
1
2
3
4
5
6
7
8
9
10
11
# 4,注册标志验证器
- 为了校验参数是否符合自定义的要求,可以为定义标志注册一个验证器函数;
- 每当该标志解析或修改时,都会调用验证器函数 使用新值作为参数;
- 验证器函数应该返回一个布尔值,如果标志值有效,则返回
true
,否则返回false
; - 如果函数返回
false
,则标志将保留其当前值; - 确保注册函数发生在命令行解析的开头;
点击查看
static bool ValidatePort(const char* flagname, int32 value) {
if (value > 0 && value < 32768) // value is ok
return true;
printf("Invalid value for --%s: %d\n", flagname, (int)value);
return false;
}
DEFINE_int32(port, 0, "What port to listen on");
static const bool port_dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort);
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 如果注册成功,注册函数返回值为ture。否则返回false,注册失败一般是一下两种原因:
- 第一个参数不引用命令行标志;
- 已经为此标志注册了不同的验证器;
# 5,命令行标志
# a) 解析
- 在
main
函数的开头使用gflags::ParseCommandLineFlags(&argc, &argv, remove_flags)
函数可以帮助解析出相应的flags
; - 最后一个参数
remove_flags
:- 若设置为
true
,表示解析后将flag以及其对应的值从argv
中删除,并相应的修改argc
,即最后存放的是不包含flag的参数(不清楚为啥这样做); - 若设置为
false
,则仅对参数进行重排,标志位参数放在最前面;
- 若设置为
# b) 设置
- 标志前可用单短线或双短线,标志后可用等号或空格;
- 布尔类型标志前可以添加
no
标识false
,没有且后面没有值时表示true
; - 命令行标志的设置方式较多,实际使用时建议使用其中一种,提高可读性;
点击查看
./main --languages="chinese,japanese,korean"
./main -languages="chinese,japanese,korean"
./main --languages "chinese,japanese,korean"
./main -languages "chinese,japanese,korean"
./main --big_menu
./main --nobig_menu
./main --big_menu=true
./main --big_menu=false
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 6,特殊标志
# a) 报告标志
标志 | 作用 |
---|---|
--help | 显示所有文件的所有标志,按文件排、名称排序,显示标志名称、其默认值及其帮助 |
--helpfull | 与 -help 相同,但明确要求所有标志(以防将来帮助发生变化) |
--helpshort | 仅显示与可执行文件同名的文件的标志(通常是包含main()) |
--helpxml | 像 --help 一样,但输出是 XML 格式的,以便于解析 |
--helpon=FILE | 显示 FILE 文件中定义的标志 |
--helpmatch=S | 显示 S 中定义的标志 |
--helppackage | 显示和 main() 在相同目录的文件中的flag |
--version | 打印可执行文件的版本信息 |
# b) 功能标志
--undefok=flagname,...
:这个标志在命令行无定义时不会报错退出,即使在程序中未使用--undefok--namename
;--fromenv=bar
:从环境中读取 bar 标志的值,必须在环境变量定义该值,如export FLAGS_bar=yyy
,等效于在命令行使用--bar=yyy
,缺省时可以通过--undefok=bar
忽略错误;--tryfromenv=foo
:应用程序保留其默认值,并尝试从环境变量中获取,未定义时不会报错;--flagfile=file1
:从文件读取命令行标志,可以接一系列文件名,并支持通配符,每个标志一行,可以用#
注释;
# 7,定制版本与帮助
- 通过
--version
会输出其对应的版本,SetVersionString()
设置版本信息; - 通过
--help
会输出帮助信息,SetUsageMessage()
设置帮助信息,与上面的 help 不冲突,会先输出此处设置帮助信息,再输出标志的信息; - 参数的设置需要在调用
ParseCommandLineFlags()
之前;
gflags::SetVersionString("1.1.0");
gflags::SetUsageMessage("./main --foo=yyy");
gflags::ParseCommandLineFlags(&argc, &argv, true);
1
2
3
2
3
# 四、使用示例
# 1,目录结构
点击查看
.
├── CMakeLists.txt
├── README.md
├── build.sh
├── gflags
│ ├── AUTHORS.txt
│ ├── BUILD
│ ├── CMakeLists.txt
│ ├── COPYING.txt
│ ├── ChangeLog.txt
│ ├── INSTALL.md
│ ├── README.md
│ ├── WORKSPACE
│ ├── appveyor.yml
│ ├── bazel
│ ├── cmake
│ ├── doc
│ ├── mybuild
│ ├── src
│ └── test
├── main.cc
└── mybuild
├── CMakeCache.txt
├── CMakeFiles
├── Makefile
├── cmake_install.cmake
├── gflags
└── main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 2,示例代码
点击查看
#include <gflags/gflags.h>
#include <iostream>
// 标志验证器
static bool ValidatePort(const char *flagname, int32_t value)
{
if (value > 0 && value < 32768) // value is ok
return true;
printf("Invalid value for --%s: %d\n", flagname, (int)value);
return false;
}
// 标志定义
DEFINE_bool(big_menu, true, "Include 'advance' option in the menu listing");
DEFINE_string(languages, "english, french, chinese", "comma-separated list of languages to offer in the 'lang' menu");
DEFINE_int32(port, 9988, "What port to listen on");
// 注册标志验证器
static const bool port_dummy = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort);
int main(int argc, char **argv)
{
// 设置版本
gflags::SetVersionString("1.1.0");
// 设置使用帮助信息
gflags::SetUsageMessage("./main --big_menu --languages=\"english, french, chinese\" --port=9988");
// 命令行参数解析
gflags::ParseCommandLineFlags(&argc, &argv, true);
std::cout << std::boolalpha; // 为了让bool类型输出true/false,而不是 1/0
std::cout << "big_menu: " << FLAGS_big_menu << '\n'
<< "languages: " << FLAGS_languages << '\n'
<< "port: " << FLAGS_port << std::endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 3,编译脚本
点击查看
cmake_minimum_required(VERSION 2.8.12)
project(gflags_demo)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -w -O3 -DNDEBUG -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -w -O3 -DNDEBUG -std=c++11")
add_subdirectory(gflags) # 添加子目录
add_executable(main main.cc) # 生成目标文件 main
target_link_libraries(main gflags::gflags) # 链接到 gflags库
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 4,执行脚本
点击查看
#!/bin/bash
set -x -e
# git clone git@github.com:gflags/gflags.git 第一次执行时下载
rm -rf mybuild
mkdir mybuild
cd mybuild
cmake ..
make
./main
./main --version
./main --help
./main --port=99999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
参考文章
[1] https://gflags.github.io/gflags/ (opens new window)
[2] https://cloud.tencent.com/developer/article/1695005 (opens new window)
[3] https://izualzhy.cn/gflags-introduction (opens new window)
[4] https://gohalo.me/post/package-gflags-usage.html (opens new window)
[5] https://zhuanlan.zhihu.com/p/369214077 (opens new window)
编辑 (opens new window)
上次更新: 2023/09/05, 23:10:53