现象
一个纯 C 的共享库(两个 .c,没有一行 C++)产出的 .so 依赖 C++ 运行时:
$ readelf -d bin/libpurec.so | grep NEEDED
libstdc++.so.6 ← 纯 C 的库
libm.so.6
libgcc_s.so.1
libc.so.6
真因
链接一律走 C++ 驱动:
cxx = .../xim-x-gcc/16.1.0/bin/g++
rule cxx_shared
command = $cxx -shared @$out.rsp -o $out $ldflags $soname_flag $unit_ldflags
g++ 隐式追加 -lstdc++,而全仓 --as-needed 只用在 -latomic 那一处
(src/build/flags.cppm:240),于是 -lstdc++ 无条件成为 NEEDED ——
即使没有任何符号引用它。
⚠️ 这不是 #416。 那条把症状归因给 obj/std.o,实测证否:同一次构建里
build.ninja 根本没有 std.o,产物里 _ZGIW3std 符号数为 0,而 NEEDED 照样在。
详见 #416 (comment)
两条可能的修法(都需要评估)
- 纯 C 链接单元改用 C 驱动。 更正确 —— 一个纯 C 的库本来就该由
gcc 链。
需要 plan 能回答「这个链接单元的对象里有没有 C++ TU」。跨平台要一并考虑
(MSVC 的 link.exe 与 macOS 的 clang++ 各有各的隐式库)。
- 引入
--as-needed。 更小,但它会丢掉只被 dlopen 使用的库 ——
mcpp 现在对 -latomic 用 --push-state,--as-needed,...,--pop-state 正是
为了把作用域限死。全局启用需要单独验证 GPU / GL 那条链。
判据
- 一个纯 C 的共享库工程,
readelf -d 里没有 libstdc++.so.6
- 一个 C++ 工程仍正常链接、运行
- 一个通过
dlopen 使用某个库的工程仍能加载到它(第 2 种修法的反向判据)
复现
[package]
name = "purec"
version = "0.1.0"
[targets.purec]
kind = "shared"
sources = ["src/*.c"]
两个只含 C 函数的 .c,mcpp build --release,然后 readelf -d。
现象
一个纯 C 的共享库(两个
.c,没有一行 C++)产出的.so依赖 C++ 运行时:真因
链接一律走 C++ 驱动:
g++隐式追加-lstdc++,而全仓--as-needed只用在-latomic那一处(
src/build/flags.cppm:240),于是-lstdc++无条件成为NEEDED——即使没有任何符号引用它。
obj/std.o,实测证否:同一次构建里build.ninja根本没有std.o,产物里_ZGIW3std符号数为 0,而NEEDED照样在。详见 #416 (comment)
两条可能的修法(都需要评估)
gcc链。需要 plan 能回答「这个链接单元的对象里有没有 C++ TU」。跨平台要一并考虑
(MSVC 的
link.exe与 macOS 的clang++各有各的隐式库)。--as-needed。 更小,但它会丢掉只被 dlopen 使用的库 ——mcpp 现在对
-latomic用--push-state,--as-needed,...,--pop-state正是为了把作用域限死。全局启用需要单独验证 GPU / GL 那条链。
判据
readelf -d里没有libstdc++.so.6dlopen使用某个库的工程仍能加载到它(第 2 种修法的反向判据)复现
两个只含 C 函数的
.c,mcpp build --release,然后readelf -d。