Embedding files using build.zig

Really simple example:

Project structure:

build.zig:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe_mod = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .imports = &.{
            .{
                .name = "spec.xml",
                .module = b.createModule(.{
                    .root_source_file = b.path("assets/spec.xml"),
                }),
            },
        },
    });

    const exe_compile = b.addExecutable(.{
        .name = "foo",
        .root_module = exe_mod,
    });

    b.installArtifact(exe_compile);

    const run_step = b.step("run", "Run the app");

    const run_cmd = b.addRunArtifact(exe_compile);
    run_step.dependOn(&run_cmd.step);

    run_cmd.step.dependOn(b.getInstallStep());

    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
}

src/main.zig

const std = @import("std");

const xml = @embedFile("spec.xml");

pub fn main() !void {
    std.debug.print("{s}\n", .{xml});
}

This compiles, runs and prints out everything correctly.
However I thought I was supposed to use use b.addEmbedPath, but was unable to get it working.
I managed to make it work by putting assets folder is into src and changing path to xml file in build.xml to src/assets/spec.xml, otherwise zig build run fails with:

src\main.zig:3:24: error: unable to open 'assets/spec.xml': FileNotFound
const xml = @embedFile("assets/spec.xml");

And since since assets folder is in src, there is actually no need for use of b.addEmbedPath since everything in src is already “embeddable“ by default.

My question is, is the way it’s currently written a “correct” way to embed files outside of src folder? If so, what is the purpose of b.addEmbedPath since, like I figured out, everything inside src is already “embeddable” by default?

Edit: @Sze That was a typo. I meant to use name of imported module, not path inside main.zig.

I think that’s just the build system way of specifying --embed-dir=... which is search dirs for C23’s #embed directive

@embedFile takes a path relative to the current file, or an absolute path, or the name of an import.

Adding the file to the imports list won’t do anything, you’d have to @import it which will give a compile error since it’s not a zig file.

As @cryptocode said, mod.addEmbedPath is for c compilation

Import module names work too, at least last time I checked.

Also:

path is absolute or relative to the current file, just like @import.

From my experience it seems like @import and @embedFile share most of their implementation code, where import has the additional constraint that it is a zig or zon file.


I don’t know what happens with file extensions in module names, but assuming they just get ignored I would expect either .name = "assets/spec.xml", or @embedFile("spec.xml"); to work, basically using matching import names.

I tested it, and couldn’t get @embedFile working with a named import at all. Though I definitely remember at least talk about it.

@Cloudef @Sze :woman_facepalming: I added the import to the wrong module when testing

2 Likes