5个不稳定版本
0.3.1 | 2023年2月23日 |
---|---|
0.3.0 | 2023年2月22日 |
0.2.1 | 2023年2月14日 |
0.1.1 | 2023年2月13日 |
#1362 在 算法
每月24次下载
73KB
1.5K SLoC
matlab-sys
matlab-sys
提供了对Matlab C API的低级别绑定。这允许使用Rust编写MEX函数,使用C矩阵API,通过C MAT API交互,并使用Rust编写Matlab引擎应用程序。
绑定主要是由bindgen自动生成的,名称与C头文件中的名称相同或类似。对绑定进行了一些手动更改,以便于使用或简化暴露的API,同时不牺牲功能,例如用Rust的本地固定大小整数类型替换固定大小整数类型的类型定义。
使用方法
为了使用此crate提供的功能,必须将其链接到Matlab安装提供的库文件 libmex.lib
、libmx.lib
、libmat.lib
和 libeng.lib
。如果环境变量 MATLABPATH
设置为要链接的Matlab安装目录,则将优先使用此路径。否则,构建脚本将尝试通过在构建机器上运行以下命令来查找默认matlab安装的安装目录: matlab -batch "disp(matlabroot)"
。这通常需要Matlab启动几秒钟,因此明确在上述环境变量中提供路径有助于编译时间,应优先使用。
如果您对链接过程有特殊要求,无法通过上述方法处理,则可以在包含rustc-link-lib和rustc-link-search键的.config
文件中指定必要的链接指令。更多信息请见此处。
直接构建MEX函数
要在Rust中构建mex函数,crate类型必须是一个使用C ABI的动态链接库。在你的cargo.toml
中设置crate-type = ["cdylib"]
。无论从Matlab中以什么名称调用,每个MEX函数都需要以下签名的入口点
#[no_mangle]
pub unsafe extern "C" fn mexFunction(
nlhs: c_int,
plhs: *mut *mut mxArray,
nrhs: c_int,
prhs: *const *const mxArray,
){/* your calculation */}
构建完成后,将构建工件文件的扩展名更改为Windows上的*.mexw64
或Linux上的*.mexa64
。将重命名的文件复制到Matlab可以找到的位置。现在你应该能够使用不带扩展名的文件名调用你的mex函数。
示例
以下是arrayProduct示例的快速简单翻译,该示例将标量与矩阵相乘(为简洁起见省略了大多数错误处理)
use matlab_sys::interleaved_complex as raw;
use std::ffi::{c_int, CString};
#[no_mangle]
pub unsafe extern "C" fn mexFunction(
nlhs: c_int,
plhs: *mut *mut raw::mxArray,
nrhs: c_int,
prhs: *const *const raw::mxArray,
) {
if nrhs != 2 {
// Letting the standard library do the work of making Rusts strings C-compatible
raw::mexErrMsgIdAndTxt(
CString::new("MyToolbox:arrayProduct:nrhs").unwrap().as_ptr(),
CString::new("Two inputs required.").unwrap().as_ptr()
);
}
if nlhs != 1 {
// Writing C-compatible strings manually
raw::mexErrMsgIdAndTxt(
b"MyToolbox:arrayProduct:nlhs\0".as_ptr().cast(),
b"One output required.\0".as_ptr().cast()
);
}
// SAFETY: nlhs and nrhs should get verified to be greater or equal to 0 and all pointers should get tested for validity
let plhs = std::slice::from_raw_parts_mut(plhs, nlhs as usize);
let prhs = std::slice::from_raw_parts(prhs, nrhs as usize);
/* get the value of the scalar input */
let multiplier = raw::mxGetScalar(prhs[0]);
/* create a pointer to the real data in the input matrix */
let inMatrix = raw::mxGetDoubles(prhs[1]);
/* get dimensions of the input matrix */
let ncols = raw::mxGetN(prhs[1]);
/* create the output matrix */
plhs[0] = raw::mxCreateDoubleMatrix(1, ncols, raw::mxComplexity::mxREAL);
/* get a pointer to the real data in the output matrix */
let outMatrix = raw::mxGetDoubles(plhs[0]);
/* call the computational routine */
array_product(multiplier, inMatrix, outMatrix, ncols);
}
unsafe fn array_product(x: f64, y: *mut f64, z: *mut f64, n: usize) {
unsafe {
for i in 0..n {
*z.add(i) = x * *y.add(i);
}
}
}
更多示例可以在mex-examples目录中找到。这些示例是Matlab随原版C示例一起分发的直接翻译。它们也用作绑定的测试,因此它们应该始终能够编译并工作。
在matlab-sys
上构建抽象
虽然Rust与C库交互的能力很好,但它的真正力量在于它构建安全、易于使用、不易误用的抽象的能力。这个crate旨在作为Matlab扩展上下文中这些抽象的共同构建块。
如果你正在开发这样的抽象,请告诉我!我很乐意了解我的工作是如何被使用的,并在这里推广你的crate。
特性
matlab-sys
公开了较旧的单独复数 C API,Mathworks计划在未来弃用,以及较新的交错复数 C API,它将在Matlab中成为默认选项。虽然单独复数 API中的大多数函数也存在于交错复数 API中,但有一些重要差异。例如,交错复数 API提供了新的方便和更安全的类型数据访问功能。最重要的是,尽管API保持不变,但某些类型有不同的表示(例如复数的mxArray)和某些函数的行为也不同(例如mxGetData)。为了最小化这两种API版本之间产生的混淆风险,matlab-sys
在单独的命名空间中公开它们。
不要使用一个命名空间中的函数与另一个命名空间中的类型。由于命名空间是类型的一部分,Rust的类型系统有助于防止此问题。为了进一步防止此问题,建议在crate中使用相应功能激活你打算使用的API。有关API差异的更多信息,请参阅此处。
在 Matlab 中,使用 mex
命令时无法同时启用 API 的两个版本,这有助于减轻 API 混用的风险。虽然可以通过使用互斥功能在此 crate 中实现互斥的 API,但这会导致一些显著的缺点。Cargo 的依赖解析器统一了 crate 中所有由依赖树中任何依赖 crate 启用的功能,实际上是将所有启用的功能组合在一起编译 crate。对于互斥功能,这会导致多个独立的中间依赖无法使用不同的 API,即使是在内部。通过将它们保存在不同的命名空间中,启用它们的功能满足Cargo 对功能必须是纯累加的要求。
separate-complex
此功能启用较旧的 API 版本,并对应于使用 Matlab 的 mex
命令不带额外参数或带额外参数 -R2017b
编译时提供的 API。正如其名称所暗示的,复杂数组的内部表示由分别表示实部和虚部的数组组成。这是 Matlab 版本 R2017b
及以前版本唯一可用的选项。对于所有后续版本,Matlab 在内部使用交错复数表示。使用此 API 与 R2017b
之后的 Matlab 版本一起使用,在转换为单独的复数表示时可能会发生不必要的复制。此外,许多较新 API 的新功能,如类型数据访问,也不可用。
interleaved-complex - default
此功能启用较新的 API 版本,并对应于使用 Matlab 的 mex
命令带额外参数 -R2018a
编译时提供的 API。此 API 将成为未来使用 Matlab 的 mex
命令编译的新默认 API。复杂数组的内部表示由一个单一数组表示,其中实部和虚部是交错的。这是 Matlab 自 R2018a
版本以来内部使用的表示。因此,在接口处不需要复制。这种表示也由大多数流行的数值库使用,进一步减少了复制或转换的需要。使用此功能与 R2018a
之前的 Matlab 版本将无法正常工作!对于所有较新版本,这是推荐的 API。