若是咱們要寫跨平臺的c/c++代碼,不少時候須要處理因爲不一樣編譯器對c/c++各個標準支持力度不一樣致使的兼容性問題,通常一般的解決辦法是:本身在代碼中經過宏去判斷各個編譯器的版本、內置宏、標準庫宏、__has_feature
等來檢測處理。c++
本身若是在代碼中按上述的方式檢測,會很繁瑣,尤爲是像c++這種存在大量語法特性,若是一一檢測過來,工做量是很是大的。git
另外比較省事的方式,就是依賴構建工具提早作好檢測,而後把檢測結果做爲宏添加到編譯中去,這樣代碼只須要判斷對應的特性宏是否存在,就能夠進行處理了。github
在cmake中就有相似的檢測機制,很是強大,所以xmake也對其進行了支持,提供更加靈活強大的編譯器特性預先檢測支持:macos
target("test") on_load(function (target) import("core.tool.compiler") if compiler.has_features("cxx_constexpr") then target:add("defines", "HAS_CXX_CONSTEXPR=1") end end)
經過core.tool.compiler
模塊的compiler.has_features接口,在xmake.lua
中預先判斷當前編譯期支持的語言特性,實現條件編譯。工具
此處也是參考了cmake的設計,具體詳情見:issues#83。測試
上述代碼,在加載target的時候,判斷當前編譯器是否支持c++的常量表達式語法特性,若是支持則添加宏定義:HAS_CXX_CONSTEXPR=1
。lua
咱們也能夠在判斷時候,追加一些參數控制編譯選項,例如上述特性須要c++11
支持,咱們能夠啓用它:設計
if compiler.has_features({"c_static_assert", "cxx_constexpr"}, {languages = "cxx11"}) then -- ok end
經過上面的代碼能夠看到,此接口是能夠同時檢測多個特性的,返回值爲實際支持的特性列表。c++11
若是以前對這個target已經設置了c++11
,那麼咱們也能夠傳入target對象,繼承target的全部設置,甚至指定一些其餘擴展編譯配置:code
if compiler.has_features("cxx_constexpr", {target = target, defines = "..", includedirs = ".."}) then -- ok end
c++的語言特性很是多,這個時候咱們能夠經過腳本實現快速的批量檢測:
target("test") on_load(function (target) import("core.tool.compiler") for feature, _ in pairs(compiler.features("cxx", {target = target})) do -- 傳入target在檢測特性時繼承target的全部編譯配置 target:add("defines", "has_feature_" .. feature) end end)
上述代碼,會在加載target的時候,把當前編譯器對c++的全部支持特性,都添加到target的宏定義中進行編譯,例如:-Dhas_feature_cxx_constexpr
。
咱們只須要在代碼中,經過判斷對應的特性宏是否存在就好了:
#ifdef has_feature_cxx_constexpr // TODO #endif
目前支持的全部c/c++編譯器特性列表,見:compiler.features
若是咱們要指定獲取具體哪一個編譯器的特性支持,則須要更加底層的接口支持了,例如:
import("lib.detect.has_features") local features = has_features("clang", "cxx_constexpr") local features = has_features("clang", {"cxx_constexpr", "c_static_assert"}, {flags = {"-g", "-O0"}, program = "xcrun -sdk macosx clang"}) local features = has_features("clang", {"cxx_constexpr", "c_static_assert"}, {flags = "-g"})
lib.detect.has_features屬於探測模塊的接口,能夠指定須要檢測的工具名,例如這裏經過傳入clang,只對clang編譯器進行檢測。
固然此接口,還能夠檢測其餘非編譯器的工具特性,更加的通用。
對於一些複雜的編譯器特性,連compiler.has_features都沒法檢測到的時候,能夠經過自定義代碼片斷嘗試編譯來檢測它。
import("lib.detect.check_cxsnippets") local ok = check_cxsnippets("constexpr int f(int x) { return x ? x+f(x-1) : 0; } constexpr int x = f(5); static_assert(x == 15);", {sourcekind = "cxx", languages = "cxx11"})
上述代碼經過自定義一個constexpr的測試代碼,去檢測c++11的constexpr支持。
此接口是detect.has_cfuncs, detect.has_cincludes和detect.has_ctypes等接口的通用版本,也更加底層。
所以咱們能夠用它來檢測:types, functions, includes 還有 links,或者是組合起來一塊兒檢測。
第一個參數爲代碼片斷列表,通常用於一些自定義特性的檢測,若是爲空,則能夠僅僅檢測可選參數中條件,例如:
local ok = check_cxsnippets({"void test() {}", "void test2() {}"}, {types = {"wchar_t", "char*"}, includes = "stdio.h", funcs = {"sigsetjmp", "sigsetjmp((void*)0, 0)"}})
上面那個調用,會去同時檢測types, includes和funcs是否都知足,若是經過返回true。