Open mdmaas opened 1 year ago
Ok, here's a more elaborate example:
### Let's define a C function and compile it
using Libdl
C_code= """
double mean(double a, double b) {
return ( a + b ) / 2;
}
"""
Clib = "clib"
open(`gcc -fPIC -O3 -xc -shared -o $(Clib * "." * Libdl.dlext) -`, "w") do f
print(f, C_code)
end
# Now the real code
using StaticTools, StaticCompiler
function static_ccall(lib_path, func_name, a, b)
lib = StaticTools.dlopen(lib_path)
mean = StaticTools.dlsym(lib, func_name)
ra, rb = Ref(a), Ref(b)
GC.@preserve ra rb begin
pa, pb = pointer_from_objref(ra), pointer_from_objref(rb)
c = @ptrcall mean(pa::Ptr{Nothing}, pb::Ptr{Nothing}) :: Float64
end
return c
end
function test()
lib_path = c"/home/martin/static_compiler_test/clib.so"
func_name = c"mean"
c = static_ccall(lib_path, func_name, 1.0, 2.0)
printf(c"Result is %f:\n", c)
return 0
end
test()
This doesn't even work (I get a segmentation fault), but if I replace StaticTools.dlopen
and StaticTools.dlsym
with Libdl.dlopen
and Libdl.dlsym
this does work. However, I won't be able then to statically compile.
Maybe I'm doing something wrong, or there is an issue with these functions from StaticTools I guess?
Your mean
takes its arguments by value, but by reference/pointer.
You also don't need ptrcall
ccall supports just calling a runtime pointer.
Your
mean
takes its arguments by value, but by reference/pointer.
Oh, that was silly. I guess Julia converted it under the hood so it managed to work anyway with StaticCompiler.dlopen
.
I modified my calling function to:
function static_ccall(lib_path, func_name, a, b)
lib = StaticCompiler.dlopen(lib_path)
mean = StaticCompiler.dlsym(lib, func_name)
c = @ptrcall mean(a::Float64, b::Float64) :: Float64
return c
end
and it's still the same result: works with StaticCompiler.dlopen
, doesn't work with StaticTools.dlopen
(segfaults). Maybe @brenhinkeller can shed some light on this. I can try to look into StaticTools.dlopen
, as well.
You also don't need
ptrcall
ccall supports just calling a runtime pointer.
Yes, but for what I know, code containing ccall
can't be statically compiled, so what I thought was that we have to replaced it with something else (like a static_ccall), so I began running some experiments.
The point in this second test would be to compile it with
compile_executable(test, (), "./", cflags=`-ldl -L./`)
but I didn't even get there.
Oh, I'm just not being able to use StaticTools.dlopen
properly, as it returns a null pointer, while StaticCompiler.dlopen
does work.
Try with @ccall
, it might just work nowdays
StaticCompiler actually doesn’t provide a dlopen
unless I’m much mistaken so that’s probably giving you Libdl dlopen
Try with @.***
, it might just work nowdays StaticCompiler actually doesn’t provide a
dlopen` unless I’m much mistaken so that’s probably giving you Libdl dlopen
is that something you do on mac? I'm on Linux...
Yes, I thinkg StaticCompiler imports dlopen from Libdl... I just checked what Libdl.dlope does, and it is implemented in C, and esentially searches every possible path (including Julia's DL_LOAD_PATH, and every possible extension:
https://github.com/JuliaLang/julia/blob/01ddf80f18fc618e20df307945a9c19e74005270/src/dlload.c#L263
Hmm, judging from @brenhinkeller's MPI example, maybe @symbolcall and linking via cflags is preferable to dlopen and dlsym? I mean, we would leave the trouble of finding the shared library to the c compiler... as long as we have anything we need in LD_LIBRARY_PATH, that could work.
Oh wow sending from email really messed up the formatting on that.. I meant @ccall
Oh wow sending from email really messed up the formatting on that.. I meant
@ccall
Lol.
So you guys say that somehow ccall now should work with StaticCompiler?
I tried to no sucess:
function ccall_time()
t = @ccall time(C_NULL::Ptr{Nothing})::Int
printf(c"Result is: %i\n", t)
end
compile_executable(ccall_time, (), "./", cflags=`-ldl -L./`)
it compiles, but then it segfaults when run:
shell> ./ccall_time
/bin/bash: line 1: 13734 Segmentation fault ( './ccall_time' )
On the other hand, I can compile a call to time
with StaticTools.dlopen + @ptrcall:
function dltime()
lib_path = c"libc.so"
func_name = c"time"
lib = StaticTools.dlopen(lib_path)
fp = StaticTools.dlsym(lib, func_name)
t = @ptrcall fp(C_NULL::Ptr{Nothing})::Int
printf(c"Result is: %i\n", t)
end
compile_executable(dltime, (), "./", cflags=`-ldl -L./`)
shell> ./dltime
Result is: 1685051481
Hey, I said might :)
That actually works for me
julia> function ccall_time()
t = @ccall time(C_NULL::Ptr{Nothing})::Int
printf(c"Result is: %i\n", t)
end
ccall_time (generic function with 1 method)
julia> compile_executable(ccall_time, (), "./", cflags=`-ldl -L./`)
"/Users/cbkeller/ccall_time"
shell> ./ccall_time
Result is: 1685051694
I wonder what the difference is?
Wow, that's interesting.
Something curious is that I get the segfault in line 1, so even if I add some inocent code before ccall, it fails:
function ccall_clock()
printf(c"Calling clock")
t = @ccall clock(C_NULL::Ptr{Nothing})::Int
printf(c"Result is: %i\n", t)
end
compile_executable(ccall_clock, (), "./")
shell> ./ccall_clock
/bin/bash: line 1: 23619 Segmentation fault ( './ccall_clock' )
By the way, @symbolcall works nicely for me:
function sym_clock()
t = @symbolcall clock(C_NULL::Ptr{Nothing})::Int
printf(c"Result is: %i\n", t)
end
compile_executable(sym_clock, (), "./")
shell> ./sym_clock
Result is: 773
From the last time I tried this I was left with the idea that ccall
wouldn't work, and had to be overriden perhaps via Mixtape. But aparently ccall
is almost working now... maybe we should add some tests and let the CI run them different OSs and on the latest package banch?
I can also get "mean" to work with just symbolcall and a cflag to link to that library...
function test()
a = 1.0
b = 2.0
c = @symbolcall mean(a::Float64, b::Float64) :: Float64
printf(c"Result is %f:\n", c)
return 0
end
# this works
compile_executable(test, (), "./", cflags=`-L . -lmean`)
(I renamed clib.so to libmean.so, and also had to set the env variable for library paths in order to run the executable).
Huh, interesting. Yeah, adding some ccall examples to the test suite seems like a good idea to me!
Hi,
Even though this is well beyond my skill level I'm trying to get something like a "static ccall" working... This is actually my second attempt, after a year or so...
From the last time, I got the idea that a the way to implement a "static ccall" would be to replace
ccall
with something like@ptrcall
, but we need to get the function's pointer somehow, and that is whatStaticTools.dlopen
does.So I guess the minimal example should be something that compiles a function which contains
StaticTools.dlopen
... Does this sound reasonable?Anyway, in the StaticTools docs I found a very small function
dltime()
, which could be worth trying to get to compile:Edit: silly me, I was forgetting to link with -ldl... this works...
Anyway, I'll try to continue with a more complex example that passes some arguments to the c function...