Xmake v2.6.6 發佈,分佈式編譯和緩存支持

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 主要提供以下幾種認證機制,另外,它對分佈式編譯和遠程緩存也同樣生效。

  1. Token 認證
  2. 密碼認證
  3. 可信主機驗證

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_bindirset_cross 等接口配置。

如果交叉工具鏈比較規範,我們通常只需要配置 sdkdir,xmake 就能自動檢測到。

而客戶端編譯也只需要指定 sdk 目錄。

$ xmake f -p cross --sdk=/xxx/arm-linux-xxx
$ xmake

清理服務器緩存

每個項目在服務端的編譯,都會產生一些緩存文件,他們都是按工程粒度分別存儲的,我們可以通過下面的命令,對當前工程清理每個服務器對應的緩存。

$ xmake service --clean --distcc

一些內部優化

  1. 緩存服務器端編譯結果,避免重複編譯
  2. 本地緩存,遠程緩存優化,避免不必要的服務端通信
  3. 服務器負載均衡調度,合理分配服務器資源
  4. 預處理後小文件直接本地編譯,通常會更快
  5. 大文件實時壓縮傳輸,基於 lz4 快速壓縮
  6. 內部狀態維護,相比 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,在連接了遠程服務的狀態下,也會去自動清理所有的緩存。

一些內部優化

  1. 拉取遠程緩存的快照,通過 bloom filter + lz4 回傳本地後,用於快速判斷緩存是否存在,避免頻繁的查詢服務端緩存信息
  2. 配合本地緩存,可以避免頻繁地請求遠程服務器,拉取緩存。
  3. 內部狀態維護,相比 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 棧不平衡導致的崩潰問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章