Hi guys,
I am creating a C++ software that calls multiple functions of my Julia package. Something like:
jl_init();
jl_eval_string("using SatelliteToolbox");
jl_module_t* SatelliteToolbox =
(jl_module_t*)jl_eval_string("SatelliteToolbox");
jl_function_t *read_tle = jl_get_function(SatelliteToolbox, "read_tle");
jl_value_t *filename = jl_eval_string("\"amz1.tle\"");
jl_array_t *array_tle = (jl_array_t*)jl_call1(read_tle, filename);
jl_function_t* getindex = jl_get_function(jl_main_module, "getindex");
jl_value_t* tle =
(jl_value_t*)jl_call2(getindex, (jl_value_t*)array_tle, jl_box_int64(1));
jl_function_t* init_orbit_propagator =
jl_get_function(SatelliteToolbox, "init_orbit_propagator");
jl_value_t* tipo_prop = jl_eval_string("Val{:J2}");
jl_value_t* orb_prop = jl_call2(init_orbit_propagator, tipo_prop, tle);
jl_function_t* propagate = jl_get_function(SatelliteToolbox, "propagate!");
jl_value_t* t = jl_box_float64(0.0);
jl_value_t* ret = jl_call2(propagate, orb_prop, t);
jl_value_t* orb = jl_fieldref(ret,0);
By reading the documentation, I saw that I need to use JL_GC_PUSH1
to avoid, for example, array_tle
to be freed by the GC. However, when I call JL_GC_PUSH1
twice in this function, I get the following error:
main.cpp:43:5: error: redefinition of '__gc_stkf'
JL_GC_PUSH1(&tle);
^
/Applications/Julia-1.0.app/Contents/Resources/julia/include/julia/julia.h:667:9: note: expanded from macro 'JL_GC_PUSH1'
void *__gc_stkf[] = {(void*)3, jl_pgcstack, arg1}; \
^
main.cpp:35:5: note: previous definition is here
JL_GC_PUSH1(&array_tle);
^
/Applications/Julia-1.0.app/Contents/Resources/julia/include/julia/julia.h:667:9: note: expanded from macro 'JL_GC_PUSH1'
void *__gc_stkf[] = {(void*)3, jl_pgcstack, arg1}; \
^
1 error generated.
So, can anyone tell me what is the best practice here?
Another problem is that I would like that the variable orb_prop
, which will reside in a class, to never be GCed, since it will be used many times. How can I do that?
Well, I am going to describe what I did here, because I am finding very difficult to obtain clear information about the process of embedding Julia into C++ (when I get better, I will submit a PR to improve the documentation).
(Please, correct me if I am wrong!)
In fact, Julia will not GCed a variable if it is referenced somewhere. Since I want a variable inside a C++ class to not be freed, I need to make it global or add it reference to a global object. Since the second option seems better, I create a global IdDict
at the initialization:
jl_value_t* refs = jl_eval_string("refs = IdDict()");
Then, when my variable inside the class is created, I add the reference to this IdDict
by:
jl_value_t* refs = jl_eval_string("refs");
jl_function_t* setindex = jl_get_function(jl_main_module, "setindex!");
...
tle = (jl_value_t*)jl_call2(getindex, (jl_value_t*)array_tle, jl_box_int64(1));
jl_call3(setindex, refs, tle, tle);
In this case, since tle
is referenced in the global variable refs
, it seems that the GC will not delete it.
Seems right?
The JL_GC_PUSH1
macro (and the other variations) use the stack. In the past, I’ve just introduced a new scoping block for every push/pop pair.
jl_value_t *a = jl_eval_string("foo()");
JL_GC_PUSH1(&a);
{
jl_value_t *b = jl_eval_string("bar()");
JL_GC_PUSH1(&b);
// do something with a and b
JL_GC_POP();
}
JL_GC_POP();
As for keeping a value alive beyond a given scope, I think you are on the right track. I’ve only ever had to do it for instances of a mutable struct
, so it sufficed to just generate a new global symbol and bind it to my value. If you are dealing with immutables, I think you need to do something more involved, like wrap it in a Ref
.
1 Like
If this approach (to add the variable ref to a global container), can I submit a PR with a doc update? I am not sure if this is described in the section High-Level Embedding of the manual.
1 Like
I had a similar problem and I went for the same approach, which appears to be working just fine. I think you are on the right track with this.
1 Like
I created a PR to make this clear:
https://github.com/JuliaLang/julia/pull/30399
Any suggestions are welcome!