Hello everyone,
I am currently embedding Julia inside of some cross-platform C++ shared libraries that will be loaded by an already developed application with calls to dlopen()
. I am experiencing different behaviours with MacOS and Linux. In MacOS, my shared libraries get loaded correctly, while on Linux receive errors from dlopen()
not finding Julia libraries that are not libjulia.so (I am going to explain it better with the example below). I think that the problem relies on how linking and -Wl,--export-dynamic
work in Linux, but I am not sure.
Here is the example:
Consider a simple test executable, called DummyJuliaExe
, that will load a shared library linked against Julia called libTestCJulia
and call a function testFunction()
.
The two source codes, DummyJuliaExe.cpp
(the executable source code) and testCJulia.cpp
(the .so source code) are in the same folder.
The DummyJuliaExe.cpp source code is as follows, and it is compiled with g++ with the command:
g++ -o DummyJuliaExe DummyJuliaExe.cpp -std=c++11 -fPIC -Wl,-rpath,'.' -ldl
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(void)
{
void *handle;
char *error;
handle = dlopen("libTestCJulia.so", RTLD_LAZY);
if (!handle) {
fprintf (stderr, "%s\n", dlerror());
exit(1);
}
dlerror();
typedef void (*function_call_t)();
function_call_t testFunction = (function_call_t) dlsym(handle, "testFunction");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}
testFunction();
dlclose(handle);
return 0;
}
The libTestCJulia.so is compiled from this source code, using g++, with these two commands (change the path to Julia to your machine’s):
g++ -c testCJulia.cpp -std=c++11 -fPIC -I'/home/francesco/Sources/julia-native/usr/include/julia'
g++ -shared -o libTestCJulia.so testCJulia.o -std=c++11 -fPIC -L'/home/francesco/Sources/julia-native/usr/lib' -Wl,--export-dynamic -Wl,-rpath,'/home/francesco/Sources/julia-native/usr/lib' -Wl,-rpath,'/home/francesco/Sources/julia-native/usr/lib/julia' -ljulia
testCJulia.cpp:
#include <julia.h>
extern "C" void testFunction()
{
jl_init();
jl_eval_string("println(sqrt(2))");
jl_atexit_hook(0);
}
When running the executable, ./DummyJuliaExe
, on Linux I get this error:
fatal: error thrown and no exception handler available.
InitError(mod=:Sys, error=ErrorException("could not load symbol "jl_cpu_threads":
./DummyJuliaExe: undefined symbol: jl_cpu_threads"))
rec_backtrace at /home/francesco/Sources/julia-native/src/stackwalk.c:94
record_backtrace at /home/francesco/Sources/julia-native/src/task.c:246 [inlined]
jl_throw at /home/francesco/Sources/julia-native/src/task.c:577
jl_errorf at /home/francesco/Sources/julia-native/src/rtutils.c:77
jl_dlerror at /home/francesco/Sources/julia-native/src/dlload.c:74 [inlined]
jl_dlsym at /home/francesco/Sources/julia-native/src/dlload.c:228
jlplt_jl_cpu_threads_15689 at /home/francesco/Sources/julia-native/usr/lib/julia/sys.so (unknown line)
__init__ at ./sysinfo.jl:104
jl_apply_generic at /home/francesco/Sources/julia-native/src/gf.c:2184
jl_apply at /home/francesco/Sources/julia-native/src/julia.h:1537 [inlined]
jl_module_run_initializer at /home/francesco/Sources/julia-native/src/toplevel.c:90
_julia_init at /home/francesco/Sources/julia-native/src/init.c:813
julia_init at /home/francesco/Sources/julia-native/src/task.c:302
jl_init_with_image at /home/francesco/Sources/julia-native/src/jlapi.c:53
jl_init at /home/francesco/Sources/julia-native/src/jlapi.c:81
testFunction at ./libTestCJulia.so (unknown line)
main at ./DummyJuliaExe (unknown line)
__libc_start_main at /usr/lib/libc.so.6 (unknown line)
_start at ./DummyJuliaExe (unknown line)
It looks like the libTestCJulia.so
shared library can’t find all the other Julia libraries it needs to link against. Thus, it cannot resolve the jl_cpu_threads
symbol.
On the other hand, with the same source code compiled on MacOs (and the same Julia version, 1.0.2), Julia boots correctly in the shared library and I get the correct output of 1.4142135623730951
. The compiler and linker flags for MacOS are the same, with the exception of removing Wl,--export-dynamic
. The Julia version I am using is simply 1.0.2 with JL_THREADS=0
in Make.user
. I get the same errors with the distributed binaries release with threading enabled.
Linux distro is Manjaro 18.0.0, with 4.14.83-1-MANJARO kernel. MacOs version is HighSierra 10.13.6.
I don’t know if it is just a problem of compiler and linker flags needing to be different on Linux, or a Julia bug.