如何从源码构建pfapack并在Rust crate中供依赖链接?
我需要在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

