xmake 是一个基于 Lua 的轻量级跨平台构建工具,使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对新手非常友好,短时间内就能快速入门,能够让用户把更多的精力集中在实际的项目开发上。
这个版本,我们主要增加了对 Pascal 语言项目和 Swig 模块的构建支持,而对于上个版本新增的 Vala 语言支持,我们也做了进一步改进,增加了对动态库和静态库的构建支持。
除此之外,xmake 现在也已经支持了可选的 Lua5.3 运行时,提供更好的跨平台支持能力,目前 xmake 已经能够在 LoongArch 架构上正常运行。
目前,我们可以使用跨平台的 Free pascal 工具链 fpc 去编译构建 Pascal 程序,例如:
add_rules("mode.debug", "mode.release")
target("test")
set_kind("binary")
add_files("src/*.pas")
add_rules("mode.debug", "mode.release")
target("foo")
set_kind("shared")
add_files("src/foo.pas")
target("test")
set_kind("binary")
add_deps("foo")
add_files("src/main.pas")
我们也可以通过 add_fcflags()
接口添加 Pascal 代码相关的编译选项。
更多例子见:Pascal examples
上个版本,我们新增了对 Vala 语言的支持,但是之前只能支持控制台程序的编译,无法生成库文件。而这个版本中,我们额外增加了对静态库和动态库的编译支持。
我们能够通过 add_values("vala.header", "mymath.h")
设置导出的接口头文件名,通过 add_values("vala.vapi", "mymath-1.0.vapi")
设置导出的 vapi 文件名。
add_rules("mode.release", "mode.debug")
add_requires("glib")
target("mymath")
set_kind("static")
add_rules("vala")
add_files("src/mymath.vala")
add_values("vala.header", "mymath.h")
add_values("vala.vapi", "mymath-1.0.vapi")
add_packages("glib")
target("test")
set_kind("binary")
add_deps("mymath")
add_rules("vala")
add_files("src/main.vala")
add_packages("glib")
add_rules("mode.release", "mode.debug")
add_requires("glib")
target("mymath")
set_kind("shared")
add_rules("vala")
add_files("src/mymath.vala")
add_values("vala.header", "mymath.h")
add_values("vala.vapi", "mymath-1.0.vapi")
add_packages("glib")
target("test")
set_kind("binary")
add_deps("mymath")
add_rules("vala")
add_files("src/main.vala")
add_packages("glib")
更多例子见:Vala examples
我们提供了 swig.c
和 swig.cpp
规则,可以对指定的脚本语言,调用 swig 程序生成 c/c++ 模块接口代码,然后配合 xmake 的包管理系统实现完全自动化的模块和依赖包整合。
相关 issues: #1622
add_rules("mode.release", "mode.debug")
add_requires("lua")
target("example")
add_rules("swig.c", {moduletype = "lua"})
add_files("src/example.i", {swigflags = "-no-old-metatable-bindings"})
add_files("src/example.c")
add_packages("lua")
其中,swigflags 可以设置传递一些 swig 特有的 flags 选项。
add_rules("mode.release", "mode.debug")
add_requires("python 3.x")
target("example")
add_rules("swig.c", {moduletype = "python"})
add_files("src/example.i", {scriptdir = "share"})
add_files("src/example.c")
add_packages("python")
如果设置了 scriptdir,那么我们执行安装的时候,会将对应模块的 python wrap 脚本安装到指定目录。
add_rules("mode.release", "mode.debug")
add_requires("python 3.x")
target("example")
add_rules("swig.cpp", {moduletype = "python"})
add_files("src/example.i", {scriptdir = "share"})
add_files("src/example.cpp")
add_packages("python")
xmake 之前一直使用的 Luajit 作为默认的运行时,因为当初考虑到 Luajit 相对更加快速,并且固定的 lua 5.1 语法更加适合 xmake 内部实现的需要。
但是考虑到 Luajit 的更新不给力,作者维护不是很积极,并且它的跨平台性比较差,对于一些新出的架构,比如:Loongarch,riscv 等支持不及时,这多少限制了 xmake 的平台支持力度。
为此,新版本中,我们也将 Lua5.3 作为可选的运行时内置了进来,我们只需要通过下面的命令编译安装 xmake,就可以从 Luajit 切换到 Lua5.3 运行时:
$ make RUNTIME=lua
$ cd core
$ xmake f --runtime=lua
$ xmake
目前,当前版本还是默认采用的 luajit 运行时,用户可以根据自己的需求切换到 Lua5.3 运行时,但这对于用户的项目 xmake.lua 配置脚本几乎没有任何兼容性影响。
因为 xmake 的配置接口都已经做了一层的抽象封装,一些 Luajit/Lua5.3 存在兼容性差异的原生接口是不会开放给用户使用的,所以对项目构建来说,是完全无感知的。
唯一的区别就是,带有 Lua5.3 的 xmake 支持更多的平台和架构。
我做过一些基础构建测试,不管是启动时间,构建性能还是内存占用,Lua5.3 和 Luajit 的 xmake 都几乎没有任何差别。因为对于构建系统,主要的性能瓶颈是在编译器上,自身脚本的损耗占比是非常小的。
而且 xmake 内部的一些底层 Lua 模块,比如 io,字符编码,字符串操作等,都自己用 c 代码全部重写过的,完全不依赖特定的 Lua 运行时引擎。
由于我们刚刚支持 Lua5.3,尽管目前测试下来已经比较稳定,但是为了确保用户环境不受到任何影响,我们还需要再观察一段时间,短期还是默认使用 Luajit。
等到 2.6.1 版本开始,我们会全面开始切换到 Lua5.3 作为默认的运行时环境,大家有兴趣的话,也可以线帮忙测试下,如果遇到问题,欢迎到 issues 上反馈。
由于我们增加了 Lua5.3 运行时支持,所以现在我们已经可以支持再 LoongArch 架构上运行 xmake,并且所有测试例子都已经测试通过。
目前,我们对 Lua 5.4 还保持观望状态,如果后面等 lua5.4 稳定了,我们也会尝试考虑继续升级到 Lua5.4。
新版本中,我们已经能够通过 xmake 的包模式直接集成自己项目中带有 CMakeLists.txt 的代码库,而不是通过远程下载安装。
相关 issues: #1714
例如,我们有如下项目结构:
├── foo
│ ├── CMakeLists.txt
│ └── src
│ ├── foo.c
│ └── foo.h
├── src
│ └── main.c
├── test.lua
└── xmake.lua
foo 目录下是一个使用 cmake 维护的静态库,而根目录下使用了 xmake 来维护,我们可以在 xmake.lua 中通过定义 package("foo")
包来描述如何构建 foo 代码库。
add_rules("mode.debug", "mode.release")
package("foo")
add_deps("cmake")
set_sourcedir(path.join(os.scriptdir(), "foo"))
on_install(function (package)
local configs = {}
table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release"))
table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF"))
import("package.tools.cmake").install(package, configs)
end)
on_test(function (package)
assert(package:has_cfuncs("add", {includes = "foo.h"}))
end)
package_end()
add_requires("foo")
target("demo")
set_kind("binary")
add_files("src/main.c")
add_packages("foo")
其中,我们通过 set_sourcedir()
来设置 foo 包的代码目录位置,然后通过 import 导入 package.tools.cmake
辅助模块来调用 cmake 构建代码,xmake 会自动获取生成的 libfoo.a 和对应的头文件。
!> 如果仅仅本地源码集成,我们不需要额外设置 add_urls
和 add_versions
。
关于包的配置描述,详情见:包描述说明
定义完包后,我们就可以通过 add_requires("foo")
和 add_packages("foo")
来集成使用它了,就跟集成远程包一样的使用方式。
另外,on_test
是可选的,如果想要严格检测包的编译安装是否成功,可以在里面做一些测试。
完整例子见:Library with CMakeLists
我们也可以使用 package.tools.autoconf
来本地集成带有 autoconf 维护的第三方代码库。
package("pcre2")
set_sourcedir(path.join(os.scriptdir(), "3rd/pcre2"))
add_configs("jit", {description = "Enable jit.", default = true, type = "boolean"})
add_configs("bitwidth", {description = "Set the code unit width.", default = "8", values = {"8", "16", "32"}})
on_load(function (package)
local bitwidth = package:config("bitwidth") or "8"
package:add("links", "pcre2-" .. bitwidth)
package:add("defines", "PCRE2_CODE_UNIT_WIDTH=" .. bitwidth)
if not package:config("shared") then
package:add("defines", "PCRE2_STATIC")
end
end)
on_install("macosx", "linux", "mingw", function (package)
local configs = {}
table.insert(configs, "--enable-shared=" .. (package:config("shared") and "yes" or "no"))
table.insert(configs, "--enable-static=" .. (package:config("shared") and "no" or "yes"))
if package:debug() then
table.insert(configs, "--enable-debug")
end
if package:config("pic") ~= false then
table.insert(configs, "--with-pic")
end
if package:config("jit") then
table.insert(configs, "--enable-jit")
end
local bitwidth = package:config("bitwidth") or "8"
if bitwidth ~= "8" then
table.insert(configs, "--disable-pcre2-8")
table.insert(configs, "--enable-pcre2-" .. bitwidth)
end
import("package.tools.autoconf").install(package, configs)
end)
on_test(function (package)
assert(package:has_cfuncs("pcre2_compile", {includes = "pcre2.h"}))
end)
package.tools.autoconf
和 package.tools.cmake
模块都是可以支持 mingw/cross/iphoneos/android 等交叉编译平台和工具链的,xmake 会自动传递对应的工具链进去,用户不需要做任何其他事情。
我们还支持集成 Meson/Scons/Make 等其他构建系统维护的代码库,仅仅只需要导入对应的构建辅助模块,这里就不一一细讲了,我们可以进一步查阅文档:集成本地第三方源码库
在之前的版本中,我们可以通过 check_features
辅助接口来检测指定的编译器特性,比如:
includes("check_features.lua")
target("test")
set_kind("binary")
add_files("*.c")
add_configfiles("config.h.in")
configvar_check_features("HAS_CONSTEXPR", "cxx_constexpr")
configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"})
config.h.in
${define HAS_CONSTEXPR}
${define HAS_CONSEXPR_AND_STATIC_ASSERT}
config.h
/* #undef HAS_CONSTEXPR */
#define HAS_CONSEXPR_AND_STATIC_ASSERT 1
如果当前 cxx_constexpr 特性支持,就会在 config.h 中启用 HAS_CONSTEXPR 宏。
2.5.8 之后,我们继续新增了对 cstd 和 c++ std 版本检测支持,相关 issues: #1715
例如:
configvar_check_features("HAS_CXX_STD_98", "cxx_std_98")
configvar_check_features("HAS_CXX_STD_11", "cxx_std_11", {languages = "c++11"})
configvar_check_features("HAS_CXX_STD_14", "cxx_std_14", {languages = "c++14"})
configvar_check_features("HAS_CXX_STD_17", "cxx_std_17", {languages = "c++17"})
configvar_check_features("HAS_CXX_STD_20", "cxx_std_20", {languages = "c++20"})
configvar_check_features("HAS_C_STD_89", "c_std_89")
configvar_check_features("HAS_C_STD_99", "c_std_99")
configvar_check_features("HAS_C_STD_11", "c_std_11", {languages = "c11"})
configvar_check_features("HAS_C_STD_17", "c_std_17", {languages = "c17"})
我们还能检测编译器存在一些内置的宏定义,比如:__GNUC__
等,我们可以通过 check_macros
和 configvar_check_macros
辅助脚本来检测它们是否存在。
相关 issues: #1715
-- 检测宏是否定义
configvar_check_macros("HAS_GCC", "__GNUC__")
-- 检测宏没有被定义
configvar_check_macros("NO_GCC", "__GNUC__", {defined = false})
-- 检测宏条件
configvar_check_macros("HAS_CXX20", "__cplusplus >= 202002L", {languages = "c++20"})
除了 Qt 5.x 和 6.x,我们对于一些基于 Qt 4.x 的老项目,xmake 也增加了支持。
由于 google 对 Android NDK 的一些结构改动,导致 r23 影响了 xmake 对 android 项目部分编译特性的支持,在这个版本中,我们也做了修复。
另外,如果基于 Unicode 作为项目目录,那么生成的 vsxmake 项目会收到影响,导致 vs 项目编译和访问上存在很多问题,我们也在新版本中做了修复。
check_macros
检测接口set_symbols("debug")
支持 clang/windows 生成 pdb 文件set_languages
新增 c++latest
和 clatest
配置值save_scope
和 restore_scope
去修复 check_xxx
相关接口