package backend import "../linker" import "../target" import "../cimport" import "core:fmt" import "core:mem" import "core:os" import "core:os/os2" import "core:strings" append_owned :: proc(command: ^[dynamic]string, value: string, allocator: mem.Allocator) { append(command, strings.clone(value, allocator)) } build_command :: proc( llvm_path, output_path: string, link_arguments: []linker.Argument, selected := target.DEFAULT, c_options := cimport.Options{}, allocator := context.allocator, ) -> []string { command: [dynamic]string command.allocator = allocator append_owned(&command, "/usr/bin/env", allocator) append_owned(&command, "zig", allocator) append_owned(&command, "cc", allocator) append_owned(&command, "-target", allocator) append_owned(&command, target.name(selected), allocator) append_owned(&command, "-Wno-override-module", allocator) append_owned(&command, "-Wno-unused-command-line-argument", allocator) append_owned(&command, llvm_path, allocator) for path in c_options.include_paths { append(&command, fmt.aprintf("-I%s", path, allocator=allocator)) } for define in c_options.defines { append(&command, fmt.aprintf("-D%s", define, allocator=allocator)) } for argument in link_arguments { switch argument.kind { case .Input: append_owned(&command, argument.value, allocator) case .Library_Path: append(&command, fmt.aprintf("-L%s", argument.value, allocator=allocator)) case .Library: append(&command, fmt.aprintf("-l%s", argument.value, allocator=allocator)) } } append_owned(&command, "-o", allocator) append_owned(&command, output_path, allocator) return command[:] } destroy_command :: proc(command: []string, allocator := context.allocator) { for argument in command { delete(argument, allocator) } delete(command, allocator) } compile :: proc( llvm_path, output_path: string, link_arguments: []linker.Argument = nil, selected := target.DEFAULT, c_options := cimport.Options{}, ) -> bool { pid := os2.get_pid() temporary_output := fmt.tprintf("%s.brolang-tmp-%d", output_path, pid) defer _ = os.remove(temporary_output) command := build_command(llvm_path, temporary_output, link_arguments, selected, c_options) defer destroy_command(command) state, stdout, stderr, err := os2.process_exec( os2.Process_Desc{command=command}, context.allocator, ) defer delete(stdout) defer delete(stderr) if len(stdout) > 0 { fmt.print(string(stdout)) } if len(stderr) > 0 { fmt.eprint(string(stderr)) } if err != nil || state.exit_code != 0 { if err != nil { fmt.eprintln("failed to execute zig cc:", err) } return false } if rename_err := os2.rename(temporary_output, output_path); rename_err != nil { fmt.eprintln("failed to atomically replace output:", rename_err) return false } return true }