Get the output of a Julia function called from C

I have a Julia module called MyGramSchmidt which contains a function called fwht that takes a Vector{Float64} as input and returns a Vector{Float64}. I would like to define a C variable and use it to get the output of fwht called from C. I tried the following

#include <julia.h>
JULIA_DEFINE_FAST_TLS

int main(int argc, char *argv[]) {
  jl_init();
  jl_eval_string("using MyGramSchmidt: fwht");
  double z[8];
  z = jl_eval_string("fwht(rand(8))");
  jl_atexit_hook(0);
  return 0;
}

However, I get an “error: assignment to expression with array type” when I compile the C code. I wonder what is the proper way to do what I am trying to do.

https://docs.julialang.org/en/v1/manual/embedding/#Working-with-Arrays
In particular

In order to access the data of x, we can use jl_array_data:

double *xData = (double*)jl_array_data(x);

Firstly, jl_eval_string returns jl_value_t*, which is a pointer to an arbitrary Julia value. To manipulate that value, you need to cast the value to the C representation of the data. In this case, it’s jl_array_data.

What’s more, you need to root that return value. The return value of jl_eval_string is by default not assigned to any Julia variable. Then the next time when GC happens, it will be reclaimed, which can lead to memory fault if you still hold and use this return value. You can choose to instead evaluate ans = ... or use JL_GC_PUSH and JL_GC_POP to root the value.

I am now doing the following:

#include <julia.h>
#include <stdio.h>
JULIA_DEFINE_FAST_TLS

int main(int argc, char *argv[]) {
  jl_init();
  jl_eval_string("using MyGramSchmidt: fwht");
  jl_array_t *z = (jl_array_t*)jl_eval_string("fwht(rand(8))");
  double *z_data = (double*)jl_array_data(z);
  printf("%g\n", z_data[0]);
  free(z_data);
  jl_atexit_hook(0);
  return 0;
}

This compiles correctly, but I get a segmentation fault when executing the code.

First of all, I recommend doing something simple which doesn’t involve your packages no one else has access to and can’t help you with, so for example do

  jl_array_t *z = (jl_array_t*)jl_eval_string("rand(8)");

instead of

  jl_eval_string("using MyGramSchmidt: fwht");
  z = jl_eval_string("fwht(rand(8))");

Then, you should really read the documentation carefully before diving into this: Embedding Julia · The Julia Language. @ChenNingCong already outlined above what you have to do.

Okay, so let’s use this following example:

#include <julia.h>
#include <stdio.h>
JULIA_DEFINE_FAST_TLS
int main(int argc, char *argv[]) {
  jl_init();
  jl_array_t *z = (jl_array_t*)jl_eval_string("rand(8)");
  JL_GC_PUSH1(&z);
  double *z_data = (double*)jl_array_data(z);
  JL_GC_POP();
  printf("%g\n", z_data[0]);
  free(z_data);
  jl_atexit_hook(0);
  return 0;
}

I read the documentation, which is clear for how to proceed with scalar returned values, but all it says about accessing returned arrays is to cast the returned value as a jl_array_t pointer, which I do. I also follow what @ChenNingCong said by using JL_GC_PUSH1 before I try to access the data, and JL_GC_POP after extracting the data with jl_array_data. I don’t understand what I am doing wrong.

Okay, the following works:

#include <julia.h>
#include <stdio.h>
JULIA_DEFINE_FAST_TLS
int main(int argc, char *argv[]) {
  jl_init();
  jl_array_t *z = (jl_array_t*)jl_eval_string("rand(8)");
  double *z_data = (double*)jl_array_data(z);
  printf("%g\n", z_data[0]);
  jl_atexit_hook(0);
  return 0;
}