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

如何从源码构建pfapack并在Rust crate中供依赖链接?

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

我需要在Rust中对接小众库pfapack,由于该库很少预装在用户机器上,最优方案是用户只需在Cargo.toml中添加依赖即可自动编译。我希望将目标文件输出到OUT_DIR,以便引入pfapack-sys的crates能链接到编译后的库,为此编写了Makefile并通过build.rs调用,但目前无法通过rustc-link-lib=pfapack从其他crate链接到这些库。请问这种处理方式是否正确?能否这样使用build.rs?


我的Makefile示例:

CC = gcc
CFLAGS = -O3
C_DIR = $(OUT_DIR)/c_interface
OBJECTS= $(C_DIR)/skpfa.o $(C_DIR)/skpf10.o $(C_DIR)/skbpfa.o $(C_DIR)/skbpf10.o $(C_DIR)/sktrf.o $(C_DIR)/sktrd.o $(C_DIR)/skbtrd.o

all: $(OBJECTS)
    $(AR) rvu $(C_DIR)/libcpfapack.a $(OBJECTS)

clean:
    rm -f *.o
    rm -f libcpfapack.a

.SUFFIXES: .o .c

.c.o:
    $(CC) $(CFLAGS) -c $< -o $(C_DIR)/$@

我的build.rs脚本:

// build script
use std::process::Command;
use std::path::Path;
use std::env;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir);
    let c_interface = out_dir.join(Path::new("c_interface"));
    let fortran = out_dir.join(Path::new("fortran"));

    // Compile source
    Command::new("make").output()
        .expect("Failed to make");

    println!("cargo:rustc-link-search={}", c_interface.display());
    println!("cargo:rustc-link-search={}", fortran.display());
    println!("cargo:rustc-link-lib=gfortran");
    println!("cargo:rustc-link-lib=lapack");
    println!("cargo:rustc-link-lib=blas");
}

解决方案

你的核心思路是对的,但实现中有几个关键问题导致链接失败,调整如下:

  • 传递OUT_DIR给Makefile
    Makefile里引用了$(OUT_DIR),但调用make时没有把Rust环境中的OUT_DIR传进去,导致路径失效。修改build.rs的调用逻辑:

    Command::new("make")
        .env("OUT_DIR", &out_dir)
        .output()
        .expect("Failed to make");
    
  • 添加静态库链接声明
    你漏了告诉Cargo要链接编译好的cpfapack和pfapack静态库,需要在build.rs末尾补充:

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

    加static=前缀是明确指定链接静态库,避免Cargo去搜索系统中的动态库。

  • 修正Makefile的clean命令
    当前clean操作只会删除当前目录的文件,而编译产物在$(OUT_DIR)/c_interface下,修改后:

    clean:
        rm -f $(C_DIR)/*.o
        rm -f $(C_DIR)/libcpfapack.a
    
  • 确保Fortran库的编译路径正确
    你在build.rs中添加了fortran目录的搜索路径,但要确认pfapack的Fortran源码已经正确编译为libpfapack.a并放在$(OUT_DIR)/fortran目录下,否则会出现未定义符号问题。

另外注意:如果是开发pfapack-sys这类底层绑定库,所有链接声明都应该放在该库的build.rs中,上层依赖库只需添加pfapack-sys为依赖,Cargo会自动传递链接参数,不需要上层手动添加rustc-link-lib。同时要在README中说明用户需要预先安装gfortran、lapack、blas的开发包。

内容的提问来源于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 05:07:53