Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Make nob__go_rebuild_urself preserve the exit code; Add `nob_proc_wait_exit_code` to the public API

Open
#273 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
70/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
c

Research direction

Start in nob.h by reading the declarations and implementation of nob_proc_wait, then trace nob__go_rebuild_urself and the stripped alias definitions. Check the Windows and Unix process-wait paths described in the issue, and verify that the rebuild wrapper preserves the child exit code while the existing nob_proc_wait behavior remains available.

Written by the indexing model from the issue text.

Description

I thought it'd be more natural to present how I originally wrote it out, but that changes the public API, and per the CONTRIBUTING.md that cannot be a PR. I hope this is acceptable.

The rational lies around the expectation for nob__go_rebuild_urself to be a "transparent" kind of wrapper around your e.g. nob.exe, i.e., when it needs to rebuild itself, your new executable shouldn't really change its behavior beyond your own changes. But because of the way the API is designed around compressing many types of errors into a boolean with functions like nob_cmd_run_opt, it so naturally ended up that nob__go_rebuild_urself compressed all nonzero error codes of the rebuilt version of itself into 1.

I think the lack of preservation here breaks expectations -- I did indeed expect this in some of my own code. So this is how I went about fixing it.

However, to note as an aside first:

Aside / Preamble on why its written this way

It would be "nicest" if actually the family of functions like nob_cmd_run_opt allowed for sync (easier) and async (more work) invocations to preserve exit codes if you wanted, or something offering like this. But this would require some more thinking and work, and I'm not sure if that's what you want. So instead I sort of "hand wrote" what nob_cmd_run_opt did for nob__go_rebuild_urself but just made sure to preserve the exit code this time, and so the function nob_proc_wait_exit_code sort of "popped out" of that.

Code

Add this below nob_proc_wait's top level declaration:

#ifdef _WIN32
typedef DWORD Nob_Exit_Code;
#else
typedef int Nob_Exit_Code;
#endif // _WIN32

// Wait until the process has finished, and save its exit code to the out pointer
NOBDEF bool nob_proc_wait_exit_code(Nob_Proc proc, Nob_Exit_Code *exit_code);

Then delete all of the code inside of nob_proc_wait and put it inside the implementation for nob_proc_wait_exit_code under the now vacant implementation for nob_proc_wait, and put some new code inside nob_proc_wait, as you'll see below:

NOBDEF bool nob_proc_wait(Nob_Proc proc)
{
    return nob_proc_wait_exit_code(proc, NULL);
}

NOBDEF bool nob_proc_wait_exit_code(Nob_Proc proc, Nob_Exit_Code *exit_code)
{
    // has the code that was previously inside `nob_proc_wait` above
}

Then inside nob_proc_wait_exit_code, under this part of the _WIN32 implementation, add the the commented "NEW" code:

    DWORD exit_status;
    if (!GetExitCodeProcess(proc, &exit_status)) {
        nob_log(NOB_ERROR, "could not get process exit code: %s", nob_win32_error_message(GetLastError()));
        return false;
    }

    // NEW
    if (exit_code != NULL) {
        *exit_code = exit_status;
    }
    // ...NEW

and under the #else / UNIX part do basically the same thing:

        if (WIFEXITED(wstatus)) {
            int exit_status = WEXITSTATUS(wstatus);
            // NEW
            if (exit_code != NULL) {
                *exit_code = exit_status;
            }
            // ...NEW

            if (exit_status != 0) {
                nob_log(NOB_ERROR, "command exited with exit code %d", exit_status);
                return false;
            }

            break;
        }

Then in nob__go_rebuild_urself, at the end of the function's implementation/body, change the original snippet which is:

#endif // NOB_EXPERIMENTAL_DELETE_OLD

    nob_cmd_append(&cmd, binary_path);
    nob_da_append_many(&cmd, argv, argc);
    if (!nob_cmd_run_opt(&cmd, opt)) exit(1);
    exit(0);

to this:

#endif // NOB_EXPERIMENTAL_DELETE_OLD

    nob_cmd_append(&cmd, binary_path);
    nob_da_append_many(&cmd, argv, argc);
// NEW below:
    Nob_Exit_Code exit_code = 1;
    Nob_Proc proc = nob__cmd_start_process(cmd, NULL, NULL, NULL);
    nob_proc_wait_exit_code(proc, &exit_code);
    exit(exit_code);

and then add nob_proc_wait_exit_code and the new type to the stripped alias definitions:

        #define proc_wait nob_proc_wait
// NEW
        #define Exit_Code Nob_Exit_Code
        #define proc_wait_exit_code nob_proc_wait_exit_code
// ...NEW
        #define procs_wait nob_procs_wait

That's about it. Am running this code currently on my Windows machine and it seems to work nice.

Thank you for taking the time to look at these ideas, and I hope they brought some value.
--Fart

Dominant language
C++
Stars
3.3k
Forks
215
PR merge metrics
No merged PRs in 30d

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from tsoding/nob.h

All issues in tsoding/nob.h

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.