How to clone submodule during build?

Hey :waving_hand:t3:,

I’m the creator of snek, the game designed to help you focus.

The game relies on Raylib which is currently vendored into the project using a git submodule. Since git clone doesn’t automatically clone submodules (:woman_facepalming:t3:) I frequently get reports from people trying to build the game that they get errors about Raylib missing. How can I clone Raylib as part of the build?

Currently, my project looks like

// build.zig.zon
.{
    .name = .snek,
    .version = "0.0.0",
    .paths = .{
        "snek.zig",
        "build.zig",
        "build.zig.zon",
    },
    .dependencies = .{
        .raylib = .{ .path = "./raylib" },
    },
    .fingerprint = 0xd86d1176857ecf02,
}
// build.zig
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});
    const exe = b.addExecutable(.{
        .name = "snek",
        .root_source_file = b.path("snek.zig"),
        .target = target,
        .optimize = optimize,
    });
    const check_step = b.step("check", "");
    check_step.dependOn(&exe.step);

    exe.linkLibC();
    exe.linkSystemLibrary("m");

    if (target.result.os.tag.isDarwin()) {
        exe.linkFramework("IOKit");
        exe.linkFramework("Cocoa");
    } else if (target.result.os.tag == .windows) {
        exe.linkSystemLibrary("opengl32");
        exe.linkSystemLibrary("gdi32");
        exe.linkSystemLibrary("winmm");
    }

    const raylib = b.dependency("raylib", .{
        .target = target,
        .optimize = optimize,
    });
    exe.linkLibrary(raylib.artifact("raylib"));

    b.installArtifact(exe);

    const game_exe = b.addRunArtifact(exe);
    const play_step = b.step("play", "");
    play_step.dependOn(&game_exe.step);
}

I want to somehow detect if Raylib is cloned, and if not run git submodule update --init.

I tried doing

diff --git a/build.zig b/build.zig
--- a/build.zig
+++ b/build.zig
@@ -11,6 +11,10 @@
     });
     const check_step = b.step("check", "");
     check_step.dependOn(&exe.step);
+    const submodule_step = b.addSystemCommand(&.{ "git", "submodule", "update", "--init" });
+    submodule_step.addFileArg(std.Build.LazyPath{ .cwd_relative = "./raylib" });
+    check_step.dependOn(&submodule_step.step);
+    exe.step.dependOn(&submodule_step.step);
 
     exe.linkLibC();
     exe.linkSystemLibrary("m");

But it doesn’t seem to do anything.

Thanks for the help! :slightly_smiling_face:

Hi Welcome to Ziggit

For end users, it would be better if u can instead use “zig fetch” to pull raylib instead of using it as a submodule. This basically would be

zig fetch --save git+https://github.com/raysan5/raylib#5f497d068788722c6a4b02e6bcc6a35ea7d2e8a7

Then it will link to the online version instead of the local submodule in your build.zig.zon.

With this users will not be required to clone raylib as submodule since ‘zig build’ would pull it

3 Likes

Thanks! I understand this is an option too. Ideologically I prefer vendoring the code. Is there a way to clone it as a submodule inside of zig build?

I appreciate the help. To show my appreciation I’d like to gift you a free copy of snek. You can download your free copy here.

You need the submodules to be available before the make phase, so you must initialize them during the configure phase. addSystemCommand creates a step that executes during the make phase of the build process, not during the configure phase. Fortunately, there is b.run which runs during the configure phase.

I think alternatively you could just add a Readme that explains to users to use:

git clone --recurse-submodules https://github.com/vegerot/snek.git
cd snek
zig build run -Doptimize=ReleaseSafe

To build and run your game.
I think with a Readme you would get way less questions about what to do.

Personally I don’t really like vendored raylib, makes it a bit more difficult to vet the project (I guess you can argue that, but I think not every person used to git is used to submodules, where people used to Zig will be more used to normal dependencies) to see whether the raylib dependency is still the original upstream project or was used to hide changed code. And I prefer build.zig.zon over submodules, especially for Zig projects.

3 Likes