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
  • 项目源码
  • 官方文档
  • 入门课程
Xmake v2.7.8 发布,改进包虚拟环境和构建速度

新特性介绍

快速切换暂时虚拟环境

Xmake 很早就支撑了包的虚拟环境办理,能够经过装备文件的方法,完成不同包环境之间的切换。

咱们能够经过在当时目录下,增加 xmake.lua 文件,定制化一些包装备,然后进入特定的包虚拟环境。

add_requires("zlib 1.2.11")
add_requires("python 3.x", "luajit")
$ xrepo env shell
> python --version
> luajit --version

也能够经过导入自界说环境装备文件,来切换环境:

$ xrepo env --add /tmp/base.lua
$ xrepo env -b base shell

而在新版别中,咱们进一步做了改善,让 Xrepo 能够直接在命令行暂时指定需求绑定的环境包列表,完成快速切换,无需任何装备。

而且支撑一起指定多个包环境。

例如,咱们想进入一个带有 python 3.0, luajit 和 cmake 的环境,只需求履行:

$ xrepo env -b "python 3.x,luajit,cmake" shell
[python,luajit,cmake] $ python --version
Python 3.10.6
[python,luajit,cmake] $ cmake --version
cmake version 3.25.3

Xmake 会主动装置相关依靠,然后敞开一个新的 shell 环境,新环境终端左边也有 prompt 提示。

假如咱们想退出当时环境,只是需求履行

[python,luajit,cmake] $ xrepo env quit
$

改善代码特性检测

has_cfuncs/check_cxxsnippets 等系列检测接口,在 option 中已经有提供,而且有对应的辅助 API 来协助检测。

相关文档能够参考:辅助检测接口。

可是现在 option 提供的检测接口只是针对大局平台东西链,无法依据每个特定的 target 装备在针对性做一些检测。

由于 target 本身可能还会顺便依靠包,不同的东西链,编译宏等差异性,检测成果也会有一些差异。

因而,假如用户想要更加灵活细粒度的检测每个 target 方针的编译特性,能够经过新版别提供的 target 方针实例接口。

  • target:has_cfuncs
  • target:has_cxxfuncs
  • target:has_ctypes
  • target:has_cxxtypes
  • target:has_cincludes
  • target:has_cxxincludes
  • target:has_cflags
  • target:has_cxxflags
  • target:has_features
  • target:check_csnippets
  • target:check_cxxsnippets

这里,只是针对其中一些比较常用的接口,稍微展开介绍下运用方法。

target:has_cfuncs

  • 检测方针编译装备能否获取给定的 C 函数

这应该在 on_config 中运用,比方能够用它来判别当时方针能否获取到 zlib 依靠包的一些函数接口,然后主动界说 HAVE_INFLATE

add_requires("zlib")
target("test")
    set_kind("binary")
    add_files("src/*.c")
    add_packages("zlib")
    on_config(function (target)
        if target:has_cfuncs("inflate", {includes = "zlib.h"}) then
            target:add("defines", "HAVE_INFLATE")
        end
    end)

尽管 option 也提供了相似的检测功用,但 option 的检测运用的是大局的平台东西链,它无法顺便上 target 相关的一些编译装备, 也无法依据 target 设置不同编译东西链来适配检测,而且无法检测包里面的一些接口。

假如咱们只是是想粗粒度的检测函数接口,而且 target 没有额定设置不同的东西链,那么 option 提供的检测功用已经足够运用了。

假如想要更细粒度控制检测,能够运用 target 实例接口提供的检测特性。

target:has_cxxfuncs

  • 检测方针编译装备能否获取给定的 C++ 函数

用法跟 target:has_cfuncs 相似,只是这里主要用于检测 C++ 的函数。

不过,在检测函数的一起,咱们还能够额定装备 std languages,来辅助检测。

target:has_cxxfuncs("foo", {includes = "foo.h", configs = {languages = "cxx17"}})

target:has_ctypes

  • 检测方针编译装备能否获取给定的 C 类型

这应该在 on_config 中运用,如下所示:

add_requires("zlib")
target("test")
    set_kind("binary")
    add_files("src/*.c")
    add_packages("zlib")
    on_config(function (target)
        if target:has_ctypes("z_stream", {includes = "zlib.h"}) then
            target:add("defines", "HAVE_ZSTEAM_T")
        end
    end)

target:has_cflags

  • 检测方针编译装备能否获取给定的 C 编译 flags
target("test")
    set_kind("binary")
    add_files("src/*.cpp")
    on_config(function (target)
        if target:has_cxxflags("-fPIC") then
            target:add("defines", "HAS_PIC")
        end
    end)

target:has_cincludes

  • 检测方针编译装备能否获取给定的 C 头文件

这应该在 on_config 中运用,比方能够用它来判别当时方针能否获取到 zlib 依靠包的 zlib.h 头文件,然后主动界说 HAVE_INFLATE

add_requires("zlib")
target("test")
    set_kind("binary")
    add_files("src/*.c")
    add_packages("zlib")
    on_config(function (target)
        if target:has_cincludes("zlib.h") then
            target:add("defines", "HAVE_ZLIB_H")
        end
    end)

target:check_cxxsnippets

  • 检测是否能够编译和链接给定的 C++ 代码片段

这应该在 on_config 中运用,如下所示:

add_requires("libtins")
target("test")
    set_kind("binary")
    add_files("src/*.cpp")
    add_packages("libtins")
    on_config(function (target)
        local has_snippet = target:check_cxxsnippets({test = [[
            #include <string>
            using namespace Tins;
            void test() {
                std::string name = NetworkInterface::default_interface().name();
                printf("%s\n", name.c_str());
            }
        ]]}, {configs = {languages = "c++11"}, includes = {"tins/tins.h"}}))
        if has_snippet then
            target:add("defines", "HAS_XXX")
        end
    end)

默许只是检测编译链接是否经过,假如想要测验运行时检测,能够再设置 tryrun = true

target("test")
    set_kind("binary")
    add_files("src/*.cpp")
    on_config(function (target)
        local has_int_4 = target:check_cxxsnippets({test = [[
            return (sizeof(int) == 4)? 0 : -1;
        ]]}, {configs = {languages = "c++11"}, tryrun = true}))
        if has_int_4 then
            target:add("defines", "HAS_INT4")
        end
    end)

咱们也能够持续经过设置 output = true 来捕获检测的运行输出,而且加上自界说的 main 进口,完成完好的测验代码,而不只是是代码片段。

target("test")
    set_kind("binary")
    add_files("src/*.cpp")
    on_config(function (target)
        local int_size = target:check_cxxsnippets({test = [[
            #include <stdio.h>
            int main(int argc, char** argv) {
                printf("%d", sizeof(int)); return 0;
                return 0;
            }
        ]]}, {configs = {languages = "c++11"}, tryrun = true, output = true}))
    end)

target:has_features

  • 检测是否指定的 C/C++ 编译特性

它比较运用 check_cxxsnippets 来检测,会更加快一些,由于它只是履行一次预处理就能检测所有的编译器特性,而不是每次都去调用编译器测验编译。

target("test")
    set_kind("binary")
    add_files("src/*.cpp")
    on_config(function (target)
        if target:has_features("c_static_assert") then
            target:add("defines", "HAS_STATIC_ASSERT")
        end
        if target:has_features("cxx_constexpr") then
            target:add("defines", "HAS_CXX_CONSTEXPR")
        end
    end)

优化编译功能

Xmake 的 build cache 加快相似 ccache,选用预处理器核算 hash 后缓存编译目标文件来完成加快,它在 linux/mac 上提速效果十分明显。

而由于 msvc 的预处理器很慢,也可能是起进程比较 linux/mac 下更重,导致敞开 build cache 后,windows 上运用 msvc 的全体编译效率反而慢了十分多。

测验运用第三方的 ccache 来测验比照,也是一样的问题,因而我暂时针对 msvc 默许禁用了 build cache,使得全体构建速度恢复到正常水平。

clang-tidy 主动修正

上个版别,咱们新增了对 clang-tidy 支撑,能够经过 xmake check clang.tidy 来检测代码。 而在这个版别中,咱们持续对它做了改善,新增了 --fix 参数,能够让 clang-tidy 去主动修正检测出来的问题代码。

$ xmake check clang.tidy --fix
$ xmake check clang.tidy --fix_errors
$ xmake check clang.tidy --fix_notes

Swig/Java 模块构建支撑

别的,其他用户也帮助贡献了 Swig/Java 模块的构建支撑。

add_rules("mode.release", "mode.debug")
target("example")
    set_kind('shared')
    -- set moduletype to java
    add_rules("swig.c", {moduletype = "java"})
    -- use swigflags to provider package name and output path of java files
    add_files("src/example.i", {swigflags = {
        "-package",
        "com.example",
        "-outdir",
        "build/java/com/example/"
    }})
    add_files("src/example.c")
    before_build(function()
        -- ensure output path exists before running swig
        os.mkdir("build/java/com/example/")
    end)

完好例子见:Swig/Java Example

开源之夏 2023

今年 Xmake 社区持续参加了开源之夏 2023 活动,它是由中科院软件所“开源软件供应链点亮方案”建议并长时间支撑的一项暑期开源活动 旨在鼓励在校学生积极参加开源软件的开发保护。

假如有感兴趣的同学,欢迎报名参加 Xmake 社区发布的项目开发(详细项目待定中),相关概况进展,请重视:Xmake 开源之夏。

更新内容

新特性

  • #3518: 分析编译和链接功能
  • #3522: 为 target 增加 has_cflags, has_xxx 等辅助接口
  • #3537: 为 clang.tidy 检测器增加 --fix 主动修正

改善

  • #3433: 改善 QT 在 msys2/mingw64 和 wasm 上的构建支撑
  • #3419: 支撑 fish shell 环境
  • #3455: Dlang 增量编译支撑
  • #3498: 改善绑定包虚拟环境
  • #3504: 增加 swig java 支撑
  • #3508: 改善 trybuild/cmake 去支撑东西链切换
  • 为 msvc 禁用 build cache 加快,由于 msvc 的预处理器太慢,反而极大影响构建功能。

Bugs 修正

  • #3436: 修正主动补全和 menuconf
  • #3463: 修正 c++modules 缓存问题
  • #3545: 修正 armcc 的头文件依靠解析 败

Xmake v2.7.8 发布,改善包虚拟环境和构建速度 (tboox.org)