1、下载、安装:
Google 的 gflags 是一套命令行参数处理的开源库。比 getopt 更方便、功能更强大。包括 C++的版本和 python 的版本。
github地址:https://github.com/gflags/gflags
1)安装cmake工具:
在安装gflags前需要先安装cmake:
官网:https://cmake.org/download/
github:https://github.com/Kitware/CMake/releases
1.1)下载:
本文下载、安装3.8.1版本,地址:
wget 64.tar.gz">https://github.com/Kitware/CMake/releases/download/v3.8.1/cmake-3.8.1-Linux-x86_64.tar.gz
或者:
1.2)编译、安装:
install_specified_deps "cmake-3.8.1"
if [ ! -d cmake-3.8.1 ]; then
tar -zxf cmake-3.8.1.tar.gz
cd cmake-3.8.1
./bootstrap
check_install_status
make -j8
check_install_status
make install
check_install_status
ldconfig
cd ../
fi
2)git下载、编译gflags:
git clone https://github.com/gflags/gflags.git
cd gflags
mkdir build && cd build #通过cmake生成的Makefile等文件放到build目录
cmake ..
make j8
make install
3)下载gflags源码tar.gz包、编译安装:(方法二)
地址:
#install gflags
install_specified_deps "gflags-2.2.0"
if [ ! -d gflags-2.2.0 ]; then
tar -zxf gflags-2.2.0.tar.gz
cd gflags-2.2.0/
cmake -DBUILD_SHARED_LIBS=1 -DBUILD_STATIC_LIBS=1 ./
check_install_status
make -j8
check_install_status
make install
check_install_status
ldconfig
cd ../
fi
注:这时 gflags 库会默认安装在 /usr/local/lib/ 下,头文件放在 /usr/local/include/gflags/ 中。
注:在编译gflags的时候如果不加参数(即:直接使用cmake),默认会采用静态编译。这个时候代码引入gflags库后,编译出来的业务代码会很大。
2、基本功能:
2.1)先看一个示例:
1)cpp代码:
#include <iostream>
#include <gflags/gflags.h>
using namespace std;
DEFINE_string(host,"127.0.0.1","ip address");
DEFINE_int32(port,3306,"server port");
int main(int argc,char* argv[]){
gflags::ParseCommandLineFlags(&argc,&argv,true);
cout<<"server ip:"<<FLAGS_host<<",port:"<<FLAGS_port<<endl;
return 0;
}
2)编译:
g++ -o run test_gflag1.cpp -lgflags -lpthread
注:不加-lpthread会报如下错:
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::(anonymous namespace)::FlagRegistry::GlobalRegistry()':
gflags.cc:(.text+0xef6): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0xf16): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0xfb7): undefined reference to `pthread_rwlock_init'
gflags.cc:(.text+0xfd0): undefined reference to `pthread_rwlock_init'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::(anonymous namespace)::RegisterCommandLineFlag(char const*, char const*, char const*, google::(anonymous namespace)::FlagValue*, google::(anonymous namespace)::FlagValue*)':
gflags.cc:(.text+0x1265): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x1285): undefined reference to `pthread_rwlock_unlock'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::(anonymous namespace)::AddFlagValidator(void const*, bool (*)())':
gflags.cc:(.text+0x1524): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x153c): undefined reference to `pthread_rwlock_wrlock'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::GetCommandLineOption(char const*, std::string*)':
gflags.cc:(.text+0x2554): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x256e): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x25de): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x266d): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x2854): undefined reference to `pthread_rwlock_init'
gflags.cc:(.text+0x286f): undefined reference to `pthread_rwlock_init'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::GetCommandLineFlagInfo(char const*, google::CommandLineFlagInfo*)':
gflags.cc:(.text+0x29ac): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x29c6): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x2a3e): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x2a54): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x2b18): undefined reference to `pthread_rwlock_init'
gflags.cc:(.text+0x2b37): undefined reference to `pthread_rwlock_init'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::GetCommandLineFlagInfoOrDie(char const*)':
gflags.cc:(.text+0x2c4c): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x2c96): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x2d0e): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x2d24): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x2dc8): undefined reference to `pthread_rwlock_init'
gflags.cc:(.text+0x2de7): undefined reference to `pthread_rwlock_init'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::FlagSaver::FlagSaver()':
gflags.cc:(.text+0x3317): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x332e): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x3397): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x33ae): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x3486): undefined reference to `pthread_rwlock_init'
gflags.cc:(.text+0x349c): undefined reference to `pthread_rwlock_init'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::FlagSaver::~FlagSaver()':
gflags.cc:(.text+0x38b7): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x38cd): undefined reference to `pthread_rwlock_wrlock'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::ShutDownCommandLineFlags()':
gflags.cc:(.text+0x4591): undefined reference to `pthread_rwlock_destroy'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::SetCommandLineOptionWithMode(char const*, char const*, google::FlagSettingMode)':
gflags.cc:(.text+0x660c): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x6624): undefined reference to `pthread_rwlock_unlock'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::ReadFlagsFromString(std::string const&, char const*, bool)':
gflags.cc:(.text+0x7827): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x783e): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x7855): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x786a): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x7880): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x7895): undefined reference to `pthread_rwlock_wrlock'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::SetCommandLineOption(char const*, char const*)':
gflags.cc:(.text+0x7b64): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x7b7c): undefined reference to `pthread_rwlock_unlock'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::ParseCommandLineFlagsInternal(int*, char***, bool, bool)':
gflags.cc:(.text+0x867a): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x868f): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x86aa): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x86c0): undefined reference to `pthread_rwlock_wrlock'
gflags.cc:(.text+0x86d6): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x86ec): undefined reference to `pthread_rwlock_wrlock'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `google::GetAllFlags(std::vector<google::CommandLineFlagInfo, std::allocator<google::CommandLineFlagInfo> >*)':
gflags.cc:(.text+0x9cd8): undefined reference to `pthread_rwlock_unlock'
gflags.cc:(.text+0x9cf3): undefined reference to `pthread_rwlock_wrlock'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `gflags_mutex_namespace::Mutex::~Mutex()':
gflags.cc:(.text._ZN22gflags_mutex_namespace5MutexD2Ev[_ZN22gflags_mutex_namespace5MutexD5Ev]+0x15): undefined reference to `pthread_rwlock_destroy'
//usr/local/lib/libgflags.a(gflags.cc.o): In function `gflags_mutex_namespace::Mutex::Unlock()':
gflags.cc:(.text._ZN22gflags_mutex_namespace5Mutex6UnlockEv[_ZN22gflags_mutex_namespace5Mutex6UnlockEv]+0x15): undefined reference to `pthread_rwlock_unlock'
collect2: error: ld returned 1 exit status
3)运行:
2.2)说明:
1)定义命令行标记:
通过DEFINE_type宏实现,该支持三种参数:变量名、默认值、说明。例如:
DEFINE_string(host,"localhost","sever ip address");
gflags 一共支持 5 种类型的命令行参数定义:
- DEFINE_bool: 布尔类型
- DEFINE_int32: 32 位整数
- DEFINE_int64: 64 位整数
- DEFINE_uint64: 无符号 64 位整数
- DEFINE_double: 浮点类型 double
- DEFINE_string: C++ string 类型
2)访问命令行标记:
所有我们定义的 gflags 变量都可以通过 FLAGS_ 前缀加参数名访问,gflags 变量也可以被自由修改。
3)命令行中指定标记:
- 可以使用--或者-;
- 可以有等号(=),也可以直接用空格;
3、进阶:
正常来说我们的代码不可能只有1个cpp,还会有很多模块。而每个模块可能都会使用命令行参数值。如何在其他模块怎么引用和使用呢?so easy,与DEFINE相对应的有DECLARE。
- 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
它的作用就相当于用 extern 声明变量。为了方便的管理变量,我们推荐在 .cpp 文件中 DEFINE 变量,然后只在对应 .h 中或者单元测试中 DECLARE 变量。看一个例子:
编译:g++ demo.cpp logic.cpp -lgflags -lpthread
4、参数检查
一般情况下,我们获取到所有命令行参数的值后,都会做一次检查。gflags里面建议使用 RegisterFlagValidator 这个方法来做参数检查。参数不通过的时候,程序是启动失败的。例如:
#include <iostream>
#include <gflags/gflags.h>
using namespace std;
DEFINE_string(host,"127.0.0.1","ip address");
DEFINE_int32(port,3306,"server port");
static bool ValidatePort(const char* flagname, gflags::int32 value) {
if (value >= 36800 && value <= 36888) {
cout<<"param "<<flagname<<"="<<value<<" is valid!"<<endl;
return true;
}
cout<<"param "<<flagname<<"="<<value<<" is invalid!"<<endl;
return false;
}
static const bool port_dummy = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort);
int main(int argc,char* argv[]){
gflags::ParseCommandLineFlags(&argc,&argv,true);
cout<<"server ip:"<<FLAGS_host<<",port:"<<FLAGS_port<<endl;
return 0;
}
编译:g++ test_gflag2.cpp -lgflags -lpthread
运行:
5、使用flagfile:
如果我们定义了很多参数,那么每次启动时都在命令行指定对应的参数显然是不合理的。gflags允许把 flag 参数和对应的值写在文件中,然后运行时使用 -flagfile 来指定对应的 flag 文件就好。例如:
1)编辑一个flags文件:vim ./test_gflag2.flags
里面的内如:
--port=36810
2)运行程序:
# ./a.out --flagfile=./test_gflag2.flags
param port=36810 is valid!
server ip:127.0.0.1,port:36810