Here is a C program that does what you want.
#include <julia.h>
#include <stdlib.h>
JULIA_DEFINE_FAST_TLS
int main(int argc, char *argv[]) {
const char *stuff[] = {"one", "two", "three"};
jl_init();
jl_value_t *array_type = jl_apply_array_type((jl_value_t *)jl_uint8pointer_type, 1);
jl_array_t *julia_stuff = jl_ptr_to_array_1d(array_type, stuff, 3, 0);
jl_function_t *prnt = jl_eval_string("x->println(unsafe_string.(x))");
jl_call1(prnt, (jl_value_t *)julia_stuff);
jl_atexit_hook(0);
return EXIT_SUCCESS;
}
Running this, I get the following.
$ ./frylock_test.exe
["one", "two", "three"]
I concur with stevengj. You want to do as much as possible on the Julia side. If you want to initiate this from C though, you should make extensive use of jl_eval_string
.
I made a few more variants.
In “frylock_test2.c”, I shift more of the work to the Julia side and just box the pointer.
$ cat frylock_test2.c
#include <julia.h>
#include <stdlib.h>
JULIA_DEFINE_FAST_TLS
int main(int argc, char *argv[]) {
const char *stuff[] = {"one", "two", "three"};
jl_init();
jl_value_t *ptr = jl_box_uint8pointer((uint8_t *)stuff);
jl_function_t *wrap = jl_eval_string("x->unsafe_wrap(Vector{Ptr{UInt8}}, Ptr{Ptr{UInt8}}(x), 3; own = false)");
jl_value_t *julia_stuff = jl_call1(wrap, (jl_value_t *)ptr);
jl_function_t *prnt = jl_eval_string("x->println(unsafe_string.(x))");
jl_call1(prnt, julia_stuff);
jl_atexit_hook(0);
return EXIT_SUCCESS;
}
In “frylock_test3.c”, I did the broadcasting manually based on the @code_lowered
Julia.
$ cat frylock_test3.c
#include <julia.h>
#include <stdlib.h>
JULIA_DEFINE_FAST_TLS
int main(int argc, char *argv[]) {
const char *stuff[] = {"one", "two", "three"};
jl_init();
jl_value_t *array_type = jl_apply_array_type((jl_value_t *)jl_uint8pointer_type, 1);
jl_array_t *julia_stuff = jl_ptr_to_array_1d(array_type, stuff, 3, 0);
jl_function_t *julia_println = jl_get_function(jl_base_module, "println");
jl_function_t *julia_broadcasted = jl_get_function(jl_base_module, "broadcasted");
jl_function_t *julia_materialize = jl_get_function(jl_base_module, "materialize");
jl_function_t *julia_unsafe_string = jl_get_function(jl_base_module, "unsafe_string");
jl_value_t *ans = jl_call2(julia_broadcasted, julia_unsafe_string, (jl_value_t *)julia_stuff);
ans = jl_call1(julia_materialize, ans);
ans = jl_call1(julia_println, ans);
jl_atexit_hook(0);
return EXIT_SUCCESS;
}
In “frylock_test4.c”, I do the conversion from C strings to Julia strings via jl_cstr_to_string
.
$ cat frylock_test4.c
#include <julia.h>
#include <stdlib.h>
JULIA_DEFINE_FAST_TLS
int main(int argc, char *argv[]) {
const char *stuff[] = {"one", "two", "three"};
jl_value_t *julia_strings[3];
jl_init();
for(int i = 0; i < 3; ++i) {
julia_strings[i] = jl_cstr_to_string(stuff[i]);
}
jl_value_t *array_type = jl_apply_array_type((jl_value_t *)jl_string_type, 1);
jl_array_t *julia_stuff = jl_ptr_to_array_1d(array_type, julia_strings, 3, 0);
jl_function_t *julia_println = jl_get_function(jl_base_module, "println");
jl_call1(julia_println, (jl_value_t *)julia_stuff);
jl_atexit_hook(0);
return EXIT_SUCCESS;
}
I did this in MSYS2 on Windows, so my compilation steps and running steps were as follows.
gcc frylock_test.c -I "/path/to/julia/include/julia" -L "/path/to/julia/bin" -ljulia -o frylock_test -g
PATH="/path/to/julia/bin" frylock_test