Hello, I’m enchanted with the idea of bringing performant julia code into a python script through a shared library, especially if it as easy as PackageCompiler seems to imply. I am almost entirely unfamiliar with compiled languages, so much of this feels new to me.
I got a simple script to work, but now the problem I am having is with the following seemingly simple script:
test.jl
Base.@ccallable function func0()::Cdouble
return sum([1.34, .7])
end
Base.@ccallable function func1()::Cdouble
return (1.2 + .1) / 2.0
end
I compile the file to a shared library with julia juliac.jl -vas test.jl
Calling func1 from python works fine, but func0 causes a segfault. I have this same problem calling any imported function, and I don’t understand why. I imagine I am misunderstanding something fundamental.
I’m not sure what’s causing the segfault, but this is certainly not the case. There’s no restriction to the type of Julia code you can use (at least if you don’t explicitly disable the JIT compiler when you call julia_init in your driver program).
Have you tried build_executable with func0 as the julia_main function? That should definitely work, and the C program it produces should give you something to pattern match if you’re trying to build a shared library with multiple ccallable functions.
Did you ever initialize the Julia runtime (IIRC via julia_init)? If not, it may be possible that func1 only runs because it doesn’t need to invoke the compiler, but func0 does, which will fail because Julia wasn’t initialized.
Note by the way that without a snoopfile (see build_executable call in the usage example), the functions are still compiled the first time they’re called from C or Python with given input types, as opposed to having their native code (for a finite set of input type tuples) incorporated into the system image.
Thanks @tkf that’s most helpful. I have this working.
My next challenge is to mimic test.py in Julia (call the library functions from Julia).
The use case is a set of users who each request a batch computation of about 30 mins running time. Each user has some idiosyncratic code that lives in its own library, so I only have to load the library for the requesting user rather than load the code for all users.
Here’s what I have so far (posted here, apologies for the double post):
using Libdl
test = Libdl.dlopen("test.so")
func0 = Libdl.dlsym(test, :func0) # Returns a Ptr(Nothing)
func0() # segfault
I’m not initializing the runtime at all, and test doesn’t have a jl_init_with_image handle exposed. Any idea how to get this going?
For my own inner peace, does this mean that the compiler will compile all functions that are called from a given snoopfile (for the arg signature actually called), including those called indirectly as dependencies?