{"record":{"id":"e7ec1d37c646bb5a","repo":"rust-lang/rust","slug":"llvm-bitcode-object-in-c-static-library-lto-not-s","errorCode":null,"errorMessage":"LLVM bitcode object in C static library (LTO not supported)","messagePattern":"LLVM bitcode object in C static library \\(LTO not supported\\)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"compiler/rustc_codegen_ssa/src/back/link.rs","lineNumber":2832,"sourceCode":"    out: &mut Vec<SymbolExport>,\n) -> io::Result<()> {\n    let file_path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);\n\n    let archive_map = unsafe { Mmap::map(File::open(&file_path)?)? };\n\n    let archive = object::read::archive::ArchiveFile::parse(&*archive_map)\n        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;\n\n    for member in archive.members() {\n        let member = member.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;\n\n        let data = member\n            .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","sourceCodeStart":2814,"sourceCodeEnd":2850,"githubUrl":"https://github.com/rust-lang/rust/blob/7088e4b63a9516ebfbfe2ab2d999cf01a528ac14/compiler/rustc_codegen_ssa/src/back/link.rs#L2814-L2850","documentation":"Emitted by add_c_staticlib_symbols in rustc's linker code when building a cdylib that needs to export symbols from a linked C static library. The function scans archive members and checks if any start with the LLVM bitcode magic bytes BC\\xc0\\xde (link.rs:2831). This indicates the C static library was compiled with clang -flto and contains raw LLVM bitcode objects instead of machine code. rustc cannot extract symbols from or link LLVM bitcode in C static libraries, so compilation aborts.","triggerScenarios":"Building a Rust cdylib crate type with a C static library dependency (declared via #[link(name = \"...\", kind = \"static\")] with export_symbols enabled) where the .a file was produced by clang -flto. The NativeLibKind must be Static { export_symbols: Some(true), .. } for add_c_staticlib_symbols to be invoked (link.rs:2928).","commonSituations":"A C/C++ dependency built with clang -flto for performance; a system package or Homebrew formula that defaults to LTO; switching a C library's build system to enable LTO; a prebuilt vendor SDK shipped with LTO bitcode objects.","solutions":["Recompile the C static library without -flto (e.g., remove -flto from CFLAGS/CXXFLAGS) and rebuild the Rust cdylib.","If you control the C build, produce two variants: an LTO version for C-only builds and a non-LTO version for Rust interop.","If using a system-provided static lib, check for a non-LTO variant or build from source without LTO.","On some systems, use -fno-lto when compiling just the static library's translation units."],"exampleFix":"# before: C lib compiled with LTO\ncmake -DCMAKE_C_FLAGS=\"-flto=thin\" ... && make\n# the resulting libfoo.a contains BC\\xc0\\xde members\n# after: compile without LTO for Rust interop\ncmake -DCMAKE_C_FLAGS=\"-fno-lto\" ... && make\n# then rebuild the Rust cdylib","handlingStrategy":"validation","validationCode":"// Before linking, scan the C static library for LLVM bitcode members.\nuse std::fs;\nuse std::path::Path;\n\nfn check_no_llvm_bitcode(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        if member_data.starts_with(b\"BC\\xc0\\xde\") {\n            return Err(format!(\"library contains LLVM bitcode (LTO): recompile without -flto\"));\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"// This error surfaces as a rustc fatal: 'failed to process C static library'.\n// There is no runtime catch — the compiler aborts. Prevent it by validating\n// the library before building, or by recompiling the C dependency without -flto.\n// In build.rs:\nfn main() {\n    // ensure the C library is built without LTO\n    println!(\"cargo:rustc-link-lib=static=foo\");\n}","preventionTips":["Compile C static libraries with -fno-lto when they will be linked into a Rust cdylib.","Check for LLVM bitcode with: objcopy --dump-section .llvm.lto=/dev/null libfoo.a /dev/null or scan for the BC magic bytes.","If using clang, pass -fno-lto or -emit-obj to produce machine code, not bitcode.","Document the no-LTO requirement for C dependencies in your project's build instructions."],"tags":["rustc","linker","lto","cdylib","static-lib","clang"],"backgroundTag":null,"analyzedSha":"7088e4b63a9516ebfbfe2ab2d999cf01a528ac14","analyzedAt":"2026-08-10T14:17:03.603Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}