From 5c82747970c145e6a09f5141560f458a0f4fb9f5 Mon Sep 17 00:00:00 2001 From: LowByteFox Date: Tue, 22 Jul 2025 15:15:20 +0200 Subject: [PATCH] Improved OpenBSD support (#2317) * add openbsd support, compiles and passses all tests * fix backtrace * gh actions should include openbsd artifacts --- .github/workflows/main.yml | 119 ++++++++++++++++++++++++++++ README.md | 15 +++- lib/std/core/env.c3 | 4 +- lib/std/libc/os/errno.c3 | 5 ++ lib/std/libc/os/openbsd.c3 | 60 ++++++++++++++ lib/std/os/backtrace.c3 | 9 ++- lib/std/os/openbsd/general.c3 | 72 +++++++++++++++++ lib/std/os/posix/process.c3 | 4 +- src/compiler/linker.c | 5 ++ src/main.c | 10 +++ test/src/test_suite_runner.c3 | 4 + test/unit/stdlib/libc/os/openbsd.c3 | 0 12 files changed, 298 insertions(+), 9 deletions(-) create mode 100644 lib/std/libc/os/openbsd.c3 create mode 100644 test/unit/stdlib/libc/os/openbsd.c3 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8301d6b17..4d7bd3864 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,8 +10,10 @@ env: LLVM_RELEASE_VERSION_WINDOWS: 18 LLVM_RELEASE_VERSION_MAC: 17 LLVM_RELEASE_VERSION_LINUX: 17 + LLVM_RELEASE_VERSION_OPENBSD: 19 LLVM_RELEASE_VERSION_UBUNTU22: 17 LLVM_DEV_VERSION: 21 + OPENBSD_RELEASE: "7.7" jobs: build-msvc: @@ -751,6 +753,119 @@ jobs: nix build -L ".#c3c-checks" fi + build-openbsd: + runs-on: ubuntu-latest + strategy: + # Don't abort runners if a single one fails + fail-fast: false + matrix: + build_type: [Release, Debug] + + steps: + - uses: actions/checkout@v4 + - name: OpenBSD VM + uses: vmactions/openbsd-vm@main + with: + prepare: | + pkg_add cmake llvm-19.1.7p3 ninja + + run: | + echo "CMake" + cmake -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ + -DLLVM_ENABLE_LIBXML2=OFF \ + -DC3_LLVM_VERSION=${LLVM_RELEASE_VERSION_OPENBSD} + cmake --build build + echo "Compile and run some examples" + cd resources + ../build/c3c compile examples/base64.c3 + ../build/c3c compile examples/binarydigits.c3 + ../build/c3c compile examples/brainfk.c3 + ../build/c3c compile examples/factorial_macro.c3 + ../build/c3c compile examples/fasta.c3 + ../build/c3c compile examples/gameoflife.c3 + ../build/c3c compile examples/hash.c3 + ../build/c3c compile-only examples/levenshtein.c3 + ../build/c3c compile examples/load_world.c3 + ../build/c3c compile-only examples/map.c3 + ../build/c3c compile examples/mandelbrot.c3 + ../build/c3c compile examples/plus_minus.c3 + ../build/c3c compile examples/nbodies.c3 + ../build/c3c compile examples/spectralnorm.c3 + ../build/c3c compile examples/swap.c3 + ../build/c3c compile examples/contextfree/boolerr.c3 + ../build/c3c compile examples/contextfree/dynscope.c3 + ../build/c3c compile examples/contextfree/guess_number.c3 + ../build/c3c compile examples/contextfree/multi.c3 + ../build/c3c compile examples/contextfree/cleanup.c3 + ../build/c3c compile-run examples/hello_world_many.c3 + ../build/c3c compile-run examples/time.c3 + ../build/c3c compile-run examples/fannkuch-redux.c3 + ../build/c3c compile-run examples/contextfree/boolerr.c3 + ../build/c3c compile-run examples/load_world.c3 + ../build/c3c compile-run examples/process.c3 + ../build/c3c compile-run examples/ls.c3 + ../build/c3c compile-run examples/args.c3 -- foo -bar "baz baz" + cd .. + echo "Compile and run dynlib-test" + cd resources/examples/dynlib-test + ../../../build/c3c -vv dynamic-lib add.c3 + mv add.so libadd.so + cc test.c -L. -ladd -Wl,-rpath=. + ./a.out + ../../../build/c3c compile-run test.c3 -L . -l add -z -Wl,-rpath=. + cd ../../../ + echo "Compile and run staticlib-test" + cd resources/examples/staticlib-test + ../../../build/c3c -vv static-lib add.c3 + mv add.a libadd.a + cc test.c -L. -ladd + ./a.out + ../../../build/c3c compile-run test.c3 -L . -l add + cd ../../../ + echo "Compile run unit tests" + cd test + ../build/c3c --max-mem 128 compile-test unit -D SLOW_TESTS + cd .. + echo "Build testproject" + cd resources/testproject + ../../build/c3c run -vvv --trust=full + cd ../../ + echo "Test WASM" + cd resources/testfragments + ../../build/c3c compile --target wasm32 -g0 --no-entry -Os wasm4.c3 + cd ../../ + echo "Build testproject direct linker" + cd resources/testproject + ../../build/c3c run -vvv --linker=builtin --trust=full + cd ../../ + echo "Init a library & a project" + ./build/c3c init-lib mylib + ls mylib.c3l + ./build/c3c init myproject + ls myproject + echo "run compiler tests" + cd test + ../build/c3c --max-mem 128 compile-run -O1 src/test_suite_runner.c3 -- ../build/c3c test_suite/ + cd .. + + - name: bundle_output + run: | + mkdir c3 + cp -r lib c3 + cp msvc_build_libraries.py c3 + cp build/c3c c3 + cp README.md c3 + cp releasenotes.md c3 + tar czf c3-openbsd-$OPENBSD_RELEASE-${{matrix.build_type}}.tar.gz c3 + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: c3-openbsd-$OPENBSD_RELEASE-${{matrix.build_type}} + path: c3-openbsd-$OPENBSD_RELEASE-${{matrix.build_type}}.tar.gz + release: runs-on: ubuntu-22.04 needs: [build-msvc, build-linux, build-mac, build-linux-ubuntu22] @@ -773,6 +888,8 @@ jobs: - run: zip -r c3-windows-debug.zip c3-windows-Debug - run: mv c3-linux-Release/c3-linux-Release.tar.gz c3-linux-Release/c3-linux.tar.gz - run: mv c3-linux-Debug/c3-linux-Debug.tar.gz c3-linux-Debug/c3-linux-debug.tar.gz + - run: mv c3-openbsd-$OPENBSD_RELEASE-Release/c3-openbsd-$OPENBSD_RELEASE-Release.tar.gz c3-openbsd-$OPENBSD_RELEASE-Release/c3-openbsd-$OPENBSD_RELEASE.tar.gz + - run: mv c3-openbsd-$OPENBSD_RELEASE-Debug/c3-openbsd-$OPENBSD_RELEASE-Debug.tar.gz c3-openbsd-$OPENBSD_RELEASE-Debug/c3-openbsd-$OPENBSD_RELEASE-debug.tar.gz - run: mv c3-ubuntu-22-Release/c3-ubuntu-22-Release.tar.gz c3-ubuntu-22-Release/c3-ubuntu-22.tar.gz - run: mv c3-ubuntu-22-Debug/c3-ubuntu-22-Debug.tar.gz c3-ubuntu-22-Debug/c3-ubuntu-22-debug.tar.gz - run: mv c3-macos-Release/c3-macos-Release.zip c3-macos-Release/c3-macos.zip @@ -794,6 +911,8 @@ jobs: c3-windows-debug.zip c3-linux-Release/c3-linux.tar.gz c3-linux-Debug/c3-linux-debug.tar.gz + c3-openbsd-$OPENBSD_RELEASE-Release/c3-openbsd-$OPENBSD_RELEASE.tar.gz + g3-openbsd-$OPENBSD_RELEASE-Debug/c3-openbsd-$OPENBSD_RELEASE-debug.tar.gz c3-ubuntu-22-Release/c3-ubuntu-22.tar.gz c3-ubuntu-22-Debug/c3-ubuntu-22-debug.tar.gz c3-macos-Release/c3-macos.zip diff --git a/README.md b/README.md index 5fa1fdcdd..dc743ce99 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Precompiled binaries for the following operating systems are available: - Debian x64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-linux.tar.gz), [install instructions](#installing-on-debian-with-precompiled-binaries). - Ubuntu x86 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-ubuntu-20.tar.gz), [install instructions](#installing-on-ubuntu-with-precompiled-binaries). - MacOS Arm64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-macos.zip), [install instructions](#installing-on-macos-with-precompiled-binaries). +- OpenBSD 7.7 x64 [download](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-openbsd-7.7.tar.gz), [install instructions](#installing-on-openbsd-with-precompiled-binaries). The manual for C3 can be found at [www.c3-lang.org](http://www.c3-lang.org). @@ -176,12 +177,14 @@ The compiler is currently verified to compile on Linux, Windows and MacOS. | NetBSD x86 | Untested | Untested | No | Yes | Untested | Yes* | | NetBSD x64 | Untested | Untested | No | Yes | Untested | Yes* | | OpenBSD x86 | Untested | Untested | No | Yes | Untested | Yes* | -| OpenBSD x64 | Untested | Untested | No | Yes | Untested | Yes* | +| OpenBSD x64 | Yes* | Yes | Yes* | Yes | Untested | Yes* | | MCU x86 | No | Untested | No | No | No | Yes* | | Wasm32 | No | Yes | No | No | No | No | | Wasm64 | No | Untested | No | No | No | No | -*\* Inline asm is still a work in progress* +*\* Inline asm is still a work in progress*
+*\* OpenBSD 7.7 is the only tested version*
+*\* OpenBSD has limited stacktrace, needs to be tested further* More platforms will be supported in the future. @@ -227,6 +230,14 @@ This installs the latest prerelease build, as opposed to the latest released ver (*Note that there is a known issue with debug symbol generation on MacOS 13, see [issue #1086](https://github.com/c3lang/c3c/issues/1086)) +#### Installing on OpenBSD with precompiled binaries +1. Download tar file: [https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-openbsd-7.7.tar.gz](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-openbsd-7.7.tar.gz) + (debug version [here](https://github.com/c3lang/c3c/releases/download/latest-prerelease/c3-openbsd-7.7-debug.tar.gz)) +2. Unpack executable and standard lib. +3. Run `./c3c`. + +(*Note that this is specifically for OpenBSD 7.7, running it on any other version is prone to ABI breaks) + #### Installing on Arch Linux Arch includes c3c in the official 'extra' repo. It can be easily installed the usual way: diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3 index 22e56f8e8..deea29b5c 100644 --- a/lib/std/core/env.c3 +++ b/lib/std/core/env.c3 @@ -143,7 +143,7 @@ const bool TRACK_MEMORY = DEBUG_SYMBOLS && (COMPILER_SAFE_MODE || TESTING); const bool X86_64 = ARCH_TYPE == X86_64; const bool X86 = ARCH_TYPE == X86; const bool AARCH64 = ARCH_TYPE == AARCH64; -const bool NATIVE_STACKTRACE = LINUX || DARWIN || WIN32; +const bool NATIVE_STACKTRACE = LINUX || DARWIN || OPENBSD || WIN32; const bool LINUX = LIBC && OS_TYPE == LINUX; const bool DARWIN = LIBC && os_is_darwin(); const bool WIN32 = LIBC && OS_TYPE == WIN32; @@ -160,7 +160,7 @@ const bool MEMORY_SANITIZER = $$MEMORY_SANITIZER; const bool THREAD_SANITIZER = $$THREAD_SANITIZER; const bool ANY_SANITIZER = ADDRESS_SANITIZER || MEMORY_SANITIZER || THREAD_SANITIZER; const int LANGUAGE_DEV_VERSION = $$LANGUAGE_DEV_VERSION; -const bool HAS_NATIVE_ERRNO = env::LINUX || env::ANDROID || env::DARWIN || env::WIN32; +const bool HAS_NATIVE_ERRNO = env::LINUX || env::ANDROID || env::OPENBSD || env::DARWIN || env::WIN32; macro bool os_is_darwin() @const { diff --git a/lib/std/libc/os/errno.c3 b/lib/std/libc/os/errno.c3 index 01c68438c..025b6835b 100644 --- a/lib/std/libc/os/errno.c3 +++ b/lib/std/libc/os/errno.c3 @@ -11,6 +11,11 @@ extern fn int* __errno() @if(env::ANDROID); macro int errno() @if(env::ANDROID) => *__errno(); macro void errno_set(int err) @if(env::ANDROID) => *(__errno()) = err; +// OpenBSD +extern fn int* __errno() @if(env::OPENBSD); +macro int errno() @if(env::OPENBSD) => *__errno(); +macro void errno_set(int err) @if(env::OPENBSD) => *(__errno()) = err; + // Darwin extern fn int* __error() @if(env::DARWIN); macro int errno() @if(env::DARWIN) => *__error(); diff --git a/lib/std/libc/os/openbsd.c3 b/lib/std/libc/os/openbsd.c3 new file mode 100644 index 000000000..ebc715e5b --- /dev/null +++ b/lib/std/libc/os/openbsd.c3 @@ -0,0 +1,60 @@ +module libc @if(env::OPENBSD); + +// Checked for x86_64 + +alias Blksize_t = int; +alias Nlink_t = $typefrom(env::X86_64 ? uint.typeid : CUInt.typeid); +alias Dev_t = int; +alias Ino_t = ulong; +alias Mode_t = uint; +alias Blkcnt_t = long; +alias Fflags_t = uint; + +struct Stat @if(env::X86_64) +{ + Mode_t st_mode; + Dev_t st_dev; + Ino_t st_ino; + Nlink_t st_nlink; + Uid_t st_uid; + Gid_t st_gid; + Dev_t st_rdev; + TimeSpec st_atime; + TimeSpec st_mtime; + TimeSpec st_ctime; + Off_t st_size; + Blkcnt_t st_blocks; + Blksize_t st_blksize; + Fflags_t st_flags; + uint st_gen; + ulong[10] st_spare; +} + +// TODO: Investigate if this needs to be fixed +struct Stat @if(!env::X86_64) +{ + Dev_t st_dev; + Ino_t st_ino; + Mode_t st_mode; + Nlink_t st_nlink; + Uid_t st_uid; + Gid_t st_gid; + Dev_t st_rdev; + CInt __pad1; + Off_t st_size; + Blksize_t st_blksize; + CInt __pad2; + Blkcnt_t st_blocks; + Time_t st_atime; + long st_atime_nsec; + Time_t st_mtime; + long st_mtime_nsec; + Time_t st_ctime; + long st_ctime_nsec; + CInt[2] __unused; +} + +extern fn CInt stat(ZString path, Stat* stat); + +extern fn CInt get_nprocs(); +extern fn CInt get_nprocs_conf(); diff --git a/lib/std/os/backtrace.c3 b/lib/std/os/backtrace.c3 index c44e771a2..a477d5b6c 100644 --- a/lib/std/os/backtrace.c3 +++ b/lib/std/os/backtrace.c3 @@ -87,11 +87,12 @@ fn void*[] capture_current(void*[] buffer) alias BacktraceList = List{Backtrace}; -alias symbolize_backtrace @if(env::LINUX) = linux::symbolize_backtrace; -alias symbolize_backtrace @if(env::WIN32) = win32::symbolize_backtrace; -alias symbolize_backtrace @if(env::DARWIN) = darwin::symbolize_backtrace; +alias symbolize_backtrace @if(env::LINUX) = linux::symbolize_backtrace; +alias symbolize_backtrace @if(env::WIN32) = win32::symbolize_backtrace; +alias symbolize_backtrace @if(env::DARWIN) = darwin::symbolize_backtrace; +alias symbolize_backtrace @if(env::OPENBSD) = openbsd::symbolize_backtrace; fn BacktraceList? symbolize_backtrace(Allocator allocator, void*[] backtrace) @if(!env::NATIVE_STACKTRACE) { return {}; -} \ No newline at end of file +} diff --git a/lib/std/os/openbsd/general.c3 b/lib/std/os/openbsd/general.c3 index 34e7112f6..292330a4c 100644 --- a/lib/std/os/openbsd/general.c3 +++ b/lib/std/os/openbsd/general.c3 @@ -1,2 +1,74 @@ module std::os::openbsd @if(env::OPENBSD); +import libc, std::os, std::collections::list; +extern fn ZString* backtrace_symbols_fmt(void **addrlist, usz len, ZString fmt); + +fn Backtrace? backtrace_line_parse(Allocator allocator, String obj, String addr2line) @local +{ + @stack_mem(256; Allocator mem) + { + String[] parts = addr2line.trim().split(mem, " at "); + if (parts.len != 2) return NOT_FOUND?; + + uint line = 0; + String source = ""; + if (!parts[1].contains("?") && parts[1].contains(":")) + { + usz index = parts[1].rindex_of_char(':')!; + source = parts[1][:index]; + line = parts[1][index + 1..].to_uint()!; + } + return { + .function = parts[0].copy(allocator), + .object_file = obj.copy(allocator), + .file = source.copy(allocator), + .line = line, + .allocator = allocator, + .is_inline = false, + }; + }; +} + +fn void? backtrace_add_addr2line(Allocator allocator, BacktraceList* list, String obj, String addr2line) @local +{ + list.push(backtrace_line_parse(allocator, obj, addr2line)!); +} + +fn void? backtrace_add_from_exec(Allocator allocator, BacktraceList* list, String fun, String obj) @local +{ + char[1024] buf @noinit; + String addr2line = process::execute_stdout_to_buffer(&buf, {"llvm-addr2line", "-fpe", obj, fun})!; + return backtrace_add_addr2line(allocator, list, obj, addr2line); +} + +fn void? backtrace_add_element(Allocator allocator, BacktraceList *list, String fun, String obj) @local +{ + return backtrace_add_from_exec(allocator, list, fun, obj); +} + +fn BacktraceList? symbolize_backtrace(Allocator allocator, void*[] backtrace) +{ + BacktraceList list; + list.init(allocator, backtrace.len); + defer catch + { + foreach (trace : list) + { + trace.free(); + } + list.free(); + } + + ZString *strings = backtrace_symbols_fmt(backtrace.ptr, backtrace.len, "%n%D %f"); + + for (int i = 0; i < backtrace.len; i++) { + String full = strings[i].str_view(); + Splitter iter = full.tokenize(" "); + String fun = iter.next()!; + String obj = iter.next()!; + backtrace_add_element(allocator, &list, fun, obj)!; + } + + free(strings); + return list; +} diff --git a/lib/std/os/posix/process.c3 b/lib/std/os/posix/process.c3 index 732dfd054..a549325bd 100644 --- a/lib/std/os/posix/process.c3 +++ b/lib/std/os/posix/process.c3 @@ -58,7 +58,9 @@ const CInt WUNTRACES = 2; JmpBuf backtrace_jmpbuf @local; alias BacktraceFn = fn CInt(void** buffer, CInt size); -fn CInt backtrace(void** buffer, CInt size) +extern fn CInt backtrace(void** buffer, CInt size) @if(env::OPENBSD); + +fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD) { if (size < 1) return 0; void* handle = libc::dlopen("libc.so.6", libc::RTLD_LAZY|libc::RTLD_NODELETE); diff --git a/src/compiler/linker.c b/src/compiler/linker.c index eaf814b7c..f0ce6f0db 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -532,6 +532,11 @@ static void linker_setup_freebsd(const char ***args_ref, Linker linker_type, boo { if (linker_type == LINKER_CC) { linking_add_link(&compiler.linking, "pthread"); + linking_add_link(&compiler.linking, "execinfo"); // for backtrace + if (compiler.build.debug_info == DEBUG_INFO_FULL) + { + add_plain_arg("-rdynamic"); + } return; } if (is_no_pie(compiler.platform.reloc_model)) add_plain_arg("-no-pie"); diff --git a/src/main.c b/src/main.c index 64b6e93e5..b56ead3d9 100644 --- a/src/main.c +++ b/src/main.c @@ -4,6 +4,9 @@ #include "utils/lib.h" #include +#ifdef __OpenBSD__ +#include +#endif bool debug_log = false; @@ -27,6 +30,13 @@ int main_real(int argc, const char *argv[]) { srand((unsigned int)time(NULL)); compiler_exe_name = argv[0]; +#ifdef __OpenBSD__ + // override data size constrain set up by the system */ + struct rlimit l; + getrlimit(RLIMIT_DATA, &l); + l.rlim_cur = l.rlim_max; + setrlimit(RLIMIT_DATA, &l); +#endif bench_begin(); // Setjmp will allow us to add things like fuzzing with diff --git a/test/src/test_suite_runner.c3 b/test/src/test_suite_runner.c3 index b3ec3423e..73098da91 100644 --- a/test/src/test_suite_runner.c3 +++ b/test/src/test_suite_runner.c3 @@ -411,6 +411,10 @@ fn void test_file(Path file_path) // Construct the compile line List{String} cmdline; cmdline.push(compiler_path.str_view()); + $if env::OPENBSD: + cmdline.push("--max-mem"); + cmdline.push("128"); + $endif cmdline.push("compile-only"); cmdline.push("--test"); if (stdlib) diff --git a/test/unit/stdlib/libc/os/openbsd.c3 b/test/unit/stdlib/libc/os/openbsd.c3 new file mode 100644 index 000000000..e69de29bb