您好,登錄后才能下訂單哦!
gflags命令行解析包如何在C++中使用?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
前言
gflags 是 Google 提供的一個命令行參數處理的開源庫,目前已經獨立開源,比傳統的 getopt() 功能更加強大,可以將不同的參數定義分布到各個源碼文件中,不需要集中管理。
提供了 C++ 和 Python 兩個版本,這里僅詳細介紹 C++ 版本的使用方式。
簡介
配置參數分開還是集中管理沒有嚴格的約束,關鍵要看項目里的統一規范,只是,gflags 可以支持這兩種方式,允許用戶更加靈活的使用。
當將參數分布到各個源碼文件中時,如果定義了相同的參數,那么在編譯的時候會直接報錯。
很多發行版本會有自己相關的開發庫,這里簡單介紹使用 CMake 從源碼進行編譯,源碼可以從 GitHub gflags Releases 中選擇相關的版本。
如下命令以最新的 2.2.2 版本為例。
$ tar xzf gflags-2.2.2.tar.gz $ cd gflags-2.2.2 $ mkdir build && cd build $ cmake -DCMAKE_INSTALL_PREFIX=/usr .. $ make $ make test # 單元測試,執行cmake時需要增加-DBUILD_TESTING=true參數 # make install # 安裝,一般需要root用戶執行
默認會安裝到 /usr/local 目錄下,需要配置動態庫、頭文件路徑等,通過上述的 -DCMAKE_INSTALL_PREFIX=/usr 參數修改該路徑,使用系統默認路徑,此時會安裝如下的文件。
/usr/lib/libgflags.a /usr/lib/libgflags_nothreads.a /usr/include/gflags/gflags.h /usr/include/gflags/gflags_declare.h /usr/include/gflags/gflags_completions.h /usr/include/gflags/gflags_gflags.h /usr/lib/cmake/gflags/gflags-config.cmake /usr/lib/cmake/gflags/gflags-config-version.cmake /usr/lib/cmake/gflags/gflags-targets.cmake /usr/lib/cmake/gflags/gflags-targets-release.cmake /usr/lib/cmake/gflags/gflags-nonamespace-targets.cmake /usr/lib/cmake/gflags/gflags-nonamespace-targets-release.cmake /usr/bin/gflags_completions.sh /usr/lib/pkgconfig/gflags.pc
詳細的安裝可以參考gflags install.md 中的介紹,可以使用 ccmake 選擇配置項,或者使用上述的 cmake + 參數的方式配置。
假設有個網絡客戶端代碼,需要指定服務端的地址和端口,希望有默認參數,同時允許用戶通過命令行來指定不同的值。
#include <iostream> #include <gflags/gflags.h> DEFINE_string(host, "localhost", "Server host address"); DEFINE_int32(port, 8080, "Server port"); int main(int argc, char **argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); std::cout << "Got '" << FLAGS_host << ":" << FLAGS_port << "'." << std::endl; return 0; }
在代碼開頭通過 DEFINE_XXX 定義參數,包括了變量名、默認值、參數介紹等;主程序中使用 gflags::ParseCommandLineFlags() 函數解析參數;使用時,在變量名稱前添加 FLAGS_ 頭即可。
通過如下命令行進行編譯。
g++ main.cc -std=c++11 -o gflags -lgflags -lpthread
默認是需要 pthread 線程庫的,暫時還不太確定沒有使用多線程時,如何關閉該參數。
然后,可以通過如下方式指定參數。
----- 不指定參數,使用默認值 $ ./gflags Got 'localhost:8080'. ----- 可以選擇指定一個參數,或者多個參數 $ ./gflags -host www.foobar.com Got 'www.foobar.com:8080'. $ ./gflags -port 80 Got 'localhost:80'. $ ./gflags -host www.foobar.com -port 80 Got 'www.foobar.com:80'. ----- 同時支持不同的參數指定方式 $ ./gflags --host www.foobar.com --port 80 Got 'www.foobar.com:80'. $ ./gflags --host=www.foobar.com=--port 80 Got 'www.foobar.com:80'.
同時也可以使用 --help 參數查看幫助信息,包含了 gflags 庫提供的參數,以及用戶提供的參數,如下是輸出的用戶參數信息。
Flags from main.cc: -host (Server host address) type: string default: "localhost" -port (Server port) type: int32 default: 8080
接著看看詳細使用方式。
包含了如何定義、解析等使用場景。
在如上的示例中定義了兩種類型的參數,分別為字符串 string 和整型 int32 ,包括了變量名、默認值、參數介紹三個入參,三個參數都是必須的。
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
可以定義到某個 NameSpace 下,這樣在使用時也必須要帶著 NameSpace 前綴。如果在不同的文件中定義,那么可以在某個集中的頭文件中通過 DECLARE_XXX(VAR) 進行聲明。
注意,不要定義相同名稱的參數,即使在不同的 NameSpace 也不可以;還有幾個保留參數,包括了 flagfile fromenv tryfromenv undefok 等等。
在上述的示例中,通過 ParseCommandLineFlags() 函數解析參數,另外還有不帶幫助文檔的解析方式,兩個函數的聲明如下。
uint32 ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags); uint32 ParseCommandLineNonHelpFlags(int* argc, char*** argv, bool remove_flags);
其中 remove_flags 標識指定參數的處理方式,如果為 true ,那么解析時會將 flag 以及 flag 對應的值從 argv 中刪除,并修改 argc ,也就是說,最后存放的是不包含 flag 的參數;如果為 false 則僅對參數重排,標志位參數放最前面。
為了檢查參數的值是否合法,可以針對某個參數注冊一個驗證函數,當參數解析或者修改 (調用 SetCommandLineOption() 時) 該驗證函數都會被調用,返回 true 表示校驗成功,否則失敗。
如下是對于 port 參數的校驗。
#include <iostream> #include <gflags/gflags.h> DEFINE_string(host, "localhost", "Server host address."); DEFINE_int32(port, 8080, "Server port."); static bool ValidatePort(const char *flag, gflags::int32 value) { if (value > 0 && value < 32768) return true; std::cerr << "Invalid value for --" << flag << ": " << value << std::endl; return false; } static const bool port_dummy = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort); int main(int argc, char **argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); std::cout << "Got '" << FLAGS_host << ":" << FLAGS_port << "'" << std::endl; return 0; }
如果超過了指定的范圍則會報錯。
提供了默認的 --help 查看幫助信息,指定參數可以使用 - 或者 -- 符號,參數和值的分割可以使用 ` ` 或者 = ,如上的示例。
對于布爾類型,還可以使用 --foobar --nofoobar --foobar=true --foobar false 的方式指定。
在通過 ParseCommandLineFlags() 函數解析完參數之后,可以通過如下方法檢查對應的變量是否被設置。
gflags::CommandLineFlagInfo info; if (gflags::GetCommandLineFlagInfo("port", &info) && info.is_default) { std::cout << "port is not set." << std::endl; } else { std::cout << "port is set." << std::endl; }
這里不是直接比對的設置值與默認值相同,即使指定了與默認值相同的值,也會被認為參數被修改了。
可以通過 --flagfile=FileName 指定參數文件名,文件名也可以使用通配符 * 以及 ?,在文件中每行標識一個參數,例如:
$ cat flags.txt # This is the test server. --host=www.foobar.com --port=80 $ ./gflags --flagfile flags.txt Got 'www.foobar.com:80'.
以 # 開頭的為注釋,也可以再次使用 --flagfile=FileName 包含一個參數配置文件。
可以使用 --fromenv 或者 --tryfromenv 從環境變量中引入參數,也可通過 --fromenv=foo,bar 指定讀取的參數,當然,需要先設置好環境變量。
export FLAGS_foo=xxx; export FLAGS_bar=yyy # sh setenv FLAGS_foo xxx; setenv FLAGS_bar yyy # tcsh
這種方式等價于在命令行指定 --foo=xxx --bar=yyy 參數。
其中 --fromenv 時如果環境變量不存在則會報錯,而 --tryfromenv 當環境變量中不存在時會使用默認值。
最常見的是允許用戶動態進行配置,也就是說動態加載,可以調用 SetCommandLineOption() 函數來實現,函數的聲明如下。
std::string SetCommandLineOption(const char* name, const char* value);
例如。
gflags::SetCommandLineOption("port", "9999");
成功則會返回 port set to 9999 字符串,否則會返回空字符串。
另外也可以通過 bool GetCommandLineOption(const char* name, std::string* OUTPUT) 函數獲取 flag 的接口,如果沒有指定,則會通過 OUTPUT 返回默認的值,只有當指定了一個未定義的 flag 名稱時,會返回 false 。
正常讀寫都可以使用 if (FLAGS_foo); FLAGS_Foo = bar 的形式,但是如果需要線程安全的調用,建議使用這兩個函數。
如上設置的完整示例如下。
#include <iostream> #include <gflags/gflags.h> DEFINE_string(host, "localhost", "Server host address."); DEFINE_int32(port, 8080, "Server port."); static bool ValidatePort(const char *flag, gflags::int32 value) { if (value > 0 && value < 32768) return true; std::cerr << "Invalid value for --" << flag << ": " << value << std::endl; return false; } static const bool port_dummy = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort); int main(int argc, char **argv) { gflags::SetVersionString("1.1.0"); gflags::SetUsageMessage("./gflags"); gflags::ParseCommandLineFlags(&argc, &argv, true); std::cout << gflags::SetCommandLineOption("port", "999") << std::endl; std::cout << "Got '" << FLAGS_host << ":" << FLAGS_port << "'" << std::endl; return 0; }
可以通過 g++ main.cc -std=c++11 -o gflags -lgflags -lpthread 命令編譯。
gflags 中包含了幾類默認的參數。
--help 顯示所有文件的所有flag,按文件、名稱排序,顯示flag名、默認值和幫助
--helpfull 和 --help 相同,顯示全部flag
--helpshort 只顯示執行文件中包含的flag,通常是 main() 所在文件
--helpxml 類似 --help,但輸出為xml
--helpon=FILE 只顯示定義在 FILE.* 中得flag
--helpmatch=S 只顯示定義在 *S*.* 中的flag
--helppackage 顯示和 main() 在相同目錄的文件中的flag
--version 打印執行文件的版本信息--undefok=flagname,flagname,... 后面列出的flag名,可以在無定義的情況下忽略而不報錯
--fromenv --tryfromenv 從環境變量中引入
--flagfile 從文件中引入
通過 --version 和 --help 默認會輸出其對應的版本和幫助信息,也可以通過 SetVersionString() 設置版本信息,通過 SetUsageMessage() 設置幫助的開始軟件信息 (幫助信息無法覆蓋)。
gflags::SetVersionString("1.1.0"); gflags::SetUsageMessage("./gflags");
注意,參數的設置需要在調用 ParseCommandLineFlags() 之前。
最新版本的 gflags 已經可以支持 CMake 了,如上安裝時所示,在安裝時會在 /usr/lib/cmake/gflags/ 目錄下安裝相關的文件,那么在項目中可以通過如下方式使用。
FIND_PACKAGE(gflags REQUIRED) INCLUDE_DIRECTORIES(${gflags_INCLUDE_DIR}) ADD_EXECUTABLE(foo main.cc) TARGET_LINK_LIBRARIES(foo gflags)
如果是將 CMake 安裝到了其它路徑下,那么可以將上述的文件復制到 CMake 的模塊路徑下再使用。
在 gflags/gflags_declare.h 中定義了 int32 int64 等類型,可以直接使用,不過編譯時需要添加 -std=c++11 參數,否則在使用 cstdint 頭文件時會報錯。
可以通過 void GetAllFlags(std::vector<CommandLineFlagInfo>* OUTPUT) 接口遍歷所有的參數,更多接口可以查看 gflags/gflags.h 頭文件。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。