首页
/ rustc_codegen_gcc 常见编译错误排障:failed to build archive 与 crtbegin.o 缺失的根因和修复

rustc_codegen_gcc 常见编译错误排障:failed to build archive 与 crtbegin.o 缺失的根因和修复

2026-09-05 23:32:01作者:侯霆垣

本文围绕 rustc_codegen_gcc(GCC 版 Rust 代码生成后端)开发者文档中的 常见错误清单,逐一拆解两类典型编译/链接失败的根因:LTO 场景下"failed to build archive"归档构建失败,以及 libgccjit 环境下链接器找不到 crtbegin.o 的问题。读完后你将能对照 rustc 源码中的诊断定义与 LTO 调用链定位错误来源,并掌握通过 y.sh 工具链配置 sysroot、修正 LIBRARY_PATH 等环境变量完成修复的实操方法。

一、这份错误清单的位置与适用范围

rustc_codegen_gcc 是 rustc 的 GCC 后端,它不通过 LLVM 生成目标码,而是经 libgccjit 调用 GCC 的编译管线。由于其构建链路(自建 GCC、交叉 libgccjit、补丁版 sysroot)与主流 cg_llvm 后端差异很大,开发者在使用 y.sh 构建 sysroot 和编译项目时,会碰到一些 cg_llvm 下不会出现的报错。

官方错误清单位于 compiler/rustc_codegen_gcc/doc/errors.md,文档开宗明义:"This file lists errors that were encountered and how to fix them."(本文件列出我们遇到过的错误及其修复方法)。同目录下的 doc/ 还有多篇配套文档:tips.md(如何传参给 GCC/链接器、自定义 sysroot、交叉编译)、debugging-libgccjit.mdgimple.md(生成 GIMPLE 中间表示)、sending-gcc-patch.md 等,排障时可结合查阅。

当前清单收录了两类错误:failed to build archive 归档构建错误ld: cannot find crtbegin.o 链接器找不到启动对象文件,下面分别展开。

二、failed to build archive 错误:LTO 与 sysroot 不匹配

2.1 错误现场

当构建出现如下报错时:

error: failed to build archive: failed to open object file: No such file or directory (os error 2)

文档给出的判断是:你可能试图以 lto = "fat" 编译,但 sysroot 并不是用 LTO 编译出来的。文档作者同时注明,这一点当时无法再次复现("Not sure if that's the reason since I cannot reproduce anymore"),推测可能与忘记设置 FAT_LTO 有关。因此该条目应视为一条"经验性线索"而非定论——若你遇到同样报错,可优先检查 LTO 配置一致性,但也要考虑其他归档构建环节的问题。

2.2 报错的源码出处

这条消息并非 rustc_codegen_gcc 自己打印的,而是 rustc 代码生成公共层 rustc_codegen_ssa 的统一诊断。在 compiler/rustc_codegen_ssa/src/diagnostics.rs 中定义了:

#[derive(Diagnostic)]
#[diag("failed to build archive at `{$path}`: {$error}")]
pub(crate) struct ArchiveBuildFailure {
    pub path: PathBuf,
    pub error: std::io::Error,
}

其中 failed to open object file ... 的前缀则来自归档成员读取逻辑 compiler/rustc_codegen_ssa/src/back/archive.rs

ArchiveEntrySource::File(file) => unsafe {
    let mmap = Mmap::map(File::open(&file).map_err(|err| {
        io_error_context(
            &format!("failed to open object file {}", file.display()),
            err,
        )
    })?)
    // ...

即 rustc 在构建/修补 rlib 归档时,需要按清单逐个打开其中的对象文件;一旦某个对象文件缺失(os error 2),外层就会包装成 failed to build archive 一并报出。这说明该错误本质是归档构建流程中引用了不存在的 .o 文件,而"fat LTO + 非 LTO sysroot"只是文档中记录到的一种诱因。

2.3 为什么 fat LTO 会对 sysroot 提出额外要求

查看 GCC 后端对 fat LTO 的实现 compiler/rustc_codegen_gcc/src/back/lto.rs,文件开头的注释直接解释了约束来源:

/// GCC requires to use the same toolchain for the whole compilation when doing LTO.
/// So, we need the same version/commit of the linker (gcc) and lto front-end binaries (lto1,
/// lto-wrapper, liblto_plugin.so).

GCC 做 LTO 时要求整个编译过程使用同一套工具链(链接器 gcc、LTO 前端二进制 lto1、lto-wrapper、liblto_plugin.so 必须同版本/同提交),这与 LLVM 后端把 bitcode 留在 rlib 里、最后统一优化再链接的模型不同。从源码结构看,GCC 后端的 fat LTO 采取的是"合并对象文件"策略:

  • run_fat 会先通过 prepare_lto 把每个参与 LTO 的 rlib 映射进内存,解析归档、挑出 Rust 对象文件(metadata_link.rust_object_files)并落盘到临时目录;
  • 随后 fat_lto 把各 CGU 的模块逐个 compile_to_file 成对象文件,按模块名排序后全部以 driver option 形式喂给基础模块,最终合并为单一对象文件再交给 codegen 输出。

这一流程中大量依赖 rlib 归档内的对象文件能正常读取——若 sysroot 侧的 rlib 与当前 LTO 配置不一致(例如 sysroot 未开 LTO、对象文件布局或命名与预期不符),就可能在归档构建阶段触发"打开对象文件失败"。这也是文档建议"sysroot 编译时同步开启 LTO(例如设置 FAT_LTO)"的内在逻辑。

对应的模块级 LTO 选项注入在 compiler/rustc_codegen_gcc/src/back/write.rs:当 lto_mode != LtoMode::None 且为 fat LTO 时,后端会给 libgccjit 上下文追加 -flto=auto-flto-partition=one 等命令行选项,并用 -Wl,-r-nostdlib 做 relocatable 链接(注释里还说明了不加 -nostdlib 会报 cannot find -lgcc_s)。排障时若怀疑 LTO 选项问题,可以从这条调用链入手检查实际生效的 gcc 命令行。

2.4 处理建议

  • 对照检查:编译项目的 rustflags/Cargo profile 中是否设了 [profile.*] lto = "fat",而 sysroot 是 ./y.sh build --sysroot 默认(无 LTO)构建的;两者保持一致;
  • 若确认按文档所述场景复现,尝试按 LTO 模式重建 sysroot(涉及 FAT_LTO 一类的环境开关);
  • 由于该条目已被作者标注"无法复现、原因未定论",若保持一致后仍报错,建议按 tips.md 中的方法用 CG_RUSTFLAGS="-Clink-args=-save-temps -v" 让链接器保存中间产物并打印命令,逐层确认是哪些对象文件缺失,再回到 archive.rs 的归档读取逻辑核对。

三、ld: cannot find crtbegin.o:libgccjit 环境下的 LIBRARY_PATH 陷阱

3.1 错误现场

用 libgccjit 编译可执行文件时,如果把 *LIBRARY_PATH 系列环境变量指向 GCC 的安装目录(install directory),链接阶段会报:

ld: cannot find crtbegin.o: No such file or directory
ld: cannot find -lgcc: No such file or directory
ld: cannot find -lgcc: No such file or directory
libgccjit.so: error: error invoking gcc driver

最后一行 libgccjit.so: error: error invoking gcc driver 是关键线索:libgccjit 内部是在代你调用 gcc driver,driver 再去找 crt 启动文件和 libgcc 做真正的链接;报错的实际上是这条内部的 gcc driver 调用,而不是你自己的顶层命令。

3.2 根因:crt 文件在 build 目录而不是 install 目录

C 运行时启动对象文件(crtbegin.ocrt1.ocrtend.o 等)和 libgcc.a 是 GCC 构建产物,它们生成在 GCC 源码树的构建目录下;而常规的安装目录(--prefix 下的 lib/)不一定完整包含它们,尤其是自编译、补丁版 GCC 的场景。把 LIBRARY_PATH 指到安装目录后,gcc driver 按该路径搜索 crt 文件便落空,于是出现上面四连报错。

3.3 修复方法

文档给出的修复只有一句话,但非常明确:

To fix this, set the variables to gcc-build/build/gcc.

即把 *LIBRARY_PATH 变量改为指向 GCC 构建目录下的 build/gcc 子目录<gcc-src>/build/gcc)。该目录是 GCC 构建过程中 crt 对象文件和 libgcc 的实际存放位置。示例(按你本地 GCC 源码树路径替换前缀):

export LIBRARY_PATH=/path/to/gcc/build/gcc:$LIBRARY_PATH

注意两点适用前提:

  1. 该问题出现在 rustc_codegen_gcc + libgccjit 的编译组合下——因为 libgccjit 驱动的是你指定的那份 GCC,它的 driver 搜索路径受 *LIBRARY_PATH 影响;
  2. 指向 gcc-build/build/gcc 要求你手上还保留着 GCC 的构建树(而非只拷贝了 install 目录)。若构建树已被清理,需重新构建 GCC 或从构建机同步该目录。

3.4 与文档中其他环境问题的呼应

同一份错误清单的姊妹文档 tips.md 里记录了一个同族问题:交叉编译场景下报 /usr/bin/ld: unrecognised emulation mode: m68kelf 时,需要把 config.toml 中的 gcc-path 指回 install 目录——可见"指到 install 目录"与"指到 build 目录"各有其正确场景:gcc-path 用于定位 libgccjit/GCC 主程序,而 *LIBRARY_PATH 负责 driver 内部搜索 crt 与库文件,两者不能混为一谈。排障时先确认你改的是哪一个变量、它服务于哪一条链路(顶层 y.sh 构建 vs libgccjit 内部 driver 调用)。

四、排障速查

报错特征 出处 根因方向 修复
error: failed to build archive: failed to open object file: No such file or directory (os error 2) rustc_codegen_ssa 诊断归档读取 归档构建时对象文件缺失;已知诱因是 lto = "fat" 但 sysroot 未开 LTO(未定论) 保持项目与 sysroot 的 LTO 配置一致,必要时按 LTO 模式重建 sysroot;用 -save-temps -v 抓取中间产物定位具体缺失文件
ld: cannot find crtbegin.o / cannot find -lgcc + libgccjit.so: error: error invoking gcc driver libgccjit 内部 gcc driver 调用 *LIBRARY_PATH 指向 GCC 安装目录,crt 文件实际在构建目录 将变量指向 gcc-build/build/gcc

五、延伸阅读

登录后查看全文
热门项目推荐
相关项目推荐