当前位置: 首页 > 工具软件 > apollo-link > 使用案例 >

百度apollo - Apollo代码解析:3. 命令行参数传递google gflags

经伟
2023-12-01

简介

  • 在百度Apollo中gflag被广泛的应用在各种全局变量中,例如节点名,变量名,各种状态标志中。
  • gflags 是google开源的一套命令行参数解析工具,比 getopt 功能更加强大,使用起来更加方便。
  • 什么是 命令行参数解析工具 呢? 这里拿python做例子,例如:python test.py cmd1 cmd2
    其中cmd1cmd2 就是命令行参数,gflags就是用来解析cmd1 cmd2 到程序中的。
  • ps: 在cpp中命令行参数就是字符串

1. 安装 gflags

下载地址:git clone https://github.com/gflags/gflags.git

build和安装教程在INSTALL文件中有, 该教程支持pkg-config, CMake, 以及 Bazel.

1.1 cmake

如果gflags不是安装在默认路径下,则环境变量gflags_DIR 需要是 <prefix>/lib/cmake/gflags 该文件夹下需要是有 gflags-config.cmake 的文件。

如果gflags安装在默认路径下CMake 可以通过 find_package(gflags REQUIRED)

或者添加单线程静态库:
find_package(gflags COMPONENTS nothreads_static)
自动找到 gflags 。

添加dependency和execute
add_executable(foo main.cc)
target_link_libraries(foo gflags)

1.2 Bazel

WORKSPACE中添加以下语句

git_repository(
    name   = "com_github_gflags_gflags",
    commit = "<INSERT COMMIT SHA HERE>",
    remote = "https://github.com/gflags/gflags.git",
)

bind(
    name = "gflags",
    actual = "@com_github_gflags_gflags//:gflags",
)

bind(
    name = "gflags_nothreads",
    actual = "@com_github_gflags_gflags//:gflags_nothreads",
)

ps
gflags_nothreads 强制单线程
gflags 多线程

然后添加到BUILD中:

cc_binary(
    name = "foo",
    srcs = ["main.cc"],
    deps = ["//external:gflags"],
)

2. 使用 gflags

2.1. 首先需要#include "gflags.h"

#include <gflags/gflags.h>

2.2. 宏定义

将需要的命令行参数使用gflags的来定义,例如:DEFINE_xxxxx(变量名,默认值,help-string) 定义在文件当中,注意:是全局的, 例如Apollo中的FLAGS_control_node_name就是一个全局的一个string。gflags支持以下类型:

DEFINE_bool: boolean
DEFINE_int32: 32-bit integer
DEFINE_int64: 64-bit integer
DEFINE_uint64: unsigned 64-bit integer
DEFINE_double: double
DEFINE_string: C++ string

2.3. main函数添加

在main函数中开始的地方加入,以下这句话:

google::ParseCommandLineFlags(&argc, &argv, true);
//如果设为true,则该函数处理完成后,argv中只保留argv[0],argc会被设置为1。
//如果为false,则argv和argc会被保留,但是注意函数会调整argv中的顺序。

2.4 调用

在后续代码中使用FLAGS_变量名访问对应的命令行参数方法如下:

printf("%s", FLAGS_mystr);

2.5 测试

在编译成可执行文件之后,使用:./exe --参数1=值1 --参数2=值2 ... 来为这些命令行参数赋值。

./mycmd --var1="test" --var2=3.141592654 --var3=32767 --mybool1=true --mybool2 --nomybool3

3. gflags进阶使用

3.1. 在其他文件中使用定义的flags变量

  • 有些时候需要在main之外的文件使用定义的flags变量,这时候可以使用宏定义DECLARE_xxx(变量名)声明一下(就和c++中全局变量的使用是一样的,extern一下一样)
DECLARE_bool: boolean
DECLARE_int32: 32-bit integer
DECLARE_int64: 64-bit integer
DECLARE_uint64: unsigned 64-bit integer
DECLARE_double: double
DECLARE_string: C++ string

在对应的.h文件中进行DECLARE_xxx声明,需要使用的文件直接include就行了。
检验输入参数是否合法:gflags库支持定制自己的输入参数检查的函数,如下:

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);

3.2 判断flags变量是否被用户使用

在gflags.h中,还定义了一些平常用不到的函数和结构体。这里举一个例子,判断参数port有没有被用户设定过

    google::CommandLineFlagInfo info;
    if(GetCommandLineFlagInfo("port" ,&info) && info.is_default) {
        FLAGS_port = 27015;
    }

3.3 定制你自己的help信息与version信息

  • version信息:使用google::SetVersionString设定,使用google::VersionString访问
  • help信息:使用google::SetUsageMessage设定,使用google::ProgramUsage访问
  • 注意:google::SetUsageMessagegoogle::SetVersionString这两个函数的调用必须google::ParseCommandLineFlags之前执行
 类似资料: