add new and init to toolchain
This commit is contained in:
@@ -13,6 +13,32 @@ append_owned :: proc(command: ^[dynamic]string, value: string, allocator: mem.Al
|
||||
append(command, strings.clone(value, allocator))
|
||||
}
|
||||
|
||||
macos_sdk_root :: proc(allocator := context.allocator) -> (string, bool) {
|
||||
candidates := []string{
|
||||
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk",
|
||||
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk",
|
||||
}
|
||||
for path in candidates {
|
||||
if os.exists(path) {
|
||||
return strings.clone(path, allocator), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
append_macos_sdk_paths :: proc(command: ^[dynamic]string, selected: target.Target, allocator: mem.Allocator) {
|
||||
if selected.kind != .Aarch64_Macos {
|
||||
return
|
||||
}
|
||||
sdk, ok := macos_sdk_root(allocator)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
defer delete(sdk, allocator)
|
||||
append(command, fmt.aprintf("-F%s/System/Library/Frameworks", sdk, allocator=allocator))
|
||||
append(command, fmt.aprintf("-L%s/usr/lib", sdk, allocator=allocator))
|
||||
}
|
||||
|
||||
build_command :: proc(
|
||||
llvm_path, output_path: string,
|
||||
link_arguments: []linker.Argument,
|
||||
@@ -29,6 +55,7 @@ build_command :: proc(
|
||||
append_owned(&command, target.name(selected), allocator)
|
||||
append_owned(&command, "-Wno-override-module", allocator)
|
||||
append_owned(&command, "-Wno-unused-command-line-argument", allocator)
|
||||
append_macos_sdk_paths(&command, selected, allocator)
|
||||
append_owned(&command, llvm_path, allocator)
|
||||
for path in c_options.include_paths {
|
||||
append(&command, fmt.aprintf("-I%s", path, allocator=allocator))
|
||||
|
||||
+93
-4
@@ -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
|
||||
|
||||
@@ -616,9 +616,22 @@ add_label_shadow_diagnostic :: proc(ctx: ^Build_Ctx, span: source.Span, label: s
|
||||
if !symbol.is_valid(label) {
|
||||
return source.INVALID_DIAGNOSTIC
|
||||
}
|
||||
yield_targets := ctx.yield_targets^[:]
|
||||
if len(yield_targets) > 0 && yield_targets[len(yield_targets) - 1].label == label {
|
||||
label_is_active_loop := false
|
||||
for loop_label in ctx.loop_labels^[:] {
|
||||
if loop_label == label {
|
||||
label_is_active_loop = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !label_is_active_loop {
|
||||
yield_targets = yield_targets[:len(yield_targets) - 1]
|
||||
}
|
||||
}
|
||||
return add_shadow_diagnostic(
|
||||
ctx.checker, span, label, "label",
|
||||
ctx.pkg, ctx.file, ctx.locals^[:], ctx.loop_labels^[:], ctx.yield_targets^[:],
|
||||
ctx.pkg, ctx.file, ctx.locals^[:], ctx.loop_labels^[:], yield_targets,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ compile_package :: proc(
|
||||
link_arguments: []linker.Argument = nil,
|
||||
selected := target.DEFAULT,
|
||||
c_options := cimport.Options{},
|
||||
project_root := "",
|
||||
) -> int {
|
||||
sources := source.init_store()
|
||||
defer source.destroy_store(&sources)
|
||||
@@ -75,6 +76,7 @@ compile_package :: proc(
|
||||
vmem.arena_allocator(&parser_arena),
|
||||
c_options,
|
||||
selected,
|
||||
project_root if len(project_root) > 0 else input_path,
|
||||
)
|
||||
if !loaded {
|
||||
source.print_all(&diagnostics)
|
||||
|
||||
@@ -1416,11 +1416,13 @@ load :: proc(
|
||||
allocator := context.allocator,
|
||||
c_options := cimport.Options{},
|
||||
selected := target.DEFAULT,
|
||||
project_root_path := "",
|
||||
) -> (ast.Module, bool) {
|
||||
module := ast.init_module(allocator)
|
||||
project_root, project_root_ok := filepath.abs(".", allocator)
|
||||
project_root_source := project_root_path if len(project_root_path) > 0 else root_path
|
||||
project_root, project_root_ok := filepath.abs(project_root_source, allocator)
|
||||
if !project_root_ok {
|
||||
project_root = strings.clone(".", allocator)
|
||||
project_root = strings.clone(project_root_source, allocator)
|
||||
}
|
||||
state := State{
|
||||
module=&module,
|
||||
|
||||
Reference in New Issue
Block a user