# Access b.install\_path after v0.17

**URL:** <https://ziggit.dev/t/access-b-install-path-after-v0-17/17906>\
**Category:** Help\
**Tags:** build-system\
**Created:** [October 10, 2026, 9:37am UTC](https://ziggit.dev/t/access-b-install-path-after-v0-17/17906 "2026-10-10T09:37:21Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![n4chh](https://ziggit.dev/user_avatar/ziggit.dev/n4chh/32/8818_2.png) [@n4chh](https://ziggit.dev/u/n4chh)\
**Post date:** [October 10, 2026, 9:37am UTC](https://ziggit.dev/t/access-b-install-path-after-v0-17/17906/1 "2026-10-10T09:37:21Z")

</div>

Hi,  
Previous to v0.17, I accessed zig-out (or the installed dir) using `b.install_path`. This was useful because it let me create steps based on the produced files. Example where I used to add a flag to a Qemu command.

```zig
b.fmt("file=fat:rw:{s}/{s},format=raw", .{ b.install_path, IMG_DIR_NAME }),

```

What’s now the best approach to do this?

Thanks in advance

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [October 10, 2026, 10:04am UTC](https://ziggit.dev/t/access-b-install-path-after-v0-17/17906/2 "2026-10-10T10:04:56Z")

</div>

The recommended way has always been to utilise `LazyPath`, `WriteFiles`, and the various helper APIs for them instead of the manually dealing paths.

I can’t give an exact answer to the example as its missing too much context: is it an input or output file/dir, if its an input then where is it coming from? from the source tree or generated?

---

<div class="post-metadata">

**Author:** ![n4chh](https://ziggit.dev/user_avatar/ziggit.dev/n4chh/32/8818_2.png) [@n4chh](https://ziggit.dev/u/n4chh)\
**Post date:** [October 10, 2026, 10:38am UTC](https://ziggit.dev/t/access-b-install-path-after-v0-17/17906/3 "2026-10-10T10:38:55Z")

</div>

I was looking to [Zig Build System ⚡ Zig Programming Language](https://ziglang.org/learn/build-system/#installing-artifacts) but I couldn’t figure out from there how to actually access the prefix.

It’s an output directory where I’m placing 2 files I generate during the compilation.  
It will look something like this:

```zig
./img
  |--efi/BOOTX64.EFI //generated in one compilation step
  \--kernel.elf //generated in the following compilation step

```

And here is the code of my compilation:

```zig
const std = @import("std");
const IMG_DIR_NAME = "img";

pub fn buildUefi(b: *std.Build) *std.Build.Step.Compile {
    // Create the bootloader executable
    const bootloader = b.addExecutable(.{
        .name = "BOOTX64.EFI",
        .root_module = b.createModule(.{
            .root_source_file = b.path("src/bootloader/boot.zig"),
            .target = b.resolveTargetQuery(.{
                .cpu_arch = .x86_64,
                .os_tag = .uefi,
            }),
            .optimize = .Debug,
            .dwarf_format = .@"64",
        }),
        .linkage = .static,
        .use_lld = true,
        .use_llvm = true,
    });
    b.installArtifact(bootloader);

    // Place the executable in the EFI fs
    const install_bootloader = b.addInstallFile(
        bootloader.getEmittedBin(),
        b.fmt("{s}/efi/boot/{s}", .{ IMG_DIR_NAME, bootloader.name }),
    );
    b.getInstallStep().dependOn(&install_bootloader.step);
    return bootloader;
}
pub fn buildKernel(b: *std.Build) *std.Build.Step.Compile {
    // Create the kernel executable
    const kernel = b.addExecutable(.{
        .name = "kernel.elf",
        .root_module = b.createModule(.{
            .root_source_file = b.path("src/kernel/main.zig"),
            .target = b.resolveTargetQuery(.{
                .os_tag = .freestanding,
                .cpu_arch = .x86_64,
                .ofmt = .elf,
            }),
            .code_model = .kernel,
        }),
        .linkage = .static,

        .use_lld = true,
        .use_llvm = true,
    });
    kernel.entry = .{ .symbol_name = "kernelEntry" };
    kernel.linker_script = b.path("src/kernel/linker.ld");
    b.installArtifact(kernel);
    // Place the kernel inside EFI
    const install_kernel = b.addInstallFile(
        kernel.getEmittedBin(),
        b.fmt("{s}/{s}", .{ IMG_DIR_NAME, kernel.name }),
    );
    b.getInstallStep().dependOn(&install_kernel.step);

    return kernel;
}
// omiting non related code:
pub fn build(b: *std.Build) void {
    const ovmf_path = b.option([]const u8, "ovmf-path", "Path to OVMF firmware file") orelse findOvmfPath(b);
    const log_level_str = b.option([]const u8, "log-level", "Log level of the application.") orelse "info";
    const log_level: std.log.Level = std.meta.stringToEnum(std.log.Level, log_level_str) orelse @panic("Invalid log level provided");

    const build_options = b.addOptions();
    build_options.addOption(std.log.Level, "log_level", log_level);

    const bootloader = buildUefi(b);
    setupBootloaderTests(b, build_options);
    const kernel = buildKernel(b);

    build_options.addOption([]const u8, "kernel_main", kernel.name);
    build_options.addOption([]const u8, "kernel_path", b.fmt("{s}/{s}", .{ IMG_DIR_NAME, kernel.name }));
    bootloader.root_module.addOptions("build_options", build_options);

    const qemu_args = [_][]const u8{
        "qemu-system-x86_64",
        "-m",
        "512M",
        "-bios",
        ovmf_path,
        // "-drive",
        // "if=pflash,format=raw,unit=0,file.filename=" ++ ovmf_path ++ ",file.locking=off,readonly=on",
        "-drive",
        b.fmt("file=fat:rw:{s}/{s},format=raw", .{ b.install_path, IMG_DIR_NAME }),
        "-nographic",
        "-serial",
        "mon:stdio",
        "-no-reboot",
        "-enable-kvm",
        "-cpu",
        "host",
    };
    const qemu_cmd = b.addSystemCommand(&qemu_args);
    qemu_cmd.step.dependOn(b.getInstallStep());
    const run_qemu_step = b.step("run", "Run QEMU");
    run_qemu_step.dependOn(&qemu_cmd.step);

    const debug_qemu_cmd = b.addSystemCommand(&qemu_args ++ [_][]const u8{"-S", "-s"});
    debug_qemu_cmd.step.dependOn(b.getInstallStep());
    const debug_qemu_step = b.step("debug", "Run QEMU and stop execution before boot.");
    debug_qemu_step.dependOn(&debug_qemu_cmd.step);
}

```

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [October 10, 2026, 10:54am UTC](https://ziggit.dev/t/access-b-install-path-after-v0-17/17906/4 "2026-10-10T10:54:46Z")

</div>

Makes sense.

The API deliberately limits what you can do with the install prefix, anything other than copying files to it should go through a `WriteFile` step instead as that gives you _a lot_ more features.

something like this:

```zig
pub fn buildUefi(b: *std.Build, img_wf: *std.Build.Step.WriteFile) *std.Build.Step.Compile {
    // ...
    _ = img_wf.addCopyFile(bootloader.getEmittedBin(), "efi/boot/");
    // ...
}

pub fn buildKernel(b: *std.Build, img_wf: *std.Build.Step.WriteFile) *std.Build.Step.Compile {
    // ...
    _ = img_wf.addCopyFile(kernel.getEmittedBin(), "");
    // ...
}

pub fn build(b: *std.Build) void {
    const img_wf = b.addWriteFiles();

    buildUefi(b, img_wf);
    buildKernel(b, img_wf);
    // ...
    qemu_cmd.addDirectoryArg2(img_wf.getDirectory(), .{ .prefix = "file=fat:rw:", .suffix = ",format=raw" });

    // if you need to install it
    b.installDirectory(.{
        .install_dir = .prefix,
        .install_subdir = IMG_DIR_NAME,
        .source_dir = img_wf.getDirectory(),
    });
}

```

The above removes the need for many of your explicit `dependOn` as the lazy path API’s will do this for you :3
