定义和设置子工程模块,每个target对应一个子工程,最后会生成一个目标程序,有可能是可执行程序,也有可能是库模块。

target的接口,都是可以放置在target外面的全局作用域中的,如果在全局中设置,那么会影响所有子工程target。

例如:

  1. -- 会同时影响testtest2目标
  2. add_defines("DEBUG")
  3. target("test")
  4. add_files("*.c")
  5. target("test2")
  6. add_files("*.c")

target域是可以重复进入来实现分离设置的。

接口 描述 支持版本
target 定义工程目标 >= 1.0.1
target_end 结束定义工程目标 >= 2.1.1
set_kind 设置目标编译类型 >= 1.0.1
set_strip 设置是否strip信息 >= 1.0.1
set_enabled 设置是否启用或禁用目标 >= 2.2.2
set_default 设置是否为默认构建安装目标 >= 2.1.3
set_options 设置关联选项 >= 1.0.1
set_symbols 设置符号信息 >= 1.0.1
set_basename 设置目标文件名 >= 2.1.2
set_filename 设置目标文件全名 >= 2.1.2
set_warnings 设置警告级别 >= 1.0.1
set_optimize 设置优化级别 >= 1.0.1
set_languages 设置代码语言标准 >= 1.0.1
set_headerdir 设置头文件安装目录 >= 1.0.1 < 2.2.5 已废弃
set_targetdir 设置生成目标文件目录 >= 1.0.1
set_objectdir 设置对象文件生成目录 >= 1.0.1
set_dependir 设置依赖文件生成目录 >= 2.2.2
add_imports 为所有自定义脚本预先导入扩展模块 >= 2.1.7
add_rules 添加规则到目标 >= 2.1.9
on_load 自定义目标加载脚本 >= 2.1.5
on_link 自定义链接脚本 >= 2.2.7
on_build 自定义编译脚本 >= 2.0.1
on_build_file 自定义编译脚本, 实现单文件构建 >= 2.2.3
on_build_files 自定义编译脚本, 实现多文件构建 >= 2.2.3
on_clean 自定义清理脚本 >= 2.0.1
on_package 自定义打包脚本 >= 2.0.1
on_install 自定义安装脚本 >= 2.0.1
on_uninstall 自定义卸载脚本 >= 2.0.1
on_run 自定义运行脚本 >= 2.0.1
before_link 在链接之前执行一些自定义脚本 >= 2.2.7
before_build 在构建之前执行一些自定义脚本 >= 2.0.1
before_build_file 自定义编译前的脚本, 实现单文件构建 >= 2.2.3
before_build_files 自定义编译前的脚本, 实现多文件构建 >= 2.2.3
before_clean 在清除之前执行一些自定义脚本 >= 2.0.1
before_package 在打包之前执行一些自定义脚本 >= 2.0.1
before_install 在安装之前执行一些自定义脚本 >= 2.0.1
before_uninstall 在卸载之前执行一些自定义脚本 >= 2.0.1
before_run 在运行之前执行一些自定义脚本 >= 2.0.1
after_link 在链接之后执行一些自定义脚本 >= 2.2.7
after_build 在构建之后执行一些自定义脚本 >= 2.0.1
after_build_file 自定义编译后的脚本, 实现单文件构建 >= 2.2.3
after_build_files 自定义编译后的脚本, 实现多文件构建 >= 2.2.3
after_clean 在清除之后执行一些自定义脚本 >= 2.0.1
after_package 在打包之后执行一些自定义脚本 >= 2.0.1
after_install 在安装之后执行一些自定义脚本 >= 2.0.1
after_uninstall 在卸载之后执行一些自定义脚本 >= 2.0.1
after_run 在运行之后执行一些自定义脚本 >= 2.0.1
set_config_h 设置自动生成的配置头文件路径 >= 1.0.1 < 2.1.5 已废弃
set_config_h_prefix 设置自动生成的头文件中宏定义命名前缀 >= 1.0.1 < 2.1.5 已废弃
set_config_header 设置自动生成的配置头文件路径和前缀 >= 2.1.5 < 2.2.5 已废弃
set_pcheader 设置c预编译头文件 >= 2.1.5
set_pcxxheader 设置c++预编译头文件 >= 2.1.5
add_deps 添加子工程目标依赖 >= 1.0.1
add_links 添加链接库名 >= 1.0.1
add_syslinks 添加系统链接库名 >= 2.2.3
add_files 添加源代码文件 >= 1.0.1
del_files 从前面的源文件列表中删除指定文件 >= 2.1.9
add_headers 添加安装的头文件 >= 1.0.1 < 2.2.5 已废弃
add_linkdirs 添加链接库搜索目录 >= 1.0.1
add_rpathdirs 添加运行时候动态链接库搜索目录 >= 2.1.3
add_includedirs 添加头文件搜索目录 >= 1.0.1
add_defines 添加宏定义 >= 1.0.1
add_undefines 取消宏定义 >= 1.0.1
add_defines_h 添加宏定义到头文件 >= 1.0.1
add_undefines_h 取消宏定义到头文件 >= 1.0.1
add_cflags 添加c编译选项 >= 1.0.1
add_cxflags 添加c/c++编译选项 >= 1.0.1
add_cxxflags 添加c++编译选项 >= 1.0.1
add_mflags 添加objc编译选项 >= 1.0.1
add_mxflags 添加objc/objc++编译选项 >= 1.0.1
add_mxxflags 添加objc++编译选项 >= 1.0.1
add_scflags 添加swift编译选项 >= 2.0.1
add_asflags 添加汇编编译选项 >= 2.0.1
add_gcflags 添加go编译选项 >= 2.1.1
add_dcflags 添加dlang编译选项 >= 2.1.1
add_rcflags 添加rust编译选项 >= 2.1.1
add_cuflags 添加cuda编译选项 >= 2.2.1
add_culdflags 添加cuda设备链接选项 >= 2.2.7
add_cugencodes 添加cuda设备的gencode设置 >= 2.2.7
add_ldflags 添加链接选项 >= 1.0.1
add_arflags 添加静态库归档选项 >= 1.0.1
add_shflags 添加动态库链接选项 >= 1.0.1
add_packages 添加包依赖 >= 2.0.1
add_options 添加关联选项 >= 2.0.1
add_languages 添加语言标准 >= 1.0.1
add_vectorexts 添加向量扩展指令 >= 1.0.1
add_frameworks 添加链接框架 >= 2.1.1
add_frameworkdirs 添加链接框架的搜索目录 >= 2.1.5
set_toolchain 设置编译链接工具链 >= 2.2.9
set_values 设置一些扩展配置值 >= 2.2.1
add_values 添加一些扩展配置值 >= 2.2.1
set_rundir 设置运行目录 >= 2.2.7
add_runenvs 添加运行环境变量 >= 2.2.7
set_runenv 设置运行环境变量 >= 2.2.8
set_installdir 设置安装目录 >= 2.2.5
add_installfiles 添加安装文件 >= 2.2.5
add_headerfiles 添加安装头文件 >= 2.2.5
set_configdir 设置模板配置文件输出目录 >= 2.2.5
set_configvar 设置模板配置变量 >= 2.2.5
add_configfiles 添加模板配置文件 >= 2.2.5

target

定义工程目标

定义一个新的控制台工程目标,工程名为test,最后生成的目标名也是test

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")

可以重复调用这个api,进入target域修改设置

  1. -- 定义目标demo,并进入demo设置模式
  2. target("demo")
  3. set_kind("binary")
  4. add_files("src/demo.c")
  5. -- 定义和设置其他目标
  6. target("other")
  7. ...
  8. -- 重新进入demo目标域,添加test.c文件
  9. target("demo")
  10. add_files("src/test.c")

所有根域的设置,会全局影响所有target目标,但是不会影响option的定义。

  1. -- 在根域对所有target添加-DDEBUG的宏定义,影响所有targetdemotest都会加上此宏定义)
  2. add_defines("DEBUG")
  3. target("demo")
  4. set_kind("binary")
  5. add_files("src/demo.c")
  6. target("test")
  7. set_kind("binary")
  8. add_files("src/test.c")

target_end

结束定义工程目标

这是一个可选的api,如果不调用,那么target("xxx")之后的所有设置都是针对这个target进行的,除非进入其他target, option, task域。

如果想设置完当前target后,显示离开target域,进入根域设置,那么可以通过这个api才操作,例如:

  1. target("test")
  2. set_kind("static")
  3. add_files("src/*.c")
  4. target_end()
  5. -- 此处已在根域
  6. -- ...

如果不调用这个api的话:

  1. target("test")
  2. set_kind("static")
  3. add_files("src/*.c")
  4. -- 此处还在上面target域中,之后的设置还是针对test进行的设置
  5. -- ...
  6. -- 这个时候才离开test,进入另外一个target域中
  7. target("test2")
  8. ...

target:set_kind

设置目标编译类型

设置目标类型,目前支持的类型有:

描述
binary 二进制程序
static 静态库程序
shared 动态库程序
  1. target("demo")
  2. set_kind("binary")

target:set_strip

设置是否strip信息

设置当前目标的strip模式,目前支持一下模式:

描述
debug 链接的时候,strip掉调试符号
all 链接的时候,strip掉所有符号,包括调试符号

这个api一般在release模式下使用,可以生成更小的二进制程序。。

  1. target("xxxx")
  2. set_strip("all")

这个api不一定非得在target之后使用,如果没有target指定,那么将会设置到全局模式。。

target:set_enabled

设置是否启用或禁用目标

如果设置set_enabled(false),则会直接禁用对应的target,包括target的加载和信息获取,而set_default仅仅只是设置默认不去编译,但是target还是能获取到相关信息的,默认也会被加载。

target:set_default

设置是否为默认构建安装目标

这个接口用于设置给定工程目标是否作为默认构建,如果没有调用此接口进行设置,那么这个目标就是默认被构建的,例如:

  1. target("test1")
  2. set_default(false)
  3. target("test2")
  4. set_default(true)
  5. target("test3")
  6. ...

上述代码的三个目标,在执行xmake, xmake install, xmake package, xmake run等命令的时候,如果不指定目标名,那么:

目标名 行为
test1 不会被默认构建、安装、打包和运行
test2 默认构建、安装、打包和运行
test3 默认构建、安装、打包和运行

通过上面的例子,可以看到默认目标可以设置多个,运行的时候也会依次运行。

需要注意的是,xmake uninstallxmake clean命令不受此接口设置影响,因为用户大部分情况下都是喜欢清除和卸载所有。

如果不想使用默认的目标,那么可以手动指定需要构建安装的目标:

  1. $ xmake build targetname
  2. $ xmake install targetname

如果要强制构建安装所有目标,可以传入[-a|--all]参数:

  1. $ xmake build [-a|--all]
  2. $ xmake install [-a|--all]

target:set_options

设置关联选项

添加选项依赖,如果通过option接口自定义了一些选项,那么只有在指定target目标域下,添加此选项,才能进行关联生效。

  1. -- 定义一个hello选项
  2. option("hello")
  3. set_default(false)
  4. set_showmenu(true)
  5. add_defines("HELLO_ENABLE")
  6. target("test")
  7. -- 如果hello选项被启用了,这个时候就会将-DHELLO_ENABLE宏应用到test目标上去
  8. set_options("hello")

只有调用set_options进行关联生效后,option 中定义的一些设置才会影响到此target目标,例如:宏定义、链接库、编译选项等等

target:set_symbols

设置符号信息

设置目标的符号模式,如果当前没有定义target,那么将会设置到全局状态中,影响所有后续的目标。

目前主要支持一下几个级别:

描述
debug 添加调试符号
hidden 设置符号不可见

这两个值也可以同时被设置,例如:

  1. -- 添加调试符号, 设置符号不可见
  2. set_symbols("debug", "hidden")

如果没有调用这个api,默认是禁用调试符号的。。

target:set_basename

设置目标文件名

默认情况下,生成的目标文件名基于target("name")中配置的值,例如:

  1. -- 目标文件名为:libxxx.a
  2. target("xxx")
  3. set_kind("static")
  4. -- 目标文件名为:libxxx2.so
  5. target("xxx2")
  6. set_kind("shared")

默认的命名方式,基本上可以满足大部分情况下的需求,但是如果有时候想要更加定制化目标文件名

例如,按编译模式和架构区分目标名,这个时候可以使用这个接口,来设置:

  1. target("xxx")
  2. set_kind("static")
  3. set_basename("xxx_$(mode)_$(arch)")

如果这个时候,编译配置为:xmake f -m debug -a armv7,那么生成的文件名为:libxxx_debug_armv7.a

如果还想进一步定制目标文件的目录名,可参考:set_targetdir

或者通过编写自定义脚本,实现更高级的逻辑,具体见:after_buildos.mv

target:set_filename

设置目标文件全名

它跟set_basename的区别在于,set_basename设置名字不带后缀跟前缀,例如:libtest.a,basename如果改成test2后就变成了libtest2.a

而filename的修改,是修改整个目标文件名,包括前后缀,例如可以直接把libtest.a改成test.dll,这个对于set_basename是做不到的。

target:set_warnings

设置警告级别

设置当前目标的编译的警告级别,一般支持一下几个级别:

描述 gcc/clang msvc
none 禁用所有警告 -w -W0
less 启用较少的警告 -W1 -W1
more 启用较多的警告 -W3 -W3
all 启用所有警告 -Wall -W3 (-Wall too more warnings)
everything 启用全部支持的警告 -Wall -Wextra -Weffc++ / -Weverything -Wall
error 将所有警告作为编译错误 -Werror -WX

这个api的参数是可以混合添加的,例如:

  1. -- 启用所有警告,并且作为编译错误处理
  2. set_warnings("all", "error")

如果当前没有目标,调用这个api将会设置到全局模式。。

target:set_optimize

设置优化级别

设置目标的编译优化等级,如果当前没有设置目标,那么将会设置到全局状态中,影响所有后续的目标。

目前主要支持一下几个级别:

描述 gcc/clang msvc
none 禁用优化 -O0 -Od
fast 快速优化 -O1 default
faster 更快的优化 -O2 -Ox
fastest 最快运行速度的优化 -O3 -Ox -fp:fast
smallest 最小化代码优化 -Os -O1
aggressive 过度优化 -Ofast -Ox -fp:fast

例如:

  1. -- 最快运行速度的优化
  2. set_optimize("fastest")

target:set_languages

设置代码语言标准

设置目标代码编译的语言标准,如果当前没有目标存在,将会设置到全局模式中。。。

支持的语言标准目前主要有以下几个:

描述
ansi c语言标准: ansi
c89 c语言标准: c89
gnu89 c语言标准: gnu89
c99 c语言标准: c99
gnu99 c语言标准: gnu99
cxx98 c++语言标准: c++98
gnuxx98 c++语言标准: gnu++98
cxx11 c++语言标准: c++11
gnuxx11 c++语言标准: gnu++11
cxx14 c++语言标准: c++14
gnuxx14 c++语言标准: gnu++14
cxx1z c++语言标准: c++1z
gnuxx1z c++语言标准: gnu++1z
cxx17 c++语言标准: c++17
gnuxx17 c++语言标准: gnu++17

c标准和c++标准可同时进行设置,例如:

  1. -- 设置c代码标准:c99 c++代码标准:c++11
  2. set_languages("c99", "cxx11")

并不是设置了指定的标准,编译器就一定会按这个标准来编译,毕竟每个编译器支持的力度不一样,但是xmake会尽最大可能的去适配当前编译工具的支持标准。。。例如:windows下vs的编译器并不支持按c99的标准来编译c代码,只能支持到c89,但是xmake为了尽可能的支持它,所以在设置c99的标准后,xmake会强制按c++代码模式去编译c代码,从一定程度上解决了windows下编译c99的c代码问题。。用户不需要去额外做任何修改。。

target:set_headerdir

设置头文件安装目录

注,2.2.5版本之后,此接口已废弃,请使用add_headerfiles代替。

设置头文件的输出目录,默认输出到build目录中。

  1. target("test")
  2. set_headerdir("$(buildir)/include")

对于需要安装哪些头文件,可参考add_headers接口。

target:set_targetdir

设置生成目标文件目录

设置目标程序文件的输出目录,一般情况下,不需要设置,默认会输出在build目录下

而build的目录可以在工程配置的时候,手动修改:

  1. xmake f -o /tmp/build

修改成/tmp/build后,目标文件默认输出到/tmp/build下面。

而如果用这个接口去设置,就不需要每次敲命令修改了,例如:

  1. target("test")
  2. set_targetdir("/tmp/build")

如果显示设置了set_targetdir, 那么优先选择set_targetdir指定的目录为目标文件的输出目录。

target:set_objectdir

设置对象文件生成目录

设置目标target的对象文件(*.o/obj)的输出目录,例如:

  1. target("test")
  2. set_objectdir("$(buildir)/.objs")

target:set_dependir

设置依赖文件生成目录

设置目标target的编译依赖文件(.deps)的输出目录,例如:

  1. target("test")
  2. set_dependir("$(buildir)/.deps")

target:add_imports

为自定义脚本预先导入扩展模块

通常,我们在on_build等自定义脚本内部,可以通过import("core.base.task")的方式导入扩展模块,但是对于自定义脚本比较多的情况下,每个自定义脚本都重复导入一遍,非常的繁琐,那么可以通过这个接口,实现预先导入,例如:

  1. target("test")
  2. on_load(function (target)
  3. import("core.base.task")
  4. import("core.project.project")
  5. task.run("xxxx")
  6. end)
  7. on_build(function (target)
  8. import("core.base.task")
  9. import("core.project.project")
  10. task.run("xxxx")
  11. end)
  12. on_install(function (target)
  13. import("core.base.task")
  14. import("core.project.project")
  15. task.run("xxxx")
  16. end)

通过此接口可以简化为:

  1. target("test")
  2. add_imports("core.base.task", "core.project.project")
  3. on_load(function (target)
  4. task.run("xxxx")
  5. end)
  6. on_build(function (target)
  7. task.run("xxxx")
  8. end)
  9. on_install(function (target)
  10. task.run("xxxx")
  11. end)

target:add_rules

添加规则到目标

我们可以通过预先设置规则支持的文件后缀,来扩展其他文件的构建支持:

  1. -- 定义一个markdown文件的构建规则
  2. rule("markdown")
  3. set_extensions(".md", ".markdown")
  4. on_build(function (target, sourcefile)
  5. os.cp(sourcefile, path.join(target:targetdir(), path.basename(sourcefile) .. ".html"))
  6. end)
  7. target("test")
  8. set_kind("binary")
  9. -- 使test目标支持markdown文件的构建规则
  10. add_rules("markdown")
  11. -- 添加markdown文件的构建
  12. add_files("src/*.md")
  13. add_files("src/*.markdown")

我们也可以指定应用局部文件到规则,具体使用见:add_files

target:on_load

自定义目标加载脚本

在target初始化加载的时候,将会执行此脚本,在里面可以做一些动态的目标配置,实现更灵活的目标描述定义,例如:

  1. target("test")
  2. on_load(function (target)
  3. target:add("defines", "DEBUG", "TEST=\"hello\"")
  4. target:add("linkdirs", "/usr/lib", "/usr/local/lib")
  5. target:add({includedirs = "/usr/include", "links" = "pthread"})
  6. end)

可以在on_load里面,通过target:set, target:add 来动态添加各种target属性。

自定义链接脚本

这个是在v2.2.7之后新加的接口,用于定制化处理target的链接过程。

  1. target("test")
  2. on_link(function (target)
  3. print("link it")
  4. end)

target:on_build

自定义编译脚本

覆盖target目标默认的构建行为,实现自定义的编译过程,一般情况下,并不需要这么做,除非确实需要做一些xmake默认没有提供的编译操作。

你可以通过下面的方式覆盖它,来自定义编译操作:

  1. target("test")
  2. -- 设置自定义编译脚本
  3. on_build(function (target)
  4. print("build it")
  5. end)

注:2.1.5版本之后,所有target的自定义脚本都可以针对不同平台和架构,分别处理,例如:

  1. target("test")
  2. on_build("iphoneos|arm*", function (target)
  3. print("build for iphoneos and arm")
  4. end)

其中如果第一个参数为字符串,那么就是指定这个脚本需要在哪个平台|架构下,才会被执行,并且支持模式匹配,例如arm*匹配所有arm架构。

当然也可以只设置平台,不设置架构,这样就是匹配指定平台下,执行脚本:

  1. target("test")
  2. on_build("windows", function (target)
  3. print("build for windows")
  4. end)

一旦对这个target目标设置了自己的build过程,那么xmake默认的构建过程将不再被执行。

target:on_build_file

自定义编译脚本, 实现单文件构建

通过此接口,可以用来hook指定target内置的构建过程,替换每个源文件编译过程:

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. on_build_file(function (target, sourcefile, opt)
  5. opt.origin(target, sourcefile, opt)
  6. end)

上面代码中的opt.origin存有内置的构建脚本,如果hook后还是想调用内置的构建脚本去编译源文件,那么直接继续调用opt.origin就行了。

如果不想重写内置的编译脚本,仅仅只是在编译前后添加一些自己的处理,其实用:target.before_build_filetarget.after_build_file会更加方便,不需要调用opt.origin

target:on_build_files

自定义编译脚本, 实现多文件构建

通过此接口,可以用来hook指定target内置的构建过程,替换一批同类型源文件编译过程:

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. on_build_files(function (target, sourcebatch, opt)
  5. opt.origin(target, sourcebatch, opt)
  6. end)

设置此接口后,对应源文件列表中文件,就不会出现在自定义的target.on_build_file了,因为这个是包含关系。

其中sourcebatch描述了这批同类型源文件:

  • sourcebatch.sourcekind: 获取这批源文件的类型,比如:cc, as, ..
  • sourcebatch.sourcefiles(): 获取源文件列表
  • sourcebatch.objectfiles(): 获取对象文件列表
  • sourcebatch.dependfiles(): 获取对应依赖文件列表,存有源文件中编译依赖信息,例如:xxx.d

上面代码中的opt.origin存有内置的构建脚本,如果hook后还是想调用内置的构建脚本去编译源文件,那么直接继续调用opt.origin就行了。

target:on_clean

自定义清理脚本

覆盖target目标的xmake [c|clean}的清理操作,实现自定义清理过程。

  1. target("test")
  2. -- 设置自定义清理脚本
  3. on_clean(function (target)
  4. -- 仅删掉目标文件
  5. os.rm(target:targetfile())
  6. end)

一些target接口描述如下:

target接口 描述
target:name() 获取目标名
target:targetfile() 获取目标文件路径
target:get(“kind”) 获取目标的构建类型
target:get(“defines”) 获取目标的宏定义
target:get(“xxx”) 其他通过 set_/add_接口设置的target信息,都可以通过此接口来获取
target:add(“links”, “pthread”) 添加目标设置
target:set(“links”, “pthread”, “z”) 覆写目标设置
target:deps() 获取目标的所有依赖目标
target:dep(“depname”) 获取指定的依赖目标
target:sourcebatches() 获取目标的所有源文件列表

target:on_package

自定义打包脚本

覆盖target目标的xmake [p|package}的打包操作,实现自定义打包过程,如果你想对指定target打包成自己想要的格式,可以通过这个接口自定义它。

这个接口还是挺实用的,例如,编译完jni后,将生成的so,打包进apk包中。

  1. -- 定义一个android app的测试demo
  2. target("demo")
  3. -- 生成动态库:libdemo.so
  4. set_kind("shared")
  5. -- 设置对象的输出目录,可选
  6. set_objectdir("$(buildir)/.objs")
  7. -- 每次编译完的libdemo.so的生成目录,设置为app/libs/armeabi
  8. set_targetdir("libs/armeabi")
  9. -- 添加jni的代码文件
  10. add_files("jni/*.c")
  11. -- 设置自定义打包脚本,在使用xmake编译完libdemo.so后,执行xmake p进行打包
  12. -- 会自动使用antapp编译成apk文件
  13. --
  14. on_package(function (target)
  15. -- 使用ant编译appapk文件,输出信息重定向到日志文件
  16. os.run("ant debug")
  17. end)

target:on_install

自定义安装脚本

覆盖target目标的xmake [i|install}的安装操作,实现自定义安装过程。

例如,将生成的apk包,进行安装。

  1. target("test")
  2. -- 设置自定义安装脚本,自动安装apk文件
  3. on_install(function (target)
  4. -- 使用adb安装打包生成的apk文件
  5. os.run("adb install -r ./bin/Demo-debug.apk")
  6. end)

target:on_uninstall

自定义卸载脚本

覆盖target目标的xmake [u|uninstall}的卸载操作,实现自定义卸载过程。

  1. target("test")
  2. on_uninstall(function (target)
  3. ...
  4. end)

target:on_run

自定义运行脚本

覆盖target目标的xmake [r|run}的运行操作,实现自定义运行过程。

例如,运行安装好的apk程序:

  1. target("test")
  2. -- 设置自定义运行脚本,自动运行安装好的app程序,并且自动获取设备输出信息
  3. on_run(function (target)
  4. os.run("adb shell am start -n com.demo/com.demo.DemoTest")
  5. os.run("adb logcat")
  6. end)

在链接之前执行一些自定义脚本

这个是在v2.2.7之后新加的接口,用于在链接之前增加一些自定义的操作。

  1. target("test")
  2. before_link(function (target)
  3. print("")
  4. end)

target:before_build

在构建之前执行一些自定义脚本

并不会覆盖默认的构建操作,只是在构建之前增加一些自定义的操作。

  1. target("test")
  2. before_build(function (target)
  3. print("")
  4. end)

target:before_build_file

自定义编译前的脚本, 实现单文件构建

通过此接口,可以用来hook指定target内置的构建过程,在每个源文件编译过程之前执行一些自定义脚本:

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. before_build_file(function (target, sourcefile, opt)
  5. end)

target:before_build_files

自定义编译前的脚本, 实现多文件构建

通过此接口,可以用来hook指定target内置的构建过程,在一批同类型源文件编译过程之前执行一些自定义脚本:

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. before_build_files(function (target, sourcebatch, opt)
  5. end)

target:before_clean

在清理之前执行一些自定义脚本

并不会覆盖默认的清理操作,只是在清理之前增加一些自定义的操作。

  1. target("test")
  2. before_clean(function (target)
  3. print("")
  4. end)

target:before_package

在打包之前执行一些自定义脚本

并不会覆盖默认的打包操作,只是在打包之前增加一些自定义的操作。

  1. target("test")
  2. before_package(function (target)
  3. print("")
  4. end)

target:before_install

在安装之前执行一些自定义脚本

并不会覆盖默认的安装操作,只是在安装之前增加一些自定义的操作。

  1. target("test")
  2. before_install(function (target)
  3. print("")
  4. end)

target:before_uninstall

在卸载之前执行一些自定义脚本

并不会覆盖默认的卸载操作,只是在卸载之前增加一些自定义的操作。

  1. target("test")
  2. before_uninstall(function (target)
  3. print("")
  4. end)

target:before_run

在运行之前执行一些自定义脚本

并不会覆盖默认的运行操作,只是在运行之前增加一些自定义的操作。

  1. target("test")
  2. before_run(function (target)
  3. print("")
  4. end)

在链接之后执行一些自定义脚本

这个是在v2.2.7之后新加的接口,用于在链接之后增加一些自定义的操作。

  1. target("test")
  2. after_link(function (target)
  3. print("")
  4. end)

target:after_build

在构建之后执行一些自定义脚本

并不会覆盖默认的构建操作,只是在构建之后增加一些自定义的操作。

例如,对于ios的越狱开发,构建完程序后,需要用ldid进行签名操作

  1. target("test")
  2. after_build(function (target)
  3. os.run("ldid -S %s", target:targetfile())
  4. end)

target:after_build_file

自定义编译前的脚本, 实现单文件构建

通过此接口,可以用来hook指定target内置的构建过程,在每个源文件编译过程之后执行一些自定义脚本:

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. after_build_file(function (target, sourcefile, opt)
  5. end)

target:after_build_files

自定义编译前的脚本, 实现多文件构建

通过此接口,可以用来hook指定target内置的构建过程,在一批同类型源文件编译过程之后执行一些自定义脚本:

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. after_build_files(function (target, sourcebatch, opt)
  5. end)

target:after_clean

在清理之后执行一些自定义脚本

并不会覆盖默认的清理操作,只是在清理之后增加一些自定义的操作。

一般可用于清理编译某target自动生成的一些额外的临时文件,这些文件xmake默认的清理规则可能没有清理到,例如:

  1. target("test")
  2. after_clean(function (target)
  3. os.rm("$(buildir)/otherfiles")
  4. end)

target:after_package

在打包之后执行一些自定义脚本

并不会覆盖默认的打包操作,只是在打包之后增加一些自定义的操作。

  1. target("test")
  2. after_package(function (target)
  3. print("")
  4. end)

target:after_install

在安装之后执行一些自定义脚本

并不会覆盖默认的安装操作,只是在安装之后增加一些自定义的操作。

  1. target("test")
  2. after_install(function (target)
  3. print("")
  4. end)

target:after_uninstall

在卸载之后执行一些自定义脚本

并不会覆盖默认的卸载操作,只是在卸载之后增加一些自定义的操作。

  1. target("test")
  2. after_uninstall(function (target)
  3. print("")
  4. end)

target:after_run

在运行之后执行一些自定义脚本

并不会覆盖默认的运行操作,只是在运行之后增加一些自定义的操作。

  1. target("test")
  2. after_run(function (target)
  3. print("")
  4. end)

target:set_config_h

设置自动生成的配置头文件路径

2.2.5版本之后,此接口已废弃,请使用add_configfiles。2.1.5版本之后,此接口已废弃,请使用set_config_header

如果你想在xmake配置项目成功后,或者自动检测某个选项通过后,把检测的结果写入配置头文件,那么需要调用这个接口来启用自动生成config.h文件。

使用方式例如:

  1. target("test")
  2. -- 启用并设置需要自动生成的config.h文件路径
  3. set_config_h("$(buildir)/config.h")
  4. -- 设置自动检测生成的宏开关的名字前缀
  5. set_config_h_prefix("TB_CONFIG")

当这个target中通过下面的这些接口,对这个target添加了相关的选项依赖、包依赖、接口依赖后,如果某依赖被启用,那么对应的一些宏定义配置,会自动写入被设置的config.h文件中去。

这些接口,其实底层都用到了option选项中的一些检测设置,例如:

  1. option("wchar")
  2. -- 添加对wchar_t类型的检测
  3. add_ctypes("wchar_t")
  4. -- 如果检测通过,自动生成 TB_CONFIG_TYPE_HAVE_WCHAR的宏开关到config.h
  5. add_defines_h("$(prefix)_TYPE_HAVE_WCHAR")
  6. target("test")
  7. -- 启用头文件自动生成
  8. set_config_h("$(buildir)/config.h")
  9. set_config_h_prefix("TB_CONFIG")
  10. -- 添加对wchar选项的依赖关联,只有加上这个关联,wchar选项的检测结果才会写入指定的config.h中去
  11. add_options("wchar")

target:set_config_h_prefix

设置自动生成的头文件中宏定义命名前缀

2.2.5版本之后,此接口已废弃,请使用add_configfiles。2.1.5版本之后,此接口已废弃,请使用set_config_header

具体使用见:set_config_h

如果设置了:

  1. target("test")
  2. set_config_h_prefix("TB_CONFIG")

那么,选项中add_defines_h("$(prefix)_TYPE_HAVE_WCHAR")的$(prefix)会自动被替换成新的前缀值。

target:set_config_header

设置自动生成的配置头文件路径和前缀

2.2.5版本之后,此接口已废弃,请使用add_configfiles

此接口是set_config_hset_config_h_prefix的升级版本,2.1.5之后支持。

如果你想在xmake配置项目成功后,或者自动检测某个选项通过后,把检测的结果写入配置头文件,那么需要调用这个接口来启用自动生成config.h文件。

使用方式例如:

  1. target("test")
  2. set_config_header("$(buildir)/config.h", {prefix = "TB_CONFIG"})

上面的代码,启用并设置需要自动生成的config.h文件路径,并且设置自动检测生成的宏开关的名字前缀:TB_CONFIG, 当然这个前缀的设置是可选的。

  1. target("test")
  2. set_config_header("$(buildir)/config.h")

如果不设置前缀,将会自动根据target名生成一个唯一字串。

2.1.8 之后版本,支持针对每个局部配置文件,单独设置版本号,优先于全局的set_version,例如:

  1. set_config_header("$(buildir)/config.h", {prefix = "TB_CONFIG", version = "2.1.8", build = "%Y%m%d%H%M"})

通过内置的检测规则生成配置

当这个target中通过下面的这些接口,对这个target添加了相关的选项依赖、包依赖、接口依赖后,如果某依赖被启用,那么对应的一些宏定义配置,会自动写入被设置的config.h文件中去。

定制化检测和生成配置头文件

这些接口,其实底层都用到了option选项中的一些检测设置,例如:

  1. option("wchar")
  2. -- 添加对wchar_t类型的检测
  3. add_ctypes("wchar_t")
  4. -- 如果检测通过,自动生成 TB_CONFIG_TYPE_HAVE_WCHAR的宏开关到config.h
  5. add_defines_h("$(prefix)_TYPE_HAVE_WCHAR")
  6. target("test")
  7. -- 启用头文件自动生成
  8. set_config_header("$(buildir)/config.h", {prefix = "TB_CONFIG"})
  9. -- 添加对wchar选项的依赖关联,只有加上这个关联,wchar选项的检测结果才会写入指定的config.h中去
  10. add_options("wchar")

甚至我们可以在xmake.lua中自己定义个function,针对option进行封装,提供更加定制化的检测和生成config.h的过程

例如:这里有个需求,我们想批量检测一些头文件,如果存在则在config.h里面输出HAVE_LIMITS_H这样的宏开关,我们可以这么写

  1. function add_checking_to_config(...)
  2. -- 批量定义option检测规则,仅检测include文件
  3. local options = {}
  4. for _, header in ipairs({...}) do
  5. local define = header:upper():gsub("[%./]", "_")
  6. option(define)
  7. add_cincludes(header)
  8. add_defines_h("HAVE_" .. define) -- 生成 HAVE_LIMITS_H 这样的宏开关到config.h
  9. option_end()
  10. table.insert(options, define)
  11. end
  12. -- 定义个内置__config空目标,仅用于关联设置automatedconfig.h,以及对应的options检测规则
  13. -- 因为set_config_header在全局设置,会影响所有target,对每个target都会检测生成一次宏开关
  14. target("__config")
  15. set_kind("phony")
  16. set_config_header("includes/automatedconfig.h")
  17. add_options(options)
  18. target_end()
  19. end
  20. -- 添加一些头文件检测
  21. add_checking_to_config("arpa/inet.h", "limits.h", "fcntl.h", "xxxx.h")

target:set_pcheader

设置c预编译头文件

xmake支持通过预编译头文件去加速c程序编译,目前支持的编译器有:gcc, clang和msvc。

使用方式如下:

  1. target("test")
  2. set_pcheader("header.h")

target:set_pcxxheader

设置c++预编译头文件

xmake支持通过预编译头文件去加速c++程序编译,目前支持的编译器有:gcc, clang和msvc。

使用方式如下:

  1. target("test")
  2. set_pcxxheader("header.h")

target:add_deps

添加子工程目标依赖

添加当前目标的依赖目标,编译的时候,会去优先编译依赖的目标,然后再编译当前目标。。。

  1. target("test1")
  2. set_kind("static")
  3. set_files("*.c")
  4. target("test2")
  5. set_kind("static")
  6. set_files("*.c")
  7. target("demo")
  8. add_deps("test1", "test2")

上面的例子,在编译目标demo的时候,需要先编译test1, test2目标,因为demo会去用到他们

target会自动继承依赖目标中的配置和属性,不需要额外调用add_links, add_linkdirsadd_rpathdirs等接口去关联依赖目标了。

并且继承关系是支持级联的,例如:

  1. target("library1")
  2. set_kind("static")
  3. add_files("*.c")
  4. add_includedirs("inc") -- 默认私有头文件目录不会被继承
  5. add_includedirs("inc1", {public = true}) -- 此处的头文件相关目录也会被继承
  6. target("library2")
  7. set_kind("static")
  8. add_deps("library1")
  9. add_files("*.c")
  10. target("test")
  11. set_kind("binary")
  12. add_deps("library2")

如果我们不想继承依赖target的任何配置,如何操作呢?

  1. add_deps("dep1", "dep2", {inherit = false})

通过显式设置inherit配置,来告诉xmake,这两个依赖的配置是否需要被继承,如果不设置,默认就是启用继承的。

2.2.5版本之后,可通过 add_includedirs("inc1", {public = true}), 设置public为true, 将includedirs的设置公开给其他依赖的子target继承。

目前对于target的编译链接flags相关接口设置,都是支持继承属性的,可以人为控制是否需要导出给其他target来依赖继承,目前支持的属性有:

属性 描述
private 默认设置,作为当前target的私有配置,不会被依赖的其他target所继承
public 公有配置,当前target,依赖的子target都会被设置
interface 接口设置,仅被依赖的子target所继承设置,当前target不参与

对于这块的详细说明,可以看下:https://github.com/xmake-io/xmake/issues/368

添加链接库名

为当前目标添加链接库,一般这个要与add_linkdirs配对使用。

  1. target("demo")
  2. -- 添加对libtest.a的链接,相当于 -ltest
  3. add_links("test")
  4. -- 添加链接搜索目录
  5. add_linkdirs("$(buildir)/lib")

添加系统链接库名

这个接口使用上跟add_links类似,唯一的区别就是,通过这个接口添加的链接库顺序在所有add_links之后。

因此主要用于添加系统库依赖,因为系统库的链接顺序是非常靠后的,例如:

  1. add_syslinks("pthread", "m", "dl")
  2. target("demo")
  3. add_links("a", "b")
  4. add_linkdirs("$(buildir)/lib")

上面的配置,即使add_syslinks被优先提前设置了,但最后的链接顺序依然是:-la -lb -lpthread -lm -ldl

target:add_files

添加源代码文件

用于添加目标工程的源文件,甚至库文件,目前支持的一些文件类型:

支持的源文件类型 描述
.c/.cpp/.cc/.cxx c++文件
.s/.S/.asm 汇编文件
.m/.mm objc文件
.swift swift文件
.go golang文件
.o/.obj 对象文件
.a/.lib 静态库文件,会自动合并库到目标程序
.rc msvc的资源文件

其中通配符*表示匹配当前目录下文件,而**则匹配多级目录下的文件。

例如:

  1. add_files("src/test_*.c")
  2. add_files("src/xxx/**.cpp")
  3. add_files("src/asm/*.S", "src/objc/**/hello.m")

add_files的使用其实是相当灵活方便的,其匹配模式借鉴了premake的风格,但是又对其进行了改善和增强。

使得不仅可以匹配文件,还有可以在添加文件同时,过滤排除指定模式的一批文件。

例如:

  1. -- 递归添加src下的所有c文件,但是不包括src/impl/下的所有c文件
  2. add_files("src/**.c|impl/*.c")
  3. -- 添加src下的所有cpp文件,但是不包括src/test.cppsrc/hello.cpp以及src下所有带xx_前缀的cpp文件
  4. add_files("src/*.cpp|test.cpp|hello.cpp|xx_*.cpp")

其中分隔符|之后的都是需要排除的文件,这些文件也同样支持匹配模式,并且可以同时添加多个过滤模式,只要中间用|分割就行了。。

添加文件的时候支持过滤一些文件的一个好处就是,可以为后续根据不同开关逻辑添加文件提供基础。

为了使得描述上更加的精简,|之后的过滤描述都是基于起一个模式:src/*.cpp*之前的目录为基础的。所以上面的例子后面过滤的都是在src下的文件,这个是要注意的。

2.1.6版本之后,对add_files进行了改进,支持基于files更细粒度的编译选项控制,例如:

  1. target("test")
  2. add_defines("TEST1")
  3. add_files("src/*.c")
  4. add_files("test/*.c", "test2/test2.c", {defines = "TEST2", languages = "c99", includedirs = ".", cflags = "-O0"})

可以在add_files的最后一个参数,传入一个配置table,去控制指定files的编译选项,里面的配置参数跟target的一致,并且这些文件还会继承target的通用配置-DTEST1

2.1.9版本之后,支持添加未知的代码文件,通过设置rule自定义规则,实现这些文件的自定义构建,例如:

  1. target("test")
  2. -- ...
  3. add_files("src/test/*.md", {rule = "markdown"})

关于自定义构建规则的使用说明,详细见:构建规则

并且在2.1.9版本之后,可以通过force参数来强制禁用cxflags,cflags等编译选项的自动检测,直接传入编译器,哪怕编译器有可能不支持,也会设置:

  1. add_files("src/*.c", {force = {cxflags = "-DTEST", mflags = "-framework xxx"}})

target:del_files

从前面的源代码文件列表中删除指定文件

通过此接口,可以从前面add_files接口添加的文件列表中,删除指定的文件,例如:

  1. target("test")
  2. add_files("src/*.c")
  3. del_files("src/test.c")

上面的例子,可以从src目录下添加除test.c以外的所有文件,当然这个也可以通过add_files("src/*.c|test.c")来达到相同的目的,但是这种方式更加灵活。

例如,我们可以条件判断来控制删除哪些文件,并且此接口也支持add_files的匹配模式,过滤模式,进行批量移除。

  1. target("test")
  2. add_files("src/**.c")
  3. del_files("src/test*.c")
  4. del_files("src/subdir/*.c|xxx.c")
  5. if is_plat("iphoneos") then
  6. add_files("xxx.m")
  7. end

通过上面的例子,我们可以看出add_filesdel_files是根据调用顺序,进行顺序添加和删除的,并且通过del_files("src/subdir/*.c|xxx.c")删除一批文件,并且排除src/subdir/xxx.c(就是说,不删除这个文件)。

target:add_headers

添加安装的头文件

注,2.2.5版本之后,此接口已废弃,请使用add_headerfiles代替。

安装指定的头文件到build目录,如果设置了set_headerdir, 则输出到指定目录。

安装规则的语法跟add_files类似,例如:

  1. -- 安装tbox目录下所有的头文件(忽略impl目录下的文件),并且按()指定部分作为相对路径,进行安装
  2. add_headers("../(tbox/**.h)|**/impl/**.h")

target:add_linkdirs

添加链接库搜索目录

设置链接库的搜索目录,这个接口的使用方式如下:

  1. target("test")
  2. add_linkdirs("$(buildir)/lib")

此接口相当于gcc的-Lxxx链接选项。

一般他是与add_links配合使用的,当然也可以直接通过add_ldflags或者add_shflags接口来添加,也是可以的。

如果不想在工程中写死,可以通过:xmake f --linkdirs=xxx或者xmake f --ldflags="-L/xxx"的方式来设置,当然这种手动设置的目录搜索优先级更高。

target:add_rpathdirs

添加程序运行时动态库的加载搜索目录

通过add_linkdirs设置动态库的链接搜索目录后,程序被正常链接,但是在linux平台想要正常运行编译后的程序,会报加载动态库失败。

因为没找到动态库的加载目录,想要正常运行依赖动态库的程序,需要设置LD_LIBRARY_PATH环境变量,指定需要加载的动态库目录。

但是这种方式是全局的,影响太广,更好的方式是通过-rpath=xxx的链接器选项,在链接程序的时候设置好需要加载的动态库搜索路径,而xmake对其进行了封装,通过add_rpathdirs更好的处理跨平台问题。

具体使用如下:

  1. target("test")
  2. set_kind("binary")
  3. add_linkdirs("$(buildir)/lib")
  4. add_rpathdirs("$(buildir)/lib")

只需要在链接的时候,在设置下rpath目录就好了,虽然也可以通过add_ldflags("-Wl,-rpath=xxx")达到相同的目的,但是这个接口更加通用。

内部会对不同平台进行处理,像在macOS下,是不需要-rpath设置的,也是可以正常加载运行程序,因此针对这个平台,xmake内部会直接忽略器设置,避免链接报错。

而在为dlang程序进行动态库链接时,xmake会自动处理成-L-rpath=xxx来传入dlang的链接器,这样就避免了直接使用add_ldflags需要自己判断和处理不同平台和编译器问题。

2.1.7版本对这个接口进行了改进,支持:@loader_path, @executable_path$ORIGIN的内置变量,来指定程序的加载目录,它们的效果基本上是一样的,主要是为了同时兼容macho, elf。

例如:

  1. target("test")
  2. set_kind("binary")
  3. add_linkdirs("$(buildir)/lib")
  4. add_rpathdirs("@loader_path/lib")

指定test程序加载当前执行目录下lib/*.[so|dylib]的动态库文件,这将有助于提升程序的可移植性,不用写死绝对路径和相对路径,导致程序和目录切换引起程序加载动态库失败。

需要注意的是,在macos下,要想add_rpathdirs设置生效,需要对dylib做一些预处理,添加@rpath/xxx路径设置:$install_name_tool -add_rpath @rpath/libxxx.dylib xxx/libxxx.dylib我们也可以通过otool -L libxxx.dylib查看是否存在带@rpath的路径

target:add_includedirs

添加头文件搜索目录

设置头文件的搜索目录,这个接口的使用方式如下:

  1. target("test")
  2. add_includedirs("$(buildir)/include")

当然也可以直接通过add_cxflags或者add_mxflags等接口来设置,也是可以的。

2.2.5之后,可通过额外的{public|interface = true}属性设置,将includedirs导出给依赖的子target,例如:

  1. target("test")
  2. set_kind("static")
  3. add_includedirs("src/include") -- 仅对当前target生效
  4. add_includedirs("$(buildir)/include", {public = true}),当前target和子target都会被设置
  5. target("demo")
  6. set_kind("binary")
  7. add_deps("test")

更多关于这块的说明,见:add_deps

如果不想在工程中写死,可以通过:xmake f --includedirs=xxx或者xmake f --cxflags="-I/xxx"的方式来设置,当然这种手动设置的目录搜索优先级更高。

target:add_defines

添加宏定义

  1. add_defines("DEBUG", "TEST=0", "TEST2=\"hello\"")

相当于设置了编译选项:

  1. -DDEBUG -DTEST=0 -DTEST2=\"hello\"

target:add_undefines

取消宏定义

  1. add_undefines("DEBUG")

相当于设置了编译选项:-UDEBUG

在代码中相当于:#undef DEBUG

target:add_defines_h

添加宏定义到头文件

2.2.5版本之后,此接口已废弃,请使用add_configfiles

添加宏定义到config.h配置文件,config.h的设置,可参考set_config_h接口。

target:add_undefines_h

取消宏定义到头文件

2.2.5版本之后,此接口已废弃,请使用add_configfiles

config.h配置文件中通过undef禁用宏定义,config.h的设置,可参考set_config_h接口。

target:add_cflags

添加c编译选项

仅对c代码添加编译选项

  1. add_cflags("-g", "-O2", "-DDEBUG")

所有选项值都基于gcc的定义为标准,如果其他编译器不兼容(例如:vc),xmake会自动内部将其转换成对应编译器支持的选项值。用户无需操心其兼容性,如果其他编译器没有对应的匹配值,那么xmake会自动忽略器设置。

在2.1.9版本之后,可以通过force参数来强制禁用flags的自动检测,直接传入编译器,哪怕编译器有可能不支持,也会设置:

  1. add_cflags("-g", "-O2", {force = true})

target:add_cxflags

添加c/c++编译选项

同时对c/c++代码添加编译选项

target:add_cxxflags

添加c++编译选项

仅对c++代码添加编译选项

target:add_mflags

添加objc编译选项

仅对objc代码添加编译选项

  1. add_mflags("-g", "-O2", "-DDEBUG")

在2.1.9版本之后,可以通过force参数来强制禁用flags的自动检测,直接传入编译器,哪怕编译器有可能不支持,也会设置:

  1. add_mflags("-g", "-O2", {force = true})

target:add_mxflags

添加objc/objc++编译选项

同时对objc/objc++代码添加编译选项

  1. add_mxflags("-framework CoreFoundation")

target:add_mxxflags

添加objc++编译选项

仅对objc++代码添加编译选项

  1. add_mxxflags("-framework CoreFoundation")

target:add_scflags

添加swift编译选项

对swift代码添加编译选项

  1. add_scflags("xxx")

target:add_asflags

添加汇编编译选项

对汇编代码添加编译选项

  1. add_asflags("xxx")

target:add_gcflags

添加go编译选项

对golang代码添加编译选项

  1. add_gcflags("xxx")

target:add_dcflags

添加dlang编译选项

对dlang代码添加编译选项

  1. add_dcflags("xxx")

target:add_rcflags

添加rust编译选项

对rust代码添加编译选项

  1. add_rcflags("xxx")

target:add_cuflags

添加cuda编译选项

对cuda代码添加编译选项

  1. add_cuflags("-gencode arch=compute_30,code=sm_30")

target:add_culdflags

添加cuda设备链接选项

v2.2.7之后,cuda默认构建会使用device-link,这个阶段如果要设置一些链接flags,则可以通过这个接口来设置。而最终的程序链接,会使用ldflags,不会调用nvcc,直接通过gcc/clang等c/c++链接器来链接。

关于device-link的说明,可以参考:https://devblogs.nvidia.com/separate-compilation-linking-cuda-device-code/

  1. add_culdflags("-gencode arch=compute_30,code=sm_30")

target:add_cugencodes

添加cuda设备的gencode设置

add_cugencodes()接口其实就是对add_cuflags("-gencode arch=compute_xx,code=compute_xx")编译flags设置的简化封装,其内部参数值对应的实际flags映射关系如下:

  1. - compute_xx --> `-gencode arch=compute_xx,code=compute_xx`
  2. - sm_xx --> `-gencode arch=compute_xx,code=sm_xx`
  3. - sm_xx,sm_yy --> `-gencode arch=compute_xx,code=[sm_xx,sm_yy]`
  4. - compute_xx,sm_yy --> `-gencode arch=compute_xx,code=sm_yy`
  5. - compute_xx,sm_yy,sm_zz --> `-gencode arch=compute_xx,code=[sm_yy,sm_zz]`
  6. - native --> match the fastest cuda device on current host,
  7. eg. for a Tesla P100, `-gencode arch=compute_60,code=sm_60` will be added,
  8. if no available device is found, no `-gencode` flags will be added

例如:

  1. add_cugencodes("sm_30")

就等价为

  1. add_cuflags("-gencode arch=compute_30,code=sm_30")
  2. add_culdflags("-gencode arch=compute_30,code=sm_30")

是不是上面的更加精简些,这其实就是个用于简化设置的辅助接口。

而如果我们设置了native值,那么xmake会自动探测当前主机的cuda设备,然后快速匹配到它对应的gencode设置,自动追加到整个构建过程中。

例如,如果我们主机目前的GPU是Tesla P100,并且能够被xmake自动检测到,那么下面的设置:

  1. add_cugencodes("native")

等价于:

  1. add_cugencodes("sm_60")

target:add_ldflags

添加链接选项

添加静态链接选项

  1. add_ldflags("-L/xxx", "-lxxx")

target:add_arflags

添加静态库归档选项

影响对静态库的生成

  1. add_arflags("xxx")

target:add_shflags

添加动态库链接选项

影响对动态库的生成

  1. add_shflags("xxx")

target:add_options

添加关联选项

这个接口跟set_options类似,唯一的区别就是,此处是追加选项,而set_options每次设置会覆盖先前的设置。

target:add_packages

添加包依赖

在target作用域中,添加集成包依赖,例如:

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

这样,在编译test目标时,如果这个包存在的,将会自动追加包里面的宏定义、头文件搜索路径、链接库目录,也会自动链接包中所有库。

用户不再需要自己单独调用add_linksadd_includedirs, add_ldflags等接口,来配置依赖库链接了。

对于如何设置包搜索目录,可参考:add_packagedirs 接口

而在v2.2.2版本之后,此接口也同时支持远程依赖包管理中add_requires定义的包。

  1. add_requires("zlib", "polarssl")
  2. target("test")
  3. add_packages("zlib", "polarssl")

v2.2.3之后,还支持覆写内置的links,控制实际链接的库:

  1. -- 默认会有 ncurses, panel, formlinks
  2. add_requires("ncurses")
  3. target("test")
  4. -- 显示指定,只使用ncurses一个链接库
  5. add_packages("ncurses", {links = "ncurses"})

或者干脆禁用links,只使用头文件:

  1. add_requires("lua")
  2. target("test")
  3. add_packages("lua", {links = {}})

target:add_languages

添加语言标准

set_languages类似,唯一区别是这个接口不会覆盖掉之前的设置,而是追加设置。

target:add_vectorexts

添加向量扩展指令

添加扩展指令优化选项,目前支持以下几种扩展指令集:

  1. add_vectorexts("mmx")
  2. add_vectorexts("neon")
  3. add_vectorexts("avx", "avx2")
  4. add_vectorexts("sse", "sse2", "sse3", "ssse3")

如果当前设置的指令集编译器不支持,xmake会自动忽略掉,所以不需要用户手动去判断维护,只需要将你需要的指令集全部设置上就行了。

target:add_frameworks

添加链接框架

目前主要用于iosmacosx平台的objcswift程序,例如:

  1. target("test")
  2. add_frameworks("Foundation", "CoreFoundation")

当然也可以使用add_mxflagsadd_ldflags来设置,不过比较繁琐,不建议这样设置。

  1. target("test")
  2. add_mxflags("-framework Foundation", "-framework CoreFoundation")
  3. add_ldflags("-framework Foundation", "-framework CoreFoundation")

如果不是这两个平台,这些设置将会被忽略。

target:add_frameworkdirs

添加链接框架搜索目录

对于一些第三方framework,那么仅仅通过add_frameworks是没法找到的,还需要通过这个接口来添加搜索目录。

  1. target("test")
  2. add_frameworks("MyFramework")
  3. add_frameworkdirs("/tmp/frameworkdir", "/tmp/frameworkdir2")

target:set_toolchain

设置编译链接工具链

对于add_files("*.c")添加的源码文件,默认都是会调用系统最匹配的编译工具去编译,或者通过xmake f --cc=clang命令手动去修改,不过这些都是全局影响所有target目标的。

如果有些特殊需求,需要对当前工程下某个特定的target目标单独指定不同的编译器、链接器或者特定版本的编译器,这个时候此接口就可以排上用途了,例如:

  1. target("test1")
  2. add_files("*.c")
  3. target("test2")
  4. add_files("*.c")
  5. set_toolchain("cc", "$(projectdir)/tools/bin/clang-5.0")

上述描述仅对test2目标的编译器进行特殊设置,使用特定的clang-5.0编译器来编译test2,而test1还是使用默认设置。

每次设置都会覆盖当前target目标下之前的那次设置,不同target之间不会被覆盖,互相独立,如果在根域设置,会影响所有子target。

前一个参数是key,用于指定工具类型,目前支持的有(编译器、链接器、归档器):

工具类型 描述
cc c编译器
cxx c++编译器
mm objc编译器
mxx objc++编译器
gc go编译器
as 汇编器
sc swift编译器
rc rust编译器
dc dlang编译器
ld c/c++/asm/objc等通用可执行程序链接器
sh c/c++/asm/objc等通用动态库链接器
ar c/c++/asm/objc等通用静态库归档器
dc-ld dlang可执行链接器, rc-ld/gc-ld等类似
dc-sh dlang动态库链接器, rc-sh/gc-sh等类似

对于一些编译器文件名不规则,导致xmake无法正常识别处理为已知的编译器名的情况下,我们也可以加一个工具名提示,例如:

  1. set_toolchain("cc", "gcc@$(projectdir)/tools/bin/mipscc.exe")

上述描述设置mipscc.exe作为c编译器,并且提示xmake作为gcc的传参处理方式进行编译。

target:set_values

设置一些扩展配置值

给target设置一些扩展的配置值,这些配置没有像set_ldflags这种内置的api可用,通过第一个参数传入一个配置名,来扩展配置。一般用于传入配置参数给自定义rule中的脚本使用,例如:

  1. rule("markdown")
  2. on_build_file(function (target, sourcefile, opt)
  3. -- compile .markdown with flags
  4. local flags = target:values("markdown.flags")
  5. if flags then
  6. -- ..
  7. end
  8. end)
  9. target("test")
  10. add_files("src/*.md", {rule = "markdown"})
  11. set_values("markdown.flags", "xxx", "xxx")

上述代码例子中,可以看出,在target应用markdown规则的时候,通过set_values去设置一些flags值,提供给markdown规则去处理。在规则脚本中可以通过target:values("markdown.flags")获取到target中设置的扩展flags值。

具体扩展配置名,根据不同的rule,会有所不同,目前有哪些,可以参考相关规则的描述:内建规则

target:add_values

添加一些扩展配置值

用法跟target:set_values类似,区别就是这个接口是追加设置,而不会每次覆盖设置。

target:set_rundir

设置运行目录

此接口用于设置默认运行target程序的当前运行目录,如果不设置,默认情况下,target是在可执行文件所在目录加载运行。

如果用户想要修改加载目录,一种是通过on_run()的方式自定义运行逻辑,里面去做切换,但仅仅为了切个目录就这么做,太过繁琐。

因此可以通过这个接口快速的对默认执行的目录环境做设置切换。

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. set_rundir("$(projectdir)/xxx")

target:add_runenvs

添加运行环境变量

此接口用于添加设置默认运行target程序的环境变量,跟set_runenv不同的是,此接口是对已有系统env中的值进行追加,并不会覆盖。

所以,对于PATH这种,通过此接口追加值是非常方便的,而且此接口支持多值设置,所以通常就是用来设置带有path sep的多值env。。

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. add_runenvs("PATH", "/tmp/bin", "xxx/bin")
  5. add_runenvs("LD_LIBRARY_PATH", "/tmp/lib", "xxx/lib")

target:set_runenv

设置运行环境变量

此接口跟add_runenvs不同的是,set_runenv是对某个环境变量的覆盖设置,会覆盖原有系统环境的env值,并且此接口是单数设置,不能传递多参。

所以,如果要覆盖设置PATH这中多路径的env,需要自己去拼接:

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. set_runenv("PATH", path.joinenv("/tmp/bin", "xxx/bin"))
  5. set_runenv("NAME", "value")

target:set_installdir

设置安装目录

2.2.5版本新增接口,用于针对每个target设置不同的默认安装目录,一般用于xmake install/uninstall命令。

默认情况下执行xmake install会安装到系统/usr/local目录,我们除了可以通过xmake install -o /usr/local指定其他安装目录外,还可以在xmake.lua中针对target设置不同的安装目录来替代默认目录。

除了上述两种方式,我们也可以通过INSTALLDIRDESTDIR环境变量设置默认的安装目录。

target:add_installfiles

添加安装文件

2.2.5版本新增接口,用于针对每个target设置对应需要安装的文件,一般用于xmake install/uninstall命令。

比如我们可以指定安装各种类型的文件到安装目录:

  1. target("test")
  2. add_installfiles("src/*.h")
  3. add_installfiles("doc/*.md")

默认在linux等系统上,我们会安装到/usr/local/*.h, /usr/local/*.md,不过我们也可以指定安装到特定子目录:

  1. target("test")
  2. add_installfiles("src/*.h", {prefixdir = "include"})
  3. add_installfiles("doc/*.md", {prefixdir = "share/doc"})

上面的设置,我们会安装到/usr/local/include/*.h, /usr/local/share/doc/*.md

我们也可以通过()去提取源文件中的子目录来安装,例如:

  1. target("test")
  2. add_installfiles("src/(tbox/*.h)", {prefixdir = "include"})
  3. add_installfiles("doc/(tbox/*.md)", {prefixdir = "share/doc"})

我们把src/tbox/*.h中的文件,提取tbox/*.h子目录结构后,在进行安装:/usr/local/include/tbox/*.h, /usr/local/share/doc/tbox/*.md

当然,用户也可以通过set_installdir接口,来配合使用。

关于此接口的详细说明,见:https://github.com/xmake-io/xmake/issues/318

target:add_headerfiles

添加安装头文件

2.2.5版本新增接口,用于针对每个target设置对应需要安装的头文件,一般用于xmake install/uninstall命令。

此接口使用方式跟add_installfiles接口几乎完全一样,都可以用来添加安装文件,不过此接口仅用于安装头文件。因此,使用上比add_installfiles简化了不少,默认不设置prefixdir,也会自动将头文件安装到对应的include子目录中。

并且此接口对于xmake project -k vs201x等插件生成的IDE文件,也会添加对应的头文件进去。

需要注意的是,之前的add_headers接口已经被废弃,新版本请用此接口替代,这个老接口在编译过程中也会自动复制头文件到build目录,这个逻辑设计的并不是很好。

target:set_configdir

设置模板配置文件的输出目录

2.2.5版本新增接口,主要用于add_configfiles接口设置的模板配置文件的输出目录。

target:set_configvar

设置模板配置变量

2.2.5版本新增接口,用于在编译前,添加一些需要预处理的模板配置变量,一般用于add_configfiles接口。

target:add_configfiles

添加模板配置文件

2.2.5版本新增接口,用于在编译前,添加一些需要预处理的配置文件,用于替代set_config_header等老接口。

因为此接口更加的通用,不仅用于处理config.h的自动生成和预处理,还可以处理各种文件类型,而set_config_header仅用于处理头文件,并且不支持模板变量替换。

先来一个简单的例子:

  1. target("test")
  2. set_kind("binary")
  3. add_files("src/*.c")
  4. set_configdir("$(buildir)/config")
  5. add_configfiles("src/config.h.in")

上面的设置,会在编译前,自动的将config.h.in这个头文件配置模板,经过预处理后,生成输出到指定的build/config/config.h

如果set_configdir不设置,那么默认输出到build目录下。

其中.in后缀会被自动识别处理掉,如果想要输出存储为其他文件名,可以通过:

  1. add_configfiles("src/config.h", {filename = "myconfig.h"})

的方式,来重命名输出,同样,这个接口跟add_installfiles类似,也是支持prefixdir和子目录提取设置:

  1. add_configfiles("src/*.h.in", {prefixdir = "subdir"})
  2. add_configfiles("src/(tbox/config.h)")

这个接口的一个最重要的特性就是,可以在预处理的时候,对里面的一些模板变量进行预处理替换,例如:

config.h.in

  1. #define VAR1 "${VAR1}"
  2. #define VAR2 "${VAR2}"
  3. #define HELLO "${HELLO}"
  1. set_configvar("VAR1", "1")
  2. target("test")
  3. set_kind("binary")
  4. add_files("main.c")
  5. set_configvar("VAR2", 2)
  6. add_configfiles("config.h.in", {variables = {hello = "xmake"}})
  7. add_configfiles("*.man", {copyonly = true})

通过set_configvar接口设置模板变量,裹着通过{variables = {xxx = ""}}中设置的变量进行替换处理。

预处理后的文件config.h内容为:

  1. #define VAR1 "1"
  2. #define VAR2 "2"
  3. #define HELLO "xmake"

{copyonly = true}设置,会强制将*.man作为普通文件处理,仅在预处理阶段copy文件,不进行变量替换。

默认的模板变量匹配模式为${var},当然我们也可以设置其他的匹配模式,例如,改为@var@匹配规则:

  1. target("test")
  2. add_configfiles("config.h.in", {pattern = "@(.-)@"})

我们也有提供了一些内置的变量,即使不通过此接口设置,也是可以进行默认变量替换的:

  1. ${VERSION} -> 1.6.3
  2. ${VERSION_MAJOR} -> 1
  3. ${VERSION_MINOR} -> 6
  4. ${VERSION_ALTER} -> 3
  5. ${VERSION_BUILD} -> set_version("1.6.3", {build = "%Y%m%d%H%M"}) -> 201902031421
  6. ${PLAT} and ${plat} -> MACOS and macosx
  7. ${ARCH} and ${arch} -> ARM and arm
  8. ${MODE} and ${mode} -> DEBUG/RELEASE and debug/release
  9. ${DEBUG} and ${debug} -> 1 or 0
  10. ${OS} and ${os} -> IOS or ios

例如:

config.h.in

  1. #define CONFIG_VERSION "${VERSION}"
  2. #define CONFIG_VERSION_MAJOR ${VERSION_MAJOR}
  3. #define CONFIG_VERSION_MINOR ${VERSION_MINOR}
  4. #define CONFIG_VERSION_ALTER ${VERSION_ALTER}
  5. #define CONFIG_VERSION_BUILD ${VERSION_BUILD}

config.h

  1. #define CONFIG_VERSION "1.6.3"
  2. #define CONFIG_VERSION_MAJOR 1
  3. #define CONFIG_VERSION_MINOR 6
  4. #define CONFIG_VERSION_ALTER 3
  5. #define CONFIG_VERSION_BUILD 201902031401

我们还可以对#define定义进行一些变量状态控制处理:

config.h.in

  1. ${define FOO_ENABLE}
  1. set_configvar("FOO_ENABLE", 1) -- or pass true
  2. set_configvar("FOO_STRING", "foo")

通过上面的变量设置后,${define xxx}就会替换成:

  1. #define FOO_ENABLE 1
  2. #define FOO_STRING "foo"

或者(设置为0禁用的时候)

  1. /* #undef FOO_ENABLE */
  2. /* #undef FOO_STRING */

这种方式,对于一些自动检测生成config.h非常有用,比如配合option来做自动检测:

  1. option("foo")
  2. set_default(true)
  3. set_description("Enable Foo")
  4. set_configvar("FOO_ENABLE", 1) -- 或者传递true,启用FOO_ENABLE变量
  5. set_configvar("FOO_STRING", "foo")
  6. target("test")
  7. add_configfiles("config.h.in")
  8. -- 如果启用foo选项 -> 添加 FOO_ENABLE FOO_STRING 定义
  9. add_options("foo")

config.h.in

  1. ${define FOO_ENABLE}
  2. ${define FOO_STRING}

config.h

  1. #define FOO_ENABLE 1
  2. #define FOO_STRING "foo"

关于option选项检测,以及config.h的自动生成,有一些辅助函数,可以看下:https://github.com/xmake-io/xmake/issues/342

除了#define,如果想要对其他非#define xxx也做状态切换处理,可以使用 ${default xxx 0} 模式,设置默认值,例如:

  1. HAVE_SSE2 equ ${default VAR_HAVE_SSE2 0}

通过set_configvar("HAVE_SSE2", 1)启用变量后,变为HAVE_SSE2 equ 1,如果没有设置变量,则使用默认值:HAVE_SSE2 equ 0

关于这个的详细说明,见:https://github.com/xmake-io/xmake/issues/320