From e685414829ec626acf1345113fbabe64917e292c Mon Sep 17 00:00:00 2001 From: Christian Brendlin <92454917+chrischtel@users.noreply.github.com> Date: Fri, 30 May 2025 10:19:46 +0200 Subject: [PATCH] Fix #1718: Add --header-output option to specify header file directory (#2161) * Fix #1718: Add --header-output option to specify header file directory - Add header_out field to BuildOptions struct - Add header_file_dir field to BuildTarget struct - Add --header-output command line option parsing with help text - Modify header_gen() to use configured output directory instead of hardcoded root - Add default behavior to use build directory when no custom path specified - Add directory creation for header output paths - Resolves issue where generated C headers were always output to root directory * Fix directory creation timing for header output - Move header output directory creation before header_gen() call - Ensures custom header output directories are created before files are written - Fixes issue where --header-output would fail if directory doesn't exist * Fix style * Fix Style * Add to releasenotes. --------- Co-authored-by: Christoffer Lerno --- releasenotes.md | 1 + src/build/build.h | 2 ++ src/build/build_options.c | 7 +++++++ src/build/builder.c | 5 +++++ src/compiler/compiler.c | 5 ++++- src/compiler/headers.c | 10 +++++++++- 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/releasenotes.md b/releasenotes.md index d41fb70be..c6960585d 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -24,6 +24,7 @@ - Deprecate `f32`, `f64` and `f128` suffixes. - Allow recursive generic modules. - Add deprecation for `@param foo "abc"`. +- Add `--header-output` and `header-output` options for controlling header output folder. ### Fixes - Assert triggered when casting from `int[2]` to `uint[2]` #2115 diff --git a/src/build/build.h b/src/build/build.h index c05031df6..bc5f0c7cb 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -562,6 +562,7 @@ typedef struct BuildOptions_ const char *output_dir; const char *llvm_out; const char *asm_out; + const char *header_out; const char *obj_out; const char *script_dir; RelocModel reloc_model; @@ -651,6 +652,7 @@ typedef struct const char *output_dir; const char *ir_file_dir; const char *asm_file_dir; + const char *header_file_dir; const char *script_dir; const char *run_dir; bool is_non_project; diff --git a/src/build/build_options.c b/src/build/build_options.c index 502d3be82..65c80fd37 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -113,6 +113,7 @@ static void usage(bool full) print_opt("--script-dir ", "Override the base directory for $exec."); print_opt("--llvm-out ", "Override llvm output directory for '--emit-llvm'."); print_opt("--asm-out ", "Override asm output directory for '--emit-asm'."); + print_opt("--header-output ", "Override header file output directory when building libraries."); print_opt("--emit-llvm", "Emit LLVM IR as a .ll file per module."); print_opt("--emit-asm", "Emit asm as a .s file per module."); print_opt("--obj", "Emit object files. (Enabled by default)"); @@ -1172,6 +1173,12 @@ static void parse_option(BuildOptions *options) options->asm_out = next_arg(); return; } + if (match_longopt("header-output")) + { + if (at_end() || next_is_opt()) error_exit("error: --header-output needs a directory."); + options->header_out = next_arg(); + return; + } if (match_longopt("lib")) { if (at_end() || next_is_opt()) error_exit("error: --lib needs a name."); diff --git a/src/build/builder.c b/src/build/builder.c index bff211120..d96801bd0 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -494,6 +494,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * } 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) { @@ -511,6 +512,10 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * { 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; + } switch (options->compile_option) { diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 21a0ccf0b..6b3589e30 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -438,9 +438,12 @@ void compiler_compile(void) { error_exit("No module to compile."); } - if (compiler.build.output_headers) { + if (compiler.build.header_file_dir) + { + create_output_dir(compiler.build.header_file_dir); + } header_gen(modules, module_count); } diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 88e33ee16..15fe2bea3 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -765,7 +765,15 @@ void header_gen(Module **modules, unsigned module_count) htable_init(&table1, 1024); htable_init(&table2, 1024); const char *name = build_base_name(); - const char *filename = str_printf("%s.h", name); + const char *filename; + if (compiler.build.header_file_dir) + { + filename = file_append_path(compiler.build.header_file_dir, str_printf("%s.h", name)); + } + else + { + filename = str_printf("%s.h", name); + } FILE *file = fopen(filename, "w"); HeaderContext context = { .file = file, .gen_def = &table1, .gen_decl = &table2 }; HeaderContext *c = &context;