Creating functions exposed to the global scope dynamically?

I wanted to use julia+IJulia to easily add a notebook interface/REPL to my large C++ program.

I wanted it to be really easy and non-intrusive on the c++ side, and in particular to add no dependencies to the c++ build process. IE, the c++ code would just be a DLL that Julia could load and call into.

Question #1:
If you load a dll from Julia, is there any way to call a function in it, passing some sort of context pointer that would let that c++ code interact with the interpreter. In particular to get it to be able to export symbols in a a way similar to what you can do with julia,h if you are embedding Julia in your app (as opposed to embedding your app in julia which is what i am doing).

Something like (on the c side)
extern “C” __declspec( dllexport ) AddExports( something *p )
{
// Julia loads our dll and calls this with ccall, passing some ref to the interpreter
Do something with p that lets us add a c function to the interpreter();
}

Question #2, I don’t care as much about question #1 as #2.
What i actually want to do is this. I want Julia code to look at a list of exported function prototypes via the dll (stored as strings+entry points), and create functions for them. This lets me have a generic header-only export interface that isn’t julia-dependent, it’s just a convention. So I coded the base of it quickly in one stand alone file:

That’s the C++ code that makes a test dll for Julia to load.
I then started to write something quick to load it and see if I could write code to create the exported functions:

So, if I compile my test lib to a .dll.
I load Julia, and include the code above.
I do

mylib=ImportCPP( “test.dll” )
CreateExportedFunctions( mylib)

Nnow, I would like to be able to do this:
HelloWorld()

and it works, in that it prints out the names of the 3 functions exported in the c code.
The names are exported as c++ prototype strings that should be easy to parse in julia to create bindings for.

The question is what to do after the line that prints “found voidfn”? This line successfully finds the prototype HelloWorld() and knows how to call it with “ccall”.
What I would like for this line to do is create something called HelloWorld, which could be called after. Would this be a closure? Or would I use metaprogramming to create the function body? Either way in some sense, some symbol/variable needs to be created called HelloWorld, such that if I then type HelloWorld() into the repl, it will end up doing a ccall into the entry point in my dll.

I guess ultimately, I would like to be able to do something like:

mylib=ImportCPP( "test.dll )
CreateExportedFunctions( mylib, :MyLIb ) // make a new module
MyLib.HelloWorld()
using MyLib
HelloWorld()

I guess you need to make a macro like what ModernGL.jl did here:

https://github.com/JuliaGL/ModernGL.jl/blob/f81e7ea6a1df8bff7fccd4708cd070fdf93e5ec5/src/functionloading.jl#L28-L71

If your large C/C++ program does not use non-builtin datatypes(like OpenGL), then it’s ok to follow this way. Otherwise, you need to map datatypes, you could also make everything an opaque pointer though.

1 Like

I’m not very worried about mapping data types as I can make my export function generate wrappers to map things into and out of a few common types, and I figured I could also export them from the dll if I want to get fancy.

Thanks for the reference to the opengl bindings, I’ll take a look. The gist is that they build a symbolic expression declaring a function, and then evaluate it to get the function created?

I want to handle reload, so I’d make my generated bindings check for stale function pointers in some way.

1 Like

I guess I know the answer to #1. You can just define a julia function that does the operations to create a new symbol in the Julia execution environment, create a c-callable function pointer to it, and then call some entry point in the dll, passing that pointer.

Thanks, I got this working, including dynamic reload!

1 Like