Zig Build to run a program resulting from a cmake command

Hi!

Short version: how can I run a program as part of the zig build process when I have a LazyPath to the exe? I need

  • Something like AddSystemCommand, but for LazyPaths
  • Something like AddRunArtifact, but for a program that doesn’t come out of a Compile step.

Longer version:

I have a project using the zig build system that is using some external (but modified) CMake projects that generate programs I then need to run as part of the build.

I have seen how to integrate the two-step cmake process in this thread and it is very useful: How should i generate CC and CXX in build.zig - #15 by castholm

However, I am not building a library with cmake, but a command-line tool that then needs to be run with some inputs and outputs as part of the build process. My problem here is that I have it working by forcing to cmake to install the exe into a path I specify in the cmake arguments, but then the dependency on this exe of subsequent steps using this exe to generate additional artifacts seems to be lost: modifying the exe doesn’t force re-running it to update subsequent artifacts.

I’d like to find the best zig-style way of getting it to detect all dependencies.

Thanks in advance!

1 Like

Maybe you could try manually constructing a run step (haven’t tried that before), maybe something like this (based on looking at the code of addRunArtifact):

const run_step = Step.Run.create(b, step_name);
run_step.producer = compile_step_which_created_the_lazypath;
// NOTE not sure if the implementation can/does handle a lazy path
// NOTE as first/exe-argument normally the code uses `addArtifactArg`
run_step.addFileArg(lazy_path_to_your_executable);
// add other inputs and output args
// use the outputs in following build steps
1 Like

I have encountered this exact case and the way I have found to do it is use something like this:

const command_with_lazy_path = std.Build.Step.Run.create(b, "something");
command_with_lazy_path.addFileArg(b.path("whatever"));

The addFileArg accepts a lazy path and since it is the first argument it is the first thing that is run.

Edit: This is just for the runSystemCommand option. I haven’t needed what you describe with AddRunArtifact

2 Likes

b.path() should only be used for paths inside your “build root” aka “repository” though.
But b.option() can return a Lazypath that you pass into the “zig build” command line, too.
If the option is not provided it would make sense to instead run “b.runSystemCommand” or use b.addArg with just the basename and assume the command is available in PATH

also I have created a repo that actually bootstraps cmake from just zig:

It contains a build.zig recipe to build the bootstrap version of cmake (which normally is build by a shellscript) and then uses it and allyourcodebase/gmake to build a full version.

But it only works on linux at the moment, and i’m not sure the stage2 cmake does not link system libraries.
It is quite “heavy”, too…consider writing your build.zig to replace your dependency’s CMakeLists.txt instead, it’ll be worth it :wink:

2 Likes

Thanks everyone for all the answers. The solution was what rob suggested (without using the “path” method).

Writing a build.zig for the dependency cmake project would be ideal but it isn’t an option, since that project is huge and has lots of additional dependencies (it is Blender).

Directly assigning to the “producer” attribute of a run step wasn’t an option either because that actually wants a Compile type, which I don’t get from a “addSystemCommand”.

1 Like