google gflags 庫完全使用
簡單介紹
gflags 是 google 開源的用於處理命令行參數的項目。
安裝編譯
項目主頁:gflags
? ~ git clone https://github.com/gflags/gflags.git # 下載源碼
? ~ cd gflags
? gflags git:(master) ? mkdir build && cd build # 建立文件夾
? build git:(master) ? cmake .. # 使用 cmake 編譯生成 Makefile 文件
? build git:(master) ? make # make 編譯
? build git:(master) ? sudo make install # 安裝庫
- 1
- 2
- 3
- 4
- 5
- 6
這時 gflags 庫會默認安裝在 /usr/local/lib/ 下,頭文件放在 /usr/local/include/gflags/ 中。
基礎使用
我們從一個簡單的需求來看 gflags 的使用,只要一分鐘。假如我們有個程序,需要知道伺服器的 ip 和埠,我們在程序中有默認的指定參數,同時希望可以通過命令行來指定不同的值。
實現如下:
#include <iostream>
#include <gflags/gflags.h>
/**
* 定義命令行參數變數
* 默認的主機地址為 127.0.0.1,變數解釋為 "the server host"
* 默認的埠為 12306,變數解釋為 "the server port"
*/
DEFINE_string(host, "127.0.0.1", "the server host");
DEFINE_int32(port, 12306, "the server port");
int main(int argc, char** argv) {
// 解析命令行參數,一般都放在 main 函數中開始位置
gflags::ParseCommandLineFlags(&argc, &argv, true);
// 訪問參數變數,加上 FLAGS_
std::cout << "The server host is: " << FLAGS_host
<< ", the server port is: " << 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
OK, 寫完了讓我們編譯運行。
? test g++ gflags_test.cc -o gflags_test -lgflags -lpthread # -l 鏈接庫進行編譯
? test ./gflags_test #不帶任何參數
The server host is: 127.0.0.1, the server port is: 12306
? test ./gflags_test -host 10.123.78.90 #只帶 host 參數
The server host is: 10.123.78.90, the server port is: 12306
? test ./gflags_test -port 8008 # 只帶 port 參數
The server host is: 127.0.0.1, the server port is: 8008
? test ./gflags_test -host 10.123.78.90 -port 8008 # host 和 port 參數
The server host is: 10.123.78.90, the server port is: 8008
? test ./gflags_test --host 10.123.78.90 --port 8008 # 用 -- 指定
The server host is: 10.123.78.90, the server port is: 8008
? test ./gflags_test --host=10.123.78.90 --port=8008 # 用 = 連接參數值
The server host is: 10.123.78.90, the server port is: 8008
? test ./gflags_test --help # 用 help 查看可指定的參數及參數說明
gflags_test: Warning: SetUsageMessage() never called
Flags from /home/rookie/code/gflags/src/gflags.cc:
.... # 略
Flags from /home/rookie/code/gflags/src/gflags_reporting.cc:
..... # 略
Flags from gflags_test.cc: #這裡是我們定義的參數說明和默認值
-host (the server host) type: string default: "127.0.0.1"
-port (the server port) type: int32 default: 12306
- 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
看,我們不僅快速完成了需求,而且似乎多了很多看起來不錯的特性。在上面我們使用了兩種類型的參數,string 和 int32,gflags 一共支持 5 種類型的命令行參數定義:
- DEFINE_bool: 布爾類型
- DEFINE_int32: 32 位整數
- DEFINE_int64: 64 位整數
- DEFINE_uint64: 無符號 64 位整數
- DEFINE_double: 浮點類型 double
- DEFINE_string: C++ string 類型
如果你希望支持更複雜的結構,比如 list,你需要通過自己做一定的定義和解析,比如字元串按某個分隔符分割得到一個列表。
每一種類型的定義和使用都跟上面我們的例子相似,有所不同的是 bool 參數,bool 參數在命令行可以不指定值也可以指定值,假如我們定義了一個 bool 參數 debug_switch,可以在命令行這樣指定:
? test ./gflags_test -debug_switch # 這樣就是 true
? test ./gflags_test -debug_switch=true # 這樣也是 true
? test ./gflags_test -debug_switch=1 # 這樣也是 true
? test ./gflags_test -debug_switch=false # 0 也是 false
- 1
- 2
- 3
- 4
所有我們定義的 gflags 變數都可以通過 FLAGS_ 前綴加參數名訪問,gflags 變數也可以被自由修改:
if (FLAGS_consider_made_up_languages)
FLAGS_languages += ",klingon";
if (FLAGS_languages.find("finnish") != string::npos)
HandleFinnish();
- 1
- 2
- 3
- 4
進階?同樣 Easy
定義規範
如果你想要訪問在另一個文件定義的 gflags 變數呢?使用 DECLARE_,它的作用就相當於用 extern 聲明變數。為了方便的管理變數,我們推薦在 .cc 或者 .cpp 文件中 DEFINE 變數,然後只在對應 .h 中或者單元測試中 DECLARE 變數。例如,在 foo.cc 定義了一個 gflags 變數 DEFINE_string(name, "bob", ""),假如你需要在其他文件中使用該變數,那麼在 foo.h 中聲明 DECLARE_string(name),然後在使用該變數的文件中 include "foo.h" 就可以。當然,這只是為了更好地管理文件關聯,如果你不想遵循也是可以的。
參數檢查
如果你定義的 gflags 參數很重要,希望檢查其值是否符合預期,那麼可以定義並註冊參數的值的檢查函數。如果採用 static 全局變數來確保檢查函數會在 main 開始時被註冊,可以保證註冊會在 ParseCommandLineFlags 函數之前。如果默認值檢查失敗,那麼 ParseCommandLineFlags 將會使程序退出。如果之後使用 SetCommandLineOption() 來改變參數的值,那麼檢查函數也會被調用,但是如果驗證失敗,只會返回 false,然後參數保持原來的值,程序不會結束。看下面的程序示例:
#include <stdint.h>
#include <stdio.h>
#include <iostream>
#include <gflags/gflags.h>
// 定義對 FLAGS_port 的檢查函數
static bool ValidatePort(const char* name, int32_t value) {
if (value > 0 && value < 32768) {
return true;
}
printf("Invalid value for --%s: %d
", name, (int)value);
return false;
}
/**
* 設置命令行參數變數
* 默認的主機地址為 127.0.0.1,變數解釋為 "the server host"
* 默認的埠為 12306,變數解釋為 "the server port"
*/
DEFINE_string(host, "127.0.0.1", "the server host");
DEFINE_int32(port, 12306, "the server port");
// 使用全局 static 變數來註冊函數,static 變數會在 main 函數開始時就調用
static const bool port_dummy = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort);
int main(int argc, char** argv) {
// 解析命令行參數,一般都放在 main 函數中開始位置
gflags::ParseCommandLineFlags(&argc, &argv, true);
std::cout << "The server host is: " << FLAGS_host
<< ", the server port is: " << FLAGS_port << std::endl;
// 使用 SetCommandLineOption 函數對參數進行設置才會調用檢查函數
gflags::SetCommandLineOption("port", "-2");
std::cout << "The server host is: " << FLAGS_host
<< ", the server port is: " << 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
- 37
- 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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
使用 flagfile
如果我們定義了很多參數,那麼每次啟動時都在命令行指定對應的參數顯然是不合理的。gflags 庫已經很好的解決了這個問題。你可以把 flag 參數和對應的值寫在文件中,然後運行時使用 -flagfile 來指定對應的 flag 文件就好。文件中的參數定義格式與通過命令行指定是一樣的。
例如,我們可以定義這樣一個文件,文件後綴名沒有關係,為了方便管理可以使用 .flags:
--host=10.123.14.11
--port=23333
- 1
- 2
然後命令行指定:
? test ./gflags_test --flagfile server.flags
The server host is: 10.123.14.11, the server port is: 23333
- 1
- 2
棒!以後再也不用擔心參數太多了~^_^
看到這裡,是不是覺得 gflags 對你的項目很有幫助?用起來吧,釋放超能力 :)
※Linux之索引式文件系統
※基於SSM實現的簡易員工管理系統
TAG:程序員小新人學習 |