extern variables and object-like macro consts
This commit is contained in:
+61
-1
@@ -15,6 +15,18 @@ import "core:fmt"
|
||||
import vmem "core:mem/virtual"
|
||||
import "core:os"
|
||||
import "core:os/os2"
|
||||
import "core:strings"
|
||||
|
||||
// write_escaped_c_string writes value into builder with `\` and `"` escaped so
|
||||
// it is safe to embed inside a C string literal (e.g. an `#include "..."`).
|
||||
write_escaped_c_string :: proc(builder: ^strings.Builder, value: string) {
|
||||
for b in transmute([]byte)value {
|
||||
if b == '\\' || b == '"' {
|
||||
strings.write_byte(builder, '\\')
|
||||
}
|
||||
strings.write_byte(builder, b)
|
||||
}
|
||||
}
|
||||
|
||||
compile_package :: proc(
|
||||
input_path, output_path: string,
|
||||
@@ -69,6 +81,54 @@ compile_package :: proc(
|
||||
fmt.eprintln("failed to load root package directory:", input_path)
|
||||
return 2
|
||||
}
|
||||
|
||||
// Generated C trampolines (for `static inline` imports) must be compiled and
|
||||
// linked with the program. Write them out and add the source as a link input
|
||||
// before the loader's arena (which owns the trampoline strings) is freed.
|
||||
trampoline_path := ""
|
||||
effective_link_arguments := link_arguments
|
||||
owns_arguments := false
|
||||
// Register the path defer first so it runs last (LIFO): the augmented
|
||||
// argument slice, whose Input value aliases trampoline_path, is freed before
|
||||
// the path string it points at.
|
||||
defer if len(trampoline_path) > 0 {
|
||||
_ = os.remove(trampoline_path)
|
||||
delete(trampoline_path)
|
||||
}
|
||||
defer if owns_arguments {
|
||||
delete(effective_link_arguments)
|
||||
}
|
||||
if len(ast_module.c_trampolines) > 0 {
|
||||
builder := strings.builder_make()
|
||||
defer strings.builder_destroy(&builder)
|
||||
seen_headers: map[string]bool
|
||||
defer delete(seen_headers)
|
||||
for trampoline in ast_module.c_trampolines {
|
||||
if seen_headers[trampoline.header] {
|
||||
continue
|
||||
}
|
||||
seen_headers[trampoline.header] = true
|
||||
strings.write_string(&builder, "#include \"")
|
||||
write_escaped_c_string(&builder, trampoline.header)
|
||||
strings.write_string(&builder, "\"\n")
|
||||
}
|
||||
for trampoline in ast_module.c_trampolines {
|
||||
strings.write_string(&builder, trampoline.source)
|
||||
}
|
||||
// Owned (stable allocator); freed in the path defer above after backend
|
||||
// compilation, which is the only consumer, has run.
|
||||
trampoline_path = fmt.aprintf("%s.brolang-trampolines-%d.c", output_path, os2.get_pid())
|
||||
if err := os.write_entire_file_or_err(trampoline_path, transmute([]byte)strings.to_string(builder)); err != nil {
|
||||
fmt.eprintln("failed to write C trampoline source:", err)
|
||||
return 2
|
||||
}
|
||||
augmented := make([]linker.Argument, len(link_arguments)+1)
|
||||
copy(augmented, link_arguments)
|
||||
augmented[len(link_arguments)] = linker.Argument{kind=.Input, value=trampoline_path}
|
||||
effective_link_arguments = augmented
|
||||
owns_arguments = true
|
||||
}
|
||||
|
||||
vmem.arena_free_all(&lexer_arena)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols, selected, vmem.arena_allocator(&checker_arena))
|
||||
vmem.arena_free_all(&parser_arena)
|
||||
@@ -87,7 +147,7 @@ compile_package :: proc(
|
||||
}
|
||||
|
||||
source.print_all(&diagnostics)
|
||||
if !backend.compile(llvm_path, output_path, link_arguments, selected, c_options) {
|
||||
if !backend.compile(llvm_path, output_path, effective_link_arguments, selected, c_options) {
|
||||
return 2
|
||||
}
|
||||
if len(diagnostics.items) > 0 {
|
||||
|
||||
Reference in New Issue
Block a user