Merge branch 'master' into bill/bedrock

This commit is contained in:
gingerBill
2026-06-24 11:07:02 +01:00
committed by GitHub
296 changed files with 26882 additions and 12209 deletions

View File

@@ -178,11 +178,44 @@ gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt,
return exit_code;
}
gb_internal void system_must_exec_command_line_app(char const *name, char const *fmt, ...) {
va_list va;
va_start(va, fmt);
system_exec_command_line_app_internal(/* exit_on_err= */ true, name, fmt, va);
va_end(va);
#if defined(GB_SYSTEM_WINDOWS)
#include <process.h>
#else
#include <spawn.h>
extern char **environ;
#endif
int run_subprocess(const char *name, const char **args) {
#if defined(GB_SYSTEM_WINDOWS)
return (int)_spawnv(_P_WAIT, name, args);
#else
pid_t pid;
int status;
status = posix_spawn(&pid, name, NULL, NULL, (char *const *)args, environ);
if (status != 0) {
gb_printf_err("Could not spawn subprocess: %s\n", strerror(errno));
return -1;
}
for (;;) {
if (waitpid(pid, &status, WUNTRACED) < 0) {
gb_printf_err("Could not wait on subprocess: (pid: %d): %s\n", pid, strerror(errno));
return -1;
}
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
struct rlimit limit = { 0, 0, };
setrlimit(RLIMIT_CORE, &limit);
raise(WTERMSIG(status));
return -1;
} else if (WIFSTOPPED(status)) {
return -1;
}
}
GB_PANIC("Subprocess failure");
#endif
}
#if defined(GB_SYSTEM_WINDOWS)
@@ -312,6 +345,7 @@ enum BuildFlagKind {
BuildFlag_Debug,
BuildFlag_DisableAssert,
BuildFlag_NoBoundsCheck,
BuildFlag_WebkitSwitchWorkaround,
BuildFlag_NoTypeAssert,
BuildFlag_NoDynamicLiterals,
BuildFlag_DynamicLiterals,
@@ -354,6 +388,7 @@ enum BuildFlagKind {
BuildFlag_NoThreadLocal,
BuildFlag_RelocMode,
BuildFlag_StackProtector,
BuildFlag_DisableRedZone,
BuildFlag_DisableUnwind,
@@ -549,6 +584,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_WebkitSwitchWorkaround, str_lit("webkit-switch-workaround"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoTypeAssert, str_lit("no-type-assert"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
@@ -591,6 +627,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build | Command_bundle_android);
add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_StackProtector, str_lit("stack-protector"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_DisableUnwind, str_lit("disable-unwind"), BuildFlagParam_None, Command__does_build);
@@ -1243,6 +1280,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_NoBoundsCheck:
build_context.no_bounds_check = true;
break;
case BuildFlag_WebkitSwitchWorkaround:
build_context.webkit_switch_workaround = true;
break;
case BuildFlag_NoTypeAssert:
build_context.no_type_assert = true;
break;
@@ -1439,6 +1479,26 @@ gb_internal bool parse_build_flags(Array<String> args) {
break;
}
case BuildFlag_StackProtector: {
GB_ASSERT(value.kind == ExactValue_String);
String v = value.value_string;
if (v == "none") {
build_context.stack_protector = StackProtector_None;
} else if (v == "base") {
build_context.stack_protector = StackProtector_Ssp;
} else if (v == "all") {
build_context.stack_protector = StackProtector_SspReq;
} else if (v == "strong") {
build_context.stack_protector = StackProtector_SspStrong;
} else {
gb_printf_err("-stack-protector flag expected one of the following\n");
gb_printf_err("\tnone\n");
gb_printf_err("\tbase\n");
gb_printf_err("\tall\n");
gb_printf_err("\tstrong\n");
bad_flags = true;
}
}
case BuildFlag_DisableRedZone:
build_context.disable_red_zone = true;
break;
@@ -2913,6 +2973,11 @@ gb_internal int print_show_help(String const arg0, String command, String option
print_usage_line(2, "Disables bounds checking program wide.");
}
if (print_flag("-webkit-switch-workaround")) {
print_usage_line(2, "Constrains 'typeid' values to 63 bits to avoid an OMG JIT crash in WebKit when running WASM builds.");
print_usage_line(2, "Only needed for 'js_wasm32'/'js_wasm64p32' targets run in Safari/WebKit. See: https://github.com/odin-lang/Odin/issues/6810");
}
if (print_flag("-no-crt")) {
print_usage_line(2, "Disables automatic linking with the C Run Time.");
}
@@ -3008,6 +3073,16 @@ gb_internal int print_show_help(String const arg0, String command, String option
print_usage_line(3, "-reloc-mode:dynamic-no-pic");
}
if (print_flag("-stack-protector:<string>")) {
print_usage_line(2, "Specifies the stack protector.");
print_usage_line(2, "Available options:");
print_usage_line(3, "-stack-protector:default");
print_usage_line(3, "-stack-protector:none");
print_usage_line(3, "-stack-protector:base");
print_usage_line(3, "-stack-protector:all");
print_usage_line(3, "-stack-protector:strong");
}
#if defined(GB_SYSTEM_WINDOWS)
if (print_flag("-resource:<filepath>")) {
print_usage_line(2, "[Windows only]");
@@ -3655,24 +3730,52 @@ int main(int arg_count, char const **arg_ptr) {
TIME_SECTION("init args");
map_init(&build_context.defined_values);
build_context.extra_packages.allocator = heap_allocator();
init_build_context_error_pos_style();
Array<String> args = setup_args(arg_count, arg_ptr);
Array<String> run_args = array_make<String>(heap_allocator(), 0, arg_count);
defer (array_free(&run_args));
String command = args[1];
String init_filename = {};
String run_args_string = {};
isize last_non_run_arg = args.count;
isize double_dash_pos = -1;
for_array(i, args) {
if (args[i] == "--") {
double_dash_pos = i;
break;
}
if (args[i] == "-help" || args[i] == "--help") {
build_context.show_help = true;
return print_show_help(args[0], command);
}
}
if (args.count > 2) {
// NOTE(bill): Allow for both `odin command path -flags` and `odin command -flags path`
// To do this, if the first argument after the command and last argument is NOT a flag,
// then put that last parameter first
isize end_arg = double_dash_pos >= 0 ? double_dash_pos : args.count-1;
if (args[1] == "bundle" && args.count > 4) {
if (string_starts_with(args[3], str_lit("-")) &&
!string_starts_with(args[end_arg], str_lit("-"))) {
String possible_path = args[end_arg];
array_ordered_remove(&args, end_arg);
array_inject_at(&args, 3, possible_path);
}
} else if (args.count > 3) {
if (string_starts_with(args[2], str_lit("-")) &&
!string_starts_with(args[end_arg], str_lit("-"))) {
String possible_path = args[end_arg];
array_ordered_remove(&args, end_arg);
array_inject_at(&args, 2, possible_path);
}
}
}
bool run_output = false;
if (command == "run" || command == "test") {
if (args.count < 3) {
@@ -3684,9 +3787,6 @@ int main(int arg_count, char const **arg_ptr) {
build_context.command_kind = Command_test;
}
Array<String> run_args = array_make<String>(heap_allocator(), 0, arg_count);
defer (array_free(&run_args));
isize run_args_start_idx = -1;
for_array(i, args) {
if (args[i] == "--") {
@@ -3708,7 +3808,6 @@ int main(int arg_count, char const **arg_ptr) {
}
}
args = array_slice(args, 0, last_non_run_arg);
run_args_string = string_join_and_quote(heap_allocator(), run_args);
init_filename = args[2];
run_output = true;
@@ -3816,6 +3915,10 @@ int main(int arg_count, char const **arg_ptr) {
usage(args[0]);
return 1;
}
// NOTE(Jeroen): `odin root` omits a newline on purpose so that it can be used in scripts.
// e.g. `ODIN_CORE="$(odin root)core"`.
// Human convenience is not a consideration.
// Further pull requests to add a newline will be closed without comment.
gb_printf("%.*s", LIT(odin_root_dir()));
return 0;
} else if (command == "clear-cache") {
@@ -4301,8 +4404,23 @@ end_of_code_gen:;
String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]);
defer (gb_free(heap_allocator(), exe_name.text));
system_must_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string));
const char* exe_name_cstring = alloc_cstring(heap_allocator(), exe_name);
Array<const char *> run_args_cstring = array_make<const char *>(heap_allocator(), 0, run_args.count);
defer({
for_array(i, run_args_cstring) { gb_free(heap_allocator(), (void*)run_args_cstring[i]); }
array_free(&run_args_cstring);
});
array_add(&run_args_cstring, exe_name_cstring);
for_array(i, run_args) {
array_add(&run_args_cstring, alloc_cstring(heap_allocator(), run_args[i]));
}
array_add(&run_args_cstring, NULL);
int subprocess_res = run_subprocess(exe_name_cstring, run_args_cstring.data);
if (subprocess_res) {
gb_exit(subprocess_res);
}
if (!build_context.keep_executable) {
char const *filename = cast(char const *)exe_name.text;
gb_file_remove(filename);