From 9aa84b5e3ad7aca24c3481edb69f9e678c9250c2 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 7 Aug 2026 14:29:08 +0900 Subject: [PATCH] src: Use `posix_spawnp` instead of `system()` when invoking the linker Thanks to Matteo on discord for pointing this out. --- src/common.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/linker.cpp | 3 ++- src/main.cpp | 23 ++++++++++++++--- 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index 3b4557cde..0c0633794 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -739,6 +739,75 @@ gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc, isize return argv; } +#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX) + +gb_internal char **command_line_to_spawn_argv(const char *cmd_line, int *_argc) { + u32 i, j; + + u32 len = cast(u32)strlen(cmd_line); + i = len*gb_size_of(void *) + gb_size_of(void *); + + char **argv = cast(char **)gb_alloc(gb_heap_allocator(), i + (len+1)); + char *_argv = (cast(char *)argv)+i; + + u32 argc = 0; + argv[argc] = _argv; + bool in_quote = false; + bool in_text = false; + bool in_space = true; + i = 0; + j = 0; + + for (;;) { + char a = cmd_line[i]; + if (a == 0) { + break; + } + if (in_quote) { + if (a == '\"') { + in_quote = false; + } else { + _argv[j++] = a; + } + } else { + switch (a) { + case '\"': + in_quote = true; + in_text = true; + if (in_space) { + // check_double_dash(); + argv[argc++] = _argv + j; + } + in_space = false; + break; + case ' ': + case '\t': + case '\n': + case '\r': + if (in_text) _argv[j++] = '\0'; + in_text = false; + in_space = true; + break; + default: + in_text = true; + if (in_space) { + // check_double_dash(); + argv[argc++] = _argv + j; + } + _argv[j++] = a; + in_space = false; + break; + } + } + i++; + } + _argv[j] = '\0'; + argv[argc] = nullptr; + + if (_argc) *_argc = argc; + return argv; +} + #endif #include "path.cpp" diff --git a/src/linker.cpp b/src/linker.cpp index 98d299eb8..cc70849f7 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -810,6 +810,7 @@ try_cross_linking:; } } else if (build_context.build_mode != BuildMode_DynamicLibrary) { if (build_context.metrics.os != TargetOs_openbsd + && build_context.metrics.os != TargetOs_darwin && build_context.metrics.arch != TargetArch_riscv64 && !is_android ) { @@ -961,7 +962,7 @@ try_cross_linking:; if (is_android) { // ignore } else { - link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,$ORIGIN "); } } } diff --git a/src/main.cpp b/src/main.cpp index 306a11689..9bea6416f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -83,6 +83,10 @@ gb_global Timings global_timings = {0}; #include "bug_report.cpp" +#if defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX) +int run_subprocess(const char *name, const char **args, bool honor_path = false); +#endif + // NOTE(bill): 'name' is used in debugging and profiling modes gb_internal i32 system_exec_command_line_app_internal(bool exit_on_err, char const *name, char const *fmt, va_list va) { isize const cmd_cap = 64<<20; // 64 MiB should be more than enough @@ -154,7 +158,11 @@ gb_internal i32 system_exec_command_line_app_internal(bool exit_on_err, char con gb_printf_err("[SYSTEM CALL] %s\n", name); gb_printf_err("%s\n\n", cmd_line); } - exit_code = system(cmd_line); + + int argc; + char **argv = command_line_to_spawn_argv(cmd_line, &argc); + + exit_code = run_subprocess(argv[0], cast(const char**)(argv), true); if (exit_on_err && WIFSIGNALED(exit_code)) { struct rlimit limit = { 0, 0, }; setrlimit(RLIMIT_CORE, &limit); @@ -236,10 +244,19 @@ int run_subprocess(String const &exe_name, wchar_t *after_double_dash_raw) { return exit_code; } #else -int run_subprocess(const char *name, const char **args) { +int run_subprocess(const char *name, const char **args, bool honor_path) { pid_t pid; int status; - status = posix_spawn(&pid, name, NULL, NULL, (char *const *)args, environ); + + String exec_name = make_string_c(args[0]); + exec_name = last_path_element(exec_name); + args[0] = alloc_cstring(gb_heap_allocator(), exec_name); + + if (!honor_path) { + status = posix_spawn(&pid, name, NULL, NULL, (char *const *)args, environ); + } else { + status = posix_spawnp(&pid, name, NULL, NULL, (char *const *)args, environ); + } if (status != 0) { gb_printf_err("Could not spawn subprocess: %s\n", strerror(errno)); return -1;