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
新特性介紹
這個版本,我們增加了大量的重量級新特性:
- 分佈式編譯支持
- 內置本地編譯緩存
- 遠程編譯緩存支持
通過這些特性,我們可以更加快速地編譯大型 C/C++ 項目。另外,它們完全是跨平臺的,不僅支持 gcc/clang 也支持 msvc,而且除了編譯器無任何第三方依賴,使用也非常方便。
因此,使用了 Xmake,就等於同時使用了 distcc/ccache/sccache
。
相比這些第三方的工具,Xmake 完全支持 Windows 和 msvc,在消除了平臺差異性的同事,也省去了獨立進程調用,以及額外的守護進程帶來的開銷。
除了這些特性之外,新版本 Xmake 還新增 Keil/c51 項目的編譯支持,以及對 nvidia-hpc-sdk 工具鏈中的 nvc/nvc++/nvfortran 編譯器的支持。
遠程編譯支持用戶認證
上個版本我們已經初步支持了遠程編譯,但是沒有提供用戶認證支持,這會帶來一些安全性問題,因此這個版本,我們新增了用戶認證支持。
目前,Xmake 主要提供以下幾種認證機制,另外,它對分佈式編譯和遠程緩存也同樣生效。
- Token 認證
- 密碼認證
- 可信主機驗證
Token 認證
這也是我們默認推薦的方式,更加安全,配置和連接也更加方便,每次連接也不用輸入密碼。
我們在執行 xmake service
命令時候,默認就會生成一個服務端和客戶端的配置文件,並且自動生成一個默認的 token,因此本地直連是不需要任何配置的。
服務端認證配置
服務端可以配置多個 token 用於對不同用戶主機進行授權連接,當然也可以共用一個 token。
$ cat ~/.xmake/service/server.conf
{
known_hosts = { },
logfile = "/Users/ruki/.xmake/service/server/logs.txt",
remote_build = {
listen = "0.0.0.0:9691",
workdir = "/Users/ruki/.xmake/service/server/remote_build"
},
tokens = {
"e438d816c95958667747c318f1532c0f"
}
}
客戶端認證配置
客戶端只需要添加服務器上的 token 到對應的客戶端配置中即可。
$ cat ~/.xmake/service/client.conf
{
remote_build = {
connect = "127.0.0.1:9691",
token = "e438d816c95958667747c318f1532c0f"
}
}
手動生成新 token
我們也可以執行下面的命令,手動生成一個新的 token,自己添加到服務器配置中。
$ xmake service --gen-token
New token a7b9fc2d3bfca1472aabc38bb5f5d612 is generated!
密碼認證
我們也提供密碼認證的授權模式,相比 token 認證,它需要用戶每次連接的時候,輸入密碼,驗證通過後,才能連接上。
服務端認證配置
密碼認證,我們不需要手動配置 token,只需要執行下面的命令,添加用戶就行了,添加過程中,會提示用戶輸入密碼。
$ xmake service --add-user=ruki
Please input user ruki password:
123456
Add user ruki ok!
然後,xmake 就會通過用戶名,密碼生成一個新的 token 添加到服務器配置的 token 列表中去。
$ cat ~/.xmake/service/server.conf
{
known_hosts = { },
logfile = "/Users/ruki/.xmake/service/server/logs.txt",
remote_build = {
listen = "0.0.0.0:9691",
workdir = "/Users/ruki/.xmake/service/server/remote_build"
},
tokens = {
"e438d816c95958667747c318f1532c0f",
"7889e25402413e93fd37395a636bf942"
}
}
當然,我們也可以刪除指定的用戶和密碼。
$xmake service --rm-user=ruki
Please input user ruki password:
123456
Remove user ruki ok!
客戶端認證配置
對於客戶端,我們不再需要設置服務器的 token 了,只需要在連接配置中,追加需要連接的用戶名即可開啓密碼認證,格式:user@address:port
$ cat ~/.xmake/service/client.conf
{
remote_build = {
connect = "[email protected]:9691"
}
}
!> 如果去掉用戶名,也沒配置 token,那就是匿名模式,如果服務器也沒配置 token,就是完全禁用認證,直接連接。
可信主機驗證
另外,爲了更進一步提高安全性,我們還提供了服務端可信主機驗證,如果在服務器配置的 known_hosts 列表中,配置了可以連接的客戶端主機 ip 地址,
那麼只有這些主機可以成功連接上這臺服務器,其他主機對它的連接都會被提示爲不可信而拒絕連接,即使 token 和密碼認證都沒問題也不行。
$ cat ~/.xmake/service/server.conf
{
logfile = "/Users/ruki/.xmake/service/logs.txt",
server = {
tokens = {
"4b928c7563a0cba10ff4c3f5ca0c8e24"
},
known_hosts = { "127.0.0.1", "xx.xx.xx.xx"}
}
}
連接遠程的服務器
接下來,我們只需要進入需要遠程編譯的工程根目錄,執行 xmake service --connect
命令,進行連接。
如果是 token 認證模式,那麼不需要的額外的密碼輸入,直接連接。
$ xmake create test
$ cd test
$ xmake service --connect
<remote_build_client>: connect 192.168.56.110:9091 ..
<remote_build_client>: connected!
<remote_build_client>: sync files in 192.168.56.110:9091 ..
Scanning files ..
Comparing 3 files ..
[+]: src/main.cpp
[+]: .gitignore
[+]: xmake.lua
3 files has been changed!
Archiving files ..
Uploading files with 1372 bytes ..
<remote_build_client>: sync files ok!
如果是密碼認證,那麼會提示用戶輸入密碼,才能繼續連接。
$ xmake service --connect
Please input user root password:
000000
<remote_build_client>: connect 127.0.0.1:9691 ..
<remote_build_client>: connected!
<remote_build_client>: sync files in 127.0.0.1:9691 ..
Scanning files ..
Comparing 3 files ..
[+]: xmake.lua
[+]: .gitignore
[+]: src/main.cpp
3 files has been changed!
Archiving files ..
Uploading files with 1591 bytes ..
<remote_build_client>: sync files ok!
如果密碼不對,就會提示錯誤。
$ xmake service --connect
Please input user root password:
123
<remote_build_client>: connect 127.0.0.1:9691 ..
<remote_build_client>: connect 127.0.0.1:9691 failed, user and password are incorrect!
分佈式編譯支持
Xmake 提供了內置的分佈式編譯服務,通常它可以跟 本地編譯緩存,遠程編譯緩存 相互配合,實現最優的編譯的加速。
另外,它是完全跨平臺支持,我們不僅支持 gcc/clang,也能夠很好地支持 Windows 和 msvc。
對於交叉編譯,只要交叉工具鏈支持,我們不要求服務器的系統環境,即使混用 linux, macOS 和 Windows 的服務器資源,也可以很好的實現分佈式編譯。
開啓服務
我們可以指定 --distcc
參數來開啓分佈式編譯服務,當然如果不指定這個參數,xmake 會默認開啓所有服務端配置的服務。
$ xmake service --distcc
<distcc_build_server>: listening 0.0.0.0:9093 ..
我們也可以開啓服務的同時,回顯詳細日誌信息。
$ xmake service --distcc -vD
<distcc_build_server>: listening 0.0.0.0:9093 ..
以 Daemon 模式開啓服務
$ xmake service --distcc --start
$ xmake service --distcc --restart
$ xmake service --distcc --stop
配置服務端
我們首先,運行 xmake service
命令,它會自動生成一個默認的 server.conf
配置文件,存儲到 ~/.xmake/service/server.conf
。
$ xmake service
generating the config file to /Users/ruki/.xmake/service/server.conf ..
an token(590234653af52e91b9e438ed860f1a2b) is generated, we can use this token to connect service.
generating the config file to /Users/ruki/.xmake/service/client.conf ..
<distcc_build_server>: listening 0.0.0.0:9693 ..
然後,我們編輯它,修復服務器的監聽端口(可選)。
$ cat ~/.xmake/service/server.conf
{
distcc_build = {
listen = "0.0.0.0:9693",
workdir = "/Users/ruki/.xmake/service/server/distcc_build"
},
known_hosts = { },
logfile = "/Users/ruki/.xmake/service/server/logs.txt",
tokens = {
"590234653af52e91b9e438ed860f1a2b"
}
}
配置客戶端
客戶端配置文件在 ~/.xmake/service/client.conf
,我們可以在裏面配置客戶端需要連接的服務器地址。
我們可以在 hosts 列表裏面配置多個服務器地址,以及對應的 token。
!> 分佈式編譯,推薦使用 token 認證模式,因爲密碼模式,每臺服務器連接時候都要輸入一次密碼,很繁瑣。
$cat ~/.xmake/service/client.conf
{
distcc_build = {
hosts = {
{
connect = "127.0.0.1:9693",
token = "590234653af52e91b9e438ed860f1a2b"
}
}
}
}
連接服務器
配置完認證和服務器地址後,就可以輸入下面的命令,將當前工程連接到配置的服務器上了。
我們需要在連接時候,輸入 --distcc
,指定僅僅連接分佈式服務。
$ cd projectdir
$ xmake service --connect --distcc
<client>: connect 127.0.0.1:9693 ..
<client>: 127.0.0.1:9693 connected!
我們也可以同時連接多個服務,比如分佈式編譯和遠程編譯緩存服務。
$ xmake service --connect --distcc --ccache
!> 如果不帶任何參數,默認連接的是遠程編譯服務。
分佈式編譯項目
連接上服務器後,我們就可以像正常本地編譯那樣,進行分佈式編譯了,例如:
$ xmake
...
[ 93%]: ccache compiling.release src/demo/network/unix_echo_client.c ----> local job
[ 93%]: ccache compiling.release src/demo/network/ipv6.c
[ 93%]: ccache compiling.release src/demo/network/ping.c
[ 93%]: distcc compiling.release src/demo/network/unix_echo_server.c. ----> distcc job
[ 93%]: distcc compiling.release src/demo/network/http.c
[ 93%]: distcc compiling.release src/demo/network/unixaddr.c
[ 93%]: distcc compiling.release src/demo/network/ipv4.c
[ 94%]: distcc compiling.release src/demo/network/ipaddr.c
[ 94%]: distcc compiling.release src/demo/math/fixed.c
[ 94%]: distcc compiling.release src/demo/libm/float.c
[ 95%]: ccache compiling.release src/demo/libm/double.c
[ 95%]: ccache compiling.release src/demo/other/test.cpp
[ 98%]: archiving.release libtbox.a
[ 99%]: linking.release demo
[100%]: build ok!
其中,帶有 distcc 字樣的是遠程編譯任務,其他的都是本地編譯任務,默認 xmake 還開啓了本地編譯緩存,對分佈式編譯結果進行緩存,避免頻繁請求服務器。
另外,我們也可以開啓遠程編譯緩存,跟其他人共享編譯緩存,進一步加速多人協同開發的編譯。
斷開連接
$ xmake service --disconnect --distcc
指定並行編譯任務數
我們先簡單介紹下,目前根據主機 cpu core 數量默認計算的並行任務數:
local default_njob = math.ceil(ncpu * 3 / 2)
因此,如果不開啓分佈式編譯,默認的最大並行編譯任務數就是這個 default_njob。
如果開啓分佈式編譯後,默認的並行編譯任務數就是:
local maxjobs = default_njob + server_count * server_default_njob
修改本地並行任務數
我們只需要通過 -jN
就能指定本地並行任務數,但是它不會影響服務端的並行任務數。
$ xmake -jN
修改服務端並行任務數
如果要修改服務端的並行任務數,需要修改客戶端的配置文件。
$cat ~/.xmake/service/client.conf
{
distcc_build = {
hosts = {
{
connect = "127.0.0.1:9693",
token = "590234653af52e91b9e438ed860f1a2b",
njob = 8 <------- modify here
},
{
connect = "192.168.01:9693",
token = "590234653af52e91b9e438ed860f1a2b",
njob = 4
}
}
}
}
可以對每個服務器主機,添加 njob = N
參數配置,指定這臺服務器可以提供的並行任務數。
分佈式編譯 Android 項目
xmake 提供的分佈式編譯服務是完全跨平臺的,並且支持 Windows, Linux, macOS, Android, iOS 甚至交叉編譯。
如果要進行 Android 項目編譯,只需要在服務端配置中,增加 toolchains
工具鏈配置,提供 NDK 的跟路徑即可。
$ cat ~/.xmake/service/server.conf
{
distcc_build = {
listen = "0.0.0.0:9693",
toolchains = {
ndk = {
ndk = "~/files/android-ndk-r21e" <------------ here
}
},
workdir = "/Users/ruki/.xmake/service/server/distcc_build"
},
known_hosts = { },
logfile = "/Users/ruki/.xmake/service/server/logs.txt",
tokens = {
"590234653af52e91b9e438ed860f1a2b"
}
}
然後,我們就可以像正常本地編譯那樣,分佈式編譯 Android 項目,甚至可以配置多臺 Windows, macOS, Linux 等不同的服務器主機,做爲分佈式編譯服務的資源,來編譯它。
只需要下載對應平臺的 NDK 就行了。
$ xmake f -p android --ndk=~/files/xxxx
$ xmake
分佈式編譯 iOS 項目
編譯 iOS 項目更加簡單,因爲 Xmake 通常能自動檢測到 Xcode,所以只需要像正常本地一樣,切一下平臺到 ios 即可。
$ xmake f -p iphoneos
$ xmake
分佈式交叉編譯配置
如果要分佈式交叉編譯,我們需要在服務端配置工具鏈 sdk 路徑,例如:
$ cat ~/.xmake/service/server.conf
{
distcc_build = {
listen = "0.0.0.0:9693",
toolchains = {
cross = {
sdkdir = "~/files/arm-linux-xxx" <------------ here
}
},
workdir = "/Users/ruki/.xmake/service/server/distcc_build"
},
known_hosts = { },
logfile = "/Users/ruki/.xmake/service/server/logs.txt",
tokens = {
"590234653af52e91b9e438ed860f1a2b"
}
}
其中,toolchains 下,每一項對應一個工具鏈,這裏配置爲 cross = {}
交叉工具鏈,對應 toolchain("cross")
。
工具鏈裏面我們可以配置 sdkdir
, bindir
, cross
等等,對應 toolchain("cross")
裏面的 set_sdkdir
, set_bindir
和 set_cross
等接口配置。
如果交叉工具鏈比較規範,我們通常只需要配置 sdkdir
,xmake 就能自動檢測到。
而客戶端編譯也只需要指定 sdk 目錄。
$ xmake f -p cross --sdk=/xxx/arm-linux-xxx
$ xmake
清理服務器緩存
每個項目在服務端的編譯,都會產生一些緩存文件,他們都是按工程粒度分別存儲的,我們可以通過下面的命令,對當前工程清理每個服務器對應的緩存。
$ xmake service --clean --distcc
一些內部優化
- 緩存服務器端編譯結果,避免重複編譯
- 本地緩存,遠程緩存優化,避免不必要的服務端通信
- 服務器負載均衡調度,合理分配服務器資源
- 預處理後小文件直接本地編譯,通常會更快
- 大文件實時壓縮傳輸,基於 lz4 快速壓縮
- 內部狀態維護,相比 distcc 等獨立工具,避免了頻繁的獨立進程加載耗時,也避免了與守護進程額外的通信
本地編譯緩存支持
默認,Xmake 就會開啓本地緩存,2.6.5 之前的版本默認使用外置的 ccache,而 2.6.6 之後版本,Xmake 提供了內置的跨平臺本地緩存方案。
相比 ccache 等第三方獨立進程,xmake 內部狀態維護,更加便於優化,也避免了頻繁的獨立進程加載耗時,也避免了與守護進程額外的通信。
另外,內置的緩存能夠更好的支持跨平臺,Windows 上 msvc 也能夠很好的支持,而 ccache 僅僅支持 gcc/clang。
當然,我們也可以通過下面的命令禁用緩存。
$ xmake f --ccache=n
注:不管是否使用內置本地緩存,配置名都是 --ccache=
,意思是 c/c++ 構建緩存,而不僅僅是指 ccache 工具的名字。
我們如果想繼續使用外置的其他緩存工具,我們也是可以通過下面的方式來配置。
$ xmake f --ccache=n --cxx="ccache gcc" --cc="ccache gcc"
$ xmake
遠程編譯緩存支持
除了本地緩存,我們也提供了遠程緩存服務,類似 mozilla 的 sscache,如果只是個人開發,平常不會用到它。
但是,如果是公司內部多人協同開發一個大型項目,僅僅靠分佈式編譯和本地緩存,是不夠的。我們還需要對編譯的對象文件緩存到獨立的服務器上進行共享。
這樣,其他人即使首次編譯,也不需要每次都去分佈式編譯它,直接從遠程拉取緩存來加速編譯。
另外,Xmake 提供的遠程緩存服務,也是全平臺支持的,不僅支持 gcc/clang 還支持 msvc。
開啓服務
我們可以指定 --ccache
參數來開啓遠程編譯緩存服務,當然如果不指定這個參數,xmake 會默認開啓所有服務端配置的服務。
$ xmake service --ccache
<remote_cache_server>: listening 0.0.0.0:9092 ..
我們也可以開啓服務的同時,回顯詳細日誌信息。
$ xmake service --ccache -vD
<remote_cache_server>: listening 0.0.0.0:9092 ..
以 Daemon 模式開啓服務
$ xmake service --ccache --start
$ xmake service --ccache --restart
$ xmake service --ccache --stop
配置服務端
我們首先,運行 xmake service
命令,它會自動生成一個默認的 server.conf
配置文件,存儲到 ~/.xmake/service/server.conf
。
$ xmake service
generating the config file to /Users/ruki/.xmake/service/server.conf ..
an token(590234653af52e91b9e438ed860f1a2b) is generated, we can use this token to connect service.
generating the config file to /Users/ruki/.xmake/service/client.conf ..
<remote_cache_server>: listening 0.0.0.0:9692 ..
然後,我們編輯它,修復服務器的監聽端口(可選)。
$ cat ~/.xmake/service/server.conf
{
distcc_build = {
listen = "0.0.0.0:9692",
workdir = "/Users/ruki/.xmake/service/server/remote_cache"
},
known_hosts = { },
logfile = "/Users/ruki/.xmake/service/server/logs.txt",
tokens = {
"590234653af52e91b9e438ed860f1a2b"
}
}
配置客戶端
客戶端配置文件在 ~/.xmake/service/client.conf
,我們可以在裏面配置客戶端需要連接的服務器地址。
我們可以在 hosts 列表裏面配置多個服務器地址,以及對應的 token。
$cat ~/.xmake/service/client.conf
{
remote_cache = {
connect = "127.0.0.1:9692,
token = "590234653af52e91b9e438ed860f1a2b"
}
}
}
連接服務器
配置完認證和服務器地址後,就可以輸入下面的命令,將當前工程連接到配置的服務器上了。
我們需要在連接時候,輸入 --ccache
,指定僅僅連接遠程編譯緩存服務。
$ cd projectdir
$ xmake service --connect --ccache
<client>: connect 127.0.0.1:9692 ..
<client>: 127.0.0.1:9692 connected!
我們也可以同時連接多個服務,比如分佈式編譯和遠程編譯緩存服務。
$ xmake service --connect --distcc --ccache
!> 如果不帶任何參數,默認連接的是遠程編譯服務。
斷開連接
$ xmake service --disconnect --ccache
清理服務器緩存
我們也可以通過下面的命令,清理當前工程對應的遠程服務器上的緩存。
$ xmake service --clean --ccache
而如果我們執行 xmake clean --all
,在連接了遠程服務的狀態下,也會去自動清理所有的緩存。
一些內部優化
- 拉取遠程緩存的快照,通過 bloom filter + lz4 回傳本地後,用於快速判斷緩存是否存在,避免頻繁的查詢服務端緩存信息
- 配合本地緩存,可以避免頻繁地請求遠程服務器,拉取緩存。
- 內部狀態維護,相比 sscache 等獨立工具,避免了頻繁的獨立進程加載耗時,也避免了與守護進程額外的通信
Keil/C51 工程支持
我們只需要綁定到 c51 工具鏈,Xmake 就能自動檢測到系統安裝的 Keil/C51 SDK 工具鏈環境,然後使用它進行編譯。
target("hello")
add_rules("c51.binary")
set_toolchains("c51")
add_files("src/main.c")
當然,如果不通過 set_toolchains("c51")
設置工具鏈,我們也可以通過 xmake f --toolchain=c51
手動切換到 c51 工具鏈上去。
更新內容
新特性
- #2327: 支持 nvidia-hpc-sdk 工具鏈中的 nvc/nvc++/nvfortran 編譯器
- 添加 path 實例接口
- #2334: 添加 lz4 壓縮模塊
- #2349: 添加 keil/c51 工程支持
- #274: 跨平臺分佈式編譯支持
- 使用內置的本地緩存替代 ccache
改進
- #2309: 遠程編譯支持用戶授權驗證
- 改進遠程編譯,增加對 lz4 壓縮支持
Bugs 修復
- 修復選擇包版本時候 lua 棧不平衡導致的崩潰問題