Trouble with add system command

why

tl;dr.
I’m trying to use zig to build my work repo. We just switched vms and our glibc jumped forward, but there is still older glibc out there so being able to target it would be great.

what

We do this thing where we place our git information into the binary. So I need to run system commands.

Current build system uses some shell to generate those object files. I’m trying to port with zig.
e.g.

# capture working branch
branch=$(git branch | grep \* | cut -d ' ' -f2)
echo -e "branch:\t\t$branch"
rm -f GIT_BRANCH
echo "$branch" >> GIT_BRANCH
objcopy --input binary \
             --output-target elf64-x86-64 \
             --binary-architecture i386 GIT_BRANCH git_branch.o

The following is what I have.

    // I HATE THIS BTW (JUD)
    // OBJECTS += version.o git_build.o git_commit.o git_tag.o
    const branch = b.addSystemCommand(
        &[_][]const u8{
            "git",
            "rev-parse",
            "--abbrev-ref",
            "HEAD",
        },
    );

    const build_git_files = b.step("gitinfo", "builds git_build.o, git_commit.o, and git_tag.o");
    build_git_files.dependOn(&branch.step);

// THEN LATER ...

    const controller_exe = b.addExecutable(.{
        .name = "controller",
        .target = target,
        .optimize = optimize,
    });
    controller_exe.step.dependOn(build_git_files);

But I can’t seem to capture the stdout.

I need to

  1. define the system command
    • I think I have this
  2. Run it and capture stdout
  3. Run another system command (“objcopy --input binary”)
  4. Capture that and add the object file

Ideally build_git_files will contain 3 steps where I repeat the “run git command and then objcopy it to a .o file”

Any help is welcome. Thanks in advance.

P.S.
I have seen the captureStdout() functions, I just can’t get them to work.

I think I got you, here’s a quick snippet:

    // Capturing Stdout from a bash script and directly treating it as a binary "file"
    const bash_script_run = b.addSystemCommand(&.{ "bash", "./some_bash_script_no_args.sh" });
    const stdout_content = bash_script_run.captureStdOut();
    exe.addObjectFile(stdout_content);

    // Having a bash script produce an actual file on disk, and depending on that
    const bash_script_which_produces_file_run = b.addSystemCommand(&.{ "bash", "./some_bash_script_takes_output_file_path.sh" });
    const output_file = bash_script_which_produces_file_run.addOutputFileArg("some_file.o");
    exe.addObjectFile(output_file);

Essentially:

  • addSystemCommand creates a “run” step
  • If you call captureStdOut() that creates a temporary “file” object that can then be depended on by some other step
  • In this case, we treat the stdout from some_bash_script_no_args.sh as a binary object to add to our exe
  • In the second example addOutputFileArg says “I would like to pass this argument to this exe/shell script/cmd whatever, and this is the name of a file I would then like to depend on”
  • We can then feed that file to our exe as well

So for your specific scenario I would:

  • Make a shell script that takes in the names of the files you would like to product as args
  • Call addOutputFileArg for each arg that will be a .o file
  • Add the returned variables to your exe using addObjectFile
2 Likes

is the same with the simpler:

branch=$(git branch --show-current)

There is builtin zig objcopy see: std.Build.addObjCopy

2 Likes