I am trying to use Ruby Fiddle to access a C function I have developed. The C code is:
#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;
}
I am using MSYS2 so I compile it with:
gcc lib.c -o lib.dll
In Ruby (2.7.1) irb console I then use:
extend Fiddle::Importer
dlload "lib.dll"
to load the dll and I do not get any error, but when I try to load the function with
extern "double* linalg_positive_matrix(double*, int, int)"
I receive the error:
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())
I use the same approach on macos and the function is imported correctly so I don't think the problem is in the code or function signature.
Just for completeness, in case it is important, I have installed MSYS2 and ruby separately, MSYS2 from the main website and Ruby from rubyinstallers. I am compiling from the MSYS2 MinGW 64
console and running irb
from the Ruby terminal created by the installer. It is supposed to use MSYS2 as well.
EDIT (add more info after the correct answer)
The key part for me was the -shared
option.
I also uninstalled the MSYS2
from MSYS2 and used directly the MSYS
from rubyinstaller as follows:
ridk enable
ridk use /27-/
At this point, if you haven't already, you can install the tool chains with
ridk install
One weird thing I still do not understand is the output of which
:
which ruby
# /c/Apps/rubies/Ruby27-x64/bin/ruby
which gcc
# /mingw64/bin/gcc
They look different, but it might be because of the way MSYS2 works when bundled with rubyinstaller.
First of all, make sure you are using a MinGW gcc and a MinGW ruby so there aren't any toolchain compatibility issues. Run
which gcc
andwhich ruby
in your shell and make sure both commands return a filename in/mingw64
or both return a filename in/mingw32
.Secondly, make sure you compile your DLL correctly. You sould remove the
main
function because DLLs shouldn't have a main function. I think the correct command is this:In your shell, run
file prog.dll
and make sure it says something like "PE32+ executable (DLL)".That might work for you. If not, you'll have to make sure your function is actually listed as one of the functions that is exported from the DLL. You can either do this by adding a dllexport attribute in the source code or by using the right compile options.