Here’s another variant of the Zig code that uses loads libjulia dynamically. If I could figure out a procedure to locate libjulia automatically, this would be more flexible.
// Compile with
// zig build-exe launch_dlopen.zig -lc -I ~/src/julia/usr/include/julia
const std = @import("std");
const jl = @cImport({
@cInclude("julia.h");
});
pub fn main() !u8 {
const allocator = std.heap.page_allocator;
// TODO: Dynamically locate Julia
const libjulia_path = "/home/mkitti/src/julia/usr/lib/libjulia.so";
var ptr = try std.DynLib.open(libjulia_path);
defer ptr.close();
// Julia command line arguments
const zig_argv = [_][*:0]const u8{
"launch",
"--project=@pluto",
"--threads=8"
};
var argc: c_int = zig_argv.len;
// We need to allocate since jl_parse_opts will return arguments
var argv = try allocator.alloc([*:0]const u8, zig_argv.len);
defer allocator.free(argv);
for (zig_argv) |_, i| {
argv[i] = zig_argv[i];
}
//std.debug.print("jl_parse_opts: {s}\n", .{@TypeOf(jl.jl_parse_opts)});
var jl_parse_opts = ptr.lookup(@TypeOf(jl.jl_parse_opts), "jl_parse_opts") orelse return 1;
var jl_init = ptr.lookup(@TypeOf(jl.jl_init), "jl_init") orelse return 2;
var jl_eval_string = ptr.lookup(@TypeOf(jl.jl_eval_string), "jl_eval_string") orelse return 3;
var jl_atexit_hook = ptr.lookup(@TypeOf(jl.jl_atexit_hook), "jl_atexit_hook") orelse return 4;
// Basic embedding
jl_parse_opts(&argc, @ptrCast([*c][*c][*c]u8, &argv));
jl_init();
_ = jl_eval_string("println(\"Hello from Julia!\")");
_ = jl_eval_string("@info \"\" Threads.nthreads() Base.active_project()");
jl_atexit_hook(0);
return 0;
}