1. 程式人生 > 程式設計 >xmake從入門到精通8:切換編譯模式

xmake從入門到精通8:切換編譯模式

xmake是一個基於Lua的輕量級現代化c/c++的專案構建工具,主要特點是:語法簡單易上手,提供更加可讀的專案維護,實現跨平臺行為一致的構建體驗。

本文我們會詳細介紹下如何在專案構建過程中切換debug/release等常用構建模式,以及自定義其他編譯模式。

除錯和釋出模式

通常,如果我們是通過xmake create命令建立的專案,會在xmake.lua裡面自動新增一行編譯規則的配置,如下:

add_rules("mode.release","mode.debug")
target("hello")
    set_kind("binary")
    add_files("src/*.c"
) 複製程式碼

通過add_rules介面,我們預設添加了release和debug兩個常用的內建規則,它們會在編譯的時候附帶上對應模式相關的一些編譯flags,來開啟優化用於釋出或者除錯編譯。

如果僅僅執行了xmake命令,沒有額外的配置,那麼預設就會是release編譯,等價於:

$ xmake f -m release
$ xmake
[  0%]: ccache compiling.release src/main.cpp
[100%]: linking.release test
build ok!
複製程式碼

如果我們要切換到debug編譯模式,只需要:

$ xmake f -m debug
$ xmake
[  0%]: ccache compiling.debug src/main.cpp
[100%]: linking.debug test
build ok! 複製程式碼

上面的-m/--mode=引數就是用來設定編譯模式,會跟mode.releasemode.debug這兩個規則做關聯。

那麼,他們是如何關聯上的呢?我們可以先來看下這兩個規則的內部實現:

rule("mode.debug")
    after_load(function (target)
        if is_mode("debug") then
            if not target:get("symbols") then
                target:set("symbols","debug")
            end
if not target:get("optimize") then target:set("optimize","none") end end end) rule("mode.release") after_load(function (target) if is_mode("release") then if not target:get("symbols") and target:targetkind() ~= "shared" then target:set("symbols","hidden") end if not target:get("optimize") then if is_plat("android","iphoneos") then target:set("optimize","smallest") else target:set("optimize","fastest") end end if not target:get("strip") then target:set("strip","all") end end end) 複製程式碼

可以看到,在target被載入階段,xmake會去判斷使用者對xmake f --mode=xxx的引數配置,如果通過is_mode()介面獲取到是debug模式,那麼會禁用相關優化並且啟用符號輸出。 而如果是release模式,那麼會開啟編譯優化並且strip掉所有除錯符號。

定製化的模式配置

當然,內建的這兩規則預設設定的這些編譯配置,只能滿足大部分場景的常規需求,如果使用者想要在不同的編譯模式下定製化一些個人的編譯配置,那麼需要自己在xmake.lua做判斷。

例如,我們想在release下也啟用除錯符號,那麼只需要:

if is_mode("release") then
    set_symbols("debug")
end
複製程式碼

或者額外增加一些編譯flags:

if is_mode("release") then
    add_cflags("-fomit-frame-pointer")
end
複製程式碼

注:如果使用者自己的配置和mode.release內建的配置衝突,會優先使用使用者的設定。

當然,我們也可以完全不去通過add_rules("mode.debug","mode.release")新增預設的配置規則,讓使用者完全自己控制模式配置:

-- 如果當前編譯模式是debug
if is_mode("debug") then

    -- 新增DEBUG編譯巨集
    add_defines("DEBUG")

    -- 啟用除錯符號
    set_symbols("debug")

    -- 禁用優化
    set_optimize("none")
end

-- 如果是release或者profile模式
if is_mode("release","profile") then

    -- 如果是release模式
    if is_mode("release") then

        -- 隱藏符號
        set_symbols("hidden")

        -- strip所有符號
        set_strip("all")

        -- 忽略幀指標
        add_cxflags("-fomit-frame-pointer")
        add_mxflags("-fomit-frame-pointer")

    -- 如果是profile模式
    else
        -- 啟用除錯符號
        set_symbols("debug")
    end

    -- 新增擴充套件指令集
    add_vectorexts("sse2","sse3","ssse3","mmx")
end
複製程式碼

其他內建模式規則

通過上文的例子,我們看到除了debug/release模式,還加了個profile模式的配置判斷,其實xmake也提供了對應的內建模式,還有哪些,我們具體來看下:

mode.debug

為當前工程xmake.lua新增debug編譯模式的配置規則,例如:

add_rules("mode.debug")
複製程式碼

相當於:

if is_mode("debug") then
    set_symbols("debug")
    set_optimize("none")
end
複製程式碼

我們可以通過:xmake f -m debug來切換到此編譯模式。

mode.release

為當前工程xmake.lua新增release編譯模式的配置規則,例如:

add_rules("mode.release")
複製程式碼

相當於:

if is_mode("release") then
    set_symbols("hidden")
    set_optimize("fastest")
    set_strip("all")
end
複製程式碼

我們可以通過:xmake f -m release來切換到此編譯模式。

mode.check

為當前工程xmake.lua新增check編譯模式的配置規則,一般用於記憶體檢測,例如:

add_rules("mode.check")
複製程式碼

相當於:

if is_mode("check") then
    set_symbols("debug")
    set_optimize("none")
    add_cxflags("-fsanitize=address","-ftrapv")
    add_mxflags("-fsanitize=address","-ftrapv")
    add_ldflags("-fsanitize=address")
end
複製程式碼

我們可以通過:xmake f -m check來切換到此編譯模式。

mode.profile

為當前工程xmake.lua新增profile編譯模式的配置規則,一般用於效能分析,例如:

add_rules("mode.profile")
複製程式碼

相當於:

if is_mode("profile") then
    set_symbols("debug")
    add_cxflags("-pg")
    add_ldflags("-pg")
end
複製程式碼

我們可以通過:xmake f -m profile來切換到此編譯模式。

mode.coverage

為當前工程xmake.lua新增coverage編譯模式的配置規則,一般用於覆蓋分析,例如:

add_rules("mode.coverage")
複製程式碼

相當於:

if is_mode("coverage") then
    add_cxflags("--coverage")
    add_mxflags("--coverage")
    add_ldflags("--coverage")
end
複製程式碼

我們可以通過:xmake f -m coverage來切換到此編譯模式。

注:生成的gcno檔案一般都是個obj所在目錄對應的哦,因此需要從build目錄下去找。

擴充套件自己的編譯模式

xmake的模式配置,並沒有固定值,使用者可以隨意傳入和配置,只要xmake f -m/--mode=xxx傳入的模式值和xmake.lua裡面的is_mode("xxx")能對應上就行。

比如,我們設定了一個自己獨有的編譯模式my_mode,可以直接在命令列配置切換;

$ xmake f -m my_mode
$ xmake
[  0%]: ccache compiling.my_mode src/main.cpp
[100%]: linking.my_mode test
build ok!
複製程式碼

然後xmake.lua裡面對相應的值進行判斷即可:

if is_mode("my_mode") then
    add_defines("ENABLE_MY_MODE")
end
複製程式碼

使用模式變數

我們也可以直接在配置值中傳遞模式變數$(mode),比如根據不同模式選擇連結不同的庫:

target("test")
    set_kind("binary")
    add_files("src/*.c")
    add_links("xxx_$(mode)")
複製程式碼

上面的配置,如果是除錯模式編譯就會選擇連結:libxxx_debug.a庫,而release下就會連結libxxx_release.a,當然,我們也可以設定到庫搜尋路徑中,根據目錄來選擇對應的庫。

target("test")
    set_kind("binary")
    add_files("src/*.c")
    add_linkdirs("lib/$(mode)")
    add_links("xxx")
複製程式碼

另外,我們可以通過get_config("mode")直接獲取到傳入的模式配置值,並且這幾種獲取方式,在自定義指令碼也是同樣有效的哦,例如:

target("test")
    set_kind("binary")
    add_files("src/*.c")
    on_load(function (target)
        if is_mode("release") then
            print(get_config("mode"),"$(mode)")
        end
    end)
複製程式碼

原文:tboox.org/cn/2019/12/…