From e1a125e3263c69b57851dd47878bd802acc2fc0c Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 29 Jun 2025 23:50:17 +0200 Subject: [PATCH] - Initial support for #1925, does not affect C compilation yet, and doesn't try to link etc. Using "--emit-only" --- releasenotes.md | 1 + src/build/build.h | 2 ++ src/build/build_options.c | 7 +++++++ src/build/builder.c | 3 +++ src/compiler/codegen_general.c | 3 ++- src/compiler/compiler.c | 12 ++++++++++++ src/compiler/compiler_internal.h | 3 ++- src/compiler/llvm_codegen.c | 1 + src/compiler/llvm_codegen_internal.h | 1 + src/compiler/llvm_codegen_module.c | 2 +- 10 files changed, 32 insertions(+), 3 deletions(-) diff --git a/releasenotes.md b/releasenotes.md index 2a1bba949..13b5d212c 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -30,6 +30,7 @@ - Compile-time comparison of constant vectors. #1575. - $member.get supports bitstructs. - $member.set for setting members without the *& trick. +- Initial support for #1925, does not affect C compilation yet, and doesn't try to link etc. Using "--emit-only" ### Fixes - `-2147483648`, MIN literals work correctly. diff --git a/src/build/build.h b/src/build/build.h index 899004ab6..154c28060 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -565,6 +565,7 @@ typedef struct BuildOptions_ const char *header_out; const char *obj_out; const char *script_dir; + const char **emit_only; RelocModel reloc_model; X86VectorCapability x86_vector_capability; X86CpuSet x86_cpu_set; @@ -656,6 +657,7 @@ typedef struct const char *header_file_dir; const char *script_dir; const char *run_dir; + const char **emit_only; bool is_non_project; bool run_after_compile; bool delete_after_run; diff --git a/src/build/build_options.c b/src/build/build_options.c index bed916798..e3b0e590d 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -158,6 +158,7 @@ static void usage(bool full) print_opt("--use-stdlib=", "Include the standard library (default: yes)."); print_opt("--link-libc=", "Link libc other default libraries (default: yes)."); print_opt("--emit-stdlib=", "Output files for the standard library. (default: yes)"); + print_opt("--emit-only ", "Output only the file matching ."); print_opt("--panicfn ", "Override the panic function name."); print_opt("--testfn ", "Override the test runner function name."); print_opt("--benchfn ", "Override the benchmark runner function name."); @@ -879,6 +880,12 @@ static void parse_option(BuildOptions *options) options->emit_stdlib = parse_opt_select(EmitStdlib, argopt, on_off); return; } + if (match_longopt("emit-only")) + { + if (at_end() || next_is_opt()) error_exit("error: --emit-only expects an output name, e.g. 'foo', to only output 'foo.o'."); + vec_add(options->emit_only, next_arg()); + return; + } if ((argopt = match_argopt("use-stdlib"))) { options->use_stdlib = parse_opt_select(UseStdlib, argopt, on_off); diff --git a/src/build/builder.c b/src/build/builder.c index 06d70fc5f..798f01f2a 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -477,7 +477,9 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * error_exit("Unable to detect the default target, please set an explicit --target value."); } + 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; if (command_accepts_files(options->command)) { target->build_dir = options->build_dir ? options->build_dir : ".build"; @@ -498,6 +500,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * } 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; diff --git a/src/compiler/codegen_general.c b/src/compiler/codegen_general.c index bd3a626a8..f650841b9 100644 --- a/src/compiler/codegen_general.c +++ b/src/compiler/codegen_general.c @@ -295,9 +295,10 @@ bool codegen_single_obj_output() return compiler.build.single_module == SINGLE_MODULE_ON; } -void codegen_setup_object_names(Module *module, const char **ir_filename, const char **asm_filename, const char **object_filename) +void codegen_setup_object_names(Module *module, const char **base_name, const char **ir_filename, const char **asm_filename, const char **object_filename) { const char *result = module_create_object_file_name(module); + *base_name = scratch_buffer_copy(); assert(compiler.build.object_file_dir); if (codegen_single_obj_output()) { diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 675f32bb6..b3297aa43 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -405,6 +405,16 @@ void compiler_parse(void) compiler_parsing_time = bench_mark(); } +bool compiler_should_ouput_file(const char *file) +{ + if (!vec_size(compiler.build.emit_only)) return true; + FOREACH(const char *, f, compiler.build.emit_only) + { + if (str_eq(file, f)) return true; + } + return false; +} + static void create_output_dir(const char *dir) { if (!dir) return; @@ -669,6 +679,7 @@ void compiler_compile(void) } error_exit("Compilation produced no object files, maybe there was no code?"); } + if (vec_size(compiler.build.emit_only)) goto SKIP; if (output_exe) { if (compiler.build.output_dir) @@ -805,6 +816,7 @@ void compiler_compile(void) } else { + SKIP: compiler_print_bench(); } free(obj_files); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 7be1944bd..bca8bb1ce 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2418,6 +2418,7 @@ File *source_file_text_load(const char *filename, char *content); File *compile_and_invoke(const char *file, const char *args, const char *stdin_data, size_t limit); void compiler_parse(void); +bool compiler_should_ouput_file(const char *file); void emit_json(void); void stable_init(STable *table, uint32_t initial_size); @@ -2445,7 +2446,7 @@ const char *symtab_preset(const char *data, TokenType type); const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type); const char *symtab_find(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type); void *llvm_target_machine_create(void); -void codegen_setup_object_names(Module *module, const char **ir_filename, const char **asm_filename, const char **object_filename); +void codegen_setup_object_names(Module *module, const char **base_name, const char **ir_filename, const char **asm_filename, const char **object_filename); void target_setup(BuildTarget *build_target); int target_alloca_addr_space(); bool os_is_apple(OsType os_type); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index a03ae56f6..9a0c2f52a 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -1068,6 +1068,7 @@ static inline void llvm_optimize(GenContext *c) const char *llvm_codegen(void *context) { GenContext *c = context; + if (!compiler_should_ouput_file(c->base_name)) return NULL; llvm_optimize(c); // Serialize the LLVM IR, if requested, also verify the IR in this case diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 57e2e3993..f02711bf6 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -96,6 +96,7 @@ typedef struct GenContext_ const char *ir_filename; const char *object_filename; const char *asm_filename; + const char *base_name; LLVMTypeRef bool_type; LLVMTypeRef byte_type; LLVMTypeRef introspect_type; diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index ec266db8e..cab62fc51 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -59,7 +59,7 @@ void gencontext_begin_module(GenContext *c) { ASSERT(!c->module && "Expected no module"); - codegen_setup_object_names(c->code_module, &c->ir_filename, &c->asm_filename, &c->object_filename); + codegen_setup_object_names(c->code_module, &c->base_name, &c->ir_filename, &c->asm_filename, &c->object_filename); DEBUG_LOG("Emit module %s.", c->code_module->name->module); c->panic_var = compiler.context.panic_var; c->panicf = compiler.context.panicf;