如何修复 Rust clang crate 的符号查找错误:undefined symbol: LLVMInitializeAArch64TargetInfo

问题

在尝试运行使用 clang crate 的 Rust 可执行文件时,你会看到类似下面的错误信息:

clang_symbol_lookup_error.txt
$ cargo run clangtest.cpp
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/asx clangtest.cpp`
target/debug/clangtest: symbol lookup error: /lib/x86_64-linux-gnu/libclang-19.so.19: undefined symbol: LLVMInitializeAArch64TargetInfo, version LLVM_19.1

解决方案

出现此错误是因为 Cargo 链接了错误的 libLLVM。常见原因是安装了 rocm(AMD 的计算栈),它自带了与 libclang 所使用的不兼容的 libLLVM

要解决此问题,请添加 build.rs

build.rs
use std::{env, path::{Path, PathBuf}};

fn main() {
    // 允许通过环境变量覆盖,以提供灵活性。
    // 示例:LLVM19_LIB_DIR=/custom/llvm19/lib cargo build
    let llvm_dir = env::var("LLVM19_LIB_DIR").unwrap_or_else(|_| "/usr/lib/llvm-19/lib".to_string());
    let llvm_so_candidates = [
        "libLLVM.so",            // soname 符号链接
        "libLLVM-19.so",         // 备选命名模式
        "libLLVM.so.19",         // 带版本号模式
        "libLLVM.so.19.1",       // 特定次版本
    ];

    let dir_path = Path::new(&llvm_dir);
    if !dir_path.is_dir() {
        panic!("LLVM directory '{llvm_dir}' does not exist. Set LLVM19_LIB_DIR to the correct path.");
    }

    // 尝试找到一个实际存在的库文件,以便显式传递给链接器,
    // 避免从其他位置(例如 /opt/amdgpu)选取。
    let chosen_lib: Option<PathBuf> = llvm_so_candidates.iter()
        .map(|name| dir_path.join(name))
        .find(|p| p.exists());

    if let Some(lib_path) = chosen_lib {
        let lib_dir = lib_path.parent().unwrap();
        // 确保优先搜索我们期望的目录
        println!("cargo:rustc-link-search=native={}", lib_dir.display());
        // 仍然发出通用的 link-lib,以满足可能分散在各组件中的符号。
        println!("cargo:rustc-link-lib=dylib=LLVM");
        // 通过将库的绝对路径作为链接器参数传递来强制使用该库
        // (放在对象之后,以便用于符号解析)
        println!("cargo:rustc-link-arg={}", lib_path.display());
        // 添加 rpath,使运行时加载器也优先使用此目录。
        println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir.display());
        // 可选地,将我们的路径添加到 RUNPATH 以同样优先使用
        // (GNU ld 对 rpath/runpath 的处理略有不同;在此使用 rpath 对大多数系统已足够)
        println!("cargo:rerun-if-env-changed=LLVM19_LIB_DIR");
    } else {
        panic!("Could not locate any libLLVM* candidate in {llvm_dir}. Candidates tried: {:?}", llvm_so_candidates);
    }
}

此外,还需要在 Cargo.toml 中配置使用该构建脚本:

Cargo.toml
[package]
build = "build.rs"

Check out similar posts by category: Rust