Launch zig build from build.zig

Hi … another question for you Zig experts… Thanks for all the help!

I’m attempting to write some software that uses shared library plugins.
I want to have plugins that come with the software and I want build and install them all into a single dist directory.

I would like to run zig build and have it build the executable and all of the individual shared library plugins. Then have it put them all together into a dist folder.

The issue is keeping the builds separate. My first thought was to launch zig build again within each plugin folder and copy the shared library. It seems like I need to use addSystemCommand to do this.

There doesn’t appear to be a way to specify a directory to compile outside of the CWD for zig build but I’m not sure about zig build-lib

So, I will need to change directory, run the system command and change back and package all that into a custom build step? Or use CMake or a Shell script.

Any ideas on the best process to use? Also, do I need to search for the zig executable or is there an easy way to get the current running path?

Thanks!

You can have as many build.addExecutable and build.addSharedLibrary as you want, just remember to install them all and set the proper dependencies. You probably want the main install step to depend on the executable and all the plugins. If you have a separate build.zig for each plugin, it’s slightly more complicated, but nothing huge.
The zig init example shows how to output an executable and a static library simultaneously.

1 Like

The idea is that each plugin will also be an example of how others can create their own plugins and build them independently of my code. They will be dynamically loaded later. They shouldn’t have to depend on the main build.zig to build. Plus, each of them will have maybe wildly different dependencies.

How do you specify a separate build.zig file?

I’ve supporsed following project directories.

/
    main_executable
        build.zig
        build.zig.zon
        src/
    lib
        plugin_a
            build.zig
            src/
            ...
        plugin_a
            build.zig
            src/
            ...

If main_executable is used plugin_a and plugin_a

  1. Add depencencies to build.zig.zon of main_executable

(main_executable/build.zig.zon)

.{
    // (snip)
    .dependencies = .{
        .plugin_a = .{ .path = "../lib/plugin_a" },
        .plugin_b = .{ .path = "../lib/plugin_b" },
    },
}
  1. Add artifacts to build.zig of main_executable

(main_executable/build.zig)

const std = @import("std");
pub fn build(b: *std.Build) !void {
    // Please add options for `std.Build.dependency` method as necessary
    const dep_plugin_a = b.dependency("plugin_a", .{});
    const dep_plugin_b = b.dependency("plugin_b", .{});

    // main executable artifact
    const exe = b.addExecutable(.{
       // (snip) options
    });
    b.installArtifact(exe);
    
    // plugin artifacts
    const plugin_a = dep_plugin_a.artifact("plugin_a");
    b.installArtifact(plugin_a);
    const plugin_b = dep_plugin_a.artifact("plugin_b");
    b.installArtifact(plugin_b);
}

It notes that plugin_a and plugin_b projects are built as executable or static/dynamic library respectively.

5 Likes

That works great! Thanks @ktz_alias

1 Like

Just for reference in case anyone is searching …

You can run zig build from build.zig or indeed any command.

    const something_path = "plugins/something/";
    var something = b.addSystemCommand(&.{ "zig", "build" });

    // sets directory to plugin path when running command
    something.setCwd(b.path(something_path));

    // checks exit code and will stop compiling if not ok
    something.addCheck(.{ .expect_term = .{ .Exited = 0 } });

    // makes sure that is run every time build is run
    something.has_side_effects = true;

    // installs library from plugin into base zig-out/lib
    b.installLibFile(something_path ++ "zig-out/lib/libsomething.so", "libsomething.so");

    // makes sure it is run before main exe
    exe.step.dependOn(&something.step);
1 Like