rust-numpy依赖的ndarray版本与项目指定版本冲突导致编译失败,寻求兼容ndarray 0.14的解决方案
问题复现场景
我按照rust-numpy README中的示例编写Python扩展代码,但由于项目需要配合ndarray-linalg必须使用ndarray 0.14版本,而rust-numpy 0.13默认依赖ndarray 0.15.3,导致编译时出现版本冲突错误。
复现代码
src/lib.rs
use ndarray::{ArrayD, ArrayViewD, ArrayViewMutD}; use numpy::{IntoPyArray, PyArrayDyn, PyReadonlyArrayDyn}; use pyo3::prelude::{pymodule, PyModule, PyResult, Python}; #[pymodule] fn rust_ext(_py: Python<'_>, m: &PyModule) -> PyResult<()> { // immutable example fn axpy(a: f64, x: ArrayViewD<'_, f64>, y: ArrayViewD<'_, f64>) -> ArrayD<f64> { a * &x + &y } // mutable example (no return) fn mult(a: f64, mut x: ArrayViewMutD<'_, f64>) { x *= a; } // wrapper of `axpy` #[pyfn(m, "axpy")] fn axpy_py<'py>( py: Python<'py>, a: f64, x: PyReadonlyArrayDyn<f64>, y: PyReadonlyArrayDyn<f64>, ) -> &'py PyArrayDyn<f64> { let x = x.as_array(); let y = y.as_array(); axpy(a, x, y).into_pyarray(py) } // wrapper of `mult` #[pyfn(m, "mult")] fn mult_py(_py: Python<'_>, a: f64, x: &PyArrayDyn<f64>) -> PyResult<()> { let x = unsafe { x.as_array_mut() }; mult(a, x); Ok(()) } Ok(()) }
Cargo.toml
[package] name = "pyotest" version = "0.1.0" edition = "2018" [dependencies] pyo3 = { version = "0.13",features=["extension-module"] } numpy = "0.13" ndarray = "0.14" [lib] name="preprocess" crate-type = ["cdylib"]
编译错误信息
Compiling pyotest v0.1.0 (/home/bokutotu/pyotesterror)
[E0308]: mismatched types
--> src/lib.rs:50:17
|
50 | axpy(a, x, y).into_pyarray(py)
| ^ expected structArrayBase, found structndarray::ArrayBase
| = note: expected structArrayBase<ViewRepr<&f64>, Dim<IxDynImpl>>
found structndarray::ArrayBase<ndarray::ViewRepr<&f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>
= note: perhaps two different versions of cratendarrayare being used?error[E0308]: mismatched types
--> src/lib.rs:50:20
|
50 | axpy(a, x, y).into_pyarray(py)
| ^ expected structArrayBase, found structndarray::ArrayBase
| = note: expected structArrayBase<ViewRepr<&f64>, Dim<IxDynImpl>>
found structndarray::ArrayBase<ndarray::ViewRepr<&f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>
= note: perhaps two different versions of cratendarrayare being used?error[E0599]: no method named
into_pyarrayfound for structArrayBase<OwnedRepr<f64>, Dim<IxDynImpl>>in the current scope
--> src/lib.rs:50:23
|
50 | axpy(a, x, y).into_pyarray(py)
| ^^^^^^^^^^^^ method not found inArrayBase<OwnedRepr<f64>, Dim<IxDynImpl>>error[E0308]: mismatched types
--> src/lib.rs:57:17
|
57 | mult(a, x);
| ^ expected structArrayBase, found structndarray::ArrayBase
| = note: expected structArrayBase<ViewRepr<&mut f64>, Dim<IxDynImpl>>
found structndarray::ArrayBase<ndarray::ViewRepr<&mut f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>
= note: perhaps two different versions of cratendarrayare being used?warning: unused import:
IntoPyArray
--> src/lib.rs:25:13
|
25 | use numpy::{IntoPyArray, PyArrayDyn, PyReadonlyArrayDyn};
| ^^^^^^^^^^^
| = note:#[warn(unused_imports)]on by defaulterror: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0308, E0599.
For more information about an error, tryrustc --explain E0308.error: could not compile
pyotestTo learn more, run the command again with --verbose.
Cargo.lock确认版本冲突
从Cargo.lock可以看到,numpy 0.13.2依赖ndarray 0.15.3,而我们的项目显式依赖ndarray 0.14.0,导致两个版本并存:
[[package]] name = "ndarray" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c0d5c9540a691d153064dc47a4db2504587a75eae07bf1d73f7a596ebc73c04" dependencies = [ "matrixmultiply 0.2.4", "num-complex 0.3.1", "num-integer", "num-traits", "rawpointer", ] [[package]] name = "ndarray" version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08e854964160a323e65baa19a0b1a027f76d590faba01f05c0cbc3187221a8c9" dependencies = [ "matrixmultiply 0.3.1", "num-complex 0.4.0", "num-integer", "num-traits", "rawpointer", ] [[package]] name = "numpy" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a996bcd58fb29bef9debf717330cd8876c3b4adbeea4939020a5326a3afad4d9" dependencies = [ "cfg-if 0.1.10", "libc", "ndarray 0.15.3", "num-complex 0.4.0", "num-traits", "pyo3", ]
解决方案
要解决这个版本冲突,我们需要让numpy crate使用我们指定的ndarray 0.14版本,而不是它默认的0.15.3。可以通过Cargo的强制依赖版本功能来实现:
修改Cargo.toml的[dependencies]部分,给numpy添加ndarray的版本强制指定:
[dependencies] pyo3 = { version = "0.13", features = ["extension-module"] } numpy = { version = "0.13", dependencies = [ "ndarray = { version = \"0.14\" }" ] } ndarray = "0.14"
说明
- 这里我们显式指定
numpy依赖的ndarray版本为0.14,Cargo会优先使用这个版本来满足所有依赖,避免重复编译不同版本的ndarray。 - 从rust-numpy的版本历史来看,0.13.x版本原本就兼容ndarray 0.14,后来才升级到0.15,所以这个强制指定是安全的。
验证修改
修改完成后,运行cargo update更新依赖,然后查看Cargo.lock,你会发现现在只有ndarray 0.14.0一个版本存在,此时重新编译项目就能正常通过了。
如果遇到num-complex的版本冲突,也可以用同样的方式强制指定版本,比如给numpy的依赖里加上num-complex = "0.3.1"来匹配ndarray 0.14的依赖。
内容的提问来源于stack exchange,提问作者musako

