Problems with `dlopen`

Ok I realize that dlopen may not be a new-to-Julia issue, but FFI is important for us to be able to expand usage of Julia in my company. I have read through the manual section on using C and Fortran (which is rather good, actually). I think what I am running into here is likely a filesystem path problem.

Here is my demo c code (OS is WSL Ubuntu):

#include <math.h>
// gcc my_exp.c -fPIC -shared -lm -o libmy_exp.so
// gcc -c my_exp.c -o my_exp.o
double my_exp(double x) {
    return exp(x);
}

After compiling it as indicated in the comments of the code, I change to the directory that the shared library is in, and start Julia:

julia> @ccall "./libmyexp".my_exp(3.0::Float64)::Float64
20.085536923187668

julia> using Libdl

julia> h = dlopen("./libmyexp")
Ptr{Nothing} @0x000000000152a330

julia> h = dlopen("./libmyexp.so")
Ptr{Nothing} @0x000000000152a330

Am I missing a path or something? Also, is it the “Julian way” to use dlopen and dlsym when the @ccall macro seems to be how you end up calling it anyhow?

What’s the issue here, exactly? Is it unexpected that @ccall already works without using dlopen beforehand?

Oh, perhaps I should have also put this, niether of the dlsym handles seems to work:

julia> @ccall h.my_exp(3.0::Float64)::Float64
ERROR: TypeError: in ccall, expected Symbol, got a value of type Ptr{Nothing}
Stacktrace:
 [1] top-level scope
   @ ./REPL[5]:1

Ah, I see - the macro only directly supports strings and symbols as literals, IIRC. To use the handle, you can use the ccall function.

@Sukera, ok thanks, that can work - just calling it like that.

I guess I had been used to using dlopen and dlsym in other FFI cases in Python …
I also tried to make the handle with an absolute path, and that didn’t work either:

julia> h = dlopen("/home/me/Projects/Julia/libmyexp.so")
Ptr{Nothing} @0x000000000152a330

dlopen still gives you a handle - that’s just represented by a pointer. Is there another error?

julia> ccall(("my_exp", h), Float64, (Float64,), 3.0)
ERROR: TypeError: in ccall, expected Symbol, got a value of type Ptr{Nothing}
Stacktrace:
 [1] top-level scope
   @ ./REPL[11]:1

(deleted something that I found out wasn’t valid)

Apologies, I got the order mixed up - you need to get the symbol from the dynamic library with dlsym first, of course:

julia> using Libdl

julia> h = dlopen("./libmy_exp.so")
Ptr{Nothing} @0x000055d013c2ce90

julia> hfunc = dlsym(h, :my_exp)
Ptr{Nothing} @0x00007f9b44833109

julia> ccall(hfunc, Float64, (Float64,), 3.0)
20.085536923187668

julia> @ccall $hfunc(3.0::Float64)::Float64
20.085536923187668

See also the docs for @ccall.

1 Like

Thanks! Apparently I missed the $ in front of my function handle?

If you had a function handle, yes - what you’ve shown so far was only the handle for the library :slight_smile: Note the hfunc = dlsym(...).

Heh, yeah it has the dollar sign right there in the documents … I just went on as if it weren’t there. Thanks.

1 Like