diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b3bbf726b..4f573a8ca 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -441,6 +441,8 @@ struct BuildContext { String extra_assembler_flags; String microarch; BuildModeKind build_mode; + bool build_only; + bool keep_test_executable; bool generate_docs; bool custom_optimization_level; i32 optimization_level; diff --git a/src/main.cpp b/src/main.cpp index 90f2aad7a..faedb9074 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -312,6 +312,8 @@ enum BuildFlagKind { BuildFlag_Collection, BuildFlag_Define, BuildFlag_BuildMode, + BuildFlag_BuildOnly, + BuildFlag_KeepTestExecutable, BuildFlag_Target, BuildFlag_Subtarget, BuildFlag_Debug, @@ -531,6 +533,8 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String, Command__does_check, true); add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String, Command__does_build); // Commands_build is not used to allow for a better error message + add_flag(&build_flags, BuildFlag_BuildOnly, str_lit("build-only"), BuildFlagParam_None, Command_test); + add_flag(&build_flags, BuildFlag_KeepTestExecutable, str_lit("keep-test-executable"), BuildFlagParam_None, Command_test); add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_Subtarget, str_lit("subtarget"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check); @@ -1193,6 +1197,24 @@ gb_internal bool parse_build_flags(Array args) { break; } + case BuildFlag_BuildOnly: + if (build_context.keep_test_executable) { + gb_printf_err("`-keep-test-executable` is mutually exclusive with `-build-only`.\n"); + gb_printf_err("We either only build or run the test and optionally keep the executable.\n"); + bad_flags = true; + } else { + build_context.build_only = true; + } + break; + case BuildFlag_KeepTestExecutable: + if (build_context.build_only) { + gb_printf_err("`-build-only` is mutually exclusive with `-keep-test-executable`.\n"); + gb_printf_err("We either only build or run the test and optionally keep the executable.\n"); + bad_flags = true; + } else { + build_context.keep_test_executable = true; + } + break; case BuildFlag_Debug: build_context.ODIN_DEBUG = true; @@ -2381,6 +2403,12 @@ gb_internal int print_show_help(String const arg0, String command, String option } } + if (test_only) { + if (print_flag("-build-only")) { + print_usage_line(2, "Only builds the test executable; does not automatically run it afterwards."); + } + } + if (check) { if (print_flag("-collection:=")) { print_usage_line(2, "Defines a library collection used for imports."); @@ -2543,6 +2571,12 @@ gb_internal int print_show_help(String const arg0, String command, String option } } + if (test_only) { + if (print_flag("-keep-test-executable")) { + print_usage_line(2, "Keep the test executable after running it instead of deleting it normally."); + } + } + if (run_or_build) { if (print_flag("-linker:")) { print_usage_line(2, "Specify the linker to use."); @@ -3861,11 +3895,16 @@ end_of_code_gen:; show_timings(checker, &global_timings); } - if (run_output) { + if (!build_context.build_only && run_output) { 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)); + + if (build_context.command_kind == Command_test && !build_context.keep_test_executable) { + char const *filename = cast(char const *)exe_name.text; + gb_file_remove(filename); + } } return 0; }