全局接口影响整个工程描述,被调用后,后面被包含进来的所有子xmake.lua都会受影响。

接口 描述 支持版本
includes 添加子工程文件和目录 >= 2.1.5
set_modes 设置支持的编译模式 >= 2.1.2
set_project 设置工程名 >= 2.0.1
set_version 设置工程版本 >= 2.0.1
set_xmakever 设置最小xmake版本 >= 2.1.1
add_subdirs 添加子工程目录 >= 1.0.1
add_subfiles 添加子工程文件 >= 1.0.1
add_moduledirs 添加模块目录 >= 2.1.5
add_plugindirs 添加插件目录 >= 2.0.1
add_packagedirs 添加包目录 >= 2.0.1
get_config 获取给的配置值 >= 2.2.2
set_config 设置默认的配置值 >= 2.2.2
add_requires 添加需要的依赖包 >= 2.2.2
add_repositories 添加依赖包仓库 >= 2.2.2

includes

添加子工程文件和目录

同时支持子工程文件和目录的添加,用于替代add_subdirsadd_subfiles接口。

另外,此接口在2.2.5之后的版本,提供了一些内置的辅助函数,可以直接includes后使用,具体有哪些内置函数可以看下:https://github.com/xmake-io/xmake/tree/master/xmake/includes

关于这块的更加完整的说明,可以看下:https://github.com/xmake-io/xmake/issues/342

例子:

检测links, c/c++ type, includes和编译器特性,并且写入宏定义到config.h

  1. includes("check_links.lua")
  2. includes("check_ctypes.lua")
  3. includes("check_cfuncs.lua")
  4. includes("check_features.lua")
  5. includes("check_csnippets.lua")
  6. includes("check_cincludes.lua")
  7. target("test")
  8. set_kind("binary")
  9. add_files("*.c")
  10. add_configfiles("config.h.in")
  11. configvar_check_ctypes("HAS_WCHAR", "wchar_t")
  12. configvar_check_cincludes("HAS_STRING_H", "string.h")
  13. configvar_check_cincludes("HAS_STRING_AND_STDIO_H", {"string.h", "stdio.h"})
  14. configvar_check_ctypes("HAS_WCHAR_AND_FLOAT", {"wchar_t", "float"})
  15. configvar_check_links("HAS_PTHREAD", {"pthread", "m", "dl"})
  16. configvar_check_csnippets("HAS_STATIC_ASSERT", "_Static_assert(1, \"\");")
  17. configvar_check_cfuncs("HAS_SETJMP", "setjmp", {includes = {"signal.h", "setjmp.h"}})
  18. configvar_check_features("HAS_CONSTEXPR", "cxx_constexpr")
  19. configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"})

config.h.in

  1. ${define HAS_STRING_H}
  2. ${define HAS_STRING_AND_STDIO_H}
  3. ${define HAS_WCHAR}
  4. ${define HAS_WCHAR_AND_FLOAT}
  5. ${define HAS_PTHREAD}
  6. ${define HAS_STATIC_ASSERT}
  7. ${define HAS_SETJMP}
  8. ${define HAS_CONSTEXPR}
  9. ${define HAS_CONSEXPR_AND_STATIC_ASSERT}

config.h

  1. /* #undef HAS_STRING_H */
  2. #define HAS_STRING_AND_STDIO_H 1
  3. /* #undef HAS_WCHAR */
  4. /* #undef HAS_WCHAR_AND_FLOAT */
  5. #define HAS_PTHREAD 1
  6. #define HAS_STATIC_ASSERT 1
  7. #define HAS_SETJMP 1
  8. /* #undef HAS_CONSTEXPR */
  9. #define HAS_CONSEXPR_AND_STATIC_ASSERT 1

set_modes

设置支持的编译模式

这个是可选接口,一般情况下不需要设置,目前仅用于对工程增加更加细致的描述信息,方便vs工程的多模式生成,以及其他xmake插件中获取模式信息。

例如:

  1. set_modes("debug", "release")

如果设置了这个,xmake就知道当前工程支持哪些编译模式,这样生成vs工程文件的时候,只需要:

  1. $ xmake project -k vs2017

不再需要额外手动指定需要的编译模式了,此外其他一些想要获取工程信息的插件,也许也会需要这些设置信息。

当然,对于is_mode接口,set_modes不是必须的,就算不设置,也是可以通过is_mode正常判断当前的编译模式。

set_project

设置工程名

设置工程名,在doxygen自动文档生成插件、工程文件生成插件中会用到,一般设置在xmake.lua的最开头,当然放在其他地方也是可以的

  1. -- 设置工程名
  2. set_project("tbox")
  3. -- 设置工程版本
  4. set_version("1.5.1")

set_version

设置工程版本

设置项目版本,可以放在xmake.lua任何地方,一般放在最开头,例如:

  1. set_version("1.5.1")

2.1.7版本支持buildversion的配置:

  1. set_version("1.5.1", {build = "%Y%m%d%H%M"})

我们也能够添加版本宏定义到头文件,请参考:add_configfiles

set_xmakever

设置最小xmake版本

用于处理xmake版本兼容性问题,如果项目的xmake.lua,通过这个接口设置了最小xmake版本支持,那么用户环境装的xmake低于要求的版本,就会提示错误。

一般情况下,建议默认对其进行设置,这样对用户比较友好,如果xmake.lua中用到了高版本的api接口,用户那边至少可以知道是否因为版本不对导致的构建失败。

设置如下:

  1. -- 设置最小版本为:2.1.0,低于此版本的xmake编译此工程将会提示版本错误信息
  2. set_xmakever("2.1.0")

add_subdirs

添加子工程目录

xmake 2.x以上版本,请尽量使用includes这个接口,这个是add_subdirs和add_subfiles的通用版本,并且支持一些内建扩展模块。

每个子工程对应一个xmake.lua的工程描述文件。

虽然一个xmake.lua也可以描述多个子工程模块,但是如果工程越来越大,越来越复杂,适当的模块化是很有必要的。。

这就需要add_subdirs了,将每个子模块放到不同目录中,并为其建立一个新的xmake.lua独立去维护它,例如:

  1. ./tbox
  2. ├── src
  3. ├── demo
  4. └── xmake.lua (用来描述测试模块)
  5. └── tbox
  6. └── xmake.lua(用来描述libtbox库模块)
  7. └── xmake.lua(用该描述通用配置信息,以及对子模块的维护)
  8. `

tbox/xmake.lua中通过add_subdirs将拥有xmale.lua的子模块的目录,添加进来,就可以了,例如:

  1. -- 添加libtbox库模块目录
  2. add_subdirs("src/tbox")
  3. -- 如果xmake f --demo=y,启用了demo模块,那么包含demo目录
  4. if is_option("demo") then
  5. add_subdirs("src/demo")
  6. end

默认情况下,xmake会去编译在所有xmake.lua中描述的所有target目标,如果只想编译指定目标,可以执行:

  1. # 仅仅编译tbox库模块
  2. $ xmake build tbox

需要注意的是,每个子xmake.lua中所有的路径设置都是相对于当前这个子xmake.lua所在的目录的,都是相对路径,这样方便维护

add_subfiles

添加子工程文件

xmake 2.x以上版本,请尽量使用includes这个接口,这个是add_subdirs和add_subfiles的通用版本,并且支持一些内建扩展模块。

add_subfiles的作用与add_subdirs类似,唯一的区别就是:这个接口直接指定xmake.lua文件所在的路径,而不是目录,例如:

  1. add_subfiles("src/tbox/xmake.lua")

add_moduledirs

添加模块目录

xmake内置的扩展模块都在xmake/modules目录下,可通过import来导入他们,如果自己在工程里面实现了一些扩展模块,可以放置在这个接口指定的目录下,import也就会能找到,并且优先进行导入。

例如定义一个find_openssl.lua的扩展模块,用于扩展内置的lib.detect.find_package接口,则只需要将它放置在:

  1. projectdir/xmake/modules/detect/packages/find_openssl.lua

然后在工程xmake.lua下指定这个模块目录,find_package就可以自动找到了:

  1. add_moduledirs("projectdir/xmake/modules")

add_plugindirs

添加插件目录

xmake内置的插件都是放在xmake/plugins目录下,但是对于用户自定义的一些特定工程的插件,如果不想放置在xmake安装目录下,那么可以在xmake.lua中进行配置指定的其他插件路径。

  1. -- 将当前工程下的plugins目录设置为自定义插件目录
  2. add_plugindirs("$(projectdir)/plugins")

这样,xmake在编译此工程的时候,也就加载这些插件。

add_packagedirs

添加包目录

通过设置依赖包目录,可以方便的集成一些第三方的依赖库,以tbox工程为例,其依赖包如下:

  1. - base.pkg
  2. - zlib.pkg
  3. - polarssl.pkg
  4. - openssl.pkg
  5. - mysql.pkg
  6. - pcre.pkg
  7. - ...

如果要让当前工程识别加载这些包,首先要指定包目录路径,例如:

  1. add_packagedirs("packages")

指定好后,就可以在target作用域中,通过add_packages接口,来添加集成包依赖了,例如:

  1. target("tbox")
  2. add_packages("zlib", "polarssl", "pcre", "mysql")

get_config

获取给定的配置值

此接口从2.2.2版本开始引入,用于快速获取给定的配置值,可用于描述域。

  1. if get_config("myconfig") == "xxx" then
  2. add_defines("HELLO")
  3. end

set_config

设置给定的默认配置值

此接口从2.2.2版本开始引入,用于快速在xmake.lua中设置一个默认配置值,仅用于描述域。

之前很多配置,包括编译工具链,构建目录等只能通过$ xmake f --name=value的方式来配置,如果我们想写死在xmake.lua提供一个默认值,就可以通过下面的方式来配置:

  1. set_config("name", "value")
  2. set_config("buildir", "other/buildir")
  3. set_config("cc", "gcc")
  4. set_config("ld", "g++")

不过,我们还是可以通过$ xmake f --name=value的方式,去修改xmake.lua中的默认配置。

add_requires

添加需要的依赖包

xmake的依赖包管理是完全支持语义版本选择的,例如:”~1.6.1”,对于语义版本的具体描述见:https://semver.org/

一些语义版本写法:

  1. add_requires("tbox 1.6.*", "pcre 1.3.x", "libpng ^1.18")
  2. add_requires("libpng ~1.16", "zlib 1.1.2 || >=1.2.11 <1.3.0")

目前xmake使用的语义版本解析器是uael贡献的sv库,里面也有对版本描述写法的详细说明,可以参考下:版本描述说明

当然,如果我们对当前的依赖包的版本没有特殊要求,那么可以直接这么写:

  1. add_requires("tbox", "libpng", "zlib")

这会使用已知的最新版本包,或者是master分支的源码编译的包,如果当前包有git repo地址,我们也能指定特定分支版本:

  1. add_requires("tbox master")
  2. add_requires("tbox dev")

如果指定的依赖包当前平台不支持,或者编译安装失败了,那么xmake会编译报错,这对于有些必须要依赖某些包才能工作的项目,这是合理的。但是如果有些包是可选的依赖,即使没有也可以正常编译使用的话,可以设置为可选包:

  1. add_requires("tbox", {optional = true})

默认的设置,xmake会去优先检测系统库是否存在(如果没设置版本要求),如果用户完全不想使用系统库以及第三方包管理提供的库,那么可以设置:

  1. add_requires("tbox", {system = false})

如果我们想同时源码调试依赖包,那么可以设置为使用debug版本的包(当然前提是这个包支持debug编译):

  1. add_requires("tbox", {debug = true})

如果当前包还不支持debug编译,可在仓库中提交修改编译规则,对debug进行支持,例如:

  1. package("openssl")
  2. on_install("linux", "macosx", function (package)
  3. os.vrun("./config %s --prefix=\"%s\"", package:debug() and "--debug" or "", package:installdir())
  4. os.vrun("make -j4")
  5. os.vrun("make install")
  6. end)

某些包在编译时候有各种编译选项,我们也可以传递进来,当然包本身得支持:

  1. add_requires("tbox", {config = {small=true}})

传递--small=true给tbox包,使得编译安装的tbox包是启用此选项的。

v2.2.3之后,可以通过optionhas_config配合,在自己定义配置选项参数中控制是否需要添加某个依赖包:

  1. option("luajit")
  2. set_default(false)
  3. set_showmenu(true)
  4. set_category("option")
  5. set_description("Enable the luajit runtime engine.")
  6. option_end()
  7. if has_config("luajit") then
  8. add_requires("luajit")
  9. else
  10. add_requires("lua")
  11. end

我们可以通过$xmake f --luajit=y去切换依赖包。

并且我们也新增了group参数,来分组依赖包,同一个组下的所有依赖包,只能有一个生效启用,启用顺序依赖add_requires添加的顺序:

  1. add_requires("openssl", {group = "ssl", optional = true})
  2. add_requires("mbedtls", {group = "ssl", optional = true})
  3. target("test")
  4. add_packages("openssl", "mbedtls")

例如上面,所以同时依赖两个ssl包,实际上只会启用生效实际安装成功的那一个ssl包,并不会同时链接两个依赖包。

2.2.5版本之后,xmake支持对对第三方包管理器里面的依赖库安装支持,例如:conan,brew, vcpkg等

添加homebrew的依赖包:

  1. add_requires("brew::zlib", {alias = "zlib"}})
  2. add_requires("brew::pcre2/libpcre2-8", {alias = "pcre2"}})
  3. target("test")
  4. set_kind("binary")
  5. add_files("src/*.c")
  6. add_packages("pcre2", "zlib")

添加vcpkg的依赖包:

  1. add_requires("vcpkg::zlib", "vcpkg::pcre2")
  2. target("test")
  3. set_kind("binary")
  4. add_files("src/*.c")
  5. add_packages("vcpkg::zlib", "vcpkg::pcre2")

添加conan的依赖包:

  1. add_requires("CONAN::zlib/1.2.11@conan/stable", {alias = "zlib", debug = true})
  2. add_requires("CONAN::OpenSSL/1.0.2n@conan/stable", {alias = "openssl",
  3. configs = {options = "OpenSSL:shared=True"}})
  4. target("test")
  5. set_kind("binary")
  6. add_files("src/*.c")
  7. add_packages("openssl", "zlib")

执行xmake进行编译后:

  1. ruki:test_package ruki$ xmake
  2. checking for the architecture ... x86_64
  3. checking for the Xcode directory ... /Applications/Xcode.app
  4. checking for the SDK version of Xcode ... 10.14
  5. note: try installing these packages (pass -y to skip confirm)?
  6. -> CONAN::zlib/1.2.11@conan/stable (debug)
  7. -> CONAN::OpenSSL/1.0.2n@conan/stable
  8. please input: y (y/n)
  9. => installing CONAN::zlib/1.2.11@conan/stable .. ok
  10. => installing CONAN::OpenSSL/1.0.2n@conan/stable .. ok
  11. [ 0%]: ccache compiling.release src/main.c
  12. [100%]: linking.release test

关于这块的更多详情见:https://github.com/xmake-io/xmake/issues/339

添加clib的依赖包:

clib是一款基于源码的依赖包管理器,拉取的依赖包是直接下载对应的库源码,集成到项目中编译,而不是二进制库依赖。

其在xmake中集成也很方便,唯一需要注意的是,还需要自己添加上对应库的源码到xmake.lua,例如:

  1. add_requires("clib::clibs/bytes@0.0.4", {alias = "bytes"})
  2. target("xmake-test")
  3. set_kind("binary")
  4. add_files("clib/bytes/*.c")
  5. add_files("src/*.c")
  6. add_packages("bytes")

add_repositories

添加依赖包仓库

如果需要的包不在官方仓库xmake-repo中,我们可以提交贡献代码到仓库进行支持。但如果有些包仅用于个人或者私有项目,我们可以建立一个私有仓库repo,仓库组织结构可参考:xmake-repo

比如,现在我们有一个一个私有仓库repo:git@github.com:myrepo/xmake-repo.git

我们可以通过此接口来添加:

  1. add_repositories("my-repo git@github.com:myrepo/xmake-repo.git")

如果我们只是想添加一两个私有包,这个时候特定去建立一个git repo太小题大做了,我们可以直接把包仓库放置项目里面,例如:

  1. projectdir
  2. - myrepo
  3. - packages
  4. - t/tbox/xmake.lua
  5. - z/zlib/xmake.lua
  6. - src
  7. - main.c
  8. - xmake.lua

上面myrepo目录就是自己的私有包仓库,内置在自己的项目里面,然后在xmake.lua里面添加一下这个仓库位置:

  1. add_repositories("my-repo myrepo")

这个可以参考benchbox项目,里面就内置了一个私有仓库。