• google_gflags使用


    gflags是google开源的一个解析命令行参数的工具。

    最简单的demo

     1 #include <iostream>
     2 #include <gflags/gflags.h>
     3 
     4 using namespace std;
     5 
     6 DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
     7 DEFINE_int32(port, 9090, "program listen port");
     8 DEFINE_bool(daemon, true, "run daemon mode");
     9 
    10 int main(int argc, char** argv)
    11 {
    12   gflags::ParseCommandLineFlags(&argc, &argv, true);
    13  
    14   cout << "confPath = " << FLAGS_confPath << endl;
    15   cout << "port = " << FLAGS_port << endl;
    16 
    17   if (FLAGS_daemon) {
    18     cout << "run background ..." << endl;
    19   }
    20   else {
    21     cout << "run foreground ..." << endl;
    22   }
    23 
    24   cout << "good luck and good bye!" << endl;
    25 
    26   gflags::ShutDownCommandLineFlags();
    27   return 0;
    28 }

    直接运行结果如下:

    [amcool@leoox build]$ ./demo
    confPath = ../conf/setup.ini
    port = 9090
    run background ...
    good luck and good bye!

    设定命令行参数

    前面直接运行我们没有输入参数,所以用的就是上面写的那些默认参数。下面来看一下传入命令行参数的情况,主要有3种情况:

    1、设定参数值

    i)可以用 –参数名=参数值 或者 -参数名=参数值 的方式来设定参数值。

    ii)对于bool类型的参数,除了上述方式外,还可以用 –参数名 的方式设定为true(即不带值), 使用 –no参数名 的方式设定为false。为了统一,建议都使用上面的 第 i 种方法来设定参数。

    加入参数值运行一下:

    [amcool@leoox build]$ ./demo --port=8888 --confPath=./setup.ini --daemon=true  
    confPath = ./setup.ini
    port = 8888
    run background ...
    good luck and good bye!
    [amcool@leoox build]$ ./demo -port=8888 -confPath=./setup.ini -daemon=false
    confPath = ./setup.ini
    port = 8888
    run foreground ...
    good luck and good bye!
    [amcool@leoox build]$ ./demo -port=8888 -confPath=./setup.ini -daemon【对于bool型最好还是和上面统一直接指定值,不要用这种特殊方式】
    confPath = ./setup.ini
    port = 8888
    run background ...
    good luck and good bye!
    [amcool@leoox build]$ ./demo -port=8888 -confPath=./setup.ini -nodaemon【对于bool型最好还是和上面统一直接指定值,不要用这种特殊方式】
    confPath = ./setup.ini
    port = 8888
    run foreground ...
    good luck and good bye!
    [amcool@leoox build]$

    2、从文件读入“命令行”参数

    如果命令行参数很多,可以用 –flagfile=命令行文件 的方式传入命令行文件。

    [amcool@leoox build]$ vi param.cmd
    --port=8888
    --confPath=./setup.ini
    --daemon=true
    [amcool@leoox build]$ ./demo --flagfile=param.cmd
    confPath = ./setup.ini
    port = 8888
    run background ...
    good luck and good bye!
    [amcool@leoox build]$

    3、从环境变量读入参数值

    gflags另外还提供了 –fromenv 和 –tryfromenv 参数,通过这两个参数,程序可以从环境变量中获取到具体的值。

    –fromenv 从环境变量读取参数值 –fromenv=port,confPath 表明要从环境变量读取port,confPath两个参数的值。但是当无法从环境变量中获取到的时候,会报错,同时程序退出。【注意:gflags的变量名是 FLAGS_我们定义的参数名】

    –tryfromenv 与–fromenv类似,当参数的没有在环境变量定义时,不退出。

    这种方式并不太常用,知道就可以了。

    [amcool@leoox build]$ ./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!
    [amcool@leoox build]$ export FLAGS_confPath=./loveyou.ini
    [amcool@leoox build]$ export FLAGS_port=36888   
    [amcool@leoox build]$ env | grep FLAGS
    FLAGS_port=36888
    FLAGS_confPath=./loveyou.ini
    [amcool@leoox build]$          
    [amcool@leoox build]$ ./demo --fromenv=port,confPath     
    confPath = ./loveyou.ini
    port = 36888
    run background ...
    good luck and good bye!
    [amcool@leoox build]$

    支持的参数类型

    使用gflags提供的宏:DEFINE_xxx(变量名,默认值,help_string)。这些变量需要在全局范围内定义。变量支持以下类型:

    定义类型
    DEFINE_bool 布尔型
    DEFINE_int32 32位整形
    DEFINE_int64 64位整形
    DEFINE_uint64 64位无符号整形
    DEFINE_double double型
    DEFINE_string C++中string类型

    针对定义的宏进行一下参数解释:

    1 DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
    

    第一个字段 confPath就是命令行里要输入的参数名,比如 –confPath=./love.ini

    第二个字段”../conf/setup.ini”,就是如果命令行里没指定这个参数,那默认值就是 ../conf/setup.ini

    第三个字段”program configure file.”,就是这个参数的帮助说明信息,当用户输入 –hlep 的时候,会显示出来。

    然后在代码中使用的变量就是:FLAGS_confPath

    解析命令行参数

    gflags是使用ParseCommandLineFlags这个方法来完成命令行参数的解析的。具体如下:

    1 gflags::ParseCommandLineFlags(&argc, &argv, true);

    一目了然,唯一值得注意的就是第三个参数了。如果设置为true,gflags就会移除解析过的参数。即argc, argv就会变了。否则gflags还会保持这些参数继续留在argc,argv中。但是参数的顺序有可能会发生变化。下面来看一个例子就清楚了:

     1 #include <iostream>
     2 #include <gflags/gflags.h>
     3  
     4 using namespace std;
     5  
     6 DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
     7 DEFINE_int32(port, 9090, "program listen port");
     8 DEFINE_bool(daemon, true, "run daemon mode");
     9  
    10 int main(int argc, char** argv)
    11 {
    12   for (int i = 0; i < argc; i++) {
    13     printf("argv[%d] = %s
    ", i, argv[i]);
    14   }
    15   printf("---------------here--------------
    ");
    16 
    17   gflags::SetVersionString("1.0.0.0");
    18   gflags::SetUsageMessage("Usage : ./demo ");
    19   gflags::ParseCommandLineFlags(&argc, &argv, true);
    20  
    21   for (int i = 0; i < argc; i++) {
    22     printf("argv[%d] = %s
    ", i, argv[i]);
    23   }
    24   printf("---------------there--------------
    ");
    25 
    26   cout << "confPath = " << FLAGS_confPath << endl;
    27   cout << "port = " << FLAGS_port << endl;
    28  
    29   if (FLAGS_daemon) {
    30     cout << "run background ..." << endl;
    31   }
    32   else {
    33     cout << "run foreground ..." << endl;
    34   }
    35  
    36   cout << "good luck and good bye!" << endl;
    37  
    38   gflags::ShutDownCommandLineFlags();
    39   return 0;
    40 }

    当第三个参数为true时,运行结果如下:

    [amcool@leoox build]$ ./demo --port=8888 --confPath=./happy.ini --daemon
    argv[0] = ./demo
    argv[1] = --port=8888
    argv[2] = --confPath=./happy.ini
    argv[3] = --daemon
    ---------------here--------------
    argv[0] = ./demo
    ---------------there--------------
    confPath = ./happy.ini
    port = 8888
    run background ...
    good luck and good bye! 

    当第三个参数为false时,运行结果如下:

    [amcool@leoox build]$ ./demo --port=8888 --confPath=./happy.ini --daemon  
    argv[0] = ./demo
    argv[1] = --port=8888
    argv[2] = --confPath=./happy.ini
    argv[3] = --daemon
    ---------------here--------------
    argv[0] = ./demo
    argv[1] = --port=8888
    argv[2] = --confPath=./happy.ini
    argv[3] = --daemon
    ---------------there--------------
    confPath = ./happy.ini
    port = 8888
    run background ...
    good luck and good bye!

    参数检查

    按照以前的习惯,我们可以获取到所有参数的值后,再在代码里面进行判断这个参数是否是我们想要的。比如,我们需要端口是36800 到 36888之间的,那我们可以这样检查。

    1 if (FLAGS_port < 36800 || FLAGS_port > 36888) {
    2     printf("port must [36800, 36888]
    ");
    3     return -1;
    4 }

    gflags里面建议使用 RegisterFlagValidator 这个方法来做参数检查。参数不通过的时候,程序是启动失败的。什么时候会调用这个参数检查函数呢?

    如果采用 static 全局变量来确保检查函数会在 main 开始时被注册,可以保证注册会在 ParseCommandLineFlags 函数之前。如果默认值检查失败,那么 ParseCommandLineFlag将会使程序退出。如果之后使用 SetCommandLineOption() 来改变参数的值,那么检查函数也会被调用,但是如果验证失败,只会返回 false,然后参数保持原来的值,程序不会结束。

     1 #include <stdint.h>
     2 #include <stdio.h>
     3 #include <iostream>
     4 
     5 #include <gflags/gflags.h>
     6 
     7 // 定义对 FLAGS_port 的检查函数
     8 static bool ValidatePort(const char* name, int32_t value) {
     9     if (value > 0 && value < 32768) {
    10         return true;
    11     }
    12     printf("Invalid value for --%s: %d
    ", name, (int)value);
    13     return false;
    14 }
    15 
    16 /**
    17  *  设置命令行参数变量
    18  *  默认的主机地址为 127.0.0.1,变量解释为 'the server host'
    19  *  默认的端口为 12306,变量解释为 'the server port'
    20  */
    21 DEFINE_string(host, "127.0.0.1", "the server host");
    22 DEFINE_int32(port, 12306, "the server port");
    23 
    24 // 使用全局 static 变量来注册函数,static 变量会在 main 函数开始时就调用
    25 static const bool port_dummy = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort);
    26 
    27 int main(int argc, char** argv) {
    28     // 解析命令行参数,一般都放在 main 函数中开始位置
    29     gflags::ParseCommandLineFlags(&argc, &argv, true);
    30     std::cout << "The server host is: " << FLAGS_host
    31         << ", the server port is: " << FLAGS_port << std::endl;
    32 
    33     // 使用 SetCommandLineOption 函数对参数进行设置才会调用检查函数
    34     gflags::SetCommandLineOption("port", "-2");
    35     std::cout << "The server host is: " << FLAGS_host
    36         << ", the server port is: " << FLAGS_port << std::endl;
    37     return 0;
    38 }

    运行结果如下:

    #命令行指定非法值,程序解析参数时直接退出
    ➜  test ./gflags_test -port -2
    Invalid value for --port: -2
    ERROR: failed validation of new value '-2' for flag 'port'
    # 这里参数默认值合法,但是 SetCommandLineOption 指定的值不合法,程序不退出,参数保持原来的值
    ➜  test ./gflags_test        
    The server host is: 127.0.0.1, the server port is: 12306
    Invalid value for --port: -2
    The server host is: 127.0.0.1, the server port is: 12306

    其他代码文件使用参数变量

    正常来说,代码可能不只有1个cpp,还会有很多模块。而每个模块可能会使用到不同的参数值。所以我们之前在demo.cpp定义的参数变量(比如FLAGS_port),在其他模块怎么引用和使用呢?so easy,与DEFINE相对应的有DECLARE。声明一下,就可以使用了。

    1 DECLARE_bool: boolean
    2 DECLARE_int32: 32-bit integer
    3 DECLARE_int64: 64-bit integer
    4 DECLARE_uint64: unsigned 64-bit integer
    5 DECLARE_double: double
    6 DECLARE_string: C++ string

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

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

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

    版本号和帮助信息

    在使用程序的时候,都离不开两个参数 –version 和 –help。来看看上面实现的demo能否支持呢?

    [amcool@leoox build]$ ./demo --version
    demo
    [amcool@leoox build]$ ./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() 之前设定。

    修改后的代码如下:

     1 #include <iostream>
     2 #include <gflags/gflags.h>
     3 
     4 using namespace std;
     5 
     6 DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");
     7 DEFINE_int32(port, 9090, "program listen port");
     8 DEFINE_bool(daemon, true, "run daemon mode");
     9 
    10 int main(int argc, char** argv)
    11 {
    12   gflags::SetVersionString("1.0.0.0");
    13   gflags::SetUsageMessage("Usage : ./demo ");
    14   gflags::ParseCommandLineFlags(&argc, &argv, true);
    15  
    16   cout << "confPath = " << FLAGS_confPath << endl;
    17   cout << "port = " << FLAGS_port << endl;
    18 
    19   if (FLAGS_daemon) {
    20     cout << "run background ..." << endl;
    21   }
    22   else {
    23     cout << "run foreground ..." << endl;
    24   }
    25 
    26   cout << "good luck and good bye!" << endl;
    27 
    28   gflags::ShutDownCommandLineFlags();
    29   return 0;
    30 }

    运行结果如下:

    [amcool@leoox build]$ ./demo --version
    demo version 1.0.0.0
    [amcool@leoox build]$ ./demo --help
    demo: Usage : ./demo

      Flags from /home/amcool/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



      Flags from /home/amcool/soft/gflags-2.1.1/src/gflags.cc:
        -flagfile (load flags from file) type: string default: ""
        -fromenv (set flags from the environment [use 'export FLAGS_flag1=value'])
          type: string default: ""
        -tryfromenv (set flags from the environment if present) type: string
          default: ""
        -undefok (comma-separated list of flag names that it is okay to specify on
          the command line even if the program does not define a flag with that
          name.  IMPORTANT: flags in this list that have arguments MUST use the
          flag=value format) type: string default: ""

      Flags from /home/amcool/soft/gflags-2.1.1/src/gflags_completions.cc:
        -tab_completion_columns (Number of columns to use in output for tab
          completion) type: int32 default: 80
        -tab_completion_word (If non-empty, HandleCommandLineCompletions() will
          hijack the process and attempt to do bash-style command line flag
          completion on this value.) type: string default: ""

      Flags from /home/amcool/soft/gflags-2.1.1/src/gflags_reporting.cc:
        -help (show help on all flags [tip: all flags can have two dashes])
          type: bool default: false currently: true
        -helpfull (show help on all flags -- same as -help) type: bool
          default: false
        -helpmatch (show help on modules whose name contains the specified substr)
          type: string default: ""
        -helpon (show help on the modules named by this flag value) type: string
          default: ""
        -helppackage (show help on all modules in the main package) type: bool
          default: false
        -helpshort (show help on only the main module for this program) type: bool
          default: false
        -helpxml (produce an xml version of help) type: bool default: false
        -version (show version and build info and exit) type: bool default: false
    [amcool@leoox build]$

    本文参考自:

    http://blog.csdn.net/u013407923/article/details/53084076

    http://blog.csdn.net/jcjc918/article/details/50876613

    http://blog.csdn.net/lezardfu/article/details/23753741

    http://www.leoox.com/?p=270

    http://www.leoox.com/?p=275

  • 相关阅读:
    今天再次认真整理了浏览器收藏夹
    今天再次认真整理了浏览器收藏夹
    【博客之星】CSDN2013博客之星--分析和预测
    【博客之星】CSDN2013博客之星--分析和预测
    CSDN博客的文章分类和战略规划
    CSDN博客的文章分类和战略规划
    《社交红利》读书总结--如何从微信微博QQ空间等社交网络带走海量用户、流量与收入
    《社交红利》读书总结--如何从微信微博QQ空间等社交网络带走海量用户、流量与收入
    个人名片与诚信
    个人名片与诚信
  • 原文地址:https://www.cnblogs.com/abc-begin/p/7895817.html
Copyright © 2020-2023  润新知