How to call a custom julia function from c++ (a custom locally created .jl file)

So I wrote a julia file myself, called function.jl, and I want to load it in C++ and call functions in it. That’s it.
I can’t find anything in the documentation about this. The docs cover jl_eval_string and jl_get_function for a library function eg,

jl_get_function(jl_base_module, "sqrt")

but my file is not part of jl_base_module. It’s something I made up myself.
I don’t want to ask too much of a leading question because there might be more than one way to call a function in a custom .jl file.
Googling the subject I found jl_load which is pretty much non-documented and not sure if it’ll help.
Googling also yields a lot of conflicting suggestions, probably due to changes to julia over time.
I found this which produces an access violation in jl_get_function:

jl_eval_string("include(\"function.jl\")");
jl_value_t *mod = jl_eval_string("Fun");
jl_function_t *add = jl_get_function((jl_module_t*)mod,"add");

What does function.jl contain?

If you set it up so that function.jl loads your function in the the Main module you can make use of jl_main_module.

You can get some more inspiration from https://github.com/JuliaLang/julia/blob/master/test/embedding/embedding.c.

For my part I approach embedding somewhat differently, as documented in GitHub - GunnarFarneback/DynamicallyLoadedEmbedding.jl: Embed Julia with dynamical loading of libjulia at runtime..

A problem with these examples is that I specifically want to load scripts from files in a local directory (like function.jl, but any arbitrary script). Writing scripts in strings in C is a non-starter.

EDIT: I could do fopen and fread to load the file I want to use into memory, then call eval string as in the examples. I thought there would be a more elegant way.

1 Like

Is it relevant? The point of what I’m trying to do is load arbitrary script files from directories in my local drive. I’m new to this and looking for guidance. How about:

module Fun
    add(a,b) = a+b
end

It’s of course possible to correctly retrieve the Fun module but I don’t know how to do that out of hand, so I’ll leave that to someone else.

As an alternative you could just skip the module Fun layer in your function.jl so that add gets defined directly in Main or do

jl_eval_string("include(\"function.jl\"); using .Foo: add");

to load it into Main. Then you can retrieve your function with jl_get_function(jl_main_module, "add").

2 Likes

Well, it matters insofar that if the file doesn’t contain a module, all functions are placed in the default Main module.

Despite julia being dynamic and looking like a scripting language, it’s compiled, so keep that in mind when trying to integrate it into a game.

1 Like

I would generally recommend (a) putting your Julia code into a module/package and (b) using cfunction to create a C++ function pointer from Julia. See the links in https://github.com/JuliaLang/julia/issues/38932

2 Likes

This bit seems like it’s tribal knowledge at the moment. From C++, how do I read and call functions that I have in my own modules and/or packages? The examples I’ve found only call existing Julia functions and special functions.

The examples using cfunction are great. Thanks for that!

The same as for the SpecialFunctions example you found: just call jl_eval_string("import MyModule");

1 Like

I get this:

ret = nullptr
The difficulty here is that all I get is a null. No errors or warning or any kind of output that helps narrow down the problem.

typing the @cfunction line in julia REPL with the module already imported and working yields:

Do the Julia commands you are evaluating with eval_string work in the REPL?

(To get more informative error messages in C++, you need to add some exception-handling code, but it is a lot easier to debug in the REPL.)

PS. Don’t post screenshots of code. Post quoted text.

2 Likes

Yes, in REPL all commands work except the @cfunction:

That’s because you are calling @cfunction incorrectly. Get it to work in the REPL first.

1 Like

I got it working, thanks!
one weird thing is that my func only had one argument:

function foo(x::Int)
    return x * x
end

@cfunction didn’t allow just one argument no matter what. I kept getting, “argument types must be a literal tuple”. So I had to do:
@cfunction(foo, Int, (Int,Int))
event though there’s only one argument.
I also made a function that didn’t return anything, which @cfunction also didn’t like so I had to return ‘Int’ no matter what.

To make a tuple with a single element you need a trailing comma.

2 Likes

specifically consider the difference here:

julia> typeof((:foo))
Symbol

julia> typeof((:foo,))
Tuple{Symbol}
2 Likes

Julia always returns the last expression.

julia> function foo()
       4
       end
foo (generic function with 1 method)

julia> a = foo()
4

julia> a
4

julia>
3 Likes

The equivalent of a C/C++ function with no (void) return value is to return nothing in the Julia function.

2 Likes