From 208b0f6d0e3d54c500c8cdac5b1646741ac5363f Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 27 Jul 2025 17:10:46 +0200 Subject: [PATCH] Fix issue where recursively creating a dir would be incorrectly marked as a failure the first time. Place output in `out` by default for projects. Use temp folder for building at the command line. --- releasenotes.md | 2 + src/build/builder.c | 83 ++++++++++++++++++++-------------- src/build/libraries.c | 2 +- src/compiler/codegen_general.c | 3 +- src/compiler/compiler.c | 16 ++++++- src/utils/file_utils.c | 42 +++++++++++++++++ src/utils/lib.h | 1 + 7 files changed, 110 insertions(+), 39 deletions(-) diff --git a/releasenotes.md b/releasenotes.md index 37cf65476..08f8050a5 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -30,6 +30,7 @@ - '$assignable' is deprecated. - Deprecate allocator::heap() and allocator::temp() - Add `thread::fence` providing a thread fence. +- Place output in `out` by default for projects. Use temp folder for building at the command line. ### Fixes - mkdir/rmdir would not work properly with substring paths on non-windows platforms. @@ -77,6 +78,7 @@ - Using @noreturn in a short body macro would not work properly #2326. - Bug when reporting error in a macro return would crash the compiler #2326. - Short body return expression would not have the correct span. +- Fix issue where recursively creating a dir would be incorrectly marked as a failure the first time. ### Stdlib changes - Improve contract for readline. #2280 diff --git a/src/build/builder.c b/src/build/builder.c index df7246b95..b151239a9 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -271,6 +271,28 @@ static LinkLibc libc_from_arch_os(ArchOsTarget target) #define OVERRIDE_IF_SET(prop_) do { if (options->prop_) target->prop_ = options->prop_; } while (0) #define set_if_updated(target_, original_) do { if ((int)original_ != -1) target_ = original_; } while (0) +static void set_dir_with_default(const char **setting, const char *option, const char *default_value) +{ + if (option) + { + *setting = option; + return; + } + if (!*setting) *setting = default_value; +} + +static void set_output_dir_from_options(const char **setting, const char *option, const char *default_value, const char *target_name, const char *out_dir) +{ + if (option) + { + *setting = option; + } + if (!*setting) + { + *setting = file_append_path(file_append_path(out_dir, default_value), target_name); + } +} + static void update_build_target_from_options(BuildTarget *target, BuildOptions *options) { switch (options->command) @@ -480,51 +502,43 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * target->emit_only = options->emit_only; const char *target_name = arch_os_target[target->arch_os_target]; - if (options->script_dir) target->script_dir = options->script_dir; + OVERRIDE_IF_SET(run_dir); + if (command_accepts_files(options->command)) { - target->build_dir = options->build_dir ? options->build_dir : ".build"; - if (!target->script_dir) target->script_dir = "."; + set_dir_with_default(&target->output_dir, options->output_dir, "."); + if (!target->build_dir) + { + if (!options->build_dir) + { + options->build_dir = dir_make_temp_dir(); + if (!options->build_dir) + { + error_exit("Unable to create temporary directory for build."); + } + } + target->build_dir = options->build_dir; + } + set_dir_with_default(&target->script_dir, options->script_dir, "."); } else { - if (!target->build_dir) target->build_dir = "build"; - if (options->build_dir) - { - target->build_dir = options->build_dir; - } - else - { - options->build_dir = target->build_dir; - } - if (!target->script_dir) target->script_dir = "scripts"; + set_dir_with_default(&target->output_dir, options->output_dir, "out"); + set_dir_with_default(&target->build_dir, options->build_dir, "build"); + set_dir_with_default(&target->script_dir, options->script_dir, "scripts"); } - if (!options->run_dir) options->run_dir = target->run_dir; - target->ir_file_dir = options->llvm_out; - target->asm_file_dir = options->asm_out; - target->header_file_dir = options->header_out; - target->object_file_dir = options->obj_out; - if (!target->ir_file_dir) + set_output_dir_from_options(&target->ir_file_dir, options->llvm_out, "llvm", target_name, target->build_dir); + set_output_dir_from_options(&target->asm_file_dir, options->asm_out, "asm", target_name, target->output_dir); + set_output_dir_from_options(&target->header_file_dir, options->header_out, "headers", target_name, target->output_dir); + if (target->type == TARGET_TYPE_OBJECT_FILES) { - target->ir_file_dir = options->build_dir - ? file_append_path(file_append_path(options->build_dir, "llvm"), target_name) - : file_append_path("llvm", target_name); - } - if (!target->asm_file_dir) - { - target->asm_file_dir = options->build_dir - ? file_append_path(file_append_path(options->build_dir, "asm"), target_name) - : file_append_path("asm", target_name); + set_output_dir_from_options(&target->object_file_dir, options->obj_out, "obj", target_name, target->output_dir); } - if (!target->object_file_dir) + else { - target->object_file_dir = file_append_path(file_append_path(target->build_dir, "obj"), target_name); - } - if (!target->header_file_dir) - { - target->header_file_dir = target->output_dir ? target->output_dir : target->build_dir; + set_output_dir_from_options(&target->object_file_dir, options->obj_out, "obj", target_name, target->build_dir); } if (options->files) @@ -577,7 +591,6 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * target->emit_asm = false; target->emit_object_files = false; } - target->run_dir = options->run_dir; if (options->no_obj) { target->emit_object_files = false; diff --git a/src/build/libraries.c b/src/build/libraries.c index b8f40b160..0c180bf2c 100644 --- a/src/build/libraries.c +++ b/src/build/libraries.c @@ -206,7 +206,7 @@ static inline JSONObject *resolve_zip_library(BuildTarget *build_target, const c scratch_buffer_clear(); assert(build_target->build_dir); scratch_buffer_append(build_target->build_dir); - scratch_buffer_printf("/_c3l/%s/", lib_name); + scratch_buffer_printf("/unpacked_c3l/%s/", lib_name); char *lib_dir = scratch_buffer_copy(); char *lib_dir_copy = scratch_buffer_copy(); scratch_buffer_append("checksum.txt"); diff --git a/src/compiler/codegen_general.c b/src/compiler/codegen_general.c index f650841b9..7fc6978ef 100644 --- a/src/compiler/codegen_general.c +++ b/src/compiler/codegen_general.c @@ -324,8 +324,7 @@ void codegen_setup_object_names(Module *module, const char **base_name, const ch *object_filename = file_append_path(compiler.build.object_file_dir, str_printf("%s%s", result, get_object_extension())); } - *ir_filename = str_printf(compiler.build.backend == BACKEND_LLVM ? "%s.ll" : "%s.ir", result); - if (compiler.build.ir_file_dir) *ir_filename = file_append_path(compiler.build.ir_file_dir, *ir_filename); + *ir_filename = file_append_path(compiler.build.ir_file_dir, str_printf(compiler.build.backend == BACKEND_LLVM ? "%s.ll" : "%s.ir", result)); if (compiler.build.emit_asm) { *asm_filename = str_printf("%s.s", result); diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index fd68d6118..f2caa0b2a 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -422,6 +422,7 @@ bool compiler_should_ouput_file(const char *file) static void create_output_dir(const char *dir) { if (!dir) return; + if (strlen(dir) == 0) return; if (file_exists(dir)) { if (!file_is_dir(dir)) error_exit("Output directory is not a directory %s.", dir); @@ -429,7 +430,8 @@ static void create_output_dir(const char *dir) } scratch_buffer_clear(); scratch_buffer_append(dir); - if (!dir_make_recursive(scratch_buffer_to_string())) + dir_make_recursive(scratch_buffer_to_string()); + if (!file_exists(dir)) { error_exit("Failed to create directory '%s'.", dir); } @@ -506,6 +508,18 @@ void compiler_compile(void) { compiler.build.single_module = SINGLE_MODULE_ON; } + if (compiler.build.emit_asm) + { + scratch_buffer_clear(); + scratch_buffer_append(compiler.build.asm_file_dir); + dir_make_recursive(scratch_buffer_to_string()); + } + if (compiler.build.emit_object_files) + { + scratch_buffer_clear(); + scratch_buffer_append(compiler.build.object_file_dir); + dir_make_recursive(scratch_buffer_to_string()); + } switch (compiler.build.backend) { case BACKEND_C: diff --git a/src/utils/file_utils.c b/src/utils/file_utils.c index ec301e349..b55577d12 100644 --- a/src/utils/file_utils.c +++ b/src/utils/file_utils.c @@ -86,6 +86,47 @@ bool dir_make(const char *path) #endif } +#if !PLATFORM_WINDOWS +const char *find_temp_dir(void) +{ + const char* temp_base; + if ((temp_base = getenv("TMPDIR"))) return temp_base; + if ((temp_base = getenv("TMP"))) return temp_base; + if ((temp_base = getenv("TEMP"))) return temp_base; + if ((temp_base = getenv("TEMPDIR"))) return temp_base; + return "/tmp"; +} +#endif + +const char *dir_make_temp_dir(void) +{ + char buffer[PATH_MAX]; +#if PLATFORM_WINDOWS + char temp_path[PATH_MAX]; + if (!GetTempPathA(PATH_MAX, temp_path)) return NULL; + + if (!GetTempFileNameA(temp_path, "c3c", 0, buffer)) return NULL; + + // Delete the temp file + if (!DeleteFileA(buffer)) return NULL; + + // Create a directory instead + if (!CreateDirectoryA(buffer, NULL)) + { + return NULL; + } + return str_copy(buffer, strlen(buffer)); +#else + const char *temp_dir = find_temp_dir(); + const char *format = str_has_suffix(temp_dir, "/") ? "%sc3cXXXXXXX" : "%s/c3cXXXXXXX"; + int result = snprintf(buffer, PATH_MAX, format, find_temp_dir()); + if (result < 0 || result >= PATH_MAX) return NULL; + const char *out = mkdtemp(buffer); + if (out == NULL) return NULL; + return str_copy(buffer, strlen(buffer)); +#endif +} + bool dir_make_recursive(char *path) { size_t len = strlen(path); @@ -591,6 +632,7 @@ void file_copy_file(const char *src_path, const char *dst_path, bool overwrite) bool file_delete_file(const char *path) { ASSERT(path); + if (!file_exists(path)) return false; #if (_MSC_VER) return DeleteFileW(win_utf8to16(path)); #else diff --git a/src/utils/lib.h b/src/utils/lib.h index 7e1d61bdb..d9ff9ed62 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -65,6 +65,7 @@ char *win_utf16to8(const uint16_t *name); // Use as if it was mkdir(..., 0755) == 0 bool dir_make(const char *path); bool dir_make_recursive(char *path); +const char *dir_make_temp_dir(void); // Use as if it was chdir(...) == 0 bool dir_change(const char *path); const char *filename(const char *path);