add new and init to toolchain

This commit is contained in:
2026-07-04 17:38:45 +02:00
parent cdde49e68b
commit e7f69ffb5a
17 changed files with 711 additions and 63 deletions
+93 -4
View File
@@ -11,6 +11,8 @@ import "./target"
import "./types"
import "core:fmt"
import vmem "core:mem/virtual"
import "core:os"
import "core:os/os2"
import "core:path/filepath"
import "core:strings"
@@ -46,6 +48,21 @@ destroy_build_config :: proc(cfg: ^BuildConfig) {
// package the config names. build.bro is only checked (never lowered/emitted),
// so the config is read straight from the HIR.
run_build :: proc(root: string) -> int {
project_root := root
owns_project_root := false
if len(project_root) == 0 {
found_root, found := find_build_root()
if !found {
fmt.eprintln("brolang build: could not find build.bro in the current directory or any parent")
return 2
}
project_root = found_root
owns_project_root = true
}
defer if owns_project_root {
delete(project_root)
}
sources := source.init_store()
defer source.destroy_store(&sources)
diagnostics := source.init_store_diagnostics(&sources)
@@ -61,10 +78,10 @@ run_build :: proc(root: string) -> int {
defer vmem.arena_destroy(&arena)
a := vmem.arena_allocator(&arena)
ast_module, loaded := loader.load(root, &sources, &diagnostics, &symbols, a, a, cimport.Options{}, target.DEFAULT)
ast_module, loaded := loader.load(project_root, &sources, &diagnostics, &symbols, a, a, cimport.Options{}, target.DEFAULT, project_root)
if !loaded {
source.print_all(&diagnostics)
fmt.eprintln("failed to load build root:", root)
fmt.eprintln("failed to load build root:", project_root)
return 2
}
// check needs no `main`: it synthesizes a trap main and emits one benign
@@ -82,9 +99,81 @@ run_build :: proc(root: string) -> int {
}
defer destroy_build_config(&cfg)
program := filepath.join({root, cfg.source_dir})
program := filepath.join({project_root, cfg.source_dir})
defer delete(program)
return compile_package(program, cfg.output_name, cfg.link_arguments, target.DEFAULT, cfg.c_options)
output, output_ok := build_output_path(project_root, cfg.output_name)
if !output_ok {
return 2
}
defer delete(output)
return compile_package(program, output, cfg.link_arguments, target.DEFAULT, cfg.c_options, project_root)
}
valid_output_name :: proc(name: string) -> bool {
return len(name) > 0 && name != "." && name != ".." &&
!strings.contains(name, "/") && !strings.contains(name, "\\")
}
build_output_path :: proc(project_root, name: string, allocator := context.allocator) -> (string, bool) {
if !valid_output_name(name) {
fmt.eprintfln("build.bro: config 'name' must be a plain executable name, got '%s'", name)
return "", false
}
build_dir, dir_error := filepath.join({project_root, "build"}, allocator)
if dir_error != nil {
return "", false
}
if err := os2.make_directory_all(build_dir); err != nil {
fmt.eprintfln("failed to create build directory '%s': %v", build_dir, err)
delete(build_dir, allocator)
return "", false
}
output, output_error := filepath.join({build_dir, name}, allocator)
delete(build_dir, allocator)
if output_error != nil {
return "", false
}
return output, true
}
find_build_root :: proc(allocator := context.allocator) -> (string, bool) {
current := os.get_current_directory(allocator)
if len(current) == 0 {
return "", false
}
defer delete(current, allocator)
return find_build_root_from(current, allocator)
}
find_build_root_from :: proc(start: string, allocator := context.allocator) -> (string, bool) {
current, current_ok := filepath.abs(start, allocator)
if !current_ok {
current = strings.clone(start, allocator)
}
for {
build_path, build_error := filepath.join({current, "build.bro"}, allocator)
if build_error != nil {
delete(current, allocator)
return "", false
}
found := os.exists(build_path)
delete(build_path, allocator)
if found {
return current, true
}
if current == "/" {
delete(current, allocator)
return "", false
}
parent := filepath.dir(current, allocator)
if parent == current {
delete(parent, allocator)
delete(current, allocator)
return "", false
}
delete(current, allocator)
current = parent
}
}
// build_bro_has_errors reports whether checking build.bro produced any diagnostic