You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Rust FFI中使用C/Fortran库pfapack时遇未定义符号问题

在Rust中调用Fortran编写的pfapack库时出现未定义符号错误

我想在Rust里使用pfapack库(该库由Fortran编写,提供C接口),于是制作了包含该库源码的Rust crate(pfapack-sys),供其他Rust项目调用,但测试项目编译时出现未定义符号错误。

操作步骤

  1. 创建包含pfapack源码的新crate
  2. 编写pfapack-sys的build.rs:
use std::process::Command;

fn main() {
// 这个Makefile会调用自定义根Makefile,仅执行c_interface/和fortran/下的两个Makefile
    Command::new("make").output() 
        .expect("Failed to make");

    println!("cargo:rustc-link-search=c_interface");
    println!("cargo:rustc-link-search=fortran");
    println!("cargo:rustc-link-lib=static=pfapack");
    println!("cargo:rustc-link-lib=static=cpfapack");
    println!("cargo:rustc-link-lib=gfortran");

}
  1. 测试项目的build.rs:
fn main() {
    println!("cargo:rustc-link-lib=lapack");
    println!("cargo:rustc-link-lib=blas");
}

参考信息

  • pfapack原始编译示例:
gcc -O3 -I c_interface/ foo.c -o foo.out c_interface/libcpfapack.a fortran/libpfapack.a -lm -lblas -llapack -lgfortran
  • 绑定生成命令(参考lapack-sys脚本):
#!/bin/bash
set -eux

bindgen --allowlist-function='^.*_$' --use-core pfapack.h \
  | sed -e 's/::std::os::raw:://g' \
  | sed -e '/__darwin_size_t/d' \
  > pfapack.rs

rustfmt pfapack.rs
  • pfapack-sys的Cargo.toml配置:
[package]
name = "pfapack-sys"
version = "0.1.0"
edition = "2021"
links = "pfapack"

[dependencies]
libc = "0.2"

[dependencies.num-complex]
version = "0.4"
default-features = false

[lib]
name = "pfapack_sys"

[build-dependencies]
cc = "1.0.79"

编译错误信息

= note: /usr/bin/ld: /home/dumbo/Documents/test_pfapack/target/debug/deps/test_pfapack-d08bc25fe63b6ef8.ka29pyd46xgunxk.rcgu.o: in function `pfapack_sys::dskpfa':
          /home/dumbo/Documents/pfapack-sys/src/pfapack-bind.rs:249: undefined reference to `dskpfa'
          collect2: error: ld returned 1 exit status
 
  = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
  = note: use the `-l` flag to specify native libraries to link
  = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo
 
error: could not compile `test_pfapack` due to previous error

问题排查与解决思路

1. 检查符号名的名称修饰问题

Fortran编译后的符号名通常会有修饰规则(比如后缀加下划线、全大写等),bindgen生成的绑定可能匹配错了符号名:

  • 用nm c_interface/libcpfapack.a | grep dskpfa查看库中实际导出的符号,比如可能是dskpfa_(带下划线)。
  • 如果符号名带下划线,要么修改bindgen命令匹配正确符号,要么在生成的绑定代码中给对应函数添加#[link_name = "dskpfa_"]属性指定正确链接名。

2. 调整链接库的顺序

链接器对库的顺序敏感,依赖库要放在被依赖库的后面。参照原始编译命令,修改pfapack-sys的build.rs链接指令顺序:

let root_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
println!("cargo:rustc-link-search={}/c_interface", root_dir);
println!("cargo:rustc-link-search={}/fortran", root_dir);

// 按依赖顺序排列:cpfapack依赖pfapack,pfapack依赖blas、lapack等
println!("cargo:rustc-link-lib=static=cpfapack");
println!("cargo:rustc-link-lib=static=pfapack");
println!("cargo:rustc-link-lib=blas");
println!("cargo:rustc-link-lib=lapack");
println!("cargo:rustc-link-lib=m");
println!("cargo:rustc-link-lib=gfortran");

3. 确保库文件路径正确

用CARGO_MANIFEST_DIR获取crate根目录的绝对路径,避免相对路径在不同编译场景下出错,如上一步代码所示。

4. 验证Makefile编译结果

手动执行make命令,确认c_interface/libcpfapack.a和fortran/libpfapack.a正常生成,没有编译报错。

5. 移除测试项目的build.rs

测试项目无需自己链接lapack和blas,Cargo会自动传递pfapack-sys的链接指令,移除测试项目的build.rs可避免重复链接或顺序冲突。

内容的提问来源于stack exchange,提问作者Dumbo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 04:12:35