Passing multiple C arguments to Julia function

Passing multiple C arguments to Julia function
Hello,

I am new to Julia, and I am trying to pass some C arguments to Julia.

So far, I was able to send only one argument from C to Julia, but when trying to send multiple I am not sure how it would be done. I tried with a C struct but it did not work. How it would be an example of using jl_call(...) or there is another way to do this?

The goal is to send multiple arrays and integers to Julia function (in the example x, y, z).

This would be my example of C code that send the variable a to Julia and print it:

#include <julia.h>
JULIA_DEFINE_FAST_TLS() // only define this once, in a executable (not in a shared library) if you want fast code

#include <stdio.h>
#include <stdint.h>

int main(){

    double x[3][2] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
    double y[2] = {7.0, 8.0};
    int64_t z = 11111111;
    
    /* required: setup the Julia context */
    jl_init();

    /* import module 'foo' from the file jmodule.jl */
    jl_eval_string("Base.include(Main, \"jmodule.jl\")");
    jl_eval_string("using Main.foo");
    jl_module_t* c_foo = (jl_module_t *)jl_eval_string("Main.foo");

    /* get 'bar' function from module */	
    jl_function_t *c_bar = jl_get_function(c_foo, "bar");

    /* set a=3 */
    jl_value_t *a = jl_box_float64(42);
    
    /* call the function 'c_bar' */
    jl_call1(c_bar, a);  
    // jl_call(jl_function_t *f, jl_value_t **args, int32_t nargs);

    /* strongly recommended: notify Julia that the
         program is about to terminate. this allows
         Julia time to cleanup pending write requests
         and run all finalizers
    */
    jl_atexit_hook(0);

    return 0;
}

And the Julia code jmodule.jl:

module foo
export bar 		# export 'bar' function

function bar(x)
    println("hello world! from Julia function, x = $x")
    return nothing
end		# end of function

end		# end of module

Or there is another way to do this task that would have a better performance?

Thanks!

1 Like

I think you will find it easier and possibly faster to work with @cfunction pointers. This is the basic idea:

jl_eval_string("const julia_sind = @cfunction(sind, Cdouble, (Cdouble,))");
double (*julia_sind)(double) = jl_unbox_voidpointer(
    jl_get_global(jl_main_module, jl_symbol("julia_sind")));
printf("%f\n", julia_sind(30.0));

For a complete example of this (and some more), see https://github.com/GunnarFarneback/DynamicallyLoadedEmbedding.jl

1 Like

Thank you!

It is much easier using @cfunction than using a struct and jl_call1. But I am having some trouble when I want to use arrays in the function.

#include <julia.h>
JULIA_DEFINE_FAST_TLS() // only define this once, in a executable (not in a shared library) if you want fast code

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[]){

    double x[3][2] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
    double y[2] = {7.0, 8.0};
    int64_t z = 11111111;

    /* required: setup the Julia context */
    jl_init();

    /* import module 'foo' from the file jmodule.jl */
    jl_eval_string("Base.include(Main, \"jmodule.jl\")");
    jl_eval_string("using Main.foo");
    jl_module_t* c_foo = (jl_module_t *)jl_eval_string("Main.foo");

    /* converting Julia function to C function with '@cfunction' */
    typedef void(*Func_VOID)(double[3][2], double[2], int64_t*);
    jl_value_t *pbar = jl_eval_string("@cfunction(bar, Cvoid, (Ref{Array{Cdouble,2}}, Ref{Array{Cdouble,1}}, Ref{Cint}))");
    Func_VOID c_bar = (Func_VOID)jl_unbox_voidpointer(pbar);
    c_bar(x, y, &z);  
    
    /* strongly recommended: notify Julia that the
         program is about to terminate. this allows
         Julia time to cleanup pending write requests
         and run all finalizers
    */
    jl_atexit_hook(0);

    return 0;
}

The Julia code is:

module foo
export bar

function bar(a::Array{Cdouble,2}, b::Array{Cdouble,1}, c::Cint)::Cvoid
    println("hello world! from Julia function")
    println("a = $a")
    println("b = $b")
    println("c = $c")
    return nothing
end

end

It works well using many arguments of the function, but it does not work with arrays at the moment.

I took a look at your complete example, but could find something related to arrays.

When you want to pass more complicated things than scalars, you basically have two options.

  1. Create Julia objects from your C code and pass those over to Julia, making sure that ownership and garbage collection is handled correctly.
  2. Pass pointers to your data and sort it out on the Julia side, living dangerously with unsafe_load and unsafe_store! functions.

Unless you’re an experienced C programmer and at least somewhat familiar with the Julia internals, the second approach is likely more tractable.

I have added an array example in https://github.com/GunnarFarneback/DynamicallyLoadedEmbedding.jl/pull/3.

Thank you a lot for your help! It was really useful all your example.