Luamake 技能排查
- 作者仓库星标 208
- 许可证 MIT
- 作者仓库 luamake
Luamake Build System
基于 Lua 的构建系统,生成 Ninja 构建文件。
快速开始
local lm = require "luamake"
lm:exe "myapp" {
sources = { "src/*.c", "!src/test.c" },
includes = "include",
defines = { "DEBUG", "VERSION=1.0" },
}
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只控制链接顺序,不能保证编译前生成文件。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 引用,不单独链接:
-- 定义共享源码集
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 中:
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:
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 { ... } — 立即生效,影响全局
不带名称调用时,属性立即应用到当前工作区的所有后续目标,相当于设置全局默认值。
-- 所有参数均为可选,按项目实际需要填写
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 属性显式引用。
-- 定义命名配置(不会自动应用到任何目标)
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目录时,可在脚本开头修改构建目录: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 构建脚本后,必须运行构建命令验证脚本的正确性:
# 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/ 目录重新构建 |
- 流狐分类
- 通用
- 作者声明 Agent
- 未找到明确声明;不据此推断已兼容或已测试
- 静态检查
- 94 / 100 · 启发式扫描,不代表运行安全
- 作者 / 版本 / 许可
- @actboy168 · MIT
- 流狐 Token 估算
- 低消耗
- 流狐接入估算
- 需简单配置
- 是否需要外部 API Key
- 未发现要求
- 检测到的系统要求
- macOS · Linux · Windows
- 底层运行要求
- 未声明
- 检测到的文件与系统行为
-
- 只读
- Shell 执行
- 检测到的网络行为
- 仅限本地
- 安装命令数
- 无(仅作为资料)
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
作者没有在当前 SKILL.md 中定义固定输出样例。 快速开始
API · 说明 · 输出 lm:exe · 可执行文件 · app.exe / app lm:dll · 动态库 · lib.dll / lib.so / lib.dylib
目标属性
属性 · 说明 · 示例 sources · 源文件 · "src/.cpp", { "a.cpp", "b.cpp" } includes · 包含目录 · "include", { "include", "3rd" }
属性 · 说明 · 示例 links · 链接库 · { "pthread", "ws232" } linkdirs · 库搜索目录 · "lib", { "lib", "/usr/lib" }
属性 · 说明 · 示例 flags · 编译器标志 · { "-Wall", "-O2" } cflags · C 编译器标志 · "-std=c11"
# 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"` |
… 作者原文负责流程事实;流狐只索引当前章节、要点、文件与命令。
章节 -> 快速开始 → 目标类型 → 目标属性 → 源文件 → 链接 → 编译
要点 -> objdeps 用法 · 注意 · lm:sourceset · lm:luasrc · lm:luaembed · lm:phony · 立即应用到当前工作区的所有后续目标 · 适用场景
文件/命令 -> lm:exe · app.exe · app · lm:dll · lib.dll · lib.so · lib.dylib · lm:lib
内容 SHA-256 -> 1d4ecf597602
原文结构
适用与边界
原文中的明确线索
lm:exe、app.exe、app、lm:dll、lib.dll、lib.so、lib.dylib、lm:lib