feat(manifest): 声明式清单能力 — features.sources / generated_files / cfg 条件… · mcpp-community/mcpp@a75ca0a · GitHub
Skip to content

Commit a75ca0a

Browse files
authored
feat(manifest): 声明式清单能力 — features.sources / generated_files / cfg 条件 sources / per-glob flags (#223)
G5+G6+G1b+G4+G8b:toml↔xpkg 对称补齐、TOML 多行字符串、featureSources 真 gate(未激活→!排除)、依赖侧 cfg 求值、有序 per-glob flags、相对 -I 绝对化;e2e 106–109;接替 #221
1 parent d440a0b commit a75ca0a

18 files changed

Lines changed: 1074 additions & 15 deletions

docs/05-mcpp-toml.md

Lines changed: 49 additions & 3 deletions

docs/zh/05-mcpp-toml.md

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,49 @@ sources = [
175175
]
176176
```
177177

178+
**per-glob 旗标**(mcpp 0.0.95+):`[build] flags`**有序**的内联表数组,把额外
179+
编译旗标只附加到 glob 命中的源文件——SIMD 多档 dispatch TU 与三方代码告警隔离的
180+
正解:
181+
182+
```toml
183+
[build]
184+
flags = [
185+
{ glob = "third_party/**", cflags = ["-w"], cxxflags = ["-w"] },
186+
{ glob = "src/simd/**/*.avx2.cpp", cxxflags = ["-mavx2"], defines = ["HAVE_AVX2"] },
187+
{ glob = "src/x86/**/*.asm", asmflags = ["-DPREFIX"] },
188+
]
189+
```
190+
191+
每条目键:`glob`(相对包根,必填)+ `cflags` / `cxxflags` / `asmflags` /
192+
`defines`(没有 `ldflags`——链接没有 per-TU 作用域)。声明顺序即应用顺序:靠后
193+
条目的旗标排在命令行更后,配合 GNU "后旗标胜",窄 glob 放在宽 glob 之后即可覆盖。
194+
所有命中条目都生效;这些是私有构建旗标,不会传播给消费者。glob 零命中会打印
195+
warning(打错的 glob 不允许静默无效)。
196+
197+
**生成文件**(mcpp 0.0.95+):`[generated_files]` 把相对路径映射到文件内容(支持
198+
TOML 多行字符串)。条目在源 glob 展开之前写入工程树——与 index 描述符合成模块
199+
包装文件是同一机制——内容进指纹,改内容即重建:
200+
201+
```toml
202+
[generated_files]
203+
"src/gen/wrap.cppm" = """
204+
module;
205+
#include <vendored.h>
206+
export module wrap;
207+
"""
208+
```
209+
210+
路径必须留在工程根之内(`..` / 绝对路径是解析错误)。
211+
212+
**汇编源**(mcpp 0.0.95+):`.S`/`.s`(GAS——由 C 驱动器预处理,覆盖 ARM 与
213+
AT&T 语法 x86)和 `.asm`(NASM——Intel 语法 x86)是一等源文件:默认 glob 收录、
214+
进指纹、增量并行构建、像任何对象一样链接。NASM 的输出格式由目标三元组推导
215+
(`elf64`/`win64`/`macho64`/...——交叉构建零特判);`nasm` 仅在存在 `.asm` 单元时
216+
惰性解析:先 `PATH`,再 mcpp 沙箱,再 `xlings install nasm`;找不到 ≥2.16 的
217+
nasm 则**硬失败**(汇编绝不静默跳过)。限制:`.asm` 仅限 x86 目标(其他目标硬
218+
报错——用条件 sources 门控)、MSVC 工具链不支持 `.S``.asm` 即 NASM 语法
219+
(MASM 源请用 `!` 排除)。
220+
178221
### 2.4 `[lib]` — 库根模块约定
179222

180223
```toml
@@ -290,7 +333,9 @@ cxxflags = ["-march=x86-64-v2"]
290333
OS/家族用裸形式;需要 arch/env 条件或组合子时用 `cfg(...)`
291334

292335
- **可放的键**:`dependencies` / `dev-dependencies` / `build-dependencies`,以及
293-
`build` 下的 `cflags` / `cxxflags` / `ldflags`
336+
`build` 下的 `cflags` / `cxxflags` / `ldflags` / `sources`(mcpp 0.0.95+——
337+
条件源 glob,如把 `src/x86/**/*.asm` 门控在 `cfg(arch = "x86_64")` 之后;
338+
`!` 排除 glob 同样可用)。
294339
- **按解析后的目标求值**——交叉构建时是 `--target` 三元组,否则是 host。所以原生
295340
Linux 构建**根本不会下载** `[target.windows]` 的依赖。
296341
- **优先级**:精确三元组表压过 `cfg`/别名表;多个命中的谓词表,其旗标会拼接。
@@ -317,7 +362,10 @@ extra = []
317362
#### 表形式 —— 让 feature 贡献的不止是隐含 feature
318363

319364
`[features]` 的条目除了写成数组,还可写成****,从而让该 feature 在隐含 feature
320-
之外,携带包自有的预处理 `defines`,以及 capability 的 `requires` / `provides`
365+
之外,携带包自有的预处理 `defines`、feature 门控的源 glob(`sources`,mcpp
366+
0.0.95+——列出的 glob 离开默认构建,仅当 feature 激活时才编译,与 index 描述符的
367+
`features.<f>.sources` 完全对等;这正是 vendored 大库最高频的形态:*feature =
368+
一组源文件 + 一个 define*),以及 capability 的 `requires` / `provides`
321369
(见 §2.8.1):
322370

323371
```toml

src/build/ninja_backend.cppm

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,15 @@ bool is_scan_exempt(const std::filesystem::path& src) {
170170
// Per-unit flags an assembler can take: the -D/-U/-I subset of the unit's C
171171
// flags (feature defines land there). NASM shares the GNU -D/-U/-I spelling
172172
// (and ≥2.14 inserts a missing -I path separator itself), so one filter
173-
// serves both asm rules.
173+
// serves both asm rules. Explicit per-glob asmflags (G4) append after the
174+
// filtered subset — author-directed flags win.
174175
std::vector<std::string> asm_unit_flags(const CompileUnit& cu) {
175176
std::vector<std::string> out;
176177
for (auto& f : cu.packageCflags) {
177178
if (f.starts_with("-D") || f.starts_with("-U") || f.starts_with("-I"))
178179
out.push_back(f);
179180
}
181+
out.insert(out.end(), cu.packageAsmflags.begin(), cu.packageAsmflags.end());
180182
return out;
181183
}
182184

src/build/plan.cppm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct CompileUnit {
2424
std::vector<std::filesystem::path> localIncludeDirs;
2525
std::vector<std::string> packageCflags;
2626
std::vector<std::string> packageCxxflags;
27+
std::vector<std::string> packageAsmflags; // per-glob asmflags (G4)
2728
std::optional<std::string> providesModule; // logical name, if .cppm export
2829
std::vector<std::string> imports; // logical names imported
2930
// Unit came from a scan_overrides declaration — plan-vs-ddi
@@ -445,6 +446,7 @@ BuildPlan make_plan(const mcpp::manifest::Manifest& manifest,
445446
cu.localIncludeDirs = u.localIncludeDirs;
446447
cu.packageCflags = u.packageCflags;
447448
cu.packageCxxflags = u.packageCxxflags;
449+
cu.packageAsmflags = u.packageAsmflags;
448450
const auto fname = object_filename_for(u.path, objExt);
449451
if (basenameCount[fname] > 1) {
450452
// Use <sanitized-pkg>/<parent-dir-name> as prefix to handle
@@ -700,6 +702,10 @@ BuildPlan make_plan(const mcpp::manifest::Manifest& manifest,
700702
main_cu.packageCflags = manifest.buildConfig.cflags;
701703
main_cu.packageCxxflags = manifest.buildConfig.cxxflags;
702704
}
705+
// Root-relative -I flags → absolute (G8b), mirroring the scanner's
706+
// treatment of every scanned unit.
707+
mcpp::modgraph::absolutize_include_flags(projectRoot, main_cu.packageCflags);
708+
mcpp::modgraph::absolutize_include_flags(projectRoot, main_cu.packageCxxflags);
703709

704710
// We didn't scan main.cpp earlier (it's not in scanner output unless globbed in).
705711
// Best-effort: scan its imports here.

src/build/prepare.cppm

Lines changed: 70 additions & 8 deletions

0 commit comments

Comments
 (0)