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
这个版本主要新增下面几个特性:
剩下的主要是一些零散的功能改进和 Bugs 修复,可以看下文末的更新内容明细,一些比较大的改动,下面也会逐一说明。
新版本中,Xmake 新增了 vcpkg 清单模式支持,通过它,我们就能支持 vcpkg 包的版本选择,例如:
add_requires("vcpkg::zlib 1.2.11+10") add_requires("vcpkg::fmt >=8.0.1", {configs = {baseline = "50fd3d9957195575849a49fa591e645f1d8e7156"}}) add_requires("vcpkg::libpng", {configs = {features = {"apng"}}}) target("test") set_kind("binary") add_files("src/*.cpp") add_packages("vcpkg::zlib", "vcpkg::fmt", "vcpkg::libpng")
但是,vcpkg 的版本选择限制还是不少,必须要硬编码指定 baseline,而且还不支持 <=1.0
, 1.x
等版本语义选择,不过总比之前不能选择版本好了不少。
我们新增了一个独立项目 xrepo-cmake。
它是一个基于 Xrepo/Xmake 的 C/C++ 包管理器的 CMake 包装器。
这允许使用 CMake 来构建您的项目,同时使用 Xrepo 来管理依赖包。这个项目的部分灵感来自 cmake-conan。
此项目的示例用例:
Xrepo 官方仓库:xmake-repo
xrepo.cmake 提供xrepo_package
函数来管理包。
xrepo_package( "foo 1.2.3" [CONFIGS feature1=true,feature2=false] [MODE debug|release] [OUTPUT verbose|diagnosis|quiet] [DIRECTORY_SCOPE] )
一些函数参数直接对应于 Xrepo 命令选项。
调用 xrepo_package(foo)
后,有两种使用 foo
包的方法:
find_package(foo)
, 参考 CMake find_package
文档了解更多详情foo_INCLUDE_DIR
和 foo_LINK_DIR
变量将设置为包包含和库路径。使用这些变量在 CMake 代码中设置包含和库路径。DIRECTORY_SCOPE
,则 xrepo_package
将运行以下代码(这样用户只需要在 target_link_libraries
中指定库名称)include_directories(foo_INCLUDE_DIR) link_directories(foo_LINK_DIR)
这是一个使用 gflags
包版本 2.2.2 的示例 CMakeLists.txt
由 Xrepo 管理。
cmake_minimum_required(VERSION 3.13.0) project(foo) # Download xrepo.cmake if not exists in build directory. if(NOT EXISTS "${CMAKE_BINARY_DIR}/xrepo.cmake") message(STATUS "Downloading xrepo.cmake from https://github.com/xmake-io/xrepo-cmake/") # mirror https://cdn.jsdelivr.net/gh/xmake-io/xrepo-cmake@main/xrepo.cmake file(DOWNLOAD "https://raw.githubusercontent.com/xmake-io/xrepo-cmake/main/xrepo.cmake" "${CMAKE_BINARY_DIR}/xrepo.cmake" TLS_VERIFY ON) endif() # Include xrepo.cmake so we can use xrepo_package function. include(${CMAKE_BINARY_DIR}/xrepo.cmake) # Call `xrepo_package` function to use gflags 2.2.2 with specific configs. xrepo_package("gflags 2.2.2" CONFIGS "shared=true,mt=true") # `xrepo_package` sets `gflags_DIR` variable in parent scope because gflags # provides cmake modules. So we can now call `find_package` to find gflags # package. find_package(gflags CONFIG COMPONENTS shared)
除了从官方维护的存储库安装软件包之外,Xrepo 还可以安装来自第三方包管理器的包,例如 vcpkg/conan/conda/pacman/homebrew/apt/dub/cargo。
关于命令行的使用,我们可以参考文档:Xrepo命令用法
我们也可以直接在 cmake 中使用它来安装来自第三方仓库的包,只需将仓库名称添加为命名空间即可。例如:vcpkg::zlib
, conan::pcre2
xrepo_package("conan::gflags/2.2.2")
xrepo_package("conda::gflags 2.2.2")
xrepo_package("vcpkg::gflags")
xrepo_package("brew::gflags")
我们可以用这个规则,配合 pybind11 生成 python 库模块,它会调整 python 库的模块名。
add_rules("mode.release", "mode.debug") add_requires("pybind11") target("example") add_rules("python.library") add_files("src/*.cpp") add_packages("pybind11") set_languages("c++11")
带有 soabi:
add_rules("mode.release", "mode.debug") add_requires("pybind11") target("example") add_rules("python.library", {soabi = true}) add_files("src/*.cpp") add_packages("pybind11") set_languages("c++11")
通过此接口,可以从 add_headerfiles
接口添加的头文件列表中,删除指定的文件,例如:
target("test") add_headerfiles("src/*.h") remove_headerfiles("src/test.h")
上面的例子,可以从src
目录下添加除test.h
以外的所有头文件,当然这个也可以通过 add_headerfiles("src/*.h|test.h")
来达到相同的目的,但是这种方式更加灵活。
在 xmake config
执行完成后,Build 之前会执行此脚本,通常用于编译前的配置工作。它与 on_load 不同的是,on_load 只要 target 被加载就会执行,执行时机更早。
如果一些配置,无法在 on_load 中过早配置,那么都可以在 on_config 中去配置它。
另外,它的执行时机比 before_build 还要早,大概的执行流程如下:
on_load -> after_load -> on_config -> before_build -> on_build -> after_build
Xmake 提供了一些内置的镜像配置可以直接使用,例如 github 的镜像加速:
$ xmake g --proxy_pac=github_mirror.lua
我们不用自己编写 pac.lua,就可以直接使用它来加速 github 源的下载。
python.library
规则去构建 pybind 模块,并且支持 soabiremove_files
, remove_headerfiles
并且标记 del_files
作为废弃接口xmake g --proxy_pac=github_mirror.lua