{"record":{"id":"3c7e04bcbf349e84","repo":"rust-lang/rust","slug":"lto-object-in-c-static-library-is-not-supported","errorCode":null,"errorMessage":"LTO object in C static library is not supported","messagePattern":"LTO object in C static library is not supported","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"compiler/rustc_codegen_ssa/src/back/link.rs","lineNumber":2845,"sourceCode":"            .data(&*archive_map)\n            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;\n\n        // clang LTO: raw LLVM bitcode\n        if data.starts_with(b\"BC\\xc0\\xde\") {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"LLVM bitcode object in C static library (LTO not supported)\",\n            ));\n        }\n\n        let object = object::File::parse(&*data)\n            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;\n\n        // gcc / clang ELF / Mach-O LTO\n        if object.sections().any(|s| {\n            s.name().map(|n| n.starts_with(\".gnu.lto_\") || n == \".llvm.lto\").unwrap_or(false)\n        }) {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"LTO object in C static library is not supported\",\n            ));\n        }\n\n        for symbol in object.symbols() {\n            // The `object` crate returns `Dynamic` for ELF/Mach-O global symbols,\n            // but always returns `Linkage` for COFF external symbols.\n            // Accept both for COFF (Windows and UEFI).\n            let scope = symbol.scope();\n            if scope != object::SymbolScope::Dynamic\n                && !(sess.target.binary_format == BinaryFormat::Coff\n                    && scope == object::SymbolScope::Linkage)\n            {\n                continue;\n            }\n\n            let name = match symbol.name() {","sourceCodeStart":2827,"sourceCodeEnd":2863,"githubUrl":"https://github.com/rust-lang/rust/blob/7088e4b63a9516ebfbfe2ab2d999cf01a528ac14/compiler/rustc_codegen_ssa/src/back/link.rs#L2827-L2863","documentation":"Emitted by add_c_staticlib_symbols alongside error 167, but for a different LTO representation. After parsing each archive member as an object file, the linker checks whether any section name starts with .gnu.lto_ or equals .llvm.lto (link.rs:2842-2843). These section names indicate gcc or clang ELF/Mach-O intermediate LTO representation — the object contains linker-ir LTO data instead of final machine code. rustc's archive symbol scanner cannot handle these, so it aborts.","triggerScenarios":"Building a Rust cdylib that links a C static library compiled with gcc -flto or clang -flto where the output uses ELF/Mach-O LTO sections (rather than raw bitcode). Triggered only when crate_type is Cdylib and the lib has NativeLibKind::Static { export_symbols: Some(true), .. }.","commonSituations":"C/C++ dependency built with gcc -flto on Linux (producing .gnu.lto_* sections); a prebuilt .a from a distribution that enables LTO by default (e.g., some Alpine or Gentoo packages); FFIs wrapping system libraries that were built with distro-wide LTO flags.","solutions":["Recompile the C static library without -flto and relink the Rust cdylib.","Check the distro build flags (e.g., Arch Linux's /etc/makepkg.conf LTOFLAGS) and disable LTO for the library in question.","Build the dependency from source with CFLAGS=\"-fno-lto\" if a non-LTO prebuilt variant is unavailable.","Verify the fix with: objdump -h libfoo.a | grep lto — output should be empty."],"exampleFix":"# before: system .a built with gcc -flto (has .gnu.lto_ sections)\n# after: rebuild from source without LTO\nCFLAGS=\"-fno-lto\" ./configure && make\n# or with cmake:\ncmake -DCMAKE_C_FLAGS=\"-fno-lto\" -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF ..","handlingStrategy":"validation","validationCode":"// Before linking, scan the C static library for ELF/Mach-O LTO sections.\nuse std::fs;\nuse std::path::Path;\n\nfn check_no_elf_lto(lib_path: &Path) -> Result<(), String> {\n    let data = fs::read(lib_path).map_err(|e| format!(\"read error: {e}\"))?;\n    let archive = object::read::archive::ArchiveFile::parse(&data)\n        .map_err(|e| format!(\"archive parse error: {e}\"))?;\n    for member in archive.members() {\n        let member = member.map_err(|e| format!(\"member error: {e}\"))?;\n        let member_data = member.data(&data).map_err(|e| format!(\"data error: {e}\"))?;\n        let obj = object::File::parse(member_data).map_err(|e| format!(\"parse error: {e}\"))?;\n        for section in obj.sections() {\n            if let Ok(name) = section.name() {\n                if name.starts_with(\".gnu.lto_\") || name == \".llvm.lto\" {\n                    return Err(format!(\"library contains LTO section '{}': recompile without -flto\", name));\n                }\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"// Same as error 167 — surfaces as a rustc fatal diagnostic.\n// Prevent by recompiling the C dependency without -flto.\n// Quick check from the command line:\n//   objdump -h libfoo.a | grep -E '\\.gnu\\.lto_|\\.llvm\\.lto'\n// If output is non-empty, the library has LTO sections.","preventionTips":["Build C dependencies with -fno-lto or CMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF.","Check distro package build flags — some distros (Arch, Gentoo) enable LTO globally.","Run objdump -h libfoo.a | grep lto before linking to catch LTO sections early.","Maintain a non-LTO build variant of C libraries specifically for Rust cdylib interop."],"tags":["rustc","linker","lto","cdylib","static-lib","gcc"],"backgroundTag":null,"analyzedSha":"7088e4b63a9516ebfbfe2ab2d999cf01a528ac14","analyzedAt":"2026-08-10T14:17:03.603Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}