translate-c libc headers
This commit is contained in:
@@ -6,7 +6,10 @@ import "./compiler/linker"
|
||||
import "./compiler/target"
|
||||
import "./compiler/translatec"
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:os/os2"
|
||||
import "core:path/filepath"
|
||||
import "core:strings"
|
||||
|
||||
Cli_Options :: struct {
|
||||
input_path: string,
|
||||
@@ -87,10 +90,86 @@ print_usage :: proc() {
|
||||
"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]>]...",
|
||||
" brolang translate-c|--translate-c <header.h> [--target aarch64-macos] [--c-include-path <dir> | --c-define <name[=value]>]...",
|
||||
)
|
||||
}
|
||||
|
||||
is_translate_c_command :: proc(arg: string) -> bool {
|
||||
return arg == "translate-c" || arg == "--translate-c"
|
||||
}
|
||||
|
||||
zig_lib_dir_from_env_output :: proc(text: string, allocator := context.allocator) -> (string, bool) {
|
||||
rest := text
|
||||
prefix := ".lib_dir = \""
|
||||
for line in strings.split_lines_iterator(&rest) {
|
||||
trimmed := strings.trim_space(line)
|
||||
if !strings.has_prefix(trimmed, prefix) {
|
||||
continue
|
||||
}
|
||||
value := trimmed[len(prefix):]
|
||||
end := strings.index_byte(value, '"')
|
||||
if end < 0 {
|
||||
return "", false
|
||||
}
|
||||
return strings.clone(value[:end], allocator), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
zig_lib_dir :: proc(allocator := context.allocator) -> (string, bool) {
|
||||
state, stdout, stderr, err := os2.process_exec(
|
||||
os2.Process_Desc{command=[]string{"/usr/bin/env", "zig", "env"}},
|
||||
context.allocator,
|
||||
)
|
||||
defer delete(stdout)
|
||||
defer delete(stderr)
|
||||
if err != nil || state.exit_code != 0 {
|
||||
return "", false
|
||||
}
|
||||
return zig_lib_dir_from_env_output(string(stdout), allocator)
|
||||
}
|
||||
|
||||
append_owned_include_path :: proc(paths, owned: ^[dynamic]string, parts: []string) {
|
||||
path, err := filepath.join(parts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
append(paths, path)
|
||||
append(owned, path)
|
||||
}
|
||||
|
||||
append_zig_libc_include_paths :: proc(paths, owned: ^[dynamic]string, selected: target.Target) -> bool {
|
||||
lib_dir, ok := zig_lib_dir()
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
defer delete(lib_dir)
|
||||
|
||||
append_owned_include_path(paths, owned, {lib_dir, "include"})
|
||||
switch selected.kind {
|
||||
case .Aarch64_Macos:
|
||||
append_owned_include_path(paths, owned, {lib_dir, "libc", "include", "any-darwin-any"})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
resolve_translate_c_header :: proc(header: string, include_paths: []string, allocator := context.allocator) -> (string, bool) {
|
||||
if os.exists(header) || filepath.is_abs(header) {
|
||||
return strings.clone(header, allocator), os.exists(header)
|
||||
}
|
||||
for path in include_paths {
|
||||
candidate, err := filepath.join({path, header}, allocator)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if os.exists(candidate) {
|
||||
return candidate, true
|
||||
}
|
||||
delete(candidate, allocator)
|
||||
}
|
||||
return strings.clone(header, allocator), false
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -101,8 +180,15 @@ run_translate_c :: proc(args: []string) -> int {
|
||||
header := args[2]
|
||||
selected := target.DEFAULT
|
||||
include_paths: [dynamic]string
|
||||
owned_include_paths: [dynamic]string
|
||||
defines: [dynamic]string
|
||||
defer delete(include_paths)
|
||||
defer {
|
||||
for path in owned_include_paths {
|
||||
delete(path)
|
||||
}
|
||||
delete(owned_include_paths)
|
||||
}
|
||||
defer delete(defines)
|
||||
cursor := 3
|
||||
for cursor < len(args) {
|
||||
@@ -131,8 +217,11 @@ run_translate_c :: proc(args: []string) -> int {
|
||||
return 2
|
||||
}
|
||||
}
|
||||
_ = append_zig_libc_include_paths(&include_paths, &owned_include_paths, selected)
|
||||
import_header, _ := resolve_translate_c_header(header, include_paths[:])
|
||||
defer delete(import_header)
|
||||
c_options := cimport.Options{include_paths=include_paths[:], defines=defines[:]}
|
||||
result := cimport.import_header(c_options, header, selected)
|
||||
result := cimport.import_header(c_options, import_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"
|
||||
@@ -144,7 +233,7 @@ run_translate_c :: proc(args: []string) -> int {
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
if len(os2.args) >= 2 && os2.args[1] == "translate-c" {
|
||||
if len(os2.args) >= 2 && is_translate_c_command(os2.args[1]) {
|
||||
os2.exit(run_translate_c(os2.args))
|
||||
}
|
||||
options, valid := parse_cli_args(os2.args)
|
||||
|
||||
Reference in New Issue
Block a user