xmake是一个基于Lua的轻量级现代化c/c++的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验。

本文我们会详细介绍下如何在项目构建过程中切换debug/release等常用构建模式,以及自定义其他编译模式。

* [项目源码](https://github.com/xmake-io/xmake)
* [官方文档](https://xmake.io/#/zh-cn/)

### 调试和发布模式

通常,如果我们是通过`xmake create`命令创建的项目,会在xmake.lua里面自动添加一行编译规则的配置,如下:

```lua
add_rules("mode.release", "mode.debug")
target("hello")
set_kind("binary")
add_files("src/*.c")
```

通过`add_rules`接口,我们默认添加了release和debug两个常用的内置规则,它们会在编译的时候附带上对应模式相关的一些编译flags,来开启优化用于发布或者调试编译。

如果仅仅执行了`xmake`命令,没有额外的配置,那么默认就会是release编译,等价于:

```bash
$ xmake f -m release
$ xmake
[ 0%]: ccache compiling.release src/main.cpp
[100%]: linking.release test
build ok!
```

如果我们要切换到debug编译模式,只需要:

```bash
$ xmake f -m debug
$ xmake
[ 0%]: ccache compiling.debug src/main.cpp
[100%]: linking.debug test
build ok!
```

上面的`-m/--mode=`参数就是用来设置编译模式,会跟`mode.release`和`mode.debug`这两个规则做关联。

那么,他们是如何关联上的呢?我们可以先来看下这两个规则的内部实现:

```lua
rule("mode.debug")
after_load(function (target)
if is_mode("debug") then
if not target:get("symbols") then
target:set("symbols", "debug")
end
if not target:get("optimize") then
target:set("optimize", "none")
end
end
end)

rule("mode.release")
after_load(function (target)
if is_mode("release") then
if not target:get("symbols") and target:targetkind() ~= "shared" then
target:set("symbols", "hidden")
end
if not target:get("optimize") then
if is_plat("android", "iphoneos") then
target:set("optimize", "smallest")
else
target:set("optimize", "fastest")
end
end
if not target:get("strip") then
target:set("strip", "all")
end
end
end)
```

可以看到,在target被加载阶段,xmake会去判断用户对`xmake f --mode=xxx`的参数配置,如果通过`is_mode()`接口获取到是debug模式,那么会禁用相关优化并且启用符号输出。
而如果是release模式,那么会开启编译优化并且strip掉所有调试符号。

### 定制化的模式配置

当然,内置的这两规则默认设置的这些编译配置,只能满足大部分场景的常规需求,如果用户想要在不同的编译模式下定制化一些个人的编译配置,那么需要自己在xmake.lua做判断。

例如,我们想在release下也启用调试符号,那么只需要:

```lua
if is_mode("release") then
set_symbols("debug")
end
```

或者额外增加一些编译flags:

```lua
if is_mode("release") then
add_cflags("-fomit-frame-pointer")
end
```

注:如果用户自己的配置和`mode.release`内置的配置冲突,会优先使用用户的设置。

当然,我们也可以完全不去通过`add_rules("mode.debug", "mode.release")`添加默认的配置规则,让用户完全自己控制模式配置:

```lua
-- 如果当前编译模式是debug
if is_mode("debug") then

-- 添加DEBUG编译宏
add_defines("DEBUG")

-- 启用调试符号
set_symbols("debug")

-- 禁用优化
set_optimize("none")
end

-- 如果是release或者profile模式
if is_mode("release", "profile") then

-- 如果是release模式
if is_mode("release") then

-- 隐藏符号
set_symbols("hidden")

-- strip所有符号
set_strip("all")

-- 忽略帧指针
add_cxflags("-fomit-frame-pointer")
add_mxflags("-fomit-frame-pointer")

-- 如果是profile模式
else
-- 启用调试符号
set_symbols("debug")
end

-- 添加扩展指令集
add_vectorexts("sse2", "sse3", "ssse3", "mmx")
end
```

### 其他内置模式规则

通过上文的例子,我们看到除了debug/release模式,还加了个profile模式的配置判断,其实xmake也提供了对应的内置模式,还有哪些,我们具体来看下:

#### mode.debug

为当前工程xmake.lua添加debug编译模式的配置规则,例如:

```lua
add_rules("mode.debug")
```

相当于:

```lua
if is_mode("debug") then
set_symbols("debug")
set_optimize("none")
end
```

我们可以通过:`xmake f -m debug`来切换到此编译模式。

#### mode.release

为当前工程xmake.lua添加release编译模式的配置规则,例如:

```lua
add_rules("mode.release")
```

相当于:

```lua
if is_mode("release") then
set_symbols("hidden")
set_optimize("fastest")
set_strip("all")
end
```

我们可以通过:`xmake f -m release`来切换到此编译模式。

#### mode.check

为当前工程xmake.lua添加check编译模式的配置规则,一般用于内存检测,例如:

```lua
add_rules("mode.check")
```

相当于:

```lua
if is_mode("check") then
set_symbols("debug")
set_optimize("none")
add_cxflags("-fsanitize=address", "-ftrapv")
add_mxflags("-fsanitize=address", "-ftrapv")
add_ldflags("-fsanitize=address")
end
```

我们可以通过:`xmake f -m check`来切换到此编译模式。

#### mode.profile

为当前工程xmake.lua添加profile编译模式的配置规则,一般用于性能分析,例如:

```lua
add_rules("mode.profile")
```

相当于:

```lua
if is_mode("profile") then
set_symbols("debug")
add_cxflags("-pg")
add_ldflags("-pg")
end
```

我们可以通过:`xmake f -m profile`来切换到此编译模式。

#### mode.coverage

为当前工程xmake.lua添加coverage编译模式的配置规则,一般用于覆盖分析,例如:

```lua
add_rules("mode.coverage")
```

相当于:

```lua
if is_mode("coverage") then
add_cxflags("--coverage")
add_mxflags("--coverage")
add_ldflags("--coverage")
end
```

我们可以通过:`xmake f -m coverage`来切换到此编译模式。

注:生成的gcno文件一般都是个obj所在目录对应的哦,因此需要从build目录下去找。

### 扩展自己的编译模式

xmake的模式配置,并没有固定值,用户可以随意传入和配置,只要`xmake f -m/--mode=xxx`传入的模式值和xmake.lua里面的`is_mode("xxx")`能对应上就行。

比如,我们设置了一个自己独有的编译模式`my_mode`,可以直接在命令行配置切换;

```bash
$ xmake f -m my_mode
$ xmake
[ 0%]: ccache compiling.my_mode src/main.cpp
[100%]: linking.my_mode test
build ok!
```

然后xmake.lua里面对相应的值进行判断即可:

```lua
if is_mode("my_mode") then
add_defines("ENABLE_MY_MODE")
end
```

### 使用模式变量

我们也可以直接在配置值中传递模式变量`$(mode)`,比如根据不同模式选择链接不同的库:

```lua
target("test")
set_kind("binary")
add_files("src/*.c")
add_links("xxx_$(mode)")
```

上面的配置,如果是调试模式编译就会选择链接:`libxxx_debug.a`库,而release下就会链接`libxxx_release.a`,当然,我们也可以设置到库搜索路径中,根据目录来选择对应的库。

```lua
target("test")
set_kind("binary")
add_files("src/*.c")
add_linkdirs("lib/$(mode)")
add_links("xxx")
```

另外,我们可以通过`get_config("mode")`直接获取到传入的模式配置值,并且这几种获取方式,在自定义脚本也是同样有效的哦,例如:

```lua
target("test")
set_kind("binary")
add_files("src/*.c")
on_load(function (target)
if is_mode("release") then
print(get_config("mode"), "$(mode)")
end
end)
```

原文:https://tboox.org/cn/2019/12/05/quickstart-8-switch-build-mode/
> [个人主页](https://tboox.org/)
> [个人项目](https://github.com/waruqi)

xmake从入门到精通8:切换编译模式的更多相关文章

  1. WPF MVVM从入门到精通1:MVVM模式简介

    原文:WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通3:数据绑定 W ...

  2. xmake从入门到精通9:交叉编译详解

    xmake是一个基于Lua的轻量级现代化c/c 的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验. 除了win, linux, macOS平台,以及an ...

  3. xmake从入门到精通12:通过自定义脚本实现更灵活地配置

    xmake是一个基于Lua的轻量级现代化c/c++的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验. 本文主要详细讲解下,如何通过添加自定义的脚本,在脚 ...

  4. xmake从入门到精通10:多个子工程目标的依赖配置

    xmake是一个基于Lua的轻量级现代化c/c++的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验. 本文主要详细讲解下,如果在一个项目中维护和生成多个 ...

  5. WPF MVVM从入门到精通8:数据验证

    原文:WPF MVVM从入门到精通8:数据验证 WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通3:数据绑定 WPF M ...

  6. WPF MVVM从入门到精通6:RadioButton等一对多控件的绑定

    原文:WPF MVVM从入门到精通6:RadioButton等一对多控件的绑定   WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM ...

  7. WPF MVVM从入门到精通7:关闭窗口和打开新窗口

    原文:WPF MVVM从入门到精通7:关闭窗口和打开新窗口 WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通3:数据绑定 ...

  8. WPF MVVM从入门到精通5:PasswordBox的绑定

    原文:WPF MVVM从入门到精通5:PasswordBox的绑定   WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通 ...

  9. WPF MVVM从入门到精通3:数据绑定

    原文:WPF MVVM从入门到精通3:数据绑定   WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通3:数据绑定 WPF ...

随机推荐

  1. Linux下修改文件权限,所有权

    Linux与Unix是多用户操作系统,所以文件的权限与所有权的实现就显得很有必要:每个文件主要与三组权限打交道,分别是用户(user),用户组(group),其他用户(other) 用户(u)是文件的 ...

  2. [考试反思]1017csp-s模拟测试77(lrd day1) :反抗

    说在前面:强烈谴责AK神Mr_zkt没有丝毫素质RP-- 然而我也想没素质一次,但是我没机会AK一套除了B组题以外的题... 太菜了,没权力.人家AK了人家就是牛逼你没话说 达哥的题必须好好写反思. ...

  3. JavaScript中继承的实现方法--详解

    最近看<JavaScript王者归来>中关于实现继承的方法,做了一些小总结: JavaScript中要实现继承,其实就是实现三层含义:1.子类的实例可以共享父类的方法:2.子类可以覆盖父类 ...

  4. 通俗易懂了解Vue组件的通信方式

    1.前言 Vue框架倡导组件化开发,力求将一个大的项目拆分成若干个小的组件,就如同我们小时玩堆积木一样,一个大房子是由若干个小积木组成.组件化开发最大问题就是组件之间数据能够流通,即组件之间能够通信. ...

  5. 如何在Vue项目中使用Typescript

    0.前言 本快速入门指南将会教你如何在Vue项目中使用TypeScript进行开发.本指南非常灵活,它可以将TypeScript集成到现有的Vue项目中任何一个阶段. 1.初始化项目 首先,创建一个新 ...

  6. 【Canvas真好玩】从黑客帝国开始

    前言 笔者之前有一段时间一直在学习Canvas相关的技术知识点,通过参考网上的一些资料文章,学着利用简单的数学和物理知识点实现了一些比较有趣的动画效果,最近刚好翻看到以前的代码,所以这次将这些代码实践 ...

  7. Kubernetes5-集群上搭建基于redis和docker的留言薄

    一.简介 1.环境依旧是kubernetes之前文章的架构 2.需要docker的镜像 1)php-forntend web 前端镜像 docker.io-kubeguide-guestbook-ph ...

  8. egret Tiledmap编写障碍物的思路

    egret Tiledmap编写障碍物的思路 获取控制对象下一刻移动的坐标,将其转换成瓦片坐标,如果getTileGIDAt(根据瓦片坐标获取瓦片id)的值不为0,说明对象将要移动的位置有障碍物,不做 ...

  9. java编程思想第四版第十八章总结

    一.概述 如何学习java I/O 学习I/O类库 学习I/O发展史,为什么要学习发展史呢? 因为,如果缺乏发展史,我们就会对什么时候使用哪个类,以及什么时候不该使用它们而感到迷惑. 了解nio 二. ...

  10. nyoj 82-迷宫寻宝(一) (多重BFS)

    82-迷宫寻宝(一) 内存限制:64MB 时间限制:1000ms 特判: No 通过数:3 提交数:5 难度:4 题目描述: 一个叫ACM的寻宝者找到了一个藏宝图,它根据藏宝图找到了一个迷宫,这是一个 ...