Xmake 是一個基於 Lua 的輕量級跨平臺構建工具。
它非常的輕量,沒有任何依賴,因爲它內置了 Lua 運行時。
它使用 xmake.lua 維護項目構建,相比 makefile/CMakeLists.txt,配置語法更加簡潔直觀,對新手非常友好,短時間內就能快速入門,能夠讓用戶把更多的精力集中在實際的項目開發上。
我們能夠使用它像 Make/Ninja 那樣可以直接編譯項目,也可以像 CMake/Meson 那樣生成工程文件,另外它還有內置的包管理系統來幫助用戶解決 C/C++ 依賴庫的集成使用問題。
目前,Xmake 主要用於 C/C++ 項目的構建,但是同時也支持其他 native 語言的構建,可以實現跟 C/C++ 進行混合編譯,同時編譯速度也是非常的快,可以跟 Ninja 持平。
Xmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache
儘管不是很準確,但我們還是可以把 Xmake 按下面的方式來理解:
Xmake ≈ Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache
新特性介紹
新版本中,我們新增了 cosmocc 工具鏈支持,使用它,我們可以實現一次編譯,到處運行。另外,我們還重構了 C++ Modules 的實現,解決了很多 C++ Modules 相關的問題。
Cosmocc 工具鏈支持
cosmocc 工具鏈是 cosmopolitan 項目提供的編譯工具鏈,使用這個工具鏈編譯的程序可以實現一次編譯,到處運行。
而新版本中,我們對這個工具鏈也做了支持,可以實現在 macosx/linux/windows 下編譯程序,並且還能夠支持自動下載 cosmocc 工具鏈。
對於用戶,僅僅只需要配置 xmake.lua 工程文件,然後執行 xmake
命令,即可實現一鍵編譯,到處運行。
xmake.lua 內容如下,這是一個最基礎的 hello world 終端程序的構建配置。
add_rules("mode.debug", "mode.release")
add_requires("cosmocc")
target("test")
set_kind("binary")
add_files("src/*.c")
set_toolchains("@cosmocc")
然後,我們執行 xmake 命令,它會先下載集成 cosmocc 工具鏈,然後使用這個工具鏈去編譯程序。
ruki:console$ xmake
checking for platform ... linux
checking for architecture ... x86_64
note: install or modify (m) these packages (pass -y to skip confirm)?
in xmake-repo:
-> cosmocc 3.2.4
please input: y (y/n/m)
=> install cosmocc 3.2.4 .. ok
[ 25%]: cache compiling.release src/main.c
[ 50%]: linking.release test
[100%]: build ok, spent 1.548s
ruki:console$ xmake run
hello world
C++ Modules 改進
非常感謝 @Arthapz 對 C++ Modules 做了大量的改進工作,使得 xmake 更好地支持 C++ Modules 構建,也修復了很多已知的問題,例如 msys2/mingw 下對 C++ Modules 編譯支持等問題。
改進 xmake test
2.8.5 版本開始,我們增加了內置的測試命令:xmake test
,我們只需要在需要測試的 target 上通過 add_tests 配置一些測試用例,就可以自動執行測試。
執行的效果如下:
ruki-2:test ruki$ xmake test
running tests ...
[ 2%]: test_1/args .................................... passed 7.000s
[ 5%]: test_1/default .................................... passed 5.000s
[ 8%]: test_1/fail_output .................................... passed 5.000s
[ 11%]: test_1/pass_output .................................... passed 6.000s
[ 13%]: test_2/args .................................... passed 7.000s
[ 16%]: test_2/default .................................... passed 6.000s
[ 19%]: test_2/fail_output .................................... passed 6.000s
[ 22%]: test_2/pass_output .................................... passed 6.000s
[ 25%]: test_3/args .................................... passed 7.000s
...
[ 77%]: test_7/pass_output .................................... failed 5.000s
[ 80%]: test_8/args .................................... passed 7.000s
[ 83%]: test_8/default .................................... passed 6.000s
[ 86%]: test_8/fail_output .................................... passed 6.000s
[ 88%]: test_8/pass_output .................................... failed 5.000s
[ 91%]: test_9/args .................................... passed 6.000s
[ 94%]: test_9/default .................................... passed 6.000s
[ 97%]: test_9/fail_output .................................... passed 6.000s
[100%]: test_9/pass_output .................................... passed 6.000s
80% tests passed, 7 tests failed out of 36, spent 0.242s
而新版本中,我們新增了對超時運行的測試支持。
如果一些測試程序長時間運行不退出,就會卡住,我們可以通過配置超時時間,強制退出,並返回失敗。
target("test_timeout")
set_kind("binary")
set_default(false)
add_files("src/run_timeout.cpp")
add_tests("run_timeout", {run_timeout = 1000})
上面的配置中,我們通過 {run_timeout = 1000}
可以配置指定的測試程序運行的超時時間,如果運行超時,就會作爲測試失敗。
$ xmake test
[100%]: test_timeout/run_timeout .................................... failed 1.006s
run failed, exit code: -1, exit error: wait process timeout
支持 Android NDK r26b
自從 Android NDK r26b 之後,NDK 對內部構建工具鏈的結構做了很大的改動,完全採用 llvm clang 來構建程序,因此新版本 xmake 對它做了一些適配,使得能夠繼續很好地支持新的 NDK。
改進運行時配置
另外,我們還改進了 set_runtimes
接口,除了先前已經支持的 MT/MD/MTd/MDd
等 windows msvc 的運行時庫配置,還新增了 c++_static
, c++_shared
, stdc++_static
, stdc++_shared
等庫配置,
它們用於 clang/gcc 的 c++ 運行時庫配置。而對於 Android 平臺編譯, 我們也將已有的 xmake f --ndk_cxxstl=
等配置,也合併統一到 xmake f --runtimes=
中,與 set_runtimes
相對應。
除了設置,我們也可以在 target 中,通過 target:runtimes()
和 target:has_runtime()
等接口去獲取和判斷當前的 runtimes 庫,在 package 中,也有一樣的接口可用。
例如:
target("test")
add_files("src/*.cpp")
on_load(function (target)
if target:has_runtime("c++_shared", "c++_static") then
-- TODO
end
end)
如果 c++_static
配置生效,在 Clang 編譯的時候,就會被自動添加 -stdlib=libc++ -static-libstdc++
等 flags,而如果 stdc++_static
則對應 -stdlib=slibtdc++
。
改進腳本匹配模式
xmake 中的所有 on_xxx
, before_xxx
和 after_xxx
等腳本配置接口,都可以在第一個參數中,設置腳本能夠被運行的平臺架構模式。
如果指定的模式和當前架構模式匹配,配置的腳本才能夠被執行,它的完整的過濾語法如下:plat|arch1,arch2@host|arch1,arch2
看上去非常的複雜,其實很簡單,其中每個階段都是可選的,可部分省略,對應:編譯平臺|編譯架構@主機平臺|主機架構
如果不設置任何平臺過濾條件,那麼默認全平臺支持,裏面的腳本對所有平臺生效,例如:
on_install(function (package)
-- TODO
end)
如果安裝腳本對特定平臺生效,那麼直接指定對應的編譯平臺,可以同時指定多個:
on_install("linux", "macosx", function (package)
-- TODO
end)
如果還要細分到指定架構才能生效,可以這麼寫:
on_install("linux|x86_64", "iphoneos|arm64", function (package)
-- TODO
end)
如果還要限制執行的主機環境平臺和架構,可以在後面追加@host|arch
,例如:
on_install("mingw@windows", function (package)
-- TODO
end)
意思就是僅對windows下編譯mingw平臺生效。
我們也可以不指定比那一平臺和架構,僅設置主機平臺和架構,這通常用於描述一些跟編譯工具相關的依賴包,只能在主機環境運行。
例如,我們編譯的包,依賴了cmake,需要添加cmake的包描述,那麼裏面編譯安裝環境,只能是主機平臺:
on_install("@windows", "@linux", "@macosx", function (package)
-- TODO
end)
其他一些例子:
-- `@linux`
-- `@linux|x86_64`
-- `@macosx,linux`
-- `android@macosx,linux`
-- `android|armeabi-v7a@macosx,linux`
-- `android|armeabi-v7a@macosx,linux|x86_64`
-- `android|armeabi-v7a@linux|x86_64`
而在 2.8.7 中,我們改進了模式匹配支持,新增排除指定平臺和架構,例如:
!plat|!arch@!subhost|!subarch
@!linux
@!linux|x86_64
@!macosx,!linux
!android@macosx,!linux
android|!armeabi-v7a@macosx,!linux
android|armeabi-v7a,!iphoneos@macosx,!linux|x86_64
!android|armeabi-v7a@!linux|!x86_64
!linux|*
同時,還提供了一個內置的 native
架構,用於匹配當前平臺的本地架構,主要用於指定或者排除交叉編譯平臺。
on_install("macosx|native", ...)
上面的配置,如果在 macOS x86_64 的設備上,它僅僅只會匹配 xmake f -a x86_64
的本地架構編譯。
如果是 xmake f -a arm64
交叉編譯,就不會被匹配到。
同理,如果只想匹配交叉編譯,可以使用 macosx|!native
進行取反排除就行了。
這個模式改進,其實主要用於倉庫包配置的簡化,更好的處理不同平臺下包安裝腳本的配置支持。
更新日誌
新特性
- #4544: 改進
xmake test
,支持等待進程超時 - #4606: 爲 package 添加
add_versionfiles
接口 - #4709: 添加 cosmocc 工具鏈支持
- #4715: 在描述域添加 is_cross() 接口
- #4747: 添加
build.always_update_configfiles
策略
改進
- #4575: 檢測無效的域參數
- 添加更多的 loong64 支持
- 改進 dlang/dmd 對 frameworks 的支持
- #4571: 改進
xmake test
的輸出支持 - #4609: 改進探測 vs 構建工具環境
- #4614: 改進支持 android ndk 26b
- #4473: 默認啓用警告輸出
- #4477: 改進 runtimes 去支持 libc++/libstdc++
- #4657: 改進腳本的模式匹配
- #4673: 重構模塊支持
- #4746: 爲 cmake generator 添加原生 c++ modules 支持