Luban

Windows-first 的 C++ 工具链管理器 + cmake/vcpkg 辅助前端。 单一静态链接二进制,零 UAC,XDG-first 目录布局。

luban 解决什么问题

如果你在 Windows 上配过现代 C++ 工具链,你就知道墙在哪:

  • 选 LLVM-MinGW 还是 MSVC 还是 mingw-w64
  • 各自下 cmake / ninja / clangd / vcpkg
  • 才发现 vcpkg 还要 git
  • 学 cmake 的怪 variable / find_package / target_link_libraries
  • 学 vcpkg.json schema、triplets、overlay ports
  • 学 CMakePresets
  • 才意识到 clangd 要 compile_commands.json 才有补全
  • 然后所有这些都不在 PATH 上——每个新 shell 还得 source 个 activate

每件事是半天的 yak-shaving。整套堆起来要好几天,每台新机器要重来一遍。

luban 把这堆全活变成两条命令:

luban setup          # 一次性,装 LLVM-MinGW + cmake + ninja + mingit + vcpkg
luban env --user     # 一次性,把所有工具注入 user PATH(rustup 风格)

之后开任何新终端,cmake / clang++ / ninja / clangd 直接可用。每个项目里:

luban new app foo    # 脚手架;自动 build;clangd 立即可用
cd foo
luban add fmt        # 一行加依赖
luban build          # cmake 通过 vcpkg manifest mode 自动取 fmt

80% 的场景下,你永远不打开 CMakeLists.txt

luban 不是什么

  • 不是构建系统。 cmake + ninja 仍然干活;luban 只生成 cmake 胶水。
  • 不是包管理器。 vcpkg 仍然解析 + 构建 C++ 包;luban 替你编辑 vcpkg.json
  • 不是替代品。git clone 一个 luban 项目到一台没装 luban 的机器 上,只要 cmake + vcpkg 在,cmake --preset default 仍然能 build—— luban 生成的 luban.cmake 进 git 跟随项目。

设计哲学

原则含义
辅助而非主导cmake / vcpkg / ninja 仍是项目主角。luban 写一个标准 cmake module(luban.cmake)让用户 include(),删一行就退出。
不发明新 manifest依赖在 vcpkg.json(vcpkg 自己的 schema)里。luban.toml可选的,只放项目级偏好(warning 等级、sanitizers)。
luban.cmake 进 git项目可重现:clone 到没装 luban 的机器仍能 build。
XDG-first 目录~/.local/share/luban/(data)、~/.cache/luban/(cache)、~/.local/state/luban/(state)、~/.config/luban/(config)。XDG_* 环境变量优先。
零 UAC所有 luban-managed 文件落在用户可写目录。绝不弹 admin 提示。
单静态二进制一个 luban.exe 包一切。不依赖 Python / MSI / Visual Studio。

完整 8 条架构不变量见 设计总览

接下来

安装

luban 是一个静态链接的 Windows 单二进制(~3 MB)。无 installer,无 PATH 仪式,无需 admin。

前置

  • Windows 10(1809+)或 Windows 11,目前仅 x64
  • 网络(luban setup 要拉 ~250 MB 工具链)

就这。不需要 Python / Visual Studio / Chocolatey / Scoop。

安装方式

方式 A —— 直接下二进制

  1. GitHub Releases 下载 luban.exeluban-shim.exe
  2. 放到任意位置,例如 %USERPROFILE%\bin\luban.exe
  3. 接下来要么直接用全路径调,要么放到 PATH(方式 C 自动做这事)

方式 B —— 从源码编译

如果你已经有 C++ 工具链(MSVC / MinGW / Clang)+ cmake + ninja:

git clone https://github.com/Coh1e/luban.git
cd luban
cmake --preset release
cmake --build --preset release
:: build/release/luban.exe + luban-shim.exe

方式 C —— 单文件自举(推荐)

luban.exe setup            :: 装 LLVM-MinGW 22 + cmake 4.3 + ninja 1.13 + mingit 2.54 + vcpkg 2026.03
luban.exe env --user       :: rustup 风格 HKCU PATH 注入

之后任何新 shell 都能直接 cmake / clang / clangd / ninja / git / vcpkg。再也不用 source activate 脚本。

小贴士luban env --user 之后,把 luban.exe 自身也复制到 <data>\bin\,这样它也在 PATH 上:

copy luban.exe %LOCALAPPDATA%\luban\bin\luban.exe
copy luban-shim.exe %LOCALAPPDATA%\luban\bin\luban-shim.exe

验证

luban doctor

期望看到:

→ Canonical homes
  ✓ data    C:\Users\you\.local\share\luban
  ...
→ Installed components
  ✓ cmake                        4.3.2
  ✓ llvm-mingw                   20260421
  ✓ mingit                       2.54.0
  ✓ ninja                        1.13.2
  ✓ vcpkg                        2026.03.18
→ Tools on PATH
  ✓ clang          C:\Users\you\.local\share\luban\bin\clang.exe
  ...

如果某个工具显示 (not found)——先开个全新终端,env 改动只对新进程生效。

装在哪

%LOCALAPPDATA%\luban\
  toolchains\
    cmake-4.3.2-x86_64\          # cmake.exe + 共享数据
    llvm-mingw-20260421-x86_64\  # clang/clang++/clangd/lld + sysroot
    ninja-1.13.2-x86_64\
    mingit-2.54.0-x86_64\
    vcpkg-2026.03.18-x86_64\
  bin\                            # rustup 风格 shim 目录(env --user 后在 PATH 上)
    cmake.cmd / cmake.ps1 / cmake / cmake.exe ...
  env\                            # 生成的 activate 脚本
%USERPROFILE%\.cache\luban\downloads\
%USERPROFILE%\.local\state\luban\
%USERPROFILE%\.config\luban\

详细 XDG 解析见 English: paths reference

升级

luban self update          :: 自动从 GH releases 拉最新版,校 SHA256,原子换

卸载

luban self uninstall --yes              :: 完全清理(含工具链)
luban self uninstall --yes --keep-data  :: 留工具链,仅清 luban 自己 + PATH 注入

luban 从不写 <data> / <cache> / <state> / <config> / HKCU\Environment 之外的位置。self uninstall 是逆向操作。

快速上手

从全新 Windows 11 到一个链了 vcpkg 库的 hello-world C++ 项目,五条命令搞定。

前置

  • Windows 10/11 x64
  • luban.exe 在某处可达

五条命令

luban setup            :: 装工具链(~250 MB,~3 分钟)
luban env --user       :: 注 user PATH(一次性)

:: --- 此时关掉当前终端,开新终端 ---

luban new app hello    :: 脚手架 + 自动 build;clangd 即用
cd hello
luban add fmt          :: 编辑 vcpkg.json + 重生成 luban.cmake
luban build            :: cmake 通过 vcpkg 自动取 fmt + 编 + 链
build\default\src\hello\hello.exe

应该看到:

hello from hello!

现在改 src/hello/main.cpp 用上 fmt

#include <fmt/core.h>
#include <fmt/color.h>

int main() {
    fmt::print(fg(fmt::color::cyan), "hello from luban via vcpkg-installed fmt!\n");
    return 0;
}

再 build 跑:

luban build
build\default\src\hello\hello.exe

在编辑器里打开

NeovimVS Code 打开。两边都自动检测:

  • 项目根的 compile_commands.jsonluban build 后产生)→ clangd 直读
  • PATH 上的 clangd.exe → LSP 立即就位

clangd 启动后,对 fmt:: 应有自动补全 + 跳定义到 vcpkg 装的 fmt 头。

刚刚发生了什么

hello/
├── CMakeLists.txt          ← 用户拥有,4 行:project + include + register_targets
├── luban.cmake             ← luban 生成;find_package(fmt) + target_link_libraries
├── vcpkg.json              ← {"name":"hello", "version":"0.1.0", "dependencies":["fmt"]}
├── vcpkg-configuration.json ← baseline 锁定到具体 vcpkg commit(可重现性保证)
├── CMakePresets.json       ← Ninja generator + vcpkg toolchain(VCPKG_ROOT 在时启用)
├── compile_commands.json   ← 从 build/ 复制过来给 clangd
├── .gitignore
├── .clang-format
├── .clang-tidy
├── .vscode/
└── src/
    └── hello/
        ├── CMakeLists.txt   ← 用户拥有,2 行
        └── main.cpp

没打开 CMakeLists.txt没写 find_package 调用。没读 vcpkg manifest mode 文档。luban 全替你做了。

接下来

日常使用循环

一次性配置(luban setup + luban env --user)做完后,一周 luban 用法是什么样。

周一:起新项目

luban new app weekly-experiment
cd weekly-experiment
nvim src/weekly-experiment/main.cpp     # clangd 立即自动补全

luban new 末尾自动跑 luban build 一次,compile_commands.json 已落盘,clangd 一启动就能吃。

周二:要个 JSON parser

luban add nlohmann-json
luban build              # vcpkg 拉它 + 编 + cache(首次 ~30s)

luban add 改了 vcpkg.json 和重写了 luban.cmake你没打开 CMakeLists.txt没查 cmake target 名(是 nlohmann_json::nlohmann_json,luban 内置映射表替你处理)。

周三:拆出一个库

main.cpp 越来越长。把 parsing 逻辑抽成静态 lib:

luban target add lib parser

得到 src/parser/{parser.h, parser.cpp, CMakeLists.txt}。改这三个文件。然后 src/weekly-experiment/CMakeLists.txt一行

target_link_libraries(weekly-experiment PRIVATE parser)

luban build —— 两个 target 全编、exe 链 lib。

周四:写测试

luban add catch2
luban target add exe test-parser

test-parser 接到 parser + Catch2::Catch2WithMain。剩下都是标准 cmake。

周五:同事 clone 你的项目

同事的机器有 cmake + ninja + vcpkg,但没装 luban

git clone <你仓库>
cd weekly-experiment
cmake --preset default
cmake --build --preset default

直接 work。luban.cmake 进了 git,cmake 直 include;vcpkg 用同 baseline 拉同版本依赖。同事根本不知道 luban 存在

每天改了什么

luban 改的文件你改的文件
周一vcpkg.json luban.cmake(初始化)
周二vcpkg.json luban.cmakemain.cpp
周三luban.cmake(加 LUBAN_TARGETS)+ 新建 src/parser/*main.cpp / src/weekly-experiment/CMakeLists.txt(+1 行)/ parser.{h,cpp}
周四vcpkg.json luban.cmake + 新建 src/test-parser/*各种
周五(无——只跑 cmake)(无——只跑 cmake)

整个周里没打开根 CMakeLists.txt 一次。没写 find_package 调用。没读 vcpkg manifest mode 文档。

什么时候应该跳出 luban

luban 擅长 80% 场景。下面这些让你直接写 cmake,不要走 luban:

  • 每文件特殊编译 flag:写在 src/<target>/CMakeLists.txtluban_apply() 之后
  • 非 vcpkg 的依赖include(luban.cmake) 之后写自己的 find_package(MyLib),luban 不会跟你抢
  • 罕见 generator(Make / VS / Xcode):改 CMakePresets.json(用户拥有)
  • header-only lib target:在 src/<lib>/CMakeLists.txtadd_library(<name> STATIC ...) 改成 add_library(<name> INTERFACE) 自行调整
  • 非 vcpkg 来源的依赖:跳过 luban add,自己写 find_package / FetchContent

退出方式:把根 CMakeLists.txt 里的 include(luban.cmake) 删掉,整个项目变成普通 cmake 工程。

设计总览

一页讲清:luban 为什么长这样?

如果你只读一篇架构文档,读这篇。其他架构文章(philosophy two-tier-deps why-cmake-module roadmap)放大讲单个话题——这篇是综合。

luban 解决的问题

Windows 上的现代 C++ 项目要用户自己拼装

  1. 工具链(LLVM-MinGW / MSVC / mingw-w64)
  2. cmake —— 项目级 meta-build
  3. ninja —— 实际构建器
  4. clangd —— 编辑器 LSP
  5. vcpkg —— 包管理
  6. git —— vcpkg 要它,自己也用
  7. 一堆胶水:compile_commands.json / find_package / target_link_libraries / triplets / CMakePresets / CMAKE_TOOLCHAIN_FILE / vcpkg-configuration.json baseline 锁定 / target_include_directories(... PUBLIC) / 等等

每件事是半天 yak-shaving。整套堆起来要好几天,每台新机器要重来。

luban 的工作:把这些变成两条一次性命令 + 一个很小的项目内循环

luban setup                       :: ~3 min,~250 MB 工具链
luban env --user                  :: 注 user PATH(rustup 风格)
:: 开新终端

luban new app foo
cd foo
luban add fmt                     :: 编辑 vcpkg.json + luban.cmake
luban build                       :: vcpkg 在 cmake configure 期间自动拉 fmt

用户全程不打开 CMakeLists.txt不写 find_package不读 vcpkg manifest mode 文档。

luban 不是

  • 不是构建系统。 cmake + ninja 仍然干构建。
  • 不是包管理器。 vcpkg 仍然解析 + 构建 C++ 包。
  • 不是 fork / 替换。 luban-managed 项目仍然是标准 cmake 项目—— clone 到没装 luban 的机器,cmake --preset default && cmake --build --preset default 照样能 build。

luban 是带主见的胶水:把对的工具用对的方式粘起来,给初学者默认就走在轨道上的体验。

8 条架构不变量

锁死的设计决策。打破任何一条都让 luban 的根本契约失效:

1. cmake 永远是项目主角

luban 不发明 IR。luban 不发明新 manifest 格式取代 CMakeLists.txt。 luban 写一个标准 cmake moduleluban.cmake),用户代码 include() 即用。 删掉一行 luban 就退出。

2. luban.cmake 进 git

"辅助"二字的整个意义就是项目得在没有 luban 时仍能 build。luban.cmake 是普通 cmake module,进 git 跟随项目,永远可重现。

3. 不发明新 manifest

项目依赖在 vcpkg.json(vcpkg 自己的 schema)里。luban add 编辑它。没有 平行的 [deps] 字段在 luban.toml 里——那会造成双真相。

luban.toml 仅作为可选项目偏好存在(warning 等级、sanitizers、默认 preset、triplet)—— 那些不适合放 vcpkg.json 的零碎东西。

4. luban.toml 是可选的

很多 luban 项目根本没有 luban.toml。只在用户真有偏好时才出现。默认值 cover 80% 场景。

5. XDG-first 路径,Windows 上也是

luban 尊重 XDG_DATA_HOME / XDG_CACHE_HOME / XDG_STATE_HOME / XDG_CONFIG_HOMELUBAN_PREFIX 总开关变量,优先%LOCALAPPDATA% / %APPDATA% fallback。

让 container / CI / 多用户场景一行配置搞定,Linux port 时无惊喜。

6. 零 UAC

每个 luban-managed 文件落在用户可写目录。luban 永不写 Program Files、 永不碰 HKLM、永不弹 admin。luban env --user 只写 HKCU(当前用户)。

7. 单静态链接二进制

luban.exe 一个文件:release ~3 MB / debug ~32 MB(含 vendored miniz / json / toml++ 单 header 三件)。无配套 DLL、无 Python、无 MSI。U 盘装得下、新 VM 拷过去就跑。

8. 二层依赖模型

内容落点谁管
系统层cmake / ninja / clang / clangd / lld / git / vcpkg<data>/toolchains/luban setup
项目层fmt / spdlog / boost / catch2<project>/vcpkg_installed/<triplet>/luban add(编辑 vcpkg.json)

混淆是被拒绝的。luban add cmake 会报错,引导到 luban setup。系统工具 machine-wide 锁版本,项目库每项目独立 baseline。

为什么是这个形态(拒绝的备选)

备选 A:luban 自己的 DSL → lower 到 cmake

xmake / meson / build2 / premake 都走这条路。用户写 xmake.luameson.build,工具生成实际 build 文件。

为什么我们说 no:C++ 有几十年的 cmake 习惯。custom commands、 target-specific flags、conditional features——每个真实项目都会撞到 DSL 没覆盖的边界,fall through 到"反正还是要懂 cmake"。这时候 DSL 只是个 额外要学的东西,没真的把 cmake 藏住。更糟的是 DSL 与 cmake 的接缝很敌意 (eject 仪式、单向转换)。

备选 B:在 CMakeLists.txt 里用标记块原地编辑

像 code generator 插入 # >>> BEGIN luban / # <<< END luban 段。luban 拥有那些块;用户拥有其余。

为什么我们说 no:原地编辑很脆。用户在标记内手改的东西被覆盖。靠近 标记的改动跟重生成 race。边界处永远是混乱源。

luban.cmake 干净解决这事:luban 拥有整个文件,用户 include() 它, 边界是硬切。

备选 C:顶层一个统一 manifest

luban.toml 包一切——deps / scripts / profiles / workspace / toolchain pin。 Cargo 风格。

为什么我们说 no:vcpkg 的 vcpkg.json 已经存在,是 C++ 事实 manifest。 发明并行的 [deps] 段意味着维持双真相,两边永远 drift。让 vcpkg 拥有它的 schema、luban 通过 luban add 编辑它就好。

备选 D:luban-init.exe 自举安装器

rustup 风格:一个小 installer 下载 luban + 跑 setup。

为什么我们说 no:luban.exe 本来就是单文件下载。用户从 GH Releases curl -O luban.exe 直接跑就好。bootstrapper 是无价值的中间层。改成 luban self updateluban self uninstall 把生命周期闭环放进同一个二进制, uv 风格。

我们接受的 trade-off

  • Windows-first。Linux/macOS port 是 M3+ 工作;短期失多平台卫生,长期 让我们在最需要帮助的平台(Windows C++ tooling)上快速迭代。
  • 只 vendor 单 header。不消费系统 find_package(zlib) 类。多 ~10MB 二进制 换"一个文件、随处能跑"。
  • .cmake module 模式假设用户会 include(luban.cmake)。不 include 就没有 自动 find_package 魔法——掉进普通 cmake。这是设计,不是 bug。
  • curated pkg→target 表luban add 内置 ~50 流行库的映射。未知 port 写 find_package(<port>) 但不自动 link,用户自己填 target 名。长尾未来通过 scrape vcpkg 的 usage 文件解决。

操作模型

luban 作为三层运作,每层都有稳定接口:

┌─ 用户 ─────────────────────────────────────────────────┐
│   luban CLI(16 verb,分 4 组)                         │
└──────────────────────────────────────────────────────┘
            │ 编辑 vcpkg.json / luban.toml
            │ 调 cmake / vcpkg
            ▼
┌─ luban-managed 产物 ──────────────────────────────────┐
│   luban.cmake     ← luban 写;进 git                   │
│   <data>/bin/     ← shim 目录;在 user PATH 上          │
│   <state>/installed.json   ← 组件 registry             │
└──────────────────────────────────────────────────────┘
            │ shell out to
            ▼
┌─ 外部工具 ────────────────────────────────────────────┐
│   cmake / ninja / clang / vcpkg / git                 │
│   (luban 下载 + 管理它们,但不侵入它们的 config       │
│    —— 它们仍然是"现成"的)                              │
└──────────────────────────────────────────────────────┘

中间那层是 luban "辅助"性的体现:薄、稳、可 git 跟踪的 spec,桥接用户意图与 标准工具。抽掉中间层,下面那层仍然是能用的工具。

接下来读

命令清单

luban 共 16 个 verb,分 4 组。

工具链 / 环境(每台机器一次性)

命令作用
luban setup装 LLVM-MinGW + cmake + ninja + mingit + vcpkg
luban env显示 env 状态;改 activate 脚本;注册 HKCU PATH(rustup 风格)

单项目(在项目目录里跑)

命令作用
[`luban new applib ` →](https://luban.coh1e.com/commands/new.html)
luban buildcmake --preset && cmake --build;同步 compile_commands.json
[`luban target addremove` →](https://luban.coh1e.com/commands/target.html)

依赖管理(vcpkg.json + luban.cmake)

命令作用
luban add <pkg>[@version]编辑 vcpkg.json + 重生成 luban.cmake(自动 find_package + link)
luban remove <pkg>luban add 反操作
luban sync重读 vcpkg.json + luban.toml,重生成 luban.cmake
luban search <pattern>搜 vcpkg ports(包 vcpkg search

诊断 / 自治

命令作用
luban doctor报告目录、已装组件、PATH 上的工具
luban run <cmd> [args...]uv 风格透传执行;用 luban 工具链 env 跑 cmd
luban which <alias>打印 alias 解析到的绝对 exe 路径
luban describe [--json]dump 系统 + 项目状态(IDE / scripts 用)
luban shim重生成 <data>/bin/ shim(文本 + .exe;修复用)
luban self {update,uninstall}自更新二进制 / 完全卸载 luban

全局 flag

放在子命令前:

Flag作用
-V, --version打印 luban X.Y.Z 退出
-h, --help顶层帮助
-v, --verbose详细 log

约定

  • 幂等:每个命令都能安全重跑。luban setup 跳过已装组件、luban add 替换已有 dep、luban target add 拒绝同名 target。
  • 原子文件写:每次配置 / manifest 写入走 tmp + rename,崩了就只剩 老文件或新文件,绝不会留半个文件。
  • 退出码约定0 成功,1 运行失败(下载失败、cmake 出错),2 用户错 (参数错、操作被拒绝)。
  • log 走 stderr ! 前缀的行进 stderr。stdout 留给机读输出 (比如 compile_commands.json 路径)。pipe stdout 干净。

详细单页参考

每个命令的 examples / flags / behavior 详细见 英文版命令参考

英文完整文档站

中文版仅翻译了核心几页(简介安装快速上手日常使用循环设计总览命令清单)。完整内容在英文版上:

直链到英文站

类别链接
完整命令参考(每个 verb 详细页)https://luban.coh1e.com/commands/overview.html
工作流(首次配置 / 加 vcpkg / 多 target / IDE / 复现)https://luban.coh1e.com/workflows/first-run.html
参考文档(XDG paths / luban.toml / vcpkg.json / luban.cmake)https://luban.coh1e.com/reference/paths.html
架构哲学(philosophy / two-tier-deps / why-cmake-module)https://luban.coh1e.com/architecture/philosophy.html
Roadmaphttps://luban.coh1e.com/architecture/roadmap.html
Doxygen 贡献者参考(C++ 源码层面)https://luban.coh1e.com/api/
Contributing 指南https://luban.coh1e.com/contributing.html

中文版迭代会逐渐覆盖更多页——欢迎 PR 翻译你常用的章节。

反方向跳

  • 在英文版页面上看到顶部的 🌐 中文版 → 链接可以回到本站