Prototype Julia Launcher via Zig

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;
}
2 Likes