Skip to content

A pure-C shared library depends on libstdc++.so.6: everything is linked with the C++ driver #426

Description

@Sunrisepeak

现象

一个纯 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)

两条可能的修法(都需要评估)

  1. 纯 C 链接单元改用 C 驱动。 更正确 —— 一个纯 C 的库本来就该由 gcc 链。
    需要 plan 能回答「这个链接单元的对象里有没有 C++ TU」。跨平台要一并考虑
    (MSVC 的 link.exe 与 macOS 的 clang++ 各有各的隐式库)。
  2. 引入 --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

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