Repository navigation
增设关闭src自动扫描字段 - mcpp.toml 使用问题 #386
Description
Activity
感谢报告,已复现并定位。结论先说:这里缺的不是一个"关扫描"的字段,而是根包的角色没定下来——你的问题现在就有解;不过你指出的表达力缺口是真的,我们会修,只是修法和你提的不同。下面分四段:现象、参考方案、你清单里另外两处坑、以及我们打算怎么改。
(以下结论都在本机 mcpp 2026.8.6.2 / main 上实测过,不是纸面推导。)
1. 现在发生了什么
根清单同时写了
[package]和[workspace],这在 mcpp 里是 rooted workspace(带根包的工作区),它的语义是:- 裸
mcpp build只构建根包——[workspace] members里的成员一个都不会建; - 而你的根目录正好压在 spdlog 上游源码树上,根包按约定扫描
src/**→ 缺SPDLOG_COMPILED_LIB→ 报错。
也就是说,现在这份配置不只是"多编了不该编的东西",而是你想建的那个成员压根没被建。最小复现:
写法 实际结果 根 [package]+[workspace],裸mcpp build编根目录的 src/**→ 报错;成员未构建根加 sources = []被静默忽略,照样打印 Inferred sources […]并失败(见第 4 段)根删掉 [package]✅ Workspace building member …,正常mcpp build -p spdlog/--workspace✅ 只建成员,根包不参与 2. 参考方案
方案 A(推荐;改一行,现在就能用)
根清单去掉
[package],只留[workspace]:[workspace] members = ['cmake2mcpp_generated/spdlog']
理由:根本身没有源码、也不产出任何东西,它就是个管理节点——这正是 mcpp 的虚拟工作区(见
docs/06-workspace.md§2.2)。这样:mcpp build构建全部成员,mcpp test --workspace测全部成员;- 根目录下的
src/不再被任何包认领,自动扫描无从触发——问题从根上消失,而不是被一个开关压住。
对 cmake2mcpp 来说这也是更稳的生成策略:生成器不知道自己会被写进什么样的上游目录,不声明
[package]就不会去认领脚下的任何文件。方案 B(仅当你需要"一条命令建出一张完整链接图"时)
根保留
[package],但必须补[dependencies]把成员挂进依赖图,并且根清单不能落在别人的源码树上:[package] name = 'spdlog-workspace' # 注意:别和成员同名 version = '0.1.0' [dependencies] spdlog = { path = 'cmake2mcpp_generated/spdlog' } [workspace] members = ['cmake2mcpp_generated/spdlog']
这是 mbun 的形状(99 个成员,根包用
path依赖聚合整张图,[workspace] members只服务mcpp test --workspace的扇出)。实测:只要根目录下没有src/,这样一个"无源码聚合根"今天就能正常工作。但在你的场景里根目录就是 spdlog 源码树,所以 B 在第 4 段的修复落地之前走不通——这正是我们认为你的需求成立的原因。
⚠️ 顺带:你现在根包名和成员包名都是spdlog。-p spdlog命中成员、裸mcpp build命中根,同名两套语义,建议错开。3. 你贴的成员清单里另外两处(都实测过,建议 cmake2mcpp 一并改)
(1)
[targets.spdlog] cxxflags = ['-O3 -DNDEBUG']现在是空转,一个字都没落地。per-target 的
cxxflags/cflags/defines只作用于该 target 的 entry main(docs/05-mcpp-toml.md§2.2 有标注),而kind = 'lib'没有 entry。我核对了生成的build.ninja,编译行里没有-O3。应该写在[build]:[build] cxxflags = ['-O3'] defines = ['SPDLOG_COMPILED_LIB', 'NDEBUG']
另外
'-O3 -DNDEBUG'是一个字符串而不是两个数组元素——Linux 上靠 shell 分词侥幸能过,但它不是一个 argv token,别依赖。(2) 成员的
sources是相对「成员目录」解析的,不是相对工作区根。你的成员在
cmake2mcpp_generated/spdlog/,所以sources = ['src/async.cpp']找的是cmake2mcpp_generated/spdlog/src/async.cpp。如果真实源码在上游树里,现在的行为是:匹配不到任何文件 → 产出一个空的.a→ 打印Finished,零告警。请确认这一点,否则你拿到的是一个"绿色的空包"。两种写法都实测可用:
sources = ['../../src/async.cpp'] # 相对成员目录,可以往上走 sources = ['/home/tz/cmake2mcpp/spdlog-1.17.0/src/async.cpp'] # 绝对路径,原样采纳
对生成器建议用绝对路径,和你已经在
include_dirs里用绝对路径的做法一致。("声明了却匹配不到任何文件"应该至少给个告警,而不是静默出空包——这条我们会补。)
4. 关于"增设关闭 src 自动扫描字段"
需求成立,但我们不打算新增字段,而是把已有写法修对。 具体三条:
sources = []现在被静默忽略。 引擎只判.empty(),分不清"写了空列表"和"根本没写",于是照样注入默认 glob,还反过来打印Inferred sources […]——用户明确说了话,引擎当没听见。这是 bug。修完之后sources = []就是字面意思:零源文件,不做任何推导。- "自动扫描"其实有两个,得一起关。 除了源 glob,还有目标推导(
src/main.cpp→ bin、src/**/*.cppm→ lib)。目前sources = ['!src/**']能关掉前者(未文档化的偏方),但关不掉后者——实测根目录有src/main.cpp时,它仍会被推导成二进制入口并编译。所以"显式空源集"会同时关掉目标推导,否则这个开关只关了一半,反而更难排查。 - 不加
auto_scan = false的理由:它和sources = []是同一句话的两种说法,多一个词汇就要在解析、缓存键、文档、序列化等多处同步维护;而sources = []已经是这句话最自然的写法。另外参考 mbun 的 99 份清单——0 份声明显式sources,0 份用排除模式:布局正确时约定扫描完全够用。这个能力只在"清单被生成进别人的源码树"这一类场景(也就是 cmake2mcpp 这类转换工具)才需要,做成"显式空值生效"比做成一个常驻开关更贴切。
已按这个方向排进修复。在它落地之前,请先用方案 A,那条路径今天就是通的。再次感谢反馈 🙏
- 裸
mbun 真实的workspace 示例
https://github.com/Sunrisepeak/mbun/blob/rewrite_bun_in_mcpp/mcpp.toml
插件最近在做 mcpp.toml 里字段的语法的代码提示 后面应该能缓解很多这个问题
根据你的推荐,我修改了根mcpp.toml
[dependencies.spdlog] path = 'cmake2mcpp_generated/spdlog' [package] name = 'spdlog-workspace' version = '0.1.0' [workspace] members = [ 'cmake2mcpp_generated/spdlog' ]子toml保持不变,但是此时报错,找不到宏定义
#error Please define SPDLOG_COMPILED_LIB to compile this file.但是,如果将根mcpp.toml改为您提及的A做法时,则可以正常构建.但是无法作为包被其他项目依赖
[workspace] members = [ 'cmake2mcpp_generated/spdlog' ]mcpp run Resolving toolchain Resolved llvm@22.1.8 → @mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++ error: path dependency 'spdlog' (at '/home/tz/test/spdlog') has no mcpp.toml根据你的推荐,我修改了根mcpp.toml
[dependencies.spdlog] path = 'cmake2mcpp_generated/spdlog' [package] name = 'spdlog-workspace' version = '0.1.0' [workspace] members = [ 'cmake2mcpp_generated/spdlog' ]子toml保持不变,但是此时报错,找不到宏定义
#error Please define SPDLOG_COMPILED_LIB to compile this file.但是,如果将根mcpp.toml改为您提及的A做法时,则可以正常构建.
从贴的两个 toml 结构推测 是一个项目 spdlog
- 方法一: 只要保留一个mcpp.toml
[package] name = 'spdlog' version = '0.1.0' [build] include_dirs = ['/home/tz/cmake2mcpp/spdlog-1.17.0/include', 'include'] defines = ['SPDLOG_COMPILED_LIB'] sources = [ 'src/async.cpp', 'src/bundled_fmtlib_format.cpp', 'src/cfg.cpp', 'src/color_sinks.cpp', 'src/file_sinks.cpp', 'src/spdlog.cpp', 'src/stdout_sinks.cpp', ] [targets.spdlog] cxxflags = ['-O3 -DNDEBUG'] kind = 'lib'- 方法二: 还是使用 workspace 机制 顶层只保留
[workspace] members = [ 'cmake2mcpp_generated/spdlog' ]感觉最核心的还是你的意图是什么 / 以及可以上传一个临时仓库 贴一下链接可能才知道具体项目结构是什么样 (以上都是我根据你描述推论的不准确)
结合
以及
如果将根mcpp.toml改为您提及的A做法时,则可以正常构建.但是无法作为包被其他项目依赖保留单个 toml 应该就可以了
[package] name = 'spdlog' version = '0.1.0' [build] include_dirs = ['/home/tz/cmake2mcpp/spdlog-1.17.0/include', 'include'] defines = ['SPDLOG_COMPILED_LIB'] sources = [ 'src/async.cpp', 'src/bundled_fmtlib_format.cpp', 'src/cfg.cpp', 'src/color_sinks.cpp', 'src/file_sinks.cpp', 'src/spdlog.cpp', 'src/stdout_sinks.cpp', 'cmake2mcpp_generated/cmake2mcpp_generated.cpp' ] [targets.spdlog] cxxflags = ['-O3 -DNDEBUG'] kind = 'lib'如果是一个库, 使用 单 mcpp.toml 加 feature 机制。具体 把mcpp文档链接 给 Agent 然后描述你的需求 就可以
这条 issue 要的能力已经有了:
sources = []现在生效,写下它就等于「什么都不要编」。可以关闭。为什么这不是新增一个「关闭扫描」的键
当时的答复是「缺的不是一个关扫描的字段,而是根包的角色没定下来」—— 那半对半错。根包角色的部分是对的(rooted workspace 的语义,以及 Sunrisepeak 后来给的单 toml 方案)。错的是把表达力缺口推给了配置形态:解析器在向量为空时一律填默认 glob,所以作者没有任何写法能表达「这个包不编译任何东西」。你在第 4 段实测到的「根加
sources = []被静默忽略,照样打印Inferred sources […]」正是这个。修法是记键有没有出现,而不是向量空不空 ——
BuildConfig::sourcesDeclared,与XlingsConfig::subosDeclared同一个模式。modules/manifest/src/toml.cppm:// `!sourcesDeclared` and not `sources.empty()`: an author who wrote // `sources = []` asked for NOTHING, and filling the default glob over that // answers a question they already answered. if (!m.buildConfig.sourcesDeclared) { m.buildConfig.sources = mcpp::default_source_globs(extTable); ... }
真正把它逼出来的是二进制分发:一个纯头文件的包不编译任何东西,而
src/下任何遗留文件都会被扫进消费者的构建,并可能与预编译库里的符号重复定义。你的 cmake2mcpp 场景和它是同一个需求的两个面。顺带修掉的第二条
同一轮核验发现默认 glob 有两份且已经漂移(一处 4 项、一处 7 项),于是走多版本 staging 的包当时会漏掉汇编源。现在两处都从唯一的
default_source_globs(extTable)派生,并且这份表由module_extensions决定 —— 否则声明.ixx会改变它被如何对待却不改变它是否被找到,那个键就等于什么都没做。你原来那个工程
单 mcpp.toml 的形态(Sunrisepeak 在上面给的)仍然是首选。你图里那种「按 bin / lib / shared 拆成多个 toml」的结构现在也更好写了:
[workspace.package]与[workspace.build]的继承在 2026.8.30.2 落地,成员可以从工作区根继承standard/defines/include_dirs而不必每份清单重写一遍,并且继承会到达作为兄弟成员的path依赖被编译的那个成员(#527 / #539,docs/06-workspace.md中英双份)。如果按这条路走下来还有表达不出来的形状,另开一条 issue 贴出目录结构,比在这条下面接着长更容易被排期。

workspace中子模块
cmake2mcpp_generated/spdlog/mcpp.toml
中包含各种宏定义
而主模块mcpp.toml
则会因为自动扫描src目录下代码,缺少宏定义导致报错。