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次下载

MIT/Apache

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.liblibmx.liblibmat.liblibeng.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。

依赖项