Skip to content

[bug] macOS 上 dep build.mcpp 收不到 G3 契约环境(MCPP_OUT_DIR 等):capture_exec 的 shell 前缀 env 绑定到 cd 而非 build.mcpp(cd && bin 跨 && 丢 env) #248

Description

@Sunrisepeak

现象

macOS 上,消费一个带内联 ["build.mcpp"] 的依赖(consumer-side 合成源码——如 compat.opencv 合成 jpeg12/16 tu-stub、字体、OpenCL kernel)时,dep 的 build.mcpp 一起步就 abort:

error: dependency 'compat.opencvmac': build.mcpp exited with 1 (build aborted):
compat.opencv build.mcpp: MCPP_OUT_DIR unset (mcpp >= 0.0.95 required)
build.mcpp compiling
build.mcpp running

同一份包在 linux 上 build.mcpp 正常(MCPP_OUT_DIR 有值)。即 dep build.mcpp 拿不到 G3 契约环境(MCPP_OUT_DIR / MCPP_MANIFEST_DIR / MCPP_FEATURE_* / MCPP_DEP_*_DIR)仅发生在 macOS

根因

src/platform/process.cppmcapture_exec 按平台分叉:

  • linux(L337 #if defined(__linux__)):posix_spawn + merged_environ(extraEnv) + addchdir_np(cwd) —— 子进程 envp 正确带上 extraEnv,cwd 也对。✅
  • macOS/其它(L378 #else):
    std::string cmd = command_from_argv(argv) + " 2>&1";
    if (!cwd.empty())
    cmd = "cd " + shell::quote(cwd) + " && " + cmd; // ← "cd <cwd> && <bin>"return capture_with_env(cmd, extraEnv);
    capture_with_env(L218 #else)把 env 拼成命令最前缀:
    prefixed = "KEY1='v1' KEY2='v2' ... " + command; // = "ENV... cd <cwd> && <bin>"

最终 shell 收到:

MCPP_OUT_DIR='...' MCPP_MANIFEST_DIR='...' ... cd <cwd> && <bin> 2>&1

POSIX shell 语义:VAR=val cmd1 && cmd2VAR=val只对 cmd1(这里是 cd)生效,不跨 && 传给 cmd2(真正的 <bin>=build.mcpp)。于是 build.mcpp 一个 MCPP_* 都收不到 → getenv("MCPP_OUT_DIR")==nullptr → abort。

build.mcpp 是唯一同时传入非空 cwd 且非空 extraEnv 的调用点(L598 capture_exec({bin}, childEnv, root));编译探针那些调用 extraEnv 为空(L295),所以此 bug 只在 macOS 的 dep build.mcpp 上暴露。linux 走 posix_spawn 无此问题;windows 走 _putenv_s(改父进程 env,子进程继承)也没问题——只有 macOS 的 shell 前缀路径炸。openblas/spdlog 等 macOS build.mcpp 之所以"没事",是它们的 build.mcpp 不读 MCPP_OUT_DIR/契约变量,静默容忍了缺失。

影响

挡死 macOS 上一切依赖 consumer-side build.mcpp 合成的源码构建包 —— compat.opencv(jpeg12/16 tu-stub + 可选 unifont 字体 + OpenCL kernel 合成)首当其冲,是 mcpp 生态 macOS 全平台的最后一道系统性障碍(FFmpeg 无 build.mcpp 已在 macos 全绿,见 mcpp-index PR#89)。

建议修复

代码里 L301-303 已有 TODO(launcher-unify)预判此场景("if macOS/Windows ever need the same child-only env isolation … unify both onto posix_spawn")。macOS 完全支持 posix_spawnp + posix_spawn_file_actions_addchdir_np(10.15+)+ environ,把 #if defined(__linux__) 扩为 #if defined(__linux__) || defined(__APPLE__)(run_execcapture_exec 两处)即可让 macOS 走与 linux 相同的直接 exec + merged_environ 路径,契约 env 正确落到子进程,cwd 也对。

最小替代方案(不改 launch primitive):macOS 分支把 env 前缀放到 cd &&之后绑定到真正的 bin——cd <cwd> && KEY='v' ... <bin> 2>&1(即 capture_exec 自己拼前缀,不再交给 capture_with_env 拼到最前)。但 posix_spawn 统一更干净且消掉 shell quoting/注入面。

复现

任意带内联 ["build.mcpp"] 且 build.mcpp 读 MCPP_OUT_DIR 的包,在 macos-15 上 mcpp test -p <member>。手边:mcpp-index 临时 spike PR#90(compat.opencvmac,headless aarch64)。

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