From 5832a6e43068c6dcc1830c413ac20f3312cd4030 Mon Sep 17 00:00:00 2001 From: LeonardoBizzoni Date: Thu, 21 Aug 2025 19:01:49 +0200 Subject: [PATCH] Improved file writing api --- .gitmodules | 4 +- cbuild.h | 114 ++++++++++++------ examples/01-basics/build.c | 2 +- examples/02-async-commands/build.c | 2 +- examples/03-stream-redirection/build.c | 4 +- .../build.c | 30 +++++ .../gen_arcs.c | 31 +++++ .../src/main.c | 9 ++ .../src/trajectory.h | 6 + examples/XX-codebase-build/build.c | 2 +- 10 files changed, 161 insertions(+), 43 deletions(-) mode change 100644 => 100755 examples/01-basics/build.c create mode 100644 examples/04-multiple-build-files-and-rebuild-opt/build.c create mode 100755 examples/04-multiple-build-files-and-rebuild-opt/gen_arcs.c create mode 100644 examples/04-multiple-build-files-and-rebuild-opt/src/main.c create mode 100644 examples/04-multiple-build-files-and-rebuild-opt/src/trajectory.h diff --git a/.gitmodules b/.gitmodules index eef7b55..1f7464e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "examples/XX-codebase-build/src/base"] - path = examples/XX-codebase-build/src/base - url = git@github.com:LeonardoBizzoni/Codebase.git + path = examples/XX-codebase-build/src/base + url = git@github.com:LeonardoBizzoni/Codebase.git diff --git a/cbuild.h b/cbuild.h index 0e307b5..fba557c 100755 --- a/cbuild.h +++ b/cbuild.h @@ -122,14 +122,14 @@ typedef enum {false, true} bool; : ((Last) ? ((Last)->Next = (Nodeptr), (Last) = (Nodeptr)) \ : ((Head)->Next = (Last) = (Nodeptr)))) -struct cb_path_list { +struct CB_PathList { char **values; size_t count; size_t capacity; }; -typedef struct cb_path_list cb_cmd; +typedef struct CB_PathList CB_Cmd; -struct cb_run_args { +struct CB_RunArgs { bool async; bool reset; @@ -167,10 +167,16 @@ enum { # define CB_DYN_DEFAULT_CAPACITY 8 #endif +#ifndef CB_RECOMPILE_OPTIONS +# define CB_RECOMPILE_OPTIONS +#endif + #if OS_WINDOWS -# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) "cl.exe", "/Fe:", (Exe_name), (Builder_src) +# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) "cl.exe", "/Fe:", (Exe_name), \ + (Builder_src), CB_RECOMPILE_OPTIONS #else -# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) "cc", "-o", (Exe_name), (Builder_src) +# define CB_CMD_REBUILD_SELF(Exe_name, Builder_src) "cc", "-o", (Exe_name), (Builder_src), \ + CB_RECOMPILE_OPTIONS #endif #define cb_dyn_reserve(Dynarr, HowMany) cb_dyn_reserve_custom((Dynarr), (HowMany), values, count, capacity) @@ -182,12 +188,13 @@ enum { #define cb_cmd_append(Dynarr, ...) cb_dyn_append((Dynarr), \ ((char*[]){__VA_ARGS__}), \ (sizeof((char*[]){__VA_ARGS__}) / sizeof(char*))) +#define cb_println(Level, Fmt, ...) cb_print((Level), Fmt "\n", ##__VA_ARGS__) #define cb_rebuild_self(argc, argv) _cb_rebuild(argc, argv, __FILE__, 0) #define cb_rebuild_self_with(argc, argv, ...) _cb_rebuild(argc, argv, __FILE__, __VA_ARGS__, 0) -#define cb_run(Cmd, ...) _cb_run((Cmd), (struct cb_run_args) { \ - .async = false, \ - .reset = true, \ - __VA_ARGS__ \ +#define cb_run(Cmd, ...) _cb_run((Cmd), (struct CB_RunArgs) { \ + .async = false, \ + .reset = true, \ + __VA_ARGS__ \ }) #define cb_proclist_push(Dynarr, Value) cb_dyn_push(Dynarr, Value) @@ -222,6 +229,14 @@ enum { (Dynarr)->Count += (Size); \ } while(0) +#define cb_handle_write(Handle, Content) _is_literal(Content) ? _cb_handle_write_lit(Handle, Content) : _cb_handle_write_dyn(Handle, Content) +#define _cb_handle_write_lit(Handle, Content) \ + _cb_handle_write((Handle), (Content), (sizeof((Content)) / sizeof(*(Content)))) +#define _cb_handle_write_dyn(Handle, Content) \ + _cb_handle_write((Handle), (Content), strlen((Content))) +#define _is_literal(x) _is_literal_(x) +#define _is_literal_(x) _is_literal_f(#x, sizeof(#x) - 1) + static char* cb_format(const char *format, ...); static void cb_print(CB_LogLevel level, const char *fmt, ...); static char* cb_getenv(char *varname); @@ -231,17 +246,18 @@ static void cb_proclist_wait(CB_ProcessList *procs); static CB_Handle cb_handle_open(char *path, CB_AccessFlag permission); static void cb_handle_close(CB_Handle fd); static char* cb_handle_read(CB_Handle fd); -static void cb_handle_write(CB_Handle fd, char *buffer, size_t buffsize); static bool cb_dir_create(char *path); static void cb_dir_delete(char *path); static void cb_file_delete(char *path); static bool cb_file_rename(char *path, char *to); +internal void _cb_handle_write(CB_Handle fd, char *buffer, size_t buffsize); internal char* _cb_format(const char *format, va_list args); -internal bool _cb_need_rebuild(char *output_path, struct cb_path_list sources); +internal bool _cb_need_rebuild(char *output_path, struct CB_PathList sources); internal void _cb_rebuild(int argc, char **argv, char *cb_src, ...); -internal CB_Process _cb_run(cb_cmd *cmd, struct cb_run_args args); +internal CB_Process _cb_run(CB_Cmd *cmd, struct CB_RunArgs args); internal size_t _last_occurance_of(char *string, char ch); +internal bool _is_literal_f(char *str, size_t l); // ============================================================================== @@ -279,7 +295,7 @@ static void cb_print(CB_LogLevel level, const char *fmt, ...) { print_str: ; va_start(args, fmt); - printf("%s\n", _cb_format(fmt, args)); + printf("%s", _cb_format(fmt, args)); va_end(args); #undef ANSI_COLOR_RED #undef ANSI_COLOR_GREEN @@ -313,7 +329,7 @@ static bool cb_setenv(char *varname, char *value) { static void cb_process_wait(CB_Process *proc) { if (proc->handle == CB_PROC_INVALID) { - cb_print(CB_LogLevel_Warn, "Waiting on invalid process handle"); + cb_println(CB_LogLevel_Warn, "Waiting on invalid process handle"); return; } @@ -378,7 +394,7 @@ static CB_Handle cb_handle_open(char *path, CB_AccessFlag permission) { static void cb_handle_close(CB_Handle fd) { if (fd == CB_HANDLE_INVALID) { - cb_print(CB_LogLevel_Warn, "Closing invalid handle"); + cb_println(CB_LogLevel_Warn, "Closing invalid handle"); return; } @@ -393,7 +409,7 @@ static void cb_handle_close(CB_Handle fd) { static char* cb_handle_read(CB_Handle fd) { if (fd == CB_HANDLE_INVALID) { - cb_print(CB_LogLevel_Warn, "Reading from invalid handle"); + cb_println(CB_LogLevel_Warn, "Reading from invalid handle"); return 0; } @@ -433,12 +449,13 @@ static char* cb_handle_read(CB_Handle fd) { #endif } -static void cb_handle_write(CB_Handle fd, char *buffer, size_t buffsize) { +static void _cb_handle_write(CB_Handle fd, char *buffer, size_t buffsize) { if (fd == CB_HANDLE_INVALID) { - cb_print(CB_LogLevel_Warn, "Writing to invalid handle"); + cb_println(CB_LogLevel_Warn, "Writing to invalid handle"); return; } + while (!buffer[buffsize - 1]) { buffsize -= 1; } #if OS_WINDOWS uint64_t to_write = buffsize; uint64_t total_write = 0; @@ -509,7 +526,7 @@ internal char* _cb_format(const char *format, va_list args) { return res; } -internal CB_Process _cb_run(cb_cmd *cmd, struct cb_run_args args) { +internal CB_Process _cb_run(CB_Cmd *cmd, struct CB_RunArgs args) { CB_Process res = {}; #if OS_WINDOWS @@ -538,8 +555,8 @@ internal CB_Process _cb_run(cb_cmd *cmd, struct cb_run_args args) { FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, 0); - cb_print(CB_LogLevel_Error, "Child process creation failed with error %u: %s", - error, lpMsgBuf); + cb_println(CB_LogLevel_Error, "Child process creation failed with error %u: %s", + error, lpMsgBuf); exit(-1); } @@ -548,8 +565,8 @@ internal CB_Process _cb_run(cb_cmd *cmd, struct cb_run_args args) { #else res.handle = fork(); if (res.handle < 0) { - cb_print(CB_LogLevel_Error, "Child process creation failed with error %d: %s\n", - errno, strerror(errno)); + cb_println(CB_LogLevel_Error, "Child process creation failed with error %d: %s\n", + errno, strerror(errno)); exit(-1); } else if (!res.handle) { if (args.stdout) { dup2(args.stdout, STDOUT_FILENO); } @@ -559,12 +576,12 @@ internal CB_Process _cb_run(cb_cmd *cmd, struct cb_run_args args) { dup2(args.stdin, STDIN_FILENO); } - cb_cmd _cmd = {}; + CB_Cmd _cmd = {}; cb_cmd_append_dyn(&_cmd, cmd->values, cmd->count); cb_cmd_push(&_cmd, 0); if (execvp(_cmd.values[0], _cmd.values) < 0) { - cb_print(CB_LogLevel_Error, "Child process creation failed with error %d: %s\n", - errno, strerror(errno)); + cb_println(CB_LogLevel_Error, "Child process creation failed with error %d: %s\n", + errno, strerror(errno)); exit(-1); } // NOTE(lb): unreachable, execvp only returns on error. @@ -585,9 +602,8 @@ internal void _cb_rebuild(int argc, char **argv, char *builder_src, ...) { Assert(argc >= 1); char *exe_name = argv[0]; - struct cb_path_list sources = {}; + struct CB_PathList sources = {}; cb_dyn_push(&sources, builder_src); - va_list args; va_start(args, builder_src); for (;;) { @@ -601,18 +617,24 @@ internal void _cb_rebuild(int argc, char **argv, char *builder_src, ...) { cb_dyn_free(&sources); return; } + cb_println(CB_LogLevel_Info, "rebuilding %s", exe_name); #if OS_WINDOWS char *exe_name_old = cb_format("%s.old", exe_name); if (!cb_file_rename(exe_name, exe_name_old)) { - cb_print(CB_LogLevel_Error, "File rename failed: %s -> %s", - exe_name, exe_name_old); + cb_println(CB_LogLevel_Info, "File rename failed: %s -> %s", + exe_name, exe_name_old); exit(-1); } #endif - cb_cmd cmd = {}; + CB_Cmd cmd = {}; cb_cmd_append(&cmd, CB_CMD_REBUILD_SELF(exe_name, builder_src)); + cb_print(CB_LogLevel_Info, "running: `"); + for (int32_t i = 0; i < cmd.count; ++i) { + printf("%s ", cmd.values[i]); + } + printf("\b`\n"); CB_Process recompiler = cb_run(&cmd); if (recompiler.status_code) { #if OS_WINDOWS @@ -627,7 +649,7 @@ internal void _cb_rebuild(int argc, char **argv, char *builder_src, ...) { exit(0); } -internal bool _cb_need_rebuild(char *output_path, struct cb_path_list sources) { +internal bool _cb_need_rebuild(char *output_path, struct CB_PathList sources) { #if OS_WINDOWS FILETIME output_mtime_large = {}; HANDLE output_handle = CreateFileA(output_path, GENERIC_READ, FILE_SHARE_READ, @@ -663,13 +685,18 @@ internal bool _cb_need_rebuild(char *output_path, struct cb_path_list sources) { } return false; #else - // NOTE(lb): on `fstat` failure assume needed rebuild struct stat output_stat = {}; - if (stat(output_path, &output_stat) < 0) { return true; } + if (stat(output_path, &output_stat) < 0) { goto rebuild_failure; } for (size_t i = 0; i < sources.count; ++i) { struct stat source_stat = {}; - if (stat(sources.values[i], &source_stat) < 0 || - output_stat.st_mtime < source_stat.st_mtime) { return true; } + if (stat(sources.values[i], &source_stat) < 0) { + rebuild_failure: + cb_println(CB_LogLevel_Error, + "`%s` modification time unreadable. Is the file path correct?", + sources.values[i]); + exit(-1); + } + if (output_stat.st_mtime < source_stat.st_mtime) { return true; } } return false; #endif @@ -683,4 +710,19 @@ internal size_t _last_occurance_of(char *string, char ch) { return res - string; } +internal bool _is_literal_f(char *str, size_t l) { + const char *e = str + l; + if (str[0] == 'L') str++; + if (str[0] != '"') return false; + for (; str != e; str = strchr(str + 1, '"')) { + if (!str) { return false; } + for (str++; + *str == '\f' || *str == '\n' || *str == '\r' || + *str == '\t' || *str == '\v'; + ++str); + if (*str != '"') { return false; } + } + return true; +} + #endif diff --git a/examples/01-basics/build.c b/examples/01-basics/build.c old mode 100644 new mode 100755 index 179a18d..53535de --- a/examples/01-basics/build.c +++ b/examples/01-basics/build.c @@ -3,7 +3,7 @@ int main(int argc, char **argv) { cb_rebuild_self(argc, argv); - cb_cmd cmd = {}; + CB_Cmd cmd = {}; #if OS_WINDOWS cb_cmd_append(&cmd, "cl.exe", "main.c", "/Femain.exe"); #else diff --git a/examples/02-async-commands/build.c b/examples/02-async-commands/build.c index 5cfe60d..76824d7 100644 --- a/examples/02-async-commands/build.c +++ b/examples/02-async-commands/build.c @@ -3,7 +3,7 @@ int main(int argc, char **argv) { cb_rebuild_self(argc, argv); - cb_cmd cmd = {}; + CB_Cmd cmd = {}; CB_ProcessList procs = {}; cb_cmd_append(&cmd, "ls", "-lah", "."); cb_proclist_push(&procs, cb_run(&cmd, .async = true)); diff --git a/examples/03-stream-redirection/build.c b/examples/03-stream-redirection/build.c index 82c39ee..2ca8083 100644 --- a/examples/03-stream-redirection/build.c +++ b/examples/03-stream-redirection/build.c @@ -4,9 +4,9 @@ int main(int argc, char **argv) { cb_rebuild_self(argc, argv); CB_Handle file = cb_handle_open("ls-curdir-log", CB_AccessFlag_Read | - CB_AccessFlag_Write); + CB_AccessFlag_Write); - cb_cmd cmd = {}; + CB_Cmd cmd = {}; cb_cmd_append(&cmd, "ls", "-lah", "."); cb_run(&cmd, .stdout = file); diff --git a/examples/04-multiple-build-files-and-rebuild-opt/build.c b/examples/04-multiple-build-files-and-rebuild-opt/build.c new file mode 100644 index 0000000..289c10c --- /dev/null +++ b/examples/04-multiple-build-files-and-rebuild-opt/build.c @@ -0,0 +1,30 @@ +#define CB_RECOMPILE_OPTIONS "-lm" +#include "../../cbuild.h" + +#include "gen_arcs.c" + +int main(int argc, char **argv) { + cb_rebuild_self_with(argc, argv, "../../cbuild.h", "gen_arcs.c"); + + CB_Handle trajectory = cb_handle_open("src/trajectory.h", CB_AccessFlag_Write); + cb_handle_write(trajectory, "#ifndef GEN_TRAJECTORY_H\n#define GEN_TRAJECTORY_H\n"); + cb_handle_write(trajectory, cb_format("#define N_POINTS %d\n", N_POINTS * Chunks)); + + cb_handle_write(trajectory, "typedef struct { float x, y; } Points;\n"); + + generate_arc_points(0, 900, 900, -90.f, 0.f); + generate_arc_points(1800, 900, 900, 180.f, 90.f); + generate_line_points(1800, 1800, 900, 0.f); + + cb_handle_write(trajectory, "static Points waypoints[N_POINTS] = {"); + for (int32_t i = 0; i < N_POINTS * Chunks; ++i) { + cb_handle_write(trajectory, cb_format("{%f,%f}", waypoints[i].x, waypoints[i].y)); + if (i < (N_POINTS * Chunks) - 1) { cb_handle_write(trajectory, ","); } + } + cb_handle_write(trajectory, "};\n#endif\n"); + cb_handle_close(trajectory); + + CB_Cmd cmd = {}; + cb_cmd_append(&cmd, "cc", "-o", "main", "src/main.c"); + cb_run(&cmd); +} diff --git a/examples/04-multiple-build-files-and-rebuild-opt/gen_arcs.c b/examples/04-multiple-build-files-and-rebuild-opt/gen_arcs.c new file mode 100755 index 0000000..fac5338 --- /dev/null +++ b/examples/04-multiple-build-files-and-rebuild-opt/gen_arcs.c @@ -0,0 +1,31 @@ +#include + +#define Chunks 3 +#define N_POINTS 50 + +static struct {float x, y;} waypoints[N_POINTS * Chunks] = {0}; + +static int32_t chunk = 0; +static void generate_arc_points(float center_x, float center_y, float radius, + float start_angle, float end_angle) { + float start_radians = start_angle * M_PI / 180.f; + float end_radians = end_angle * M_PI / 180.f; + for (int32_t i = 0; i < N_POINTS; ++i) { + float t = (float)i / (N_POINTS - 1); + float radians = start_radians + t * (end_radians - start_radians); + waypoints[i + chunk * N_POINTS].x = center_x + radius * cosf(radians); + waypoints[i + chunk * N_POINTS].y = center_y + radius * sinf(radians); + } + chunk += 1; +} + +static void generate_line_points(float start_x, float start_y, float length_mm, float angle) { + float radians = angle * M_PI / 180.f; + for (int32_t i = 0; i < N_POINTS; ++i) { + float amount = i * (length_mm / N_POINTS); + if (amount > length_mm) { amount = length_mm; } + waypoints[i + chunk * N_POINTS].x = start_x + amount * cosf(radians); + waypoints[i + chunk * N_POINTS].y = start_y + amount * sinf(radians); + } + chunk += 1; +} diff --git a/examples/04-multiple-build-files-and-rebuild-opt/src/main.c b/examples/04-multiple-build-files-and-rebuild-opt/src/main.c new file mode 100644 index 0000000..c218df4 --- /dev/null +++ b/examples/04-multiple-build-files-and-rebuild-opt/src/main.c @@ -0,0 +1,9 @@ +#include + +#include "trajectory.h" + +int main(void) { + for (int i = 0; i < N_POINTS; ++i) { + printf("(%f, %f)\n", waypoints[i].x, waypoints[i].y); + } +} diff --git a/examples/04-multiple-build-files-and-rebuild-opt/src/trajectory.h b/examples/04-multiple-build-files-and-rebuild-opt/src/trajectory.h new file mode 100644 index 0000000..dbb2135 --- /dev/null +++ b/examples/04-multiple-build-files-and-rebuild-opt/src/trajectory.h @@ -0,0 +1,6 @@ +#ifndef GEN_TRAJECTORY_H +#define GEN_TRAJECTORY_H +#define N_POINTS 150 +typedef struct { float x, y; } Points; +static Points waypoints[N_POINTS] = {{-0.000039,0.000000},{28.846359,0.462402},{57.663120,1.849121},{86.420731,4.158813},{115.089432,7.388977},{143.639877,11.536377},{172.042725,16.596741},{200.268768,22.564880},{228.289062,29.434631},{256.074829,37.198914},{283.597382,45.849854},{310.828522,55.378418},{337.740234,65.774902},{364.304962,77.028564},{390.495392,89.128052},{416.284485,102.060608},{441.645782,115.813171},{466.553253,130.371521},{490.981415,145.720703},{514.904968,161.844971},{538.299500,178.727783},{561.140808,196.351624},{583.405518,214.698608},{605.070801,233.749817},{626.114258,253.485596},{646.514404,273.885681},{666.250122,294.929138},{685.301331,316.594360},{703.648376,338.859192},{721.272217,361.700500},{738.155029,385.094971},{754.279297,409.018585},{769.628479,433.446686},{784.186829,458.354187},{797.939453,483.715607},{810.872009,509.504669},{822.971375,535.695007},{834.225098,562.259705},{844.621582,589.171448},{854.150146,616.402588},{862.801086,643.925232},{870.565369,671.710938},{877.435120,699.731201},{883.403259,727.957275},{888.463623,756.360107},{892.611023,784.910522},{895.841187,813.579346},{898.150818,842.336853},{899.537598,871.153625},{900.000000,900.000000},{900.000000,899.999939},{900.462402,928.846313},{901.849121,957.663086},{904.158752,986.420593},{907.388977,1015.089294},{911.536316,1043.639771},{916.596741,1072.042725},{922.564880,1100.268799},{929.434631,1128.289062},{937.198914,1156.074829},{945.849792,1183.597290},{955.378418,1210.828491},{965.774902,1237.740234},{977.028564,1264.304932},{989.127991,1290.495239},{1002.060547,1316.284302},{1015.813049,1341.645630},{1030.371582,1366.553345},{1045.720703,1390.981445},{1061.844971,1414.905029},{1078.727783,1438.299438},{1096.351562,1461.140747},{1114.698608,1483.405518},{1133.749756,1505.070801},{1153.485474,1526.114258},{1173.885620,1546.514404},{1194.929077,1566.250122},{1216.594238,1585.301270},{1238.859131,1603.648438},{1261.700562,1621.272217},{1285.094971,1638.155029},{1309.018555,1654.279297},{1333.446655,1669.628418},{1358.354126,1684.186768},{1383.715454,1697.939331},{1409.504761,1710.872070},{1435.695068,1722.971436},{1462.259644,1734.225098},{1489.171387,1744.621582},{1516.402588,1754.150146},{1543.925171,1762.801025},{1571.710938,1770.565430},{1599.731201,1777.435059},{1627.957153,1783.403320},{1656.359985,1788.463623},{1684.910522,1792.611084},{1713.579346,1795.841187},{1742.336792,1798.150879},{1771.153564,1799.537598},{1800.000000,1800.000000},{1800.000000,1800.000000},{1818.000000,1800.000000},{1836.000000,1800.000000},{1854.000000,1800.000000},{1872.000000,1800.000000},{1890.000000,1800.000000},{1908.000000,1800.000000},{1926.000000,1800.000000},{1944.000000,1800.000000},{1962.000000,1800.000000},{1980.000000,1800.000000},{1998.000000,1800.000000},{2016.000000,1800.000000},{2034.000000,1800.000000},{2052.000000,1800.000000},{2070.000000,1800.000000},{2088.000000,1800.000000},{2106.000000,1800.000000},{2124.000000,1800.000000},{2142.000000,1800.000000},{2160.000000,1800.000000},{2178.000000,1800.000000},{2196.000000,1800.000000},{2214.000000,1800.000000},{2232.000000,1800.000000},{2250.000000,1800.000000},{2268.000000,1800.000000},{2286.000000,1800.000000},{2304.000000,1800.000000},{2322.000000,1800.000000},{2340.000000,1800.000000},{2358.000000,1800.000000},{2376.000000,1800.000000},{2394.000000,1800.000000},{2412.000000,1800.000000},{2430.000000,1800.000000},{2448.000000,1800.000000},{2466.000000,1800.000000},{2484.000000,1800.000000},{2502.000000,1800.000000},{2520.000000,1800.000000},{2538.000000,1800.000000},{2556.000000,1800.000000},{2574.000000,1800.000000},{2592.000000,1800.000000},{2610.000000,1800.000000},{2628.000000,1800.000000},{2646.000000,1800.000000},{2664.000000,1800.000000},{2682.000000,1800.000000}}; +#endif diff --git a/examples/XX-codebase-build/build.c b/examples/XX-codebase-build/build.c index ab655c7..26ca473 100644 --- a/examples/XX-codebase-build/build.c +++ b/examples/XX-codebase-build/build.c @@ -78,7 +78,7 @@ int main(int argc, char **argv) { } } - cb_cmd cmd = {}; + CB_Cmd cmd = {}; cb_cmd_append(&cmd, "git", "submodule", "update", "--recursive"); CB_Process codebase_updater = cb_run(&cmd, .async = true); -- 2.52.0