首页 > 解决方案 > Ruby Fiddle - 在 WINdows MSYS2 中找不到函数

问题描述

我正在尝试使用Ruby Fiddle访问我开发的 C 函数。C代码是:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

double *linalg_positive_matrix(double *mat_a, int rows_a, int cols_a);

int main(void) {
}

double *linalg_positive_matrix(double *mat_a, int rows_a, int cols_a) {
    double *pos_mat = (double *) malloc(rows_a * cols_a * sizeof (double));
    int i, j;

    for (i = 0; i < rows_a; i++) {
        for (j = 0; j < cols_a; j++) {
            if (mat_a[i * cols_a + j] < 0.0) {
                pos_mat[i * cols_a + j] = 0.0;
            } else {
                pos_mat[i * cols_a + j] = mat_a[i * cols_a + j];
            }

        }
    }

    return pos_mat;
}

我正在使用MSYS2,所以我编译它:

gcc lib.c -o lib.dll

然后在 Ruby (2.7.1) irb 控制台中使用:

extend Fiddle::Importer
dlload "lib.dll"

加载dll,我没有收到任何错误,但是当我尝试加载函数时

extern "double* linalg_positive_matrix(double*, int, int)"

我收到错误:

Traceback (most recent call last):
        6: from C:/Apps/rubies/Ruby27-x64/bin/irb.cmd:31:in `<main>'
        5: from C:/Apps/rubies/Ruby27-x64/bin/irb.cmd:31:in `load'
        4: from C:/Apps/rubies/Ruby27-x64/lib/ruby/gems/2.7.0/gems/irb-1.2.3/exe/irb:11:in `<top (required)>'
        3: from (irb):5
        2: from C:/Apps/rubies/Ruby27-x64/lib/ruby/2.7.0/fiddle/import.rb:172:in `extern'
        1: from C:/Apps/rubies/Ruby27-x64/lib/ruby/2.7.0/fiddle/import.rb:299:in `import_function'
Fiddle::DLError (cannot find the function: linalg_positive_matrix())

我在 macos 上使用了相同的方法,并且函数被正确导入,所以我认为问题不在于代码或函数签名。

为了完整起见,如果它很重要,我已经分别安装了 MSYS2 和 ruby​​,MSYS2 来自主网站,Ruby 来自ruby​​installers。我正在从MSYS2 MinGW 64控制台编译并irb从安装程序创建的 Ruby 终端运行。它也应该使用 MSYS2。

编辑(在正确答案后添加更多信息) 对我来说关键部分是-shared选项。

我还MSYS2MSYS2卸载并直接使用了MSYSfrom ruby​​installer,如下所示:

ridk enable
ridk use /27-/

此时,如果您还没有安装工具链,您可以使用

ridk install

我仍然不明白的一件奇怪的事情是输出which

which ruby
# /c/Apps/rubies/Ruby27-x64/bin/ruby
which gcc
# /mingw64/bin/gcc

它们看起来不同,但这可能是因为 MSYS2 与 ruby​​installer 捆绑在一起时的工作方式。

标签: rubyffimsys2fiddleruby-ffi

解决方案


首先,确保您使用的是 MinGW gcc 和 MinGW ruby​​,因此不存在任何工具链兼容性问题。在您的 shell 中运行which gccwhich ruby确保两个命令都返回一个文件名 in/mingw64或都返回一个文件名 in /mingw32

其次,确保正确编译 DLL。您应该删除该main函数,因为 DLL 不应该具有 main 函数。我认为正确的命令是这样的:

gcc lib.c -shared -o lib.dll

在您的 shell 中,运行file prog.dll并确保它显示类似“PE32+ 可执行文件 (DLL)”的内容。

这可能对你有用。如果没有,您必须确保您的函数实际上被列为从 DLL 导出的函数之一。您可以通过在源代码中添加 dllexport 属性或使用正确的编译选项来执行此操作。


推荐阅读