163 lines
4.2 KiB
Odin
163 lines
4.2 KiB
Odin
package main
|
|
|
|
import "./compiler"
|
|
import "./compiler/cimport"
|
|
import "./compiler/linker"
|
|
import "./compiler/target"
|
|
import "./compiler/translatec"
|
|
import "core:fmt"
|
|
import "core:os/os2"
|
|
|
|
Cli_Options :: struct {
|
|
input_path: string,
|
|
output_path: string,
|
|
link_arguments: []linker.Argument,
|
|
c_options: cimport.Options,
|
|
target: target.Target,
|
|
}
|
|
|
|
parse_cli_args :: proc(args: []string, allocator := context.allocator) -> (Cli_Options, bool) {
|
|
if len(args) < 4 {
|
|
return {}, false
|
|
}
|
|
options := Cli_Options{input_path=args[1], target=target.DEFAULT}
|
|
link_arguments: [dynamic]linker.Argument
|
|
link_arguments.allocator = allocator
|
|
include_paths: [dynamic]string
|
|
include_paths.allocator = allocator
|
|
defines: [dynamic]string
|
|
defines.allocator = allocator
|
|
success := false
|
|
defer {
|
|
if !success {
|
|
delete(link_arguments)
|
|
delete(include_paths)
|
|
delete(defines)
|
|
}
|
|
}
|
|
output_set := false
|
|
cursor := 2
|
|
for cursor < len(args) {
|
|
option := args[cursor]
|
|
cursor += 1
|
|
if cursor >= len(args) {
|
|
return {}, false
|
|
}
|
|
value := args[cursor]
|
|
cursor += 1
|
|
switch option {
|
|
case "-o":
|
|
if output_set {
|
|
return {}, false
|
|
}
|
|
output_set = true
|
|
options.output_path = value
|
|
case "--c-link":
|
|
append(&link_arguments, linker.Argument{kind=.Input, value=value})
|
|
case "--c-library-path":
|
|
append(&link_arguments, linker.Argument{kind=.Library_Path, value=value})
|
|
case "--c-library":
|
|
append(&link_arguments, linker.Argument{kind=.Library, value=value})
|
|
case "--c-include-path":
|
|
append(&include_paths, value)
|
|
case "--c-define":
|
|
append(&defines, value)
|
|
case "--target":
|
|
selected, ok := target.parse(value)
|
|
if !ok {
|
|
return {}, false
|
|
}
|
|
options.target = selected
|
|
case:
|
|
return {}, false
|
|
}
|
|
}
|
|
if !output_set || len(options.output_path) == 0 {
|
|
return {}, false
|
|
}
|
|
options.link_arguments = link_arguments[:]
|
|
options.c_options.include_paths = include_paths[:]
|
|
options.c_options.defines = defines[:]
|
|
success = true
|
|
return options, true
|
|
}
|
|
|
|
print_usage :: proc() {
|
|
fmt.eprintln(
|
|
"usage: brolang <package-directory> -o <executable> [--target aarch64-macos] [--c-link <path> | --c-library-path <dir> | --c-library <name> | --c-include-path <dir> | --c-define <name[=value]>]...",
|
|
)
|
|
fmt.eprintln(
|
|
" brolang translate-c <header.h> [--target aarch64-macos] [--c-include-path <dir> | --c-define <name[=value]>]...",
|
|
)
|
|
}
|
|
|
|
// run_translate_c emits native brolang bindings for a C header to stdout, the
|
|
// offline counterpart of `native :: import "x.h"`.
|
|
run_translate_c :: proc(args: []string) -> int {
|
|
if len(args) < 3 {
|
|
print_usage()
|
|
return 2
|
|
}
|
|
header := args[2]
|
|
selected := target.DEFAULT
|
|
include_paths: [dynamic]string
|
|
defines: [dynamic]string
|
|
defer delete(include_paths)
|
|
defer delete(defines)
|
|
cursor := 3
|
|
for cursor < len(args) {
|
|
option := args[cursor]
|
|
cursor += 1
|
|
if cursor >= len(args) {
|
|
fmt.eprintfln("missing value for %s", option)
|
|
return 2
|
|
}
|
|
value := args[cursor]
|
|
cursor += 1
|
|
switch option {
|
|
case "--c-include-path":
|
|
append(&include_paths, value)
|
|
case "--c-define":
|
|
append(&defines, value)
|
|
case "--target":
|
|
parsed, ok := target.parse(value)
|
|
if !ok {
|
|
fmt.eprintfln("unknown target '%s'", value)
|
|
return 2
|
|
}
|
|
selected = parsed
|
|
case:
|
|
fmt.eprintfln("unknown option '%s'", option)
|
|
return 2
|
|
}
|
|
}
|
|
c_options := cimport.Options{include_paths=include_paths[:], defines=defines[:]}
|
|
result := cimport.import_header(c_options, header, selected)
|
|
defer cimport.destroy_result(&result)
|
|
if !result.available {
|
|
message := result.error_message if len(result.error_message) > 0 else "failed to import header"
|
|
fmt.eprintln(message)
|
|
return 1
|
|
}
|
|
fmt.print(translatec.emit(&result, header))
|
|
return 0
|
|
}
|
|
|
|
main :: proc() {
|
|
if len(os2.args) >= 2 && os2.args[1] == "translate-c" {
|
|
os2.exit(run_translate_c(os2.args))
|
|
}
|
|
options, valid := parse_cli_args(os2.args)
|
|
if !valid {
|
|
print_usage()
|
|
os2.exit(2)
|
|
}
|
|
defer delete(options.link_arguments)
|
|
defer delete(options.c_options.include_paths)
|
|
defer delete(options.c_options.defines)
|
|
status := compiler.compile_package(options.input_path, options.output_path, options.link_arguments, options.target, options.c_options)
|
|
if status != 0 {
|
|
os2.exit(status)
|
|
}
|
|
}
|