What I'm essentially attempting to do here is this: I'm creating an ISO file by invoking an external command, then I want another command to change that same ISO file, although this second command isn't really an external command, we can treat it as external for this particular question.
Here's the way that I have implemented this in my build.zig file:
const staging_files = b.addWriteFiles();
// ...prepare the filesystem tree for the ISO...
const create_image = b.addSystemCommand(&.{ "xorriso", "-as", "mkisofs" });
// ...roughly thirty thousand invocations of `create_image.addArgs`...
create_image.addArg("-output");
const image_path = create_image.addOutputFileArg("brindlequasar.iso");
create_image.addDirectoryArg(
staging_files.getDirectory(),
);
const install_boot = b.addRunArtifact(limine_binary); // imagine `addSystemCommand` here
install_boot.addArg("bios-install");
install_boot.addFileArg(image_path);
(limine_binary comes from compiling a C program supplied by a package dependency, and it supports only changing files in place.)
The next thing I want to do is launch QEMU with that ISO file passed as an argument. I thought this simply required calling addFileArg with the ISO's LazyPath (stored above as image_path):
const launch_vm = b.addSystemCommand(&.{"qemu-system-x86_64"});
// ...other arguments omitted...
launch_vm.addArg("-cdrom");
launch_vm.addFileArg(image_path);
That doesn't behave as intended, though. On a clean build (after removing zig-cache), the runner executes create_image and launch_vm but omits install_boot. To get the expected behavior, I must add an explicit dependency from launch_vm to install_boot:
// FIXME: Required here, though I haven't fully understood the reason.
launch_vm.step.dependOn(&install_boot.step);
With that addition it all appears to run correctly (at least, I haven't yet discovered a way to break it), but this approach feels off.
My original assumption was that a LazyPath remembered all the steps receiving it, allowing the runner to arrange dependancies, but reading the implementation seems to disprove that; as far as I can see, this type stores only a single *Step, presumably the step which originally constructed that LazyPath. Further searching turned up documentation comments implying that modifying a file behind a LazyPath after its generating step isn't supported, or at least isn't the right approach here.
So my questions boil down to:
Is my reading of the intended behavior right?
What's the supported way of changing this generated file without risking damage to the build cache or comparable machinery?