xmake 是一个基于 lua 的轻量级跨平台构建工具,使用 xmake.lua 文件维护项目构建。相比 makefile/cmakelists.txt,xmake 的配置语法更加简洁直观,对新手非常友好,短时间内即可快速上手,让用户能够将更多精力集中在实际的项目开发上。
在 2.5.2 版本中,xmake 增加了一个重量级的新特性:自动拉取远程交叉编译工具链。这个功能对于有过交叉编译和 C/C++ 项目移植经验的开发者来说尤为重要,因为配置和下载交叉编译工具链是一个复杂且容易出错的过程。现在,xmake 可以自动下载项目所需的工具链,并使用这些工具链直接编译项目,用户无需关心如何配置工具链,只需执行
xmake命令即可完成编译。

不仅如此,对于 C/C++ 依赖包的集成,xmake 也可以自动切换到对应工具链进行编译和安装,整个过程完全自动化,用户无需手动干预。
除了交叉编译工具链,xmake 还可以自动拉取其他工具链,例如特定版本的 llvm、llvm-mingw 和 zig 等,用于参与 C/C++/Zig 项目的编译。即使是 cmake 也不支持工具链的自动拉取,顶多只能配合 vcpkg/conan 等第三方包管理工具对 C/C++ 依赖包进行集成,而 xmake 则内置了自己的包管理工具,无需任何外部依赖。
从 2.5.2 版本开始,xmake 支持拉取指定的工具链来集成编译项目,并且可以将依赖包切换到对应的远程工具链进行编译后集成。目前,xmake-repo 仓库中已经收录了以下工具链包:llvm、llvm-mingw、gnu-rm、muslcc 和 zig。虽然目前支持的工具链包数量有限,但整体架构已经打通,后续将收录更多的工具链,如 gcc、tinyc 和 vs-buildtools 等。
由于 xmake 的包支持语义版本,如果项目依赖特定版本的 gcc/clang 编译器,xmake 会自动检测当前系统的 gcc/clang 版本是否满足需求。如果版本不满足,xmake 会自动拉取并安装特定版本的 gcc/clang,然后再进行项目编译。
以下是使用特定版本的 llvm 工具链(例如 llvm-10)编译项目的示例代码:
add_requires("llvm 10.x", {alias = "llvm-10"})
target("test")
set_kind("binary")
add_files("src/*.c")
set_toolchains("llvm@llvm-10")其中,
llvm@llvm-10中的前半部分为工具链名,后半部分为需要关联的工具链包名。如果设置了别名,则优先使用别名
llvm-10。
后续还将增加 gcc 工具链包到 xmake-repo,使得用户可以自由切换到 gcc-10、gcc-11 等特定版本的 gcc 编译器,而无需手动安装。
以下是拉取指定的交叉编译工具链(例如 muslcc)来编译项目的示例代码:
add_requires("muslcc")
target("test")
set_kind("binary")
add_files("src/*.c")
set_toolchains("@muslcc")muslcc 是 https://www.php.cn/link/3f54e27d6a63e1397fe94938013a9161 提供的一款交叉编译工具链,默认 xmake 会自动集成编译
x86_64-linux-musl-目标平台。当然,也可以通过
xmake f -a arm64切换到
aarch64-linux-musl-目标平台进行交叉编译。
使用指定的 muslcc 交叉编译工具链去编译和集成所有的依赖包的示例代码如下:
add_requires("muslcc")
add_requires("zlib", "libogg", {system = false})
set_toolchains("@muslcc")
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("zlib", "libogg")此时,工程中配置的 zlib、libogg 等依赖包会切换使用 muslcc 工具链,自动下载编译然后集成进来。也可以通过
set_plat/set_arch固定平台,只需一个 xmake 命令即可完成整个交叉编译环境的集成以及架构切换。
拉取并集成特定版本的 zig 工具链的示例代码如下:
add_rules("mode.debug", "mode.release")
add_requires("zig 0.7.x")
target("test")
set_kind("binary")
add_files("src/*.zig")
set_toolchains("@zig")xmake 会先下载特定版本的 zig 工具链,然后使用此工具链编译 zig 项目。如果用户已经自行安装了 zig 工具链,xmake 会自动检测对应版本是否满足需求,如果满足则直接使用,无需重复下载安装。
zig cc是 zig 内置的 C/C++ 编译器,可以独立进行 C/C++ 代码的编译和链接,完全不依赖 gcc/clang/msvc,非常强大。使用
zig cc编译 C/C++ 项目的示例如下:
$ xmake f --toolchain=zig $ xmake [ 25%]: compiling.release src/main.c "zig cc" -c -arch x86_64 -fvisibility=hidden -O3 -DNDEBUG -o build/.objs/xmake_test/macosx/x86_64/release/src/main.c.o src/main.c [ 50%]: linking.release test "zig c++" -o build/macosx/x86_64/release/test build/.objs/xmake_test/macosx/x86_64/release/src/main.c.o -arch x86_64 -stdlib=libc++ -Wl,-x -lz [100%]: build ok!
zig cc还支持不同架构的交叉编译,例如在 macOS 上交叉编译 windows/x64 目标程序,替代了 mingw 的功能:
$ xmake f -p windows -a x64 --toolchain=zig $ xmake
xmake 还提供了类似于 cmake 中
WINDOWS_EXPORT_ALL_SYMBOLS的特性,可以快速全量导出 windows/dll 中的符号,简化对第三方项目移植过程中对符号导出的处理。配置
utils.symbols.export_all规则即可实现这一功能:
target("foo")
set_kind("shared")
add_files("src/foo.c")
add_rules("utils.symbols.export_all")
target("test")
set_kind("binary")
add_deps("foo")
add_files("src/main.c")xmake 还提供了将 MinGW 生成的动态库(xxx.dll & xxx.dll.a)转换成 Visual Studio 可以识别的格式(xxx.dll & xxx.lib)的功能,参考自 CMAKE_GNUtoMS 功能。这一功能对 Fortran & C++ 混合项目特别有帮助,可以使用如下辅助模块接口:
import("utils.platform.gnu2mslib")
gnu2mslib("xxx.lib", "xxx.dll.a")
gnu2mslib("xxx.lib", "xxx.def")
gnu2mslib("xxx.lib", "xxx.dll.a", {dllname = "xxx.dll", arch = "x64"})为了简化用户自定义 rule 的配置,xmake 新提供了
on_buildcmd_file和
on_buildcmd_files等自定义脚本入口,可以通过 batchcmds 对象构造一个批处理命令行任务,xmake 在实际执行构建时一次性执行这些命令。这对于
xmake project此类工程生成器插件非常有用,因为生成器生成的第三方工程文件不支持
on_build_files此类内置脚本的执行支持。
以下是使用
on_buildcmd_file构造批处理命令的示例:
rule("foo")
set_extensions(".xxx")
on_buildcmd_file(function (target, batchcmds, sourcefile, opt)
batchcmds:vrunv("gcc", {"-o", objectfile, "-c", sourcefile})
end)除了
batchcmds:vrunv,还支持其他批处理命令,例如:
batchcmds:show("hello %s", "xmake")
batchcmds:vrunv("gcc", {"-o", objectfile, "-c", sourcefile}, {envs = {LD_LIBRARY_PATH="/xxx"}})
batchcmds:mkdir("/xxx") -- and cp, mv, rm, ln ..
batchcmds:compile(sourcefile_cx, objectfile, {configs = {includedirs = sourcefile_dir, languages = (sourcekind == "cxx" and "c++11")}})
batchcmds:link(objectfiles, targetfile, {configs = {linkdirs = ""}})以下是一个完整的示例,展示了如何使用
on_buildcmd_file实现 lex 规则:
rule("lex")
set_extensions(".l", ".ll")
on_buildcmd_file(function (target, batchcmds, sourcefile_lex, opt)
-- imports
import("lib.detect.find_tool")
-- get lex
local lex = assert(find_tool("flex") or find_tool("lex"), "lex not found!")
-- get c/c++ source file for lex
local extension = path.extension(sourcefile_lex)
local sourcefile_cx = path.join(target:autogendir(), "rules", "lex_yacc", path.basename(sourcefile_lex) .. (extension == ".ll" and ".cpp" or ".c"))
-- add objectfile
local objectfile = target:objectfile(sourcefile_cx)
table.insert(target:objectfiles(), objectfile)
-- add commands
batchcmds:show_progress(opt.progress, "${color.build.object}compiling.lex %s", sourcefile_lex)
batchcmds:mkdir(path.directory(sourcefile_cx))
batchcmds:vrunv(lex.program, {"-o", sourcefile_cx, sourcefile_lex})
batchcmds:compile(sourcefile_cx, objectfile)
-- add deps
batchcmds:add_depfiles(sourcefile_lex)
batchcmds:set_depmtime(os.mtime(objectfile))
batchcmds:set_depcache(target:dependfile(objectfile))
end)关于依赖包配置的改进,xmake 新增了
add_extsources和
on_fetch两个配置接口,可以更好的配置 xmake 在安装 C/C++ 包的过程中,对系统库的查找过程。例如,通过
add_extsources("pkgconfig::libusb-1.0") 改进查找逻辑,使 xmake 能够找到通过 apt install libusb-1.0安装的系统库:
package("libusb")
add_extsources("pkgconfig::libusb-1.0")
on_install(function (package)
-- ...
end)如果需要更复杂的查找逻辑,可以使用
on_fetch完全定制化查找系统库逻辑,例如:
package("libusb")
on_fetch("linux", function(package, opt)
if opt.system then
return find_package("pkgconfig::libusb-1.0")
end
end)在新版本中,xmake 还新增了对 windows
.manifest文件的支持,只需通过
add_files添加即可:
add_rules("mode.debug", "mode.release")
target("test")
set_kind("binary")
add_files("src/*.cpp")
add_files("src/*.manifest")关于 xrepo 命令的改进,现在可以通过
xrepo remove --all命令批量卸载删除已经安装的包,支持模式匹配:
$ xrepo remove --all $ xrepo remove --all zlib pcr*
最后,xmake 改进了
add_packages,使其支持
{public = true} 来导出包配置给父 target。例如:add_rules("mode.debug", "mode.release")
add_requires("pcre2")
target("test")
set_kind("shared")
add_packages("pcre2", {public = true})
add_files("src/test.cpp")
target("demo")
add_deps("test")
set_kind("binary")
add_files("src/main.cpp")
-- 我们可以在这里使用被 test 目标导出的 pcre2 库具体导出的配置如下:
-- 默认私有,但是 links/linkdirs 还是会自动导出
add_packages("pcre2")
-- 全部导出,包括 includedirs, defines
add_packages("pcre2", {public = true})更新内容包括以下新特性:
- 支持
zig cc
和zig c++
作为 C/C++ 编译器 - 支持使用 zig 进行交叉编译
- 改进终端和 color codes 探测
- 传递自定义 includes 脚本给 xrepo
- 添加 linuxos 内置模块获取 linux 系统信息
- 支持在编译项目时自动拉取工具链
- 添加
rule("utils.symbols.export_all")自动导出所有 windows/dll 中的符号 - 添加
utils.platform.gnu2mslib(mslib, gnulib)
模块接口去转换 mingw/xxx.dll.a 到 msvc xxx.lib - 改进规则支持新的批处理命令去简化自定义规则实现
- 添加
add_extsources
去改进外部包的查找 - 支持为 windows 程序添加 .manifest 文件参与链接
- 支持使用
xrepo remove --all
命令去移除所有的包,并且支持模式匹配 - 支持导出包配置给父 target,实现包配置的依赖继承
改进包括:
- 添加缺失的 Qt 头文件搜索路径
- 改进 C++ 语言标准,以便支持 Qt6
- 为 vsxmake 插件添加 qt.ui 文件
- 改进 vs/vsxmake 插件去支持预编译头文件和智能提示
- 简化自定义规则
- 改进 protobuf 规则,支持 compile_commands 生成器
- 改进 vs/vsxmake 生成器去支持启动工程设置
- 改进 add_deps 和 add_packages 直接的导出 links 顺序
- 移除废弃的
add_defines_h_if_ok
和add_defines_h
接口
Bugs 修复包括:
- 修复版本检测和更新
- 修复 includes 搜索路径中带有空格编译不过问题
关注公众号 TBOOX 开源工程,专注于 C 跨平台开发解决方案。










