diff --git a/LANGUAGE.md b/LANGUAGE.md index 4586538..f826e0e 100644 --- a/LANGUAGE.md +++ b/LANGUAGE.md @@ -61,6 +61,7 @@ roadmap and milestone history. - supported static inline C functions through generated external wrappers - C function pointer types, imported nullable callback typedefs, concrete `c_func` callback values, and postfix calls through non-null function pointers - `brolang translate-c ` for native `.bro` bindings from supported C declarations +- `brolang --translate-c stdio.h` for offline bindings from Zig-bundled standard C headers - ordered linking of additional C sources, objects, archives, library paths, and libraries through compiler CLI options ### standard packages diff --git a/README.md b/README.md index 7fb1bad..9525a6c 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ signatures on `aarch64-macos`. Unsupported or incomplete records remain pointer-only. Header imports never add linker inputs; implementations must still be supplied explicitly with the C-prefixed linking options. Set `BROLANG_LIBCLANG_PATH` when libclang is not installed in a standard location. +For offline bindings, `brolang --translate-c stdio.h` resolves standard C +headers through the Zig libc headers used by the backend. ```bro native :: import "../include/native.h" diff --git a/TODO.md b/TODO.md index e199417..0234873 100644 --- a/TODO.md +++ b/TODO.md @@ -632,6 +632,10 @@ 27. comptime polymorphism (zig inspired) +28. comptime execution + +29. brolang build system (requires comptime execution) + ## A word on multi-unwrap Unwrap multiple optionals with `and`. This **short-circuits**: if the first optional is none, subsequent expressions are not evaluated. diff --git a/compiler_tests.odin b/compiler_tests.odin index ab519e3..ba7feec 100644 --- a/compiler_tests.odin +++ b/compiler_tests.odin @@ -641,6 +641,22 @@ cli_parses_ordered_link_options_and_rejects_invalid_forms :: proc(t: ^testing.T) testing.expect(t, !legacy_library) } +@(test) +translate_c_helpers_resolve_zig_libc_headers :: proc(t: ^testing.T) { + lib_dir, parsed := zig_lib_dir_from_env_output(".{\n .lib_dir = \"/zig/lib\",\n}\n") + defer delete(lib_dir) + + header, resolved := resolve_translate_c_header("native.h", []string{"examples/interop/header/include"}) + defer delete(header) + + testing.expect(t, is_translate_c_command("--translate-c")) + testing.expect(t, is_translate_c_command("translate-c")) + testing.expect(t, parsed) + testing.expect_value(t, lib_dir, "/zig/lib") + testing.expect(t, resolved) + testing.expect(t, strings.has_suffix(header, "examples/interop/header/include/native.h")) +} + @(test) parser_accepts_bare_and_aliased_imports :: proc(t: ^testing.T) { text := `import diff --git a/ffi/c/stdio.bro b/ffi/c/stdio.bro new file mode 100644 index 0000000..c072d5d --- /dev/null +++ b/ffi/c/stdio.bro @@ -0,0 +1,420 @@ +# generated by brolang translate-c from stdio.h + +# unsupported in bindings: C union '__mbstate_t' has no native spelling +__darwin_pthread_handler_rec :: c_struct { + __routine ?*c_func(_ ?*mut void) void + __arg ?*mut void + __next ?*mut __darwin_pthread_handler_rec +} +_opaque_pthread_attr_t :: c_struct { + __sig c_long + __opaque [56]c_char +} +_opaque_pthread_cond_t :: c_struct { + __sig c_long + __opaque [40]c_char +} +_opaque_pthread_condattr_t :: c_struct { + __sig c_long + __opaque [8]c_char +} +_opaque_pthread_mutex_t :: c_struct { + __sig c_long + __opaque [56]c_char +} +_opaque_pthread_mutexattr_t :: c_struct { + __sig c_long + __opaque [8]c_char +} +_opaque_pthread_once_t :: c_struct { + __sig c_long + __opaque [8]c_char +} +_opaque_pthread_rwlock_t :: c_struct { + __sig c_long + __opaque [192]c_char +} +_opaque_pthread_rwlockattr_t :: c_struct { + __sig c_long + __opaque [16]c_char +} +_opaque_pthread_t :: c_struct { + __sig c_long + __cleanup_stack ?*mut __darwin_pthread_handler_rec + __opaque [8176]c_char +} +__sbuf :: c_struct { + _base ?*mut c_uchar + _size c_int +} +__sFILEX :: c_struct +__sFILE :: c_struct { + _p ?*mut c_uchar + _r c_int + _w c_int + _flags c_short + _file c_short + _bf __sbuf + _lbfsize c_int + _cookie ?*mut void + _close ?*c_func(_ ?*mut void) c_int + _read ?*c_func(_ ?*mut void, _ ?*mut c_char, _ c_int) c_int + _seek ?*c_func(_ ?*mut void, _ c_longlong, _ c_int) c_longlong + _write ?*c_func(_ ?*mut void, _ ?*c_char, _ c_int) c_int + _ub __sbuf + _extra ?*mut __sFILEX + _ur c_int + _ubuf [3]c_uchar + _nbuf [1]c_uchar + _lb __sbuf + _blksize c_int + _offset c_longlong +} + +__int8_t :: alias c_schar +__uint8_t :: alias c_uchar +__int16_t :: alias c_short +__uint16_t :: alias c_ushort +__int32_t :: alias c_int +__uint32_t :: alias c_uint +__int64_t :: alias c_longlong +__uint64_t :: alias c_ulonglong +__darwin_intptr_t :: alias c_long +__darwin_natural_t :: alias c_uint +__darwin_ct_rune_t :: alias c_int +__darwin_mbstate_t :: alias __mbstate_t +__darwin_ptrdiff_t :: alias c_long +__darwin_size_t :: alias c_ulong +__darwin_va_list :: alias ?*mut c_char +__darwin_wchar_t :: alias c_int +__darwin_rune_t :: alias c_int +__darwin_wint_t :: alias c_int +__darwin_clock_t :: alias c_ulong +__darwin_socklen_t :: alias c_uint +__darwin_ssize_t :: alias c_long +__darwin_time_t :: alias c_long +__darwin_blkcnt_t :: alias c_longlong +__darwin_blksize_t :: alias c_int +__darwin_dev_t :: alias c_int +__darwin_fsblkcnt_t :: alias c_uint +__darwin_fsfilcnt_t :: alias c_uint +__darwin_gid_t :: alias c_uint +__darwin_id_t :: alias c_uint +__darwin_ino64_t :: alias c_ulonglong +__darwin_ino_t :: alias c_ulonglong +__darwin_mach_port_name_t :: alias c_uint +__darwin_mach_port_t :: alias c_uint +__darwin_mode_t :: alias c_ushort +__darwin_off_t :: alias c_longlong +__darwin_pid_t :: alias c_int +__darwin_sigset_t :: alias c_uint +__darwin_suseconds_t :: alias c_int +__darwin_uid_t :: alias c_uint +__darwin_useconds_t :: alias c_uint +__darwin_uuid_t :: alias [16]c_uchar +__darwin_uuid_string_t :: alias [37]c_char +__darwin_pthread_attr_t :: alias _opaque_pthread_attr_t +__darwin_pthread_cond_t :: alias _opaque_pthread_cond_t +__darwin_pthread_condattr_t :: alias _opaque_pthread_condattr_t +__darwin_pthread_key_t :: alias c_ulong +__darwin_pthread_mutex_t :: alias _opaque_pthread_mutex_t +__darwin_pthread_mutexattr_t :: alias _opaque_pthread_mutexattr_t +__darwin_pthread_once_t :: alias _opaque_pthread_once_t +__darwin_pthread_rwlock_t :: alias _opaque_pthread_rwlock_t +__darwin_pthread_rwlockattr_t :: alias _opaque_pthread_rwlockattr_t +__darwin_pthread_t :: alias ?*mut _opaque_pthread_t +__darwin_nl_item :: alias c_int +__darwin_wctrans_t :: alias c_int +__darwin_wctype_t :: alias c_uint +int8_t :: alias c_schar +int16_t :: alias c_short +int32_t :: alias c_int +int64_t :: alias c_longlong +u_int8_t :: alias c_uchar +u_int16_t :: alias c_ushort +u_int32_t :: alias c_uint +u_int64_t :: alias c_ulonglong +register_t :: alias c_longlong +intptr_t :: alias c_long +uintptr_t :: alias c_ulong +user_addr_t :: alias c_ulonglong +user_size_t :: alias c_ulonglong +user_ssize_t :: alias c_longlong +user_long_t :: alias c_longlong +user_ulong_t :: alias c_ulonglong +user_time_t :: alias c_longlong +user_off_t :: alias c_longlong +syscall_arg_t :: alias c_ulonglong +va_list :: alias ?*mut c_char +size_t :: alias c_ulong +fpos_t :: alias c_longlong +FILE :: alias __sFILE +off_t :: alias c_longlong +ssize_t :: alias c_long + +_DARWIN_FEATURE_64_BIT_INODE c_int :: 1 +_DARWIN_FEATURE_ONLY_64_BIT_INODE c_int :: 1 +_DARWIN_FEATURE_ONLY_VERS_1050 c_int :: 1 +_DARWIN_FEATURE_ONLY_UNIX_CONFORMANCE c_int :: 1 +_DARWIN_FEATURE_UNIX_CONFORMANCE c_int :: 3 +_FORTIFY_SOURCE c_int :: 2 +RENAME_SECLUDE c_int :: 1 +RENAME_SWAP c_int :: 2 +RENAME_EXCL c_int :: 4 +RENAME_RESERVED1 c_int :: 8 +RENAME_NOFOLLOW_ANY c_int :: 16 +RENAME_RESOLVE_BENEATH c_int :: 32 +SEEK_SET c_int :: 0 +SEEK_CUR c_int :: 1 +SEEK_END c_int :: 2 +SEEK_HOLE c_int :: 3 +SEEK_DATA c_int :: 4 +_IOFBF c_int :: 0 +_IOLBF c_int :: 1 +_IONBF c_int :: 2 +BUFSIZ c_int :: 1024 +FOPEN_MAX c_int :: 20 +FILENAME_MAX c_int :: 1024 +L_tmpnam c_int :: 1024 +TMP_MAX c_int :: 308915776 +L_ctermid c_int :: 1024 +_USE_FORTIFY_LEVEL c_int :: 2 + +renameat c_func(_ c_int, _ ?*c_char, _ c_int, _ ?*c_char) c_int +renamex_np c_func(_ ?*c_char, _ ?*c_char, _ c_uint) c_int +renameatx_np c_func(_ c_int, _ ?*c_char, _ c_int, _ ?*c_char, _ c_uint) c_int +printf c_func(_ ?*c_char, ...) c_int +clearerr c_func(_ ?*mut __sFILE) void +fclose c_func(_ ?*mut __sFILE) c_int +feof c_func(_ ?*mut __sFILE) c_int +ferror c_func(_ ?*mut __sFILE) c_int +fflush c_func(_ ?*mut __sFILE) c_int +fgetc c_func(_ ?*mut __sFILE) c_int +fgetpos c_func(_ ?*mut __sFILE, _ ?*mut c_longlong) c_int +fgets c_func(_ ?*mut c_char, __size c_int, _ ?*mut __sFILE) ?*mut c_char +fopen c_func(__filename ?*c_char, __mode ?*c_char) ?*mut __sFILE +fprintf c_func(_ ?*mut __sFILE, _ ?*c_char, ...) c_int +fputc c_func(_ c_int, _ ?*mut __sFILE) c_int +fputs c_func(_ ?*c_char, _ ?*mut __sFILE) c_int +fread c_func(__ptr ?*mut void, __size c_ulong, __nitems c_ulong, __stream ?*mut __sFILE) c_ulong +freopen c_func(_ ?*c_char, _ ?*c_char, _ ?*mut __sFILE) ?*mut __sFILE +fscanf c_func(_ ?*mut __sFILE, _ ?*c_char, ...) c_int +fseek c_func(_ ?*mut __sFILE, _ c_long, _ c_int) c_int +fsetpos c_func(_ ?*mut __sFILE, _ ?*c_longlong) c_int +ftell c_func(_ ?*mut __sFILE) c_long +fwrite c_func(__ptr ?*void, __size c_ulong, __nitems c_ulong, __stream ?*mut __sFILE) c_ulong +getc c_func(_ ?*mut __sFILE) c_int +getchar c_func() c_int +gets c_func(_ ?*mut c_char) ?*mut c_char +perror c_func(_ ?*c_char) void +putc c_func(_ c_int, _ ?*mut __sFILE) c_int +putchar c_func(_ c_int) c_int +puts c_func(_ ?*c_char) c_int +remove c_func(_ ?*c_char) c_int +rename c_func(__old ?*c_char, __new ?*c_char) c_int +rewind c_func(_ ?*mut __sFILE) void +scanf c_func(_ ?*c_char, ...) c_int +setbuf c_func(_ ?*mut __sFILE, _ ?*mut c_char) void +setvbuf c_func(_ ?*mut __sFILE, _ ?*mut c_char, _ c_int, __size c_ulong) c_int +sprintf c_func(_ ?*mut c_char, _ ?*c_char, ...) c_int +sscanf c_func(_ ?*c_char, _ ?*c_char, ...) c_int +tmpfile c_func() ?*mut __sFILE +tmpnam c_func(_ ?*mut c_char) ?*mut c_char +ungetc c_func(_ c_int, _ ?*mut __sFILE) c_int +vfprintf c_func(_ ?*mut __sFILE, _ ?*c_char, _ ?*mut c_char) c_int +vprintf c_func(_ ?*c_char, _ ?*mut c_char) c_int +vsprintf c_func(_ ?*mut c_char, _ ?*c_char, _ ?*mut c_char) c_int +ctermid c_func(_ ?*mut c_char) ?*mut c_char +fdopen c_func(_ c_int, _ ?*c_char) ?*mut __sFILE +fileno c_func(_ ?*mut __sFILE) c_int +pclose c_func(_ ?*mut __sFILE) c_int +popen c_func(_ ?*c_char, _ ?*c_char) ?*mut __sFILE +__srget c_func(_ ?*mut __sFILE) c_int +__svfscanf c_func(_ ?*mut __sFILE, _ ?*c_char, _ ?*mut c_char) c_int +__swbuf c_func(_ c_int, _ ?*mut __sFILE) c_int +__sputc c_func(_c c_int, _p ?*mut __sFILE) c_int +flockfile c_func(_ ?*mut __sFILE) void +ftrylockfile c_func(_ ?*mut __sFILE) c_int +funlockfile c_func(_ ?*mut __sFILE) void +getc_unlocked c_func(_ ?*mut __sFILE) c_int +getchar_unlocked c_func() c_int +putc_unlocked c_func(_ c_int, _ ?*mut __sFILE) c_int +putchar_unlocked c_func(_ c_int) c_int +getw c_func(_ ?*mut __sFILE) c_int +putw c_func(_ c_int, _ ?*mut __sFILE) c_int +tempnam c_func(__dir ?*c_char, __prefix ?*c_char) ?*mut c_char +fseeko c_func(__stream ?*mut __sFILE, __offset c_longlong, __whence c_int) c_int +ftello c_func(__stream ?*mut __sFILE) c_longlong +snprintf c_func(__str ?*mut c_char, __size c_ulong, __format ?*c_char, ...) c_int +vfscanf c_func(__stream ?*mut __sFILE, __format ?*c_char, _ ?*mut c_char) c_int +vscanf c_func(__format ?*c_char, _ ?*mut c_char) c_int +vsnprintf c_func(__str ?*mut c_char, __size c_ulong, __format ?*c_char, _ ?*mut c_char) c_int +vsscanf c_func(__str ?*c_char, __format ?*c_char, _ ?*mut c_char) c_int +dprintf c_func(_ c_int, _ ?*c_char, ...) c_int +vdprintf c_func(_ c_int, _ ?*c_char, _ ?*mut c_char) c_int +getdelim c_func(__linep ?*mut ?*mut c_char, __linecapp ?*mut c_ulong, __delimiter c_int, __stream ?*mut __sFILE) c_long +getline c_func(__linep ?*mut ?*mut c_char, __linecapp ?*mut c_ulong, __stream ?*mut __sFILE) c_long +fmemopen c_func(__buf ?*mut void, __size c_ulong, __mode ?*c_char) ?*mut __sFILE +open_memstream c_func(__bufp ?*mut ?*mut c_char, __sizep ?*mut c_ulong) ?*mut __sFILE +asprintf c_func(_ ?*mut ?*mut c_char, _ ?*c_char, ...) c_int +ctermid_r c_func(_ ?*mut c_char) ?*mut c_char +fgetln c_func(_ ?*mut __sFILE, __len ?*mut c_ulong) ?*mut c_char +fmtcheck c_func(_ ?*c_char, _ ?*c_char) ?*c_char +fpurge c_func(_ ?*mut __sFILE) c_int +setbuffer c_func(_ ?*mut __sFILE, _ ?*mut c_char, __size c_int) void +setlinebuf c_func(_ ?*mut __sFILE) c_int +vasprintf c_func(_ ?*mut ?*mut c_char, _ ?*c_char, _ ?*mut c_char) c_int +funopen c_func(_ ?*void, _ ?*c_func(_ ?*mut void, _ ?*mut c_char, _ c_int) c_int, _ ?*c_func(_ ?*mut void, _ ?*c_char, _ c_int) c_int, _ ?*c_func(_ ?*mut void, _ c_longlong, _ c_int) c_longlong, _ ?*c_func(_ ?*mut void) c_int) ?*mut __sFILE +__snprintf_chk c_func(_ ?*mut c_char, __maxlen c_ulong, _ c_int, _ c_ulong, _ ?*c_char, ...) c_int +__vsnprintf_chk c_func(_ ?*mut c_char, __maxlen c_ulong, _ c_int, _ c_ulong, _ ?*c_char, _ ?*mut c_char) c_int +__sprintf_chk c_func(_ ?*mut c_char, _ c_int, _ c_ulong, _ ?*c_char, ...) c_int +__vsprintf_chk c_func(_ ?*mut c_char, _ c_int, _ c_ulong, _ ?*c_char, _ ?*mut c_char) c_int + +# unsupported in bindings: external variable '__stdinp' has no native spelling +# unsupported in bindings: external variable '__stdoutp' has no native spelling +# unsupported in bindings: external variable '__stderrp' has no native spelling +# unsupported in bindings: external variable 'sys_nerr' has no native spelling +# unsupported in bindings: external variable 'sys_errlist' has no native spelling +# unsupported in bindings: _STDIO_H_ — C macro has no replacement value +# unsupported in bindings: _LIBC_BOUNDS_H_ — C macro has no replacement value +# unsupported in bindings: _CDEFS_H_ — C macro has no replacement value +# unsupported in bindings: _LIBC_COUNT — C function-like macros are not supported +# unsupported in bindings: _LIBC_COUNT_OR_NULL — C function-like macros are not supported +# unsupported in bindings: _LIBC_SIZE — C function-like macros are not supported +# unsupported in bindings: _LIBC_SIZE_OR_NULL — C function-like macros are not supported +# unsupported in bindings: _LIBC_ENDED_BY — C function-like macros are not supported +# unsupported in bindings: _LIBC_SINGLE — C macro has no replacement value +# unsupported in bindings: _LIBC_UNSAFE_INDEXABLE — C macro has no replacement value +# unsupported in bindings: _LIBC_CSTR — C macro has no replacement value +# unsupported in bindings: _LIBC_NULL_TERMINATED — C macro has no replacement value +# unsupported in bindings: _LIBC_FLEX_COUNT — C function-like macros are not supported +# unsupported in bindings: _LIBC_SINGLE_BY_DEFAULT — C function-like macros are not supported +# unsupported in bindings: _LIBC_PTRCHECK_REPLACED — C function-like macros are not supported +# unsupported in bindings: _LIBC_FORGE_PTR — C function-like macros are not supported +# unsupported in bindings: MAC_OS_X_VERSION_10_0 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_5 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_6 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_7 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_8 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_9 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_10 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_10_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_10_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_11 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_11_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_11_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_11_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_12 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_12_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_12_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_12_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_13 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_13_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_13_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_13_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_14 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_14_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_14_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_14_5 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_14_6 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_15 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_15_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_15_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_X_VERSION_10_16 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_11_0 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_11_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_11_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_11_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_11_5 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_11_6 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_12_0 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_12_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_12_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_12_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_12_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_12_5 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_12_6 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_12_7 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_13_0 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_13_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_13_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_13_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_13_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_13_5 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_13_6 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_13_7 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_14_0 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_14_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_14_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_14_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_14_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_14_5 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_14_6 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_14_7 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_15_0 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_15_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_15_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_15_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_15_4 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_15_5 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_15_6 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_16_0 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_26_0 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_26_1 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_26_2 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_26_3 — C macro is not a supported constant +# unsupported in bindings: MAC_OS_VERSION_26_4 — C macro is not a supported constant +# unsupported in bindings: _SYS__TYPES_H_ — C macro has no replacement value +# unsupported in bindings: _BSD_MACHINE__TYPES_H_ — C macro has no replacement value +# unsupported in bindings: _BSD_ARM__TYPES_H_ — C macro has no replacement value +# unsupported in bindings: _SYS__PTHREAD_TYPES_H_ — C macro has no replacement value +# unsupported in bindings: _VA_LIST_T — C macro has no replacement value +# unsupported in bindings: _BSD_MACHINE_TYPES_H_ — C macro has no replacement value +# unsupported in bindings: _ARM_MACHTYPES_H_ — C macro has no replacement value +# unsupported in bindings: _MACHTYPES_H_ — C macro has no replacement value +# unsupported in bindings: _INT8_T — C macro has no replacement value +# unsupported in bindings: _INT16_T — C macro has no replacement value +# unsupported in bindings: _INT32_T — C macro has no replacement value +# unsupported in bindings: _INT64_T — C macro has no replacement value +# unsupported in bindings: _U_INT8_T — C macro has no replacement value +# unsupported in bindings: _U_INT16_T — C macro has no replacement value +# unsupported in bindings: _U_INT32_T — C macro has no replacement value +# unsupported in bindings: _U_INT64_T — C macro has no replacement value +# unsupported in bindings: _INTPTR_T — C macro has no replacement value +# unsupported in bindings: _UINTPTR_T — C macro has no replacement value +# unsupported in bindings: USER_ADDR_NULL — C macro is not a supported constant +# unsupported in bindings: CAST_USER_ADDR_T — C function-like macros are not supported +# unsupported in bindings: _SIZE_T — C macro has no replacement value +# unsupported in bindings: NULL — C macro is not a supported constant +# unsupported in bindings: _SYS_STDIO_H_ — C macro has no replacement value +# unsupported in bindings: _FSTDIO — C macro has no replacement value +# unsupported in bindings: _SEEK_SET_H_ — C macro has no replacement value +# unsupported in bindings: EOF — C macro is not a supported constant +# unsupported in bindings: P_tmpdir — C macro is not a supported constant +# unsupported in bindings: stdin — C macro is not a supported constant +# unsupported in bindings: stdout — C macro is not a supported constant +# unsupported in bindings: stderr — C macro is not a supported constant +# unsupported in bindings: _LIBC_COUNT__L_CTERMID — C macro is not a supported constant +# unsupported in bindings: _CTERMID_H_ — C macro has no replacement value +# unsupported in bindings: getc_unlocked — C function-like macros are not supported +# unsupported in bindings: putc_unlocked — C function-like macros are not supported +# unsupported in bindings: getchar_unlocked — C function-like macros are not supported +# unsupported in bindings: putchar_unlocked — C function-like macros are not supported +# unsupported in bindings: _OFF_T — C macro has no replacement value +# unsupported in bindings: _SSIZE_T — C macro has no replacement value +# unsupported in bindings: fropen — C function-like macros are not supported +# unsupported in bindings: fwopen — C function-like macros are not supported +# unsupported in bindings: feof_unlocked — C function-like macros are not supported +# unsupported in bindings: ferror_unlocked — C function-like macros are not supported +# unsupported in bindings: clearerr_unlocked — C function-like macros are not supported +# unsupported in bindings: fileno_unlocked — C function-like macros are not supported +# unsupported in bindings: _SECURE__STDIO_H_ — C macro has no replacement value +# unsupported in bindings: _SECURE__COMMON_H_ — C macro has no replacement value +# unsupported in bindings: sprintf — C function-like macros are not supported +# unsupported in bindings: vsprintf — C function-like macros are not supported +# unsupported in bindings: snprintf — C function-like macros are not supported +# unsupported in bindings: vsnprintf — C function-like macros are not supported diff --git a/main.odin b/main.odin index 9077fc5..c17c554 100644 --- a/main.odin +++ b/main.odin @@ -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 -o [--target aarch64-macos] [--c-link | --c-library-path | --c-library | --c-include-path | --c-define ]...", ) fmt.eprintln( - " brolang translate-c [--target aarch64-macos] [--c-include-path | --c-define ]...", + " brolang translate-c|--translate-c [--target aarch64-macos] [--c-include-path | --c-define ]...", ) } +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)