Skip to content

feat/RFC: [system_deps] —— 经 pkg-config 集成宿主系统库 #493

Description

@wellwei

feat/RFC: [system_deps] —— 经 pkg-config 集成宿主系统库

设计基线:.agents/docs/2026-07-24-embedded-platform-support-design.md 的 P1 条目(pkgconf via xlings + sysroot-aware)。错误路径沿用其决策表第 11 行的既有策略:有 .pc 用之,无则退回手写 ldflags,mcpp 不造 .pc
现状核实基于本地检出(2026-08-24),行号以该检出为准。

1. 问题

宿主系统库目前只能经 [build].ldflags 手工声明。以 macOS/Homebrew Qt6 为例:

[target.macos.build]
ldflags = ["-F/opt/homebrew/opt/qt/lib",
           "-framework", "QtWidgets", "-framework", "QtGui", "-framework", "QtCore"]

缺陷:路径硬编码;传递闭包人工维护;无自动化通道——build.mcpp 的 link-libTransform::LibFlag 强制为 -l<name>,无法表达 -framework(verbatim ldflag 指令系 deliberate 缺席)。而 pkg-config 输出与上述手写内容逐字等价,且 Requires: 自动展开传递依赖。

2. 提案

新增 manifest 段:

[dependencies]
compat.gtest = "1.15.2"     # 索引分发、源码构建、hermetic

[system_deps]               # 宿主已装、pkg-config 发现、host-coupled
Qt6Widgets = ">=6.5"        # 值 = 版本约束;空串 = 仅要求存在
QtCore = ""

prepare 在 target triple 解析后查询一次 pkg-config,将 --cflags / --libs 输出按 token 分类折进现有 typed 通道。关键性质:.pc 模块名跨平台中立(macOS 发 -framework,Linux 发 -l),一份声明全平台正确,无需 cfg() 条件化。

v1 范围:排除 Windows;不造 .pc;不解析 CMake config files。schema 不绑定发现机制,为将来 CPS resolver 留缝。

3. 设计

3.1 注入点

L1 漏斗:root 于 merge_conditional_config 之后、makePackageRoot 快照之前;依赖包在各自加载路径的镜像点。由此:

  • triple 已解析,可设 sysroot-aware env;
  • 结果随 buildConfig 快照自动参与 P1689 扫描、fingerprint(cache_key 已哈希 cflags/ldflags/include_dirs)、compile_commands.json,零额外接线;
  • 符合「每包恰好合并一次」不变量。

查询经 capture_exec_deadline 执行;ninja 规则静态,故必须在 prepare 期完成。system_deps 为空时直接返回,其余项目零开销。

3.2 Token 分类

token 去向 状态
-I<dir> / -idirafter <dir> includeDirs / includeDirsAfter 现成
-D<m> defines 现成
-l<n> / -L<dir> libraries / linkLibraryDirs 现成
-framework <n> LinkIntent.frameworks(MachO 渲染已有) 现成
-F<dir> 新字段 LinkIntent.frameworkDirs 需补
-Wl,… ldflags verbatim 现成
-isystem <dir> 待定(重映射或拒绝),见 §6.3

分类器为表驱动纯函数。有损分类须报 diag::degraded()(impact 必填)。

3.3 其余设计点

  • Fingerprint:哈希查询结果而非环境变量——env 漂移但输出未变时不触发重建。
  • Hermeticity:建议 v1 要求激活 hermetic 检查时显式 allow_host_libs = true(见 §6.2)。
  • Offline:查询属本地内省,--offline 下照常执行;lock 不记录结果(机器本地事实)。
  • Static:resolved linkage 为 static 时追加 --static
  • 交叉编译tc.sysroot 非空时设 PKG_CONFIG_SYSROOT_DIR / PKG_CONFIG_LIBDIR,薄接线;完整 multiarch 解析归嵌入式 P0 后续。
  • 已知限制:含空格的安装路径不可表示(生态固有问题),文档注明。
  • 版本约束:v1 仅 >=N / =N / 空,映射 --atleast-version / --exact-version / --exists

4. 错误路径

场景 处置
二进制不存在 / .pc 缺失 / 版本不满足 / 超时 硬错误 + 新 E 码;hint 给出「手写 ldflags」兜底示例(上文设计文档决策表第 11 行策略)
有损分类 diag::degraded()

配套:self doctor 增加 pkg-config 可用性与可解析性检查;mcpp why deps 标注旗标来源。

5. 测试与实施

测试以 fixture .pc 树 + PKG_CONFIG_PATH 实现,CI 完全离线,无需真实 Qt。覆盖:framework 渲染、Requires 闭包、define 到达编译行、三类失败文案快照、修改 fixture 触发重建、static 追加 --static、无 [system_deps] 项目构建图字节级不变。

PR 内容
1 schema/解析、resolver、注入、分类器、fingerprint、e2e
2 frameworkDirs 通道 + ConditionalConfig 补 frameworks 字段
3 E 码 + doctor/why + 双语文档

后续独立 RFC:sysroot env 完整接线、CPS resolver、feature 门控、build.mcpp 查询 API。

6. 开放问题

  1. Schema 落点:[system_deps](推荐,与 [dependencies] 形成语义对仗)vs [build].system_packages
  2. Hermeticity:要求 allow_host_libs = true,还是声明即授权?
  3. -isystem:降级重映射 + degraded,还是硬拒绝?
  4. ConditionalConfig.frameworks 补洞随 PR2 还是先行独立合入?
  5. 新错误码编号确认。

7. 参考

  • .agents/docs/2026-07-24-embedded-platform-support-design.md(P1 条目;决策表第 11 行 fallback 策略);open-items 分析(pkg-config 平台边界)
  • Meson dependency(method:'pkg-config');Cargo pkg-config crate
  • CPS(cps-org);CMake 4.1+ 实验性消费端
  • 实证:macOS 15 / Homebrew qt 6.9.0 / pkgconf 2.x

方向认可即可按 §5 切分提交 PR1。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions