现象
macOS 上,任何 C++ 消费者(尤其 C++23 module)include 一个把源码根目录放进 include_dirs 的依赖(compat.ffmpeg:include_dirs 含 * = 解压后的 ffmpeg-8.1.2/ 根)时,libc++ 内部的 #include <version> 被依赖根目录里的 VERSION 文件顶替,当成 C++ 解析炸掉:
In file included from …/libavutil/common.h:36: // #include <math.h>
In file included from …/llvm/20.1.7/include/c++/v1/math.h:369:
In file included from …/llvm/20.1.7/include/c++/v1/__math/hypot.h:21:
In file included from …/llvm/20.1.7/include/c++/v1/limits:119: // libc++ <limits> → #include <version>
…/compat.ffmpeg/8.1.2/ffmpeg-8.1.2/version:1:1: error: expected unqualified-id
ffmpeg-8.1.2/VERSION 是 ffmpeg.org release tarball 的顶层版本串文件(内容 8.1.2\n,git 仓库没有、只有 release dist 有)。
根因
- mcpp 把
[build].include_dirs 一律发成 -I(angle 搜索链的最前组,先于工具链 C++ 头)。确认:xpkg.cppm 保留键只有 include_dirs;无 -isystem/-iquote/-idirafter 面向描述符的变体。
- macOS 文件系统大小写不敏感:
#include <version>(libc++ <limits> 拉的 C++ 特性测试头)在 -I …/ffmpeg-8.1.2/ 里匹配到 VERSION,先于 libc++ 自带 <version>。
- C 消费者不触发(C 的
<math.h> 不拉 libc++ <version>)——所以 compat.ffmpeg 的库在 macOS 全绿(C 成员 test 通过),只有 C++ module(import ffmpeg.av)炸。linux 大小写敏感,<version>≠VERSION,无此问题。
这是通用隐患:任何依赖源码根有 VERSION/RELEASE/list/array… 等与 C++ 标准头同名(大小写不敏感)的无扩展名文件,放进 -I 后都会在 macOS 顶替标准库头,炸掉全部 C++ 消费者。
影响
挡死 macOS 上 compat.ffmpeg 的 C++ module 消费者(ffmpeg-m import ffmpeg.av)。库层已 ok(mcpp-index PR#89 macos 绿);差 module 这一层。opencv 同理有风险(其源码树也可能有同名文件)。
建议修复
给描述符一个"低优先级 include"变体,发成 -idirafter(排在工具链系统头之后):这样 <version> 命中 libc++ 自带的(正确),而 <libavutil/frame.h>(非系统头)仍能在 idirafter 的 ffmpeg 根里找到。例如:
[build]
include_dirs = ["mcpp_generated", "mcpp_generated/libavcodec"] # -I(高优先级,自有生成头)
include_dirs_after = ["*", "*/libavcodec"] # -idirafter(源码根,让系统 C++ 头优先)
(gcc/clang 都支持 -idirafter;linkmodel.cppm 里 mcpp 已在 payload 头场景用过 -idirafter/-isystem,此处是把该能力开放给依赖描述符。)也可考虑 macOS 上把依赖的源码根 include 默认降到系统头之后,但显式 include_dirs_after 更可控、跨平台一致。
复现
mcpp-index PR#91(spike/…ffmpeg-0.0.2-macos)workspace(macos) 腿:mcpp test -p ffmpeg-module,即上面的 traceback。库层参照 PR#89 macos 绿。
现象
macOS 上,任何 C++ 消费者(尤其 C++23 module)include 一个把源码根目录放进
include_dirs的依赖(compat.ffmpeg:include_dirs含*= 解压后的 ffmpeg-8.1.2/ 根)时,libc++ 内部的#include <version>被依赖根目录里的VERSION文件顶替,当成 C++ 解析炸掉:ffmpeg-8.1.2/VERSION是 ffmpeg.org release tarball 的顶层版本串文件(内容8.1.2\n,git 仓库没有、只有 release dist 有)。根因
[build].include_dirs一律发成-I(angle 搜索链的最前组,先于工具链 C++ 头)。确认:xpkg.cppm 保留键只有include_dirs;无-isystem/-iquote/-idirafter面向描述符的变体。#include <version>(libc++<limits>拉的 C++ 特性测试头)在-I …/ffmpeg-8.1.2/里匹配到VERSION,先于 libc++ 自带<version>。<math.h>不拉 libc++<version>)——所以 compat.ffmpeg 的库在 macOS 全绿(C 成员 test 通过),只有 C++ module(import ffmpeg.av)炸。linux 大小写敏感,<version>≠VERSION,无此问题。这是通用隐患:任何依赖源码根有
VERSION/RELEASE/list/array… 等与 C++ 标准头同名(大小写不敏感)的无扩展名文件,放进-I后都会在 macOS 顶替标准库头,炸掉全部 C++ 消费者。影响
挡死 macOS 上 compat.ffmpeg 的 C++ module 消费者(ffmpeg-m
import ffmpeg.av)。库层已 ok(mcpp-index PR#89 macos 绿);差 module 这一层。opencv 同理有风险(其源码树也可能有同名文件)。建议修复
给描述符一个"低优先级 include"变体,发成
-idirafter(排在工具链系统头之后):这样<version>命中 libc++ 自带的(正确),而<libavutil/frame.h>(非系统头)仍能在 idirafter 的 ffmpeg 根里找到。例如:(gcc/clang 都支持
-idirafter;linkmodel.cppm 里 mcpp 已在 payload 头场景用过-idirafter/-isystem,此处是把该能力开放给依赖描述符。)也可考虑 macOS 上把依赖的源码根 include 默认降到系统头之后,但显式include_dirs_after更可控、跨平台一致。复现
mcpp-index PR#91(spike/…ffmpeg-0.0.2-macos)workspace(macos) 腿:
mcpp test -p ffmpeg-module,即上面的 traceback。库层参照 PR#89 macos 绿。