Gflags解剖课:从DEFINE宏到命令行解析的工程化实践

文章目录

  • [一、gflags 介绍](#一、gflags 介绍)
  • [二、gflags 安装](#二、gflags 安装)
    • [1. 直接命令安装(适用于 Ubuntu/Debian 系统)](#1. 直接命令安装(适用于 Ubuntu/Debian 系统))
    • [2. 源码编译安装](#2. 源码编译安装)
  • [三、gflags 使用](#三、gflags 使用)
    • [1. 包含头文件](#1. 包含头文件)
    • [2. 定义参数](#2. 定义参数)
      • [2.1 定义参数的方法](#2.1 定义参数的方法)
      • [2.2 定义参数的作用解析](#2.2 定义参数的作用解析)
    • [3. 修改定义参数](#3. 修改定义参数)
      • [3.1 命令行输入 修改定义参数](#3.1 命令行输入 修改定义参数)
      • [3.2 通过配置文件 修改定义参数](#3.2 通过配置文件 修改定义参数)
    • [4. 不同文件访问参数(主文件 DEFINE_类型 定义,其它文件 DECLARE_类型 声明)](#4. 不同文件访问参数(主文件 DEFINE_类型 定义,其它文件 DECLARE_类型 声明))
    • [5. 特殊参数标识(如何查看定义参数时 指定的帮助信息)](#5. 特殊参数标识(如何查看定义参数时 指定的帮助信息))

一、gflags 介绍

gflags 是 Google 开发的一个开源库,用于 C++ 应用程序中命令行参数的声明、定义和解析。
gflags 库提供了一种简单的方式来添加、解析和文档化命令行标志(flags),使得程序可以根据不同的运行时配置进行调整。

它具有如下几个特点:

  • 易于使用: gflags 提供了一套简单直观的 API 来定义和解析命令行标志,使得开发者可以轻松地为应用程序添加新的参数。
  • 自动帮助和文档: gflags 可以自动生成每个标志的帮助信息和文档,这有助于用户理解如何使用程序及其参数。
  • 类型安全: gflags 支持多种数据类型的标志,包括布尔值、整数、字符串等,并且提供了类型检查和转换。
  • 多平台支持: gflags 可以在多种操作系统上使用,包括 Windows、Linux 和 macOS。
  • 可扩展性: gflags 允许开发者自定义标志的注册和解析逻辑,提供了强大的扩展性。

链接: 官方文档
链接: 代码仓库

二、gflags 安装

1. 直接命令安装(适用于 Ubuntu/Debian 系统)

(1)步骤:

bash 复制代码
sudo apt-get update                 # 更新软件源
sudo apt-get install libgflags-dev  # 安装开发库

(2)特点:

  • 简单快捷:适合快速部署,无需手动编译。
  • 版本受限:依赖系统仓库的版本,可能非最新(如 Ubuntu 20.04 默认版本较旧)。

(3)验证安装:

  • 检查头文件:ls /usr/include/gflags/
  • 检查库文件:ls /usr/lib/x86_64-linux-gnu/libgflags*

2. 源码编译安装

bash 复制代码
# 下载源码
git clone https://github.com/gflags/gflags.git
# 切换目录
cd gflags/
# 创建并进入构建目录
mkdir build
cd build/
# 执行构建命令,生成 Makefile
cmake ..
# 编译代码
make
# 安装到系统目录(默认 /usr/local)
sudo make install


至此,gflags 安装完毕。

三、gflags 使用

1. 包含头文件

使用 gflags 库来定义/解析命令行参数必须包含如下头文件

cpp 复制代码
#include <gflags/gflags.h>

2. 定义参数

2.1 定义参数的方法

利用 gflag 提供的宏定义来定义参数。该宏的 3 个参数分别为参数名,参数默认值,参数的帮助信息。

  • 基本形式:
cpp 复制代码
DEFINE_<类型>(参数名, 默认值, "帮助信息");
  • gflags 支持定义多种类型的宏函数:

仅支持基本类型,不支持自定义类型

cpp 复制代码
DEFINE_bool
DEFINE_int32
DEFINE_int64
DEFINE_uint64
DEFINE_double
DEFINE_string
  • 使用示例:
cpp 复制代码
DEFINE_bool(reuse_addr, true, "是否开始网络地址重用选项");
DEFINE_int32(log_level, 1, "日志等级: 1-DEBUG, 2-WARN, 3-ERROR");
DEFINE_string(log_file, "stdout", "日志输出位置设置,默认为标准输出");

2.2 定义参数的作用解析

  • 项目结构:
bash 复制代码
.
├── main.cc
└── Makefile

./main.cc

cpp 复制代码
#include <gflags/gflags.h>
#include <iostream>

// 设置 bool FLAGS_reuse_addr = true; 的全局变量
DEFINE_bool(reuse_addr, true, "是否开始网络地址重用选项");
// 设置 int32_t FLAGS_log_level = 3; 的全局变量
DEFINE_int32(log_level, 3, "日志等级: 1-DEBUG, 2-WARN, 3-ERROR");
// 设置 std::string FLAGS_log_file = "stdout"; 的全局变量
DEFINE_string(log_file, "stdout", "日志输出位置设置,默认为标准输出");

int main()
{
    std::cout << "FLAGS_reuse_addr: " << FLAGS_reuse_addr << std::endl;
    std::cout << "FLAGS_log_level: " << FLAGS_log_level << std::endl;
    std::cout << "FLAGS_log_file: " << FLAGS_log_file << std::endl;
    return 0;
}

./Makefile

链接时,-l显式指定库名:gflags

bash 复制代码
main:main.cc
	g++ -o main main.cc -lgflags
  • make执行编译链接过程,形成可执行文件main。再运行main,查看执行结果:

3. 修改定义参数

3.1 命令行输入 修改定义参数

cpp 复制代码
#include <gflags/gflags.h>
#include <iostream>

// 设置 bool FLAGS_reuse_addr = true; 的全局变量
DEFINE_bool(reuse_addr, true, "是否开始网络地址重用选项");
// 设置 int32_t FLAGS_log_level = 3; 的全局变量
DEFINE_int32(log_level, 3, "日志等级: 1-DEBUG, 2-WARN, 3-ERROR");
// 设置 std::string FLAGS_log_file = "stdout"; 的全局变量
DEFINE_string(log_file, "stdout", "日志输出位置设置,默认为标准输出");

int main(int argc, char* argv[])
{
    // 遍历 argv 数组,识别 --参数名=值 或 --参数名 值 格式的字符串
    // 根据命令行指示,修改所有定义参数
    gflags::ParseCommandLineFlags(&argc, &argv, true);

    std::cout << "FLAGS_reuse_addr: " << FLAGS_reuse_addr << std::endl;
    std::cout << "FLAGS_log_level: " << FLAGS_log_level << std::endl;
    std::cout << "FLAGS_log_file: " << FLAGS_log_file << std::endl;
    return 0;
}

gflags 为我们提供了多种命令行设置参数的方式:

(1)string 和 int 设置参数

  • main --参数名=值
  • main -参数名=值
  • main --参数名 值
  • main -参数名 值

(2)bool 设置参数

  • main --参数名
  • main --no参数名
  • main --参数名=true
  • main --参数名=false

3.2 通过配置文件 修改定义参数

  • 项目结构:
bash 复制代码
.
├── main
├── main.cc
├── main.conf
└── Makefile

./main.conf

配置文件中内容

bash 复制代码
--reuse_addr=false
--log_level=15
--log_file=./log/main.log

  • gflags 通过 --flagfile 参数加载配置文件,将文件内容等效转换为命令行参数

4. 不同文件访问参数(主文件 DEFINE_类型 定义,其它文件 DECLARE_类型 声明)

一个项目下往往包含多个源文件,假设 main.ccui.cc 属于同一项目:

(1)在 main.cc 开头,DEFINE_bool 定义全局变量:

cpp 复制代码
#include <gflags/gflags.h>
// bool FLAGS_big_menu = true;
DEFINE_bool(big_menu, true, "启用高级菜单");  // 实际定义

(2)如果在 ui.cc 中想使用 main.cc 中 DEFINE_bool 定义的全局变量,需要声明:

cpp 复制代码
#include <gflags/gflags.h>
DECLARE_bool(big_menu);  // 外部声明

宏定义 DECLARE_bool(big_menu); 展开是:
extern bool FLAGS_big_menu;

5. 特殊参数标识(如何查看定义参数时 指定的帮助信息)

  • gflags 也默认为我们提供了几个特殊的标识:
bash 复制代码
--help            # 显示文件中所有标识的帮助信息
--helpfull        # 和-help 一样, 帮助信息更全面一些
--helpshort       # 只显示当前执行文件里的标志
--helpxml         # 以 xml 方式打印,方便处理
--version         # 打印版本信息,由 google::SetVersionString()设定
  • 使用--help选项,查看定义参数时 指定的帮助信息

相关推荐
Tanecious.2 小时前
蓝桥杯备赛:Day8-小红杀怪
c++·蓝桥杯
wregjru2 小时前
【高并发服务器项目】2.服务器业务层设计详解
c++
样例过了就是过了3 小时前
LeetCode热题100 跳跃游戏 II
c++·算法·leetcode·贪心算法·动态规划
charlie1145141913 小时前
现代Qt开发——0.1——如何在IDE中配置Qt环境?
开发语言·c++·ide·qt·嵌入式
计算机安禾3 小时前
【数据结构与算法】第32篇:交换排序(一):冒泡排序
c语言·数据结构·c++·算法·链表·排序算法·visual studio code
胖咕噜的稞达鸭3 小时前
C/C++动态内存管理,malloc,calloc,realloc的区别,动态内存中的错误汇总
c语言·开发语言·c++
charlie1145141913 小时前
嵌入式C++教程实战之Linux下的单片机编程(6):从点亮第一盏LED开始 —— 我们为什么要用现代C++写STM32
linux·c语言·开发语言·c++·stm32·单片机
linux开发之路3 小时前
C++实现Whisper+Kimi端到端AI智能语音助手
c++·人工智能·llm·whisper·openai
艾莉丝努力练剑3 小时前
【Linux系统:多线程】线程概念与控制
linux·运维·服务器·c++·后端·学习·操作系统