Skip to content

obj/std.o 被无条件链进每个单元:纯 C 的 compat 包因此依赖 libstdc++.so.6 #416

Description

@speak-agent

现象

obj/std.o(import std 的模块对象)被无条件链进每一个 Binary / TestBinary /
SharedLibrary 单元,完全不看该单元是否真的 import std

src/build/ninja_backend.cppm:1362-1381:

switch (lu.kind) {
    case LinkUnit::Binary:
    case LinkUnit::TestBinary:
        if (has_std_artifacts)
            ins += " " + escape_ninja_path(std_o_dst);   // ← 无条件case LinkUnit::SharedLibrary:
        if (has_std_artifacts)
            ins += " " + escape_ninja_path(std_o_dst);   // ← 无条件
        …
}

has_std_artifacts 只表示"这个工具链有预构建的 std 模块",与单元自身的需求无关。

实测:bin/libXau.so 的链接输入 = 8 个纯 C 的 .o + 一个 obj/std.o
compat.xau 里没有一行 C++。

后果

#414 之前,这与共享库的 -static-libstdc++ 叠加,把整个 libstdc++.a 拖进纯 C 的
compat 包:libXau.so 39KB → 9.5MB,并导出 777 个 GLOBAL 标准库定义。

#414 把 ELF 共享库改判 toolchain-coupled 之后体积已经回落(实测 libXau 39 368 B),
std.o 仍在,于是纯 C 的 compat 包(libXau / libXdmcp / libX11)凭空多一条
NEEDED libstdc++.so.6:

$ readelf -d bin/libX11.so | grep NEEDED
 … libstdc++.so.6 …        ← compat.x11 是纯 C

一个纯 C 的库不该依赖 C++ 运行时。它现在依赖,只是因为链接输入里多了一个对象。

建议

std_o_dst 的追加条件从「工具链有 std 模块」收窄到「这个链接单元真的需要它」。

需要先确认的两点:

  1. import std 的传递性 —— 依赖的 BMI 传递 import std 是有历史坑的
    (见 dep BMI 缓存跨版本毒化那次)。判据不能只看本单元的源码。
  2. 静态库单元:StaticLibraryar,本来就不追加,不受影响。

判据

  • 一个纯 C 的 compat 包产出的 .so,readelf -d没有 libstdc++.so.6
  • 一个 import std 的工程仍正常链接、运行
  • 一个间接通过依赖的模块接口用到 std 的工程仍正常链接(传递性不能漏)

背景

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