如何确保Rust FFI crate中SuperLU始终以-fPIC编译?
问题
我的Rust项目通过superlu-sys(绑定C库SuperLU的FFI crate)调用SuperLU,同时用PyO3生成Python绑定。构建时出现链接错误:
relocation R_X86_64_PC32 against symbol `stderr@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
奇怪的是,superlu-sys的build.rs里已经强制指定了-fPIC参数:
run!(cmd!("make") .current_dir(&source.join("SRC")) .arg("NOOPTS=-O0 -fPIC -w") .arg("CFLAGS=-O3 -DNDEBUG -DPRNTlevel=0 -fPIC -w") .arg("DZAUX=") .arg("SCAUX=") .arg(&format!("SuperLUroot={}", source.display())) .arg(&format!( "SUPERLULIB={}", lib.join("libsuperlu.a").display() )));
通过最小示例测试发现,只有当PyO3绑定和SuperLU构建在同一个crate时才能正常运行,推测build.rs的参数只在crate树的根目录生效。请问如何修改build.rs确保-fPIC参数被一致执行?
最小示例代码:
lib.rs
use pyo3::prelude::*; use std::os::raw::c_int; use superlu_sys; #[pyclass] pub struct Object {} #[pymethods] impl Object { pub fn test(&self) -> i32 { unsafe { *superlu_sys::intMalloc(1 as c_int) } } } #[allow(unused)] #[pymodule] fn bind_superlu(py: Python, m: &PyModule) -> PyResult<()> { m.add_class::<Object>()?; Ok(()) }
Cargo.toml
[package] name = "bind_superlu" version = "0.1.0" edition = "2021" [lib] name = "ress" crate-type = ["cdylib"] [dependencies] superlu-sys = "0.3.4" pyo3 = {version = "0.18.1", features = ["auto-initialize"]}
解决方法
强制传递全局编译参数
在根crate的build.rs中,直接设置CFLAGS环境变量,确保superlu-sys编译时必然带上-fPIC:fn main() { // 直接覆盖CFLAGS,强制加入-fPIC std::env::set_var("CFLAGS", "-fPIC"); // 若需保留原有CFLAGS,可改为追加: // let mut cflags = std::env::var("CFLAGS").unwrap_or_default(); // cflags += " -fPIC"; // std::env::set_var("CFLAGS", cflags); }清理缓存重新构建
之前superlu-sys可能已用非PIC参数编译出静态库,执行以下命令清理缓存后重新构建:cargo clean cargo build检查SuperLU Makefile参数接收逻辑
部分SuperLU版本的Makefile可能忽略传入的CFLAGS,可修改superlu-sys的build.rs,将-fPIC直接硬编码到编译命令中,或者在下载SuperLU源码后,手动修改其Makefile,在默认编译选项中加入-fPIC。确认根crate编译类型
你的Cargo.toml已设置crate-type = ["cdylib"](生成Python绑定的正确类型),需确保所有依赖的静态库都以PIC方式编译,才能被动态链接库正常引用。
内容的提问来源于Stack Exchange,提问作者Henrik
相关产品推荐
相关产品推荐

