---
url: /zh/api/description/builtin-rules.md
---
# 内置规则 {#builtin-rules}

自从2.2.1版本后，xmake提供了一些内置规则去简化日常xmake.lua描述，以及一些常用构建环境的支持。

我们可以通过运行以下命令，查看完整的内置规则列表：

```sh
$ xmake show -l rules
```

内置规则通过 [add\_rules()](/zh/api/description/project-target#add-rules) 添加到目标中使用。如需创建自定义规则，请参阅[自定义规则接口](/zh/api/description/custom-rule)。相关的策略配置请参阅[内置策略](/zh/api/description/builtin-policies)。

## 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")
```

::: tip 注意
此模式默认不会带调试符号。
:::

相当于：

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

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

## mode.releasedbg

为当前工程xmake.lua添加releasedbg编译模式的配置规则，例如：

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

::: tip 注意
内置的 releasedbg 模式会生成一个没有任何符号的可执行程序，调试符号作为单独文件存在。
:::

它们在不同平台上表现一致的行为：

* **一个不带调试符号的最小发布程序 + 一个单独的调试符号文件。**
* **在 windows 上**: 发布程序 + .pdb 调试符号文件
* **在 macOS 上**: 发布程序 + .dSYM 调试符号文件
* **在 linux 上**: 发布程序 + .sym 调试符号文件

尽管在 Linux 上，可执行程序已经剥离了调试符号，但生成的 .sym 调试符号文件已经通过 objcopy 与可执行程序关联。我们可以正常使用 gdb 加载其调试符号。

```sh
/usr/bin/objcopy --only-keep-debug build/linux/x86_64/releasedbg/test build/linux/x86_64/releasedbg/test.sym
/usr/bin/strip -s build/linux/x86_64/releasedbg/test
/usr/bin/objcopy --add-gnu-debuglink=build/linux/x86_64/releasedbg/test.sym build/linux/x86_64/releasedbg/test
```

gdb 会自动加载 test.sym 符号文件。

```sh
gdb build/linux/x86_64/releasedbg/test
Reading symbols from build/linux/x86_64/releasedbg/test...
Reading symbols from /tmp/test/build/linux/x86_64/releasedbg/test.sym...
(gdb) b main
Breakpoint 1 at 0x10e0: file src/main.cpp, line 3.
(gdb) r
Starting program: /tmp/test/build/linux/x86_64/releasedbg/test 
Breakpoint 1, main (argc=1, argv=0x7ffd8daf0618) at src/main.cpp:3
3	int main(int argc, char **argv) {
(gdb) bt
#0  main (argc=1, argv=0x7ffd8daf0618) at src/main.cpp:3
(gdb) 
```

相当于：

```lua
if is_mode("releasedbg") then
    set_symbols("debug")
    set_optimize("fastest")
    set_strip("all")
end
```

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

如果你想要生成带调试符号的单个可执行文件，你可以在项目配置中轻松覆盖 releasedbg 模式。

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

if is_mode("releasedbg") then
    set_strip("none")
end
```

你也可以完全自定义 releasedbg 模式规则，而不使用内置的 mode.releasedbg。

## mode.minsizerel

为当前工程xmake.lua添加minsizerel编译模式的配置规则，例如：

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

::: tip 注意
与release模式相比，此模式更加倾向于最小代码编译优化，而不是速度优先。
:::

相当于：

```lua
if is_mode("minsizerel") then
    set_symbols("hidden")
    set_optimize("smallest")
    set_strip("all")
end
```

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

## 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`来切换到此编译模式。

## mode.valgrind

此模式提供valgrind内存分析检测支持。

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

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

## mode.asan

此模式提供AddressSanitizer内存分析检测支持。

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

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

## mode.tsan

此模式提供ThreadSanitizer内存分析检测支持。

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

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

## mode.lsan

此模式提供LeakSanitizer内存分析检测支持。

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

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

## mode.ubsan

此模式提供UndefinedBehaviorSanitizer内存分析检测支持。

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

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

## qt.static

用于编译生成Qt环境的静态库程序：

```lua
target("test")
    add_rules("qt.static")
    add_files("src/*.cpp")
    add_frameworks("QtNetwork", "QtGui")
```

## qt.shared

用于编译生成Qt环境的动态库程序：

```lua
target("test")
    add_rules("qt.shared")
    add_files("src/*.cpp")
    add_frameworks("QtNetwork", "QtGui")
```

## qt.console

用于编译生成Qt环境的控制台程序：

```lua
target("test")
    add_rules("qt.console")
    add_files("src/*.cpp")
```

## qt.quickapp

用于编译生成Qt环境的Quick(qml) ui应用程序。

```lua
target("test")
    add_rules("qt.quickapp")
    add_files("src/*.cpp")
    add_files("src/qml.qrc")
```

## qt.quickapp\_static

用于编译生成Qt环境的Quick(qml) ui应用程序（静态链接版本）。

::: tip 注意
需要切换到静态库版本Qt SDK
:::

```lua
target("test")
    add_rules("qt.quickapp_static")
    add_files("src/*.cpp")
    add_files("src/qml.qrc")
```

## qt.widgetapp

用于编译Qt Widgets(ui/moc)应用程序

```lua
target("test")
    add_rules("qt.widgetapp")
    add_files("src/*.cpp")
    add_files("src/mainwindow.ui")
    add_files("src/mainwindow.h")  -- 添加带有 Q_OBJECT 的meta头文件
```

## qt.widgetapp\_static

用于编译Qt Widgets(ui/moc)应用程序（静态库版本）

::: tip 注意
需要切换到静态库版本Qt SDK
:::

```lua
target("test")
    add_rules("qt.widgetapp_static")
    add_files("src/*.cpp")
    add_files("src/mainwindow.ui")
    add_files("src/mainwindow.h")  -- 添加带有 Q_OBJECT 的meta头文件
```

更多Qt相关描述见：[#160](https://github.com/xmake-io/xmake/issues/160)

## xcode.bundle

用于编译生成ios/macos bundle程序

```lua
target("test")
    add_rules("xcode.bundle")
    add_files("src/*.m")
    add_files("src/Info.plist")
```

## xcode.framework

用于编译生成ios/macos framework程序

```lua
target("test")
    add_rules("xcode.framework")
    add_files("src/*.m")
    add_files("src/Info.plist")
```

## xcode.application

用于编译生成ios/macos应用程序

```lua
target("test")
    add_rules("xcode.application")
    add_files("src/*.m", "src/**.storyboard", "src/*.xcassets")
    add_files("src/Info.plist")
```

## android.native\_app

用于构建 Android Native 应用程序。

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

add_requires("raylib 5.5.0")

target("raydemo_custom_glue")
    set_kind("binary")
    set_languages("c++17")
    add_files("src/main.cpp", "src/android_native_app_glue.c")
    add_syslinks("log")
    add_packages("raylib")
    add_rules("android.native_app", {
        android_sdk_version = "35",
        android_manifest = "android/AndroidManifest.xml",
        android_res = "android/res",
        keystore = "android/debug.jks",
        keystore_pass = "123456",
        package_name = "com.raylib.custom_glue",
        native_app_glue = false, -- 禁用默认 glue
        logcat_filters = {"raydemo_custom_glue", "raylib"}
    })
```

### 参数说明

* `android_sdk_version`: 设置 Android SDK 版本
* `android_manifest`: 设置 AndroidManifest.xml 文件路径
* `android_res`: 设置资源目录
* `keystore`: 设置签名密钥文件
* `keystore_pass`: 设置签名密钥密码
* `package_name`: 设置包名
* `native_app_glue`: 是否使用默认的 `android_native_app_glue` 库，默认为 true。如果设置为 false，则需要自己处理入口和事件循环。
* `logcat_filters`: 设置 logcat 过滤关键字

## wdk.env.kmdf

应用WDK下kmdf的编译环境设置，需要配合：`wdk.[driver|binary|static|shared]`等规则来使用。

## wdk.env.umdf

应用WDK下umdf的编译环境设置，需要配合：`wdk.[driver|binary|static|shared]`等规则来使用。

## wdk.env.wdm

应用WDK下wdm的编译环境设置，需要配合：`wdk.[driver|binary|static|shared]`等规则来使用。

## wdk.driver

编译生成windows下基于WDK环境的驱动程序，目前仅支持WDK10环境。

注：需要配合：`wdk.env.[umdf|kmdf|wdm]`等环境规则使用。

```lua
-- add target
target("echo")

    -- add rules
    add_rules("wdk.driver", "wdk.env.kmdf")

    -- add files
    add_files("driver/*.c")
    add_files("driver/*.inx")

    -- add includedirs
    add_includedirs("exe")
```

## wdk.binary

编译生成windows下基于WDK环境的可执行程序，目前仅支持WDK10环境。

注：需要配合：`wdk.env.[umdf|kmdf|wdm]`等环境规则使用。

```lua
-- add target
target("app")

    -- add rules
    add_rules("wdk.binary", "wdk.env.umdf")

    -- add files
    add_files("exe/*.cpp")
```

## wdk.static

编译生成windows下基于WDK环境的静态库程序，目前仅支持WDK10环境。

注：需要配合：`wdk.env.[umdf|kmdf|wdm]`等环境规则使用。

```lua
target("nonpnp")

    -- add rules
    add_rules("wdk.static", "wdk.env.kmdf")

    -- add flags for rule: wdk.tracewpp
    add_values("wdk.tracewpp.flags", "-func:TraceEvents(LEVEL,FLAGS,MSG,...)", "-func:Hexdump((LEVEL,FLAGS,MSG,...))")

    -- add files
    add_files("driver/*.c", {rule = "wdk.tracewpp"})
```

## wdk.shared

编译生成windows下基于WDK环境的动态库程序，目前仅支持WDK10环境。

注：需要配合：`wdk.env.[umdf|kmdf|wdm]`等环境规则使用。

```lua
target("nonpnp")

    -- add rules
    add_rules("wdk.shared", "wdk.env.wdm")

    -- add flags for rule: wdk.tracewpp
    add_values("wdk.tracewpp.flags", "-func:TraceEvents(LEVEL,FLAGS,MSG,...)", "-func:Hexdump((LEVEL,FLAGS,MSG,...))")

    -- add files
    add_files("driver/*.c", {rule = "wdk.tracewpp"})
```

## wdk.tracewpp

用于启用tracewpp预处理源文件：

```lua
target("nonpnp")

    -- add rules
    add_rules("wdk.driver", "wdk.env.kmdf")

    -- add flags for rule: wdk.tracewpp
    add_values("wdk.tracewpp.flags", "-func:TraceEvents(LEVEL,FLAGS,MSG,...)", "-func:Hexdump((LEVEL,FLAGS,MSG,...))")

    -- add files
    add_files("driver/*.c", {rule = "wdk.tracewpp"})
    add_files("driver/*.rc")
```

更多WDK规则描述见：[#159](https://github.com/xmake-io/xmake/issues/159)

## win.sdk.application

编译生成winsdk应用程序。

```lua
-- add rules
add_rules("mode.debug", "mode.release")

-- define target
target("usbview")

    -- windows application
    add_rules("win.sdk.application")

    -- add files
    add_files("*.c", "*.rc")
    add_files("xmlhelper.cpp", {rule = "win.sdk.dotnet"})
```

## wdk.sdk.dotnet

用于指定某些c++源文件作为c++.net来编译。

```lua
add_files("xmlhelper.cpp", {rule = "win.sdk.dotnet"})
```

## plugin.vsxmake.autoupdate

我们可以使用此规则，在通过 `xmake project -k vsxmake` 生成的 vs 工程中，自动更新 vs 工程文件（当每次构建完成）。

```lua
add_rules("plugin.vsxmake.autoupdate")
target("test")
    set_kind("binary")
    add_files("src/*.c")
```

## plugin.compile\_commands.autoupdate

我们也可以使用这个规则来自动更新生成 `compile_commands.json`

```lua
add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
target("test")
    set_kind("binary")
    add_files("src/*.c")
```

## utils.symbols.export\_all

v2.5.2 以上版本提供，我们可以用它自动导出所有的动态库符号，目前仅支持 windows dll 目标程序的符号导出，即使没有在代码中通过 `__declspec(dllexport)` 导出接口，
xmake 也会自动导出所有 c/c++ 接口符号。

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

target("foo")
    set_kind("shared")
    add_files("src/foo.c")
    add_rules("utils.symbols.export_all")

target("test")
    set_kind("binary")
    add_deps("foo")
    add_files("src/main.c")
```

c++

```lua
add_rules("utils.symbols.export_all", {export_classes = true})
```

相关 issue [#1123](https://github.com/xmake-io/xmake/issues/1123)

2.9.5 之后的版本还支持自定义过滤器，去针对性过滤需要导出的符号名和源文件名：

```lua
target("bar")
    set_kind("shared")
    add_files("src/bar.cpp")
    add_rules("utils.symbols.export_all", {export_filter = function (symbol, opt)
        local filepath = opt.sourcefile or opt.objectfile
        if filepath and filepath:find("bar.cpp", 1, true) and symbol:find("add", 1, true) then
            print("export: %s at %s", symbol, filepath)
            return true
        end
    end})
```

## utils.symbols.export\_list

我们可以在 xmake.lua 里面直接定义导出的符号列表，例如：

```lua
target("foo")
    set_kind("shared")
    add_files("src/foo.c")
    add_rules("utils.symbols.export_list", {symbols = {
        "add",
        "sub"}})
```

或者，在 `*.export.txt` 文件中添加导出的符号列表。

```lua
target("foo2")
    set_kind("shared")
    add_files("src/foo.c")
    add_files("src/foo.export.txt")
    add_rules("utils.symbols.export_list")
```

完整的工程例子见：[导出符号例子](https://github.com/xmake-io/xmake/tree/dev/tests/projects/c/shared_library_export_list)

## utils.install.cmake\_importfiles

v2.5.3 以上版本可以使用此规则在安装 target 目标库文件的时候，导出 .cmake 文件，用于其他 cmake 项目的库导入和查找。

## utils.install.pkgconfig\_importfiles

v2.5.3 以上版本可以使用此规则在安装 target 目标库文件的时候，导出 pkgconfig/.pc 文件，用于其他项目的库导入和查找。

## utils.bin2c

v2.5.7 以上版本可以使用此规则，在项目中引入一些二进制文件，并见他们作为 c/c++ 头文件的方式提供开发者使用，获取这些文件的数据。

比如，我们可以在项目中，内嵌一些 png/jpg 资源文件到代码中。

```lua
target("console")
    set_kind("binary")
    add_rules("utils.bin2c", {extensions = {".png", ".jpg"}})
    add_files("src/*.c")
    add_files("res/*.png", "res/*.jpg")
```

::: tip 注意
extensions 的设置是可选的，默认后缀名是 .bin
:::

然后，我们就可以通过 `#include "filename.png.h"` 的方式引入进来使用，xmake 会自动帮你生成对应的头文件，并且添加对应的搜索目录。

```c
static unsigned char g_png_data[] = {
    #include "image.png.h"
};

int main(int argc, char** argv) {
    printf("image.png: %s, size: %d\n", g_png_data, sizeof(g_png_data));
    return 0;
}
```

生成头文件内容类似：

```sh
cat build/.gens/test/macosx/x86_64/release/rules/c++/bin2c/image.png.h
  0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x78, 0x6D, 0x61, 0x6B, 0x65, 0x21, 0x0A, 0x00
```

:::tip 提示
如果你使用支持 C23 `#embed` 特性的编译器（如 clang 或 gcc），也可以直接使用 `#embed` 指令来嵌入二进制文件。需要先通过 `set_languages("c23")` 设置 C23 语言标准，然后使用 [add\_embeddirs](project-target.md#add_embeddirs) 来设置搜索路径。这种方式更符合 C23 标准，无需生成额外的头文件。
:::

### 转换函数&#x20;

在v3.1.0中，xmake添加了转换函数接口。利用该接口，可以自定义被生成为头文件的二进制数据。用法请参考 [utils.bin2obj](#转换函数-1)

## utils.bin2obj

v3.0.6 以上版本可以使用此规则，相比 `utils.bin2c` 具有极快的构建速度。因为它跳过了 C 代码生成和编译步骤，直接生成对象文件（COFF, ELF, Mach-O）参与链接。

**性能对比 (120MB 文件):**

* **bin2obj**: ~1.8s
* **bin2c**: ~354s

它支持多种架构（x86, ARM, RISC-V 等）和格式（Windows COFF, Linux/Android ELF, macOS/iOS Mach-O）。

**基本用法**

```lua
target("myapp")
    set_kind("binary")
    add_rules("utils.bin2obj", {extensions = {".bin", ".ico"}})
    add_files("src/*.c")
    -- 嵌入 data.bin，并确保以零结尾
    add_files("assets/data.bin", {zeroend = true})
```

**在 C/C++ 中访问数据**

符号名称会根据文件名自动生成（例如 `_binary_<filename>_start` 和 `_binary_<filename>_end`）。

```c
#include <stdio.h>
#include <stdint.h>

extern const uint8_t _binary_data_bin_start[];
extern const uint8_t _binary_data_bin_end[];

int main() {
    // 计算大小
    const uint32_t size = (uint32_t)(_binary_data_bin_end - _binary_data_bin_start);
    
    // 访问数据
    printf("Data size: %u bytes\n", size);
    for (uint32_t i = 0; i < size; i++) {
        printf("%02x ", _binary_data_bin_start[i]);
    }
    return 0;
}
```

此外，`glsl2spv` 和 `hlsl2spv` 规则也新增了对 `bin2obj` 的支持，可以直接将编译后的 SPIR-V 文件作为对象文件嵌入。

### 转换函数&#x20;

在v3.1.0中，xmake添加了转换函数接口。利用该接口，可以自定义被生成为对象文件的二进制数据，如使用LZ4（[core.compress.lz4](../scripts/extension-modules/core/compress/lz4.md)）压缩文件后再生成为对象文件，嵌入程序中。

#### 内联转换函数

转换函数可内联在描述域中，适合简单的转换：

```lua
target("test")
    set_kind("binary")
    add_rules("utils.bin2obj")
    add_files("src/*.c")
    add_files("src/asset.bin", {transform = function (inputfile, outputfile, opt)
        import("core.base.bytes")
        local data = io.readfile(inputfile, {encoding = "binary"})
        io.writefile(outputfile, data:reverse(), {encoding = "binary"})
    end})
```

::: tip 警告
内联转换函数无法用于生成的第三方工程文件（见[生成IDE工程文件](../../guide/extensions/builtin-plugins.md#generate-ide-project-files)）。如有需要，请使用Lua文件形式
:::

#### Lua文件形式

对于更加复杂的转化，可以将转换函数单独写在Lua文件中：

`xmake.lua`:

```lua
target("test")
    set_kind("binary")
    add_rules("utils.bin2obj")
    add_files("src/*.c")
    add_files("src/asset.bin", {transform = path.join(os.projectdir(), "transform.lua")})
```

`transform.lua`:

```lua
function main(inputfile, outputfile)
    import("core.base.bytes")
    local data = io.readfile(inputfile, {encoding = "binary"})
    io.writefile(outputfile, data:reverse(), {encoding = "binary"})
end
```

#### 规则级转换函数

转换函数不仅可作用于文件或者文件组，还可以写成以下的形式，以作用于整个规则：

```lua
add_rules("utils.bin2obj", {
    transform = path.join(os.projectdir(), "transform.lua")
})
```

文件级的配置优先级高于规则级，因此规则级的转换函数仍然可以被某个具体文件覆盖。

::: tip 提示

* 在使用`io.readfile`或`io.writefile`处理二进制时，记得加入`{encoding = "binary"}`参数
* 使用Lua形式转换函数时，最好传入由`path.join(os.projectdir(), <路径>)`得到的绝对路径
* 可参考xmake提供的二进制处理API：[core.base.bytes](../scripts/extension-modules/core/base/bytes.md)
* 转换函数的最后一个参数是附加的 `opt` 表，其中 `opt.target` 是当前正在构建的 target 实例
* 转换后的文件会写到目标的自动生成目录下，并纳入依赖追踪，只有源文件真正变化时才会重新执行
* 它底层是基于 [batchcmds:call](custom-rule.md#batchcmds-call) 实现的，我们在自己的规则里也可以使用这个接口
  :::

## utils.replace&#x20;

此规则会在源码送入编译器之前对其做文本替换。替换后的文件会写到目标的自动生成目录下，同时原始文件所在目录会被自动加入 `includedirs`，所以替换后文件里的相对 `#include` 依然能正确解析。

规则带有依赖追踪，只有源文件或替换列表真正发生变化时，才会重新执行替换。

### Lua 模式替换（默认）

```lua
target("foo")
    set_kind("binary")
    add_files("src/foo.c", {rules = "utils.replace", replaces = {
        {"old_pattern", "new_text"},
    }})
```

### 纯文本替换

传入 `replace_plain = true` 时，匹配模式会被当作字面字符串处理，而不再是 Lua 模式。

```lua
target("foo")
    set_kind("binary")
    add_files("src/foo.c", {rules = "utils.replace",
        replaces = {{"old text", "new text"}},
        replace_plain = true})
```

### 函数式转换

`replaces` 也可以是一个函数，接收文件内容并返回替换后的内容。

```lua
target("foo")
    set_kind("binary")
    add_files("src/foo.c", {rules = "utils.replace", replaces = function (content)
        content = content:gsub("old", "new")
        return content
    end})
```

xmake 自身正是借助这条规则在新版 Lua 5.5 运行时下打补丁 `lparser.c`，从而保留 for-in 循环变量可以被重新赋值的特性。

## utils.glsl2spv

v2.6.1 以上版本可以使用此规则，在项目中引入 `*.vert/*.frag` 等 glsl shader 文件，然后实现自动编译生成 `*.spv` 文件。

另外，我们还支持以 C/C++ 头文件的方式，二进制内嵌 spv 文件数据，方便程序使用。

### 编译生成 spv 文件

xmake 会自动调用 glslangValidator 或者 glslc 去编译 shaders 生成 .spv 文件，然后输出到指定的 `{outputdir = "build"}` 目录下。

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

add_requires("glslang", {configs = {binaryonly = true}})

target("test")
    set_kind("binary")
    add_rules("utils.glsl2spv", {outputdir = "build"})
    add_files("src/*.c")
    add_files("src/*.vert", "src/*.frag")
    add_packages("glslang")
```

注，这里的 `add_packages("glslang")` 主要用于引入和绑定 glslang 包中的 glslangValidator，确保 xmake 总归能够使用它。

当然，如果用户自己系统上已经安装了它，也可以不用额外绑定这个包，不过我还是建议添加一下。

### 编译生成 c/c++ 头文件

我们也可以内部借助 bin2c 模块，将编译后的 spv 文件生成对应的二进制头文件，方便用户代码中直接引入，我们只需要启用 `{bin2c = true}`。:w

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

add_requires("glslang", {configs = {binaryonly = true}})

target("test")
    set_kind("binary")
    add_rules("utils.glsl2spv", {bin2c = true})
    add_files("src/*.c")
    add_files("src/*.vert", "src/*.frag")
    add_packages("glslang")
```

然后我们可以在代码这么引入：

```c
static unsigned char g_test_vert_spv_data[] = {
    #include "test.vert.spv.h"
};

static unsigned char g_test_frag_spv_data[] = {
    #include "test.frag.spv.h"
};
```

跟 bin2c 规则的使用方式类似，完整例子见：[glsl2spv example](https://github.com/xmake-io/xmake/tree/master/tests/projects/other/glsl2spv)

## utils.hlsl2spv

除了 `utils.glsl2spv` 规则，我们现在还支持 `utils.hlsl2spv` 规则。

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

add_requires("directxshadercompiler")

target("test")
    set_kind("binary")
    add_rules("utils.hlsl2spv", {bin2c = true})
    add_files("src/*.c")
    add_files("src/*.hlsl")
    add_packages("directxshadercompiler")
```

## python.library

我们可以用这个规则，配合 pybind11 生成 python 库模块，它会调整 python 库的模块名。

```lua
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：

```lua
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")
```

## nodejs.module

构建 nodejs 模块。

```lua
add_requires("node-addon-api")

target("foo")
    set_languages("cxx17")
    add_rules("nodejs.module")
    add_packages("node-addon-api")
    add_files("*.cc")
end
```

## utils.ipsc

ipsc 编译器规则支持，使用方式如下：

```lua
target("test")
    set_kind("binary")
    add_rules("utils.ispc", {header_extension = "_ispc.h"})
    set_values("ispc.flags", "--target=host")
    add_files("src/*.ispc")
    add_files("src/*.cpp")
```
