0
$\begingroup$

Recently I've asked a question somewhat related to this[*], but I consider this an actual new problem. So I hope it is indeed appropriate to ask you again.

I have created a shared C++ library (with extern "C") and want to use it in a code for CreateLibrary in Mathematica.

First of all, this is my code for CreateLibrary (reduced to what is relevant):

#include "WolframLibrary.h"

  DLLEXPORT mint WolframLibrary_getVersion(){
    return WolframLibraryVersion;
  }

  DLLEXPORT int WolframLibrary_initialize( WolframLibraryData \
libData) {
    return 0;
  }

  DLLEXPORT void WolframLibrary_uninitialize( WolframLibraryData \
libData) {
    return;
  }

#include "test.h"
//int test(){return 6;}

  DLLEXPORT int cwvTimeEvolution(WolframLibraryData libData,
            mint Argc, MArgument *Args, MArgument Res) {
    int err;    

    err=test();

    MArgument_setInteger(Res, err);
    return LIBRARY_NO _ERROR;
  }

DLLEXPORT int testfunc(WolframLibraryData libData,
            mint Argc, MArgument *Args, MArgument Res) {
    MArgument_setInteger(Res, minipotato+POTATOCOUNT);
    return LIBRARY_NO _ERROR;
  }

It shall use a shared library 'test'. I have the two files 'test.h' and 'libtest.so' (compiled with g++ as c++ code). They are placed at 'usr/local/lib'.

test.h has the form

//test.h
#ifndef testHeader_H
#define testHeader_H
#define POTATOCOUNT 8

#ifdef __cplusplus
extern "C" {
#endif

int minipotato;
int test();

#ifdef __cplusplus
}
#endif


#endif // testHeader_H

and the code basis for test.so is

//test.c
#include "test.h"

int minipotato = 26;

int test(){
    return 123;
}

I compiled the shared library via

g++ -c -Wall -Werror -fPIC ./test.c
$ g++ -shared -o libtest.so test.o

Now I tell you what happens when I try to use the library in Mathematica. The long C code (the first code I posted here) is stored as a string named 'cwvsrc' in Mathematica. Now I want to create a library out of it and call it afterwards (all in Mathematica).

cwvtwolib = CreateLibrary[cwvsrc, "libtestfunc", 
  "LibraryDirectories" -> {"/usr/local/lib"}, "Libraries" -> {"test"},
   "IncludeDirectories" -> {"/usr/local/lib"}]
Testfunc = LibraryFunctionLoad[cwvtwolib, "testfunc", {}, {Integer}]

Creating it works, and it tells me where it stored 'libtestfunc.so'. But the second command only returns

LibraryFunction::libload : The function testfunc was not loaded from the file (don't want to post the path)/libtestfunc.so. 

I assume the reason is my shared library. A motivation: If I do not plug in the flags

"LibraryDirectories" -> {"/usr/local/lib"}, "Libraries" -> {"test"}

it compiles properly as well, AND I get a function I can call. But if I call Testfunc[], it returns 8. Let me explain why. Testfunc returns the sum of two values from my test library. It returns POTATOCOUNT+minipotato. 'POTATOCOUNT' was defined in test.h to be 8. 'minipotato' was only defined to be an integer. In test.c (and hence in libtest.so) I set minipotato to be equal 26. Thus, Mathematica actually used the header, but not the corresponding library. (not surprising since I did not include the library at all, but I wanted to say that this works)

Also, if I call cwvTimeEvolution from c code above, my Mathematica kernel crashes. (also not surprising since it's lacking a definition)

I thus assume that in my first described attempt, I did link the shared library correctly, but Mathematica doesn't know where to find it anymore as soon as it calls the function itself.

I have tried several things to work around this. I have tried (but apparently failed) to follow a guide from here[**]. Also I showed Mathematica how to find the library:

$Path = Append[$Path, "/usr/local/lib"];
$LibraryPath = Append[$LibraryPath, "/usr/local/lib"];
FindFile["libtest.so"]
/usr/local/lib/libtest.so

Still it doesn't work for some reason. There were several other potential reasons I have already covered, but I do not consider it sensible to list them all. (for example I tried to cover every problem between C and C++, although I'm not certain of whether I did it properly)

Hence, I would be really grateful if anyone could help me solve this problem. By now I have done so much and read up so much that I consider this a problem likely to occur to other people as well.

Maybe here are some names not perfectly correct. The original functions do not have 'cwv' in their names. Instead their names are ridiculously long, and I tried to replace everything in a convenient way. So if there is any strange combination of words beginning with c, please tell me so I can edit it.

[*] LibraryFunctionLoad for multivariate C++ function containing several arguments

[**] How can I use shared libraries in LibraryLink code and ensure Mathematica will find them?

$\endgroup$
  • $\begingroup$ If you are linking to test dynamically (not static linking), it may be necessary to explicitly load it into Mathematica first: LibraryLoad[".../libtest.so"], before using LibraryFunctionLoad. Try this first. Use the full path to the library. Do not use LibraryLoad on the library you create with CreateLibrary, as LibraryFunctionLoad suffices for that. $\endgroup$ – Szabolcs Nov 1 '16 at 15:40
  • $\begingroup$ Another comment: not sure what cwvsrc is here, but if you can avoid it, don't pass a source code string to CreateLibrary. Put the source code in a file and pass the file name as CreateLibrary[{"file.c", ...}, ...]. This will save you trouble later and will allow using C++. $\endgroup$ – Szabolcs Nov 1 '16 at 15:41
  • $\begingroup$ Thanks for the answers! This sounds like it might be the solution. I'll write whether it has worked as soon as I find time to test it. $\endgroup$ – Fred Nov 2 '16 at 21:43
  • $\begingroup$ It took me quite a while, because I was knocked out by a flu, but now I was able to test it. LibraryLoad indeed solves the problem that Testfunc only returned 8. Now it returns the correct value 34. Thank you very much so far! Yet, a function call inside the C code still doesn't work. If I use MArgument_setInteger(Res, test()); and then try to call the edited Testfunc, my kernel crashes. Do you know why? $\endgroup$ – Fred Nov 15 '16 at 11:47
  • $\begingroup$ Thank you very much again! I have tried the cast, but it still does not work. The kernel crashes without a warning. Also I have just realised something. I have tried to use my code on my own PC (we're using an afs system, and I'm usually logged into someone else's PC). Here the error LibraryFunction::libload : The function testfunc was not loaded... is still there. I have no clue why. The files on both PCs seem to be the same... But that's just for your information. I'll figure this one out on my own. I just wanted to inform you that my code seems to be not the only problem...^^ $\endgroup$ – Fred Nov 15 '16 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.