# Luamake

> Luamake 构建系统指南——用于当前项目的 `luamake` / `make.lua` / Ninja 生成流程。当用户需要编写、修改、排查或理解 `make.lua`、目标定义、`lm:conf`、`deps` / `objdeps`、代码生成、Lua C 模块、Bee 运行时集成，或需要解决当前项目中由 `luamake` 驱动的构建问题时，使用此 skill。即使用户没有明确提到 `luamake`，但上下文明显是在处理本项目的构建脚本、构建目录、目标依赖或 `luamake` 生成的 Ninja 流程，也应使用此 skill。不要把它用于纯通用的 C/C++ 编译知识、与本项目无关的 CMake / xmake / Bazel / Meson 问题，或仅讨论编译器理论而未涉及 `luamake` / `make.lua` 的请求。 Use when this capability is needed.

- Skill: `tomevault-io/luamake` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/luamake`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/luamake/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/luamake

---

# Luamake Build System

基于 Lua 的构建系统，生成 Ninja 构建文件。

## 快速开始

```lua
local lm = require "luamake"

lm:exe "myapp" {
    sources = { "src/*.c", "!src/test.c" },
    includes = "include",
    defines = { "DEBUG", "VERSION=1.0" },
}
```

```bash
luamake          # 构建
luamake clean    # 清理
luamake rebuild  # 重建
```

---

## 目标类型

| API | 说明 | 输出 |
|-----|------|------|
| `lm:exe` | 可执行文件 | `app.exe` / `app` |
| `lm:dll` | 动态库 | `lib.dll` / `lib.so` / `lib.dylib` |
| `lm:lib` | 静态库 | `lib.lib` / `lib.a` |
| `lm:source_set` | 源码集（不链接，用于复用，通过 `deps` 引用） | 无 |
| `lm:lua_src` | Lua C 模块（静态嵌入到 `lm:lua_exe`） | 无 |
| `lm:lua_dll` | Lua C 模块（动态加载） | `module.dll` / `module.so` |
| `lm:lua_exe` | 内嵌 Lua 的可执行文件 | `app.exe` / `app` |
| `lm:lua_embed` | Lua 嵌入资源（按命名组嵌入 Lua 文件，生成 source_set；自动导出 `includes`/`objdeps`） | 无（source_set） |
| `lm:phony` | 伪目标（聚合依赖） | 无 |

---

## 目标属性

### 源文件

| 属性 | 说明 | 示例 |
|------|------|------|
| `sources` | 源文件 | `"src/*.cpp"`, `{ "a.cpp", "b.cpp" }` |
| `includes` | 包含目录 | `"include"`, `{ "include", "3rd" }` |
| `sysincludes` | 系统包含目录（抑制警告） | `"/usr/local/include"` |
| `defines` | 预处理器定义 | `{ "DEBUG", "VER=1" }` |
| `objdeps` | 对象依赖（编译前必须生成） | `"generated_header"` |

> **`objdeps` 用法**：当源文件依赖代码生成产物（如生成的头文件）时，需用 `objdeps` 声明依赖的目标名，确保生成步骤在编译前完成。`deps` 只控制链接顺序，不能保证编译前生成文件。
> ```lua
> lm:rule "gen_header" { ... }  -- 生成头文件的规则
> lm:exe "app" {
>     sources = "src/*.cpp",
>     objdeps = "gen_header",  -- 编译 src/*.cpp 前先执行 gen_header
> }
> ```
>
> **注意**：`lm:lua_embed` 目标会自动导出 `includes` 和 `objdeps`，通过 `deps` 依赖它的目标无需手动声明这两项。详见下方 `lm:lua_embed` 用法。

### 链接

| 属性 | 说明 | 示例 |
|------|------|------|
| `links` | 链接库 | `{ "pthread", "ws2_32" }` |
| `linkdirs` | 库搜索目录 | `"lib"`, `{ "lib", "/usr/lib" }` |
| `ldflags` | 链接器标志 | `"-Wl,--as-needed"` |
| `frameworks` | macOS/iOS 框架 | `{ "Foundation", "Cocoa" }` |
| `deps` | 目标依赖 | `"lib1"`, `{ "lib1", "lib2" }` |

### 编译

| 属性 | 说明 | 示例 |
|------|------|------|
| `flags` | 编译器标志 | `{ "-Wall", "-O2" }` |
| `cflags` | C 编译器标志 | `"-std=c11"` |
| `cxxflags` | C++ 编译器标志 | `"-std=c++20"` |
| `confs` | 引用命名配置 | `"myconfig"` |

> **注意**：`cflags`/`cxxflags` 直接传递给编译器命令行。在 `lm:conf` 中可用 `c = "c11"` / `cxx = "c++20"` 作为简写，luamake 会自动转换为对应编译器的标准标志（如 MSVC 的 `/std:c11`）。

### 特殊目标用法

**`lm:source_set`** — 将源文件组织为可复用的源码集，通过 `deps` 引用，不单独链接：

```lua
-- 定义共享源码集
lm:source_set "common" {
    includes = "include",
    sources = { "src/common/*.cpp" },
}

-- 多个目标复用同一组源文件
lm:exe "app1" { deps = "common", sources = "src/app1.cpp" }
lm:exe "app2" { deps = "common", sources = "src/app2.cpp" }
```

**`lm:lua_src`** — 将 Lua C 模块静态嵌入到 `lm:lua_exe` 中：

```lua
lm:lua_src "mymodule" {
    sources = "src/mymodule.c",
}

lm:lua_exe "app" {
    deps = "mymodule",
    sources = "src/main.cpp",
}
```

**`lm:lua_embed`** — 将 Lua 文件按命名组嵌入到 C 源码中，生成一个 source_set 供其他目标依赖。`data` 下每个 key 是一个组，组名直接成为生成的 `lua_embed_bundle` 结构体的字段名。每组可独立设置 `bytecode = true`。`bee_glue = true` 启用 bee 胶水层，约定 `data.preload` 注入 `_PRELOAD`、`data.main[1]` 作为入口。自动向依赖方导出 `includes` 和 `objdeps`，通过 `deps` 依赖时无需手动声明。**完整规则（分组语义、`pattern` 语法、字节码取舍、bee_glue 契约、无胶水时的接入姿势）见 `references/advanced/lua_embed.md`**：

```lua
lm:lua_embed "myembed" {
    bee_glue = true,
    data = {
        main    = { bytecode = true, "src/main.lua" },
        preload = { bytecode = true, { dir = "lualib" } },
        data    = { { name = "config.json", file = "assets/config.json" } },
    },
}

lm:lua_src "glue" {
    deps     = "myembed",       -- 自动获取 includes 和 objdeps
    includes = "3rd/bee.lua",
    sources  = "src/glue.cpp",
}
```

lm:lua_exe "app" {
    deps = { "glue", "myembed" },
    sources = "src/main.cpp",
}
```

**`lm:phony`** — 聚合多个目标为一个命名依赖，方便统一引用：

```lua
lm:phony "all_libs" {
    deps = { "libfoo", "libbar", "libqux" },
}

lm:exe "app" {
    deps = "all_libs",
    sources = "main.cpp",
}
```

---

## 配置 (lm:conf)

`lm:conf` 有两种用法，行为完全不同，不要混淆：

### 匿名配置：`lm:conf { ... }` — 立即生效，影响全局

不带名称调用时，属性**立即应用到当前工作区的所有后续目标**，相当于设置全局默认值。

```lua
-- 所有参数均为可选，按项目实际需要填写
lm:conf {
    c = "c11",        -- C 标准："c89", "c99", "c11", "c17"
    cxx = "c++20",    -- C++ 标准："c++11", "c++14", "c++17", "c++20"
    visibility = "hidden",  -- 符号可见性："hidden"（默认隐藏）或 "default"（默认可见）
}

-- 以下目标自动继承上面的配置
lm:exe "app1" { sources = "src/app1.cpp" }
lm:exe "app2" { sources = "src/app2.cpp" }
```

**适用场景**：项目中大部分目标共享相同的编译标准、模式等基础配置时使用。

### 命名配置：`lm:conf "name" { ... }` — 按需引用，不自动生效

带名称调用时，属性**不会立即生效**，仅存储起来，需要目标通过 `confs` 属性显式引用。

```lua
-- 定义命名配置（不会自动应用到任何目标）
lm:conf "mylib" {
    defines = "MYLIB_API",
    includes = "3rd/mylib",
}

-- 通过 confs 引用，只有这个目标会使用该配置
lm:exe "app" {
    confs = "mylib",
    sources = "main.cpp",
}
```

**适用场景**：多个目标需要共享同一组特定配置（如第三方库的头文件路径和宏定义），但不希望污染全局时使用。

### 如何选择

| 场景 | 用法 |
|------|------|
| 设置项目范围的 C/C++ 标准、构建模式等 | `lm:conf { ... }` |
| 为特定的几个目标共享一组 includes/defines | `lm:conf "name" { ... }` + `confs = "name"` |
| 只有一个目标需要特定配置 | 直接写在目标属性里，无需 conf |

---

## 内置变量

### 路径变量

| 变量 | 说明 | 示例 |
|------|------|------|
| `$builddir` | 构建目录（默认 `build`，可自定义） | `build` |
| `$bindir` | 二进制输出目录 | `build/bin` |
| `$objdir` | 对象文件目录 | `build/obj` |
| `$bin` | `$bindir` 别名 | |
| `$obj` | `$objdir` 别名 | |
| `$in` | 输入文件 (规则中) | |
| `$out` | 输出文件 (规则中) | |

> **自定义构建目录**：当项目已使用 `build` 目录时，可在脚本开头修改构建目录：
> ```lua
> lm.builddir = "_build"   -- 构建产物将输出到 _build/ 目录
> ```
> `$bindir` 和 `$objdir` 默认基于 `$builddir`，修改后会自动跟随变化。

### 全局变量

| 变量 | 说明 | 示例值 |
|------|------|--------|
| `lm.os` | 目标 OS | `"windows"`, `"linux"`, `"macos"`, `"ios"`, `"android"` |
| `lm.compiler` | 编译器 | `"msvc"`, `"gcc"`, `"clang"` |
| `lm.arch` | 架构 | `"x86_64"`, `"x86"`, `"arm64"` |
| `lm.mode` | 构建模式 | `"debug"`, `"release"` |
| `lm.workdir` | 工作目录 | 项目根目录 |

---

## 开发工作流

编写或修改 `make.lua` 构建脚本后，**必须**运行构建命令验证脚本的正确性：

```bash
# 1. 运行构建，验证脚本是否有语法错误或配置问题
luamake

# 2. 如果构建失败，根据错误信息修复脚本后重新运行
luamake

# 3. 如果需要从干净状态重建（排除增量构建的干扰）
luamake rebuild
```

### 注意事项

- **Windows 平台**：必须使用 **PowerShell** 运行 `luamake` 命令，不要使用 Git Bash。
- 每次修改 `make.lua` 后都要运行 `luamake` 确认构建成功，不要只写脚本不验证。
- 关注构建输出中的**警告和错误信息**，它们通常指向配置问题（如路径错误、缺少依赖等）。
- 如果构建失败，优先分析错误信息，修复后再次运行验证，直到构建通过。

---

# 最佳实践

| 主题 | 文档 | 包含内容 |
|------|------|----------|
| 依赖管理 | `references/best_practices/bp_dependency.md` | deps 定义顺序、源码集复用、增量源码集、动态模块发现 |
| 条件编译与静态分析 | `references/best_practices/bp_compilation.md` | 条件编译、静态分析集成 |
| 代码生成与 objdeps | `references/best_practices/bp_codegen.md` | 代码生成管道、objdeps 用法 |
| Lua 模块与测试 | `references/best_practices/bp_lua_and_test.md` | Lua C 模块、内置测试框架 |

### 其他详细文档

| 主题 | 文档 |
|------|------|
| Bee 运行时库（API 参考来源、模块列表、Meta 文件用法） | `references/advanced/bee_runtime.md` |
| `lm:lua_embed` 权威参考（分组 / pattern / bytecode / bee_glue / 自定义接入） | `references/advanced/lua_embed.md` |

---

## Bee 运行时库

`luamake lua script.lua` 运行脚本时预加载 bee 库。API 参考来源及模块列表详见 `references/advanced/bee_runtime.md`。

### 适用边界

优先在以下场景使用本 skill：

- 当前仓库明确使用 `luamake` 或通过 `make.lua` 定义构建目标。
- 用户正在修改 `make.lua`、排查 `luamake` 报错，或理解 `deps`、`objdeps`、`lm:conf`、目标类型、构建目录等机制。
- 用户讨论的问题与当前项目的 Ninja 生成流程、Bee 集成或 Lua C 模块构建直接相关。

以下场景通常不应使用本 skill：

- 与当前项目无关的通用 C/C++ 编译、链接、优化理论问题。
- 纯 `CMake`、`xmake`、`Bazel`、`Meson` 等其他构建系统的问题。
- 只是在问编译器语法、语言标准或平台 API，而没有落到 `luamake` / `make.lua` 的构建脚本上。

---

## 故障排除

| 问题 | 解决方案 |
|------|----------|
| "no source files found" | 检查 glob 模式，确认 `rootdir`，检查文件扩展名 |
| Windows 链接错误 | 添加系统库：`links = { "ws2_32", "iphlpapi", "user32" }` |
| 交叉编译问题 | 使用平台特定配置，检查 `lm.compiler` |
| 缺少生成文件 | 添加 `objdeps` 确保生成后再编译 |
| `build` 目录冲突 | 项目已使用 `build` 目录时，用 `lm.builddir = "_build"` 修改构建目录 |
| 找不到头文件 | 检查 `includes` 路径，使用绝对路径或 `$builddir` |
| Ninja 构建失败 | 删除 `build/` 目录重新构建 |

---
> Source: [actboy168/luamake](https://github.com/actboy168/luamake) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-06-22 -->

