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
新特性介紹
Verilog 模擬程式支援
iVerilog 模擬器
透過 add_requires("iverilog")
配置,我們能夠自動拉取 iverilog 工具鏈包,然後使用 set_toolchains("@iverilog")
自動繫結工具鏈來編譯工程。
add_requires("iverilog")
target("hello")
add_rules("iverilog.binary")
set_toolchains("@iverilog")
add_files("src/*.v")
設定抽象配置
add_requires("iverilog")
target("hello")
add_rules("iverilog.binary")
set_toolchains("@iverilog")
add_files("src/*.v")
add_defines("TEST")
add_includedirs("inc")
set_languages("v1800-2009")
我們可以透過 set_languages("v1800-2009")
來設定切換 Verilog 的語言標準。
目前支援的一些取值和對映關係如下:
["v1364-1995"] = "-g1995"
["v1364-2001"] = "-g2001"
["v1364-2005"] = "-g2005"
["v1800-2005"] = "-g2005-sv"
["v1800-2009"] = "-g2009"
["v1800-2012"] = "-g2012"
設定自定義 flags
add_requires("iverilog")
target("hello")
add_rules("iverilog.binary")
set_toolchains("@iverilog")
add_files("src/*.v")
add_values("iverilogs.flags", "-DTEST")
構建工程
$ xmake
checking for iverilog ... iverilog
checking for vvp ... vvp
[ 50%]: linking.iverilog hello.vvp
[100%]: build ok!
執行程式
$ xmake run
hello world!
LXT2 info: dumpfile hello.vcd opened for output.
src/main.v:6: $finish called at 0 (1s)
更多完整例子:iVerilog Examples
Verilator 模擬器
透過 add_requires("verilator")
配置,我們能夠自動拉取 verilator 工具鏈包,然後使用 set_toolchains("@verilator")
自動繫結到工具鏈來編譯工程。
add_requires("verilator")
target("hello")
add_rules("verilator.binary")
set_toolchains("@verilator")
add_files("src/*.v")
add_files("src/*.cpp")
verilator 工程,我們需要一個額外的 sim_main.cpp
檔案參與編譯,作為程式的入口程式碼。
#include "hello.h"
#include "verilated.h"
int main(int argc, char** argv) {
VerilatedContext* contextp = new VerilatedContext;
contextp->commandArgs(argc, argv);
hello* top = new hello{contextp};
while (!contextp->gotFinish()) { top->eval(); }
delete top;
delete contextp;
return 0;
}
設定抽象配置
add_requires("verilator")
target("hello")
add_rules("verilator.binary")
set_toolchains("@verilator")
add_files("src/*.v")
add_defines("TEST")
add_includedirs("inc")
set_languages("v1800-2009")
我們可以透過 set_languages("v1800-2009")
來設定切換 Verilog 的語言標準。
目前支援的一些取值和對映關係如下:
-- Verilog
["v1364-1995"] = "+1364-1995ext+v",
["v1364-2001"] = "+1364-2001ext+v",
["v1364-2005"] = "+1364-2005ext+v",
-- SystemVerilog
["v1800-2005"] = "+1800-2005ext+v",
["v1800-2009"] = "+1800-2009ext+v",
["v1800-2012"] = "+1800-2012ext+v",
["v1800-2017"] = "+1800-2017ext+v",
設定自定義 flags
add_requires("verilator")
target("hello")
add_rules("verilator.binary")
set_toolchains("@verilator")
add_files("src/*.v")
add_files("src/*.cpp")
add_values("verilator.flags", "--trace", "--timing")
構建工程
$ xmake
[ 0%]: compiling.verilog src/main.v
[ 15%]: cache compiling.release /Users/ruki/.xmake/packages/v/verilator/2023.1.10/cd2268409c1d44799288c7759b3cbd56/share/verilator/include/verilated.cpp
[ 15%]: cache compiling.release build/.gens/hello/macosx/x86_64/release/rules/verilator/hello___024root__Slow.cpp
[ 15%]: cache compiling.release build/.gens/hello/macosx/x86_64/release/rules/verilator/hello___024root__DepSet_h9053a130__0__Slow.cpp
[ 15%]: cache compiling.release build/.gens/hello/macosx/x86_64/release/rules/verilator/hello.cpp
[ 15%]: cache compiling.release /Users/ruki/.xmake/packages/v/verilator/2023.1.10/cd2268409c1d44799288c7759b3cbd56/share/verilator/include/verilated_threads.cpp
[ 15%]: cache compiling.release build/.gens/hello/macosx/x86_64/release/rules/verilator/hello__Syms.cpp
[ 15%]: cache compiling.release build/.gens/hello/macosx/x86_64/release/rules/verilator/hello___024root__DepSet_h07139e86__0.cpp
[ 15%]: cache compiling.release src/sim_main.cpp
[ 15%]: cache compiling.release build/.gens/hello/macosx/x86_64/release/rules/verilator/hello___024root__DepSet_h9053a130__0.cpp
[ 84%]: linking.release hello
[100%]: build ok!
執行程式
$ xmake run
ruki-2:hello ruki$ xmake run
hello world!
- src/main.v:4: Verilog $finish
更多完整例子:Verilator
支援 C++ Module 分發
非常感謝 Arthapz 在新版本中繼續幫忙改進了 xmake 對 C++ Modules 的支援。
現在,我們可以將 C++ Modules 做成包進行分發,然後在其他專案中進行快速整合和複用。
它是基於 p2473r1 中對模組分發的設計草案做的一個原型實現。
製作分發 C++ Modules 包
我們先使用 xmake.lua 維護模組的構建,並透過指定 {install = true}
,來告訴 xmake 哪些模組檔案需要安裝對外分發。
add_rules("mode.release", "mode.debug")
set_languages("c++20")
target("foo")
set_kind("static")
add_files("*.cpp")
add_files("*.mpp", { install = true })
然後,我們把它做成包,可以提交到 xmake-repo 倉庫,當然也可以直接做成本地包,或者私有倉庫包。
這裡,為了方便測試驗證,我們僅僅透過 set_sourcedir
將它做成本地包。
package("foo")
set_sourcedir(path.join(os.scriptdir(), "src"))
on_install(function(package)
import("package.tools.xmake").install(package, {})
end)
整合 C++ Modules 包
然後,我們透過 add_requires("foo")
的包整合介面,對 C++ Modules 包進行快速整合使用。
由於 foo 的模組包,我們放在私有倉庫中定義,所以我們透過 add_repositories("my-repo my-repo")
引入自己的包倉庫。
如果,包已經提交到 xmake-repo 官方倉庫,就不需要額外配置它。
add_rules("mode.release", "mode.debug")
set_languages("c++20")
add_repositories("my-repo my-repo")
add_requires("foo", "bar")
target("packages")
set_kind("binary")
add_files("src/*.cpp")
add_packages("foo", "bar")
set_policy("build.c++.modules", true)
整合好包後,我們就可以執行 xmake
命令,一鍵下載、編譯、整合 C++ Modules 包來使用。
$ xmake
checking for platform ... linux
checking for architecture ... x86_64
note: install or modify (m) these packages (pass -y to skip confirm)?
in my-repo:
-> foo latest
-> bar latest
please input: y (y/n/m)
=> install bar latest .. ok
=> install foo latest .. ok
[ 0%]: generating.module.deps src/main.cpp
[ 0%]: generating.module.deps /mnt/xmake/tests/projects/c++/modules/packages/build/.packages/b/bar/latest/4e0143c97b65425b855ad5fd03038b6a/modules/bar/bar.mpp
[ 0%]: generating.module.deps /mnt/xmake/tests/projects/c++/modules/packages/build/.packages/f/foo/latest/4e0143c97b65425b855ad5fd03038b6a/modules/foo/foo.mpp
[ 14%]: compiling.module.release bar
[ 14%]: compiling.module.release foo
[ 57%]: compiling.release src/main.cpp
[ 71%]: linking.release packages
[100%]: build ok!
注:每個包安裝後,會在包路徑下,儲存維護模組的 meta-info 檔案,這是 p2473r1.pdf
中約定的一種格式規範,也許它不是最終的標準,但這並不影響我們現在去使用模組的分發。
$ cat ./build/.packages/f/foo/latest/4e0143c97b65425b855ad5fd03038b6a/modules/foo/foo.mpp.meta-info
{"_VENDOR_extension":{"xmake":{"name":"foo","file":"foo.mpp"}},"definitions":{},"include_paths":{}}
完整的例子工程見:C++ Modules 包分發例子工程
支援 C++23 Std Modules
Arthapz 也幫忙改進了對 C++23 Std Modules 的支援。
目前三個編譯器對它的支援進展:
Msvc
最新 Visual Studio 17.5 preview 已經支援,並且非標準的 ifc std modules 將被廢棄。
對於標準的 C++23 std modules,我們是這麼引入的。
import std;
而對於 ifc std modules,我們需要這麼寫:
import std.core;
它不是 C++23 標準,僅僅 msvc 提供,對其他編譯器並不相容,以後新版本 msvc 中也會逐步廢棄。
因此新版本 Xmake 將僅僅 C++23 std modules,不再支援廢棄的 ifc std modules。
Clang
目前最新的 clang 似乎也還沒完全支援 C++23 std modules,當前還是 draft patch 狀態,#D135507。
但是,Xmake 也對它進行了支援,如果大家想要嚐鮮,可以自行合入這個 patch,然後使用 xmake 來測試。
另外,低版本的 clang 也有對非標準的 std modules 做了實驗性支援。
我們還是可以在低版本 clang 中嘗試性使用 xmake 來構建 std modules,儘管它可能還只是個玩具(會遇到很多問題)。
相關討論見:#3255
Gcc
目前還不支援。
Xrepo 自動補全支援
之前,我們僅僅支援 xmake 命令的不全,新版本中,我們還支援了 xrepo install
命令的不全,
可以自動搜尋 xmake-repo 倉庫的包,來不全我們的安裝命令。
非常感謝 @glcraft 的貢獻。
$ xrepo install libp
libpaper libpfm libpng libpqxx libpthread-stubs
libpcap libplist libpq libpsl
更新內容
新特性
- #3228: C++ modules 的安裝釋出,以及從包中匯入 C++ modules 支援
- #3257: 增加對 iverilog 和 verilator 的支援
- 支援 xp 和 vc6.0
- #3214: xrepo install 的自動補全支援
改進
- #3255: 改進 clang libc++ 模組支援
- 支援使用 mingw 編譯 xmake
- 改進 xmake 在 win xp 上的相容性
- 如果外部依賴被啟用,切換 json 模組到純 lua 實現,移除對 lua-cjson 的依賴