使用xmake檢測編譯器特性支持

若是咱們要寫跨平臺的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=1lua

咱們也能夠在判斷時候,追加一些參數控制編譯選項,例如上述特性須要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編譯器進行檢測。

固然此接口,還能夠檢測其餘非編譯器的工具特性,更加的通用。

經過自定義c/c++代碼片斷來檢測特性

對於一些複雜的編譯器特性,連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_cincludesdetect.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。

原文出處:http://tboox.org/cn/2017/08/08/compiler-features/

相關文章
相關標籤/搜索