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
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.mdthat cannot be a PR. I hope this is acceptable.The rational lies around the expectation for
nob__go_rebuild_urselfto 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 likenob_cmd_run_opt, it so naturally ended up thatnob__go_rebuild_urselfcompressed all nonzero error codes of the rebuilt version of itself into1.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_optallowed 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" whatnob_cmd_run_optdid fornob__go_rebuild_urselfbut just made sure to preserve the exit code this time, and so the functionnob_proc_wait_exit_codesort of "popped out" of that.Code
Add this below
nob_proc_wait's top level declaration:Then delete all of the code inside of
nob_proc_waitand put it inside the implementation fornob_proc_wait_exit_codeunder the now vacant implementation fornob_proc_wait, and put some new code insidenob_proc_wait, as you'll see below:Then inside
nob_proc_wait_exit_code, under this part of the_WIN32implementation, add the the commented "NEW" code:and under the
#else/ UNIX part do basically the same thing:Then in
nob__go_rebuild_urself, at the end of the function's implementation/body, change the original snippet which is:to this:
and then add
nob_proc_wait_exit_codeand the new type to the stripped alias definitions: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