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?
testdynamically (not static linking), it may be necessary to explicitly load it into Mathematica first:LibraryLoad[".../libtest.so"], before usingLibraryFunctionLoad. Try this first. Use the full path to the library. Do not useLibraryLoadon the library you create withCreateLibrary, asLibraryFunctionLoadsuffices for that. – Szabolcs Nov 01 '16 at 15:40cwvsrcis here, but if you can avoid it, don't pass a source code string toCreateLibrary. Put the source code in a file and pass the file name asCreateLibrary[{"file.c", ...}, ...]. This will save you trouble later and will allow using C++. – Szabolcs Nov 01 '16 at 15:41MArgument_setInteger(Res, test());and then try to call the edited Testfunc, my kernel crashes. Do you know why? – Fred Nov 15 '16 at 11:47Also 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
– Fred Nov 15 '16 at 12:48LibraryFunction::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...^^int err; err=test(); MArgument_setInteger(Res, 5);(cannot use paragraphs here). The kernel crashes as soon as I call the function. It does not seem to depend on Res. – Fred Nov 15 '16 at 12:53