ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | LICENSE

Commit: ea6a876212d30d4c6b91a6edb11b44ef94f5cf7e
Parent: 11de3a3a3c5f01b38610d6a673651d41e39e7672
Author: Randy Palamar
Date:   Sat, 26 Apr 2025 20:04:19 -0600

build: replace build.sh with build.c

Diffstat:
M.github/workflows/build.yml | 14+++++++-------
M.gitignore | 6+++---
Abuild.c | 570+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dbuild.sh | 137-------------------------------------------------------------------------------
Mmain_linux.c | 2+-
Mmain_w32.c | 14--------------
Mos_linux.c | 56+++++++++++++++++++++++++++++++-------------------------
Mos_win32.c | 44++++++++++++++++++++++++++++++++++++--------
8 files changed, 648 insertions(+), 195 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml @@ -9,17 +9,17 @@ jobs: matrix: os: [ubuntu-latest, ubuntu-24.04-arm] cc: ["gcc", "clang"] - env: - CC: "${{ matrix.cc }}" - runs-on: ${{ matrix.os }} + runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - name: Install dependencies run: | sudo apt update sudo apt install libxkbcommon-dev xorg-dev - name: Build - run: ./build.sh + run: ${{matrix.cc}} -march=native -O3 build.c -Iexternal/include -o build && ./build windows: runs-on: windows-latest @@ -29,13 +29,13 @@ jobs: include: - { sys: ucrt64, env: ucrt-x86_64, cc: "gcc" } - { sys: clang64, env: clang-x86_64, cc: "clang" } - env: - CC: "${{ matrix.cc }}" defaults: run: shell: msys2 {0} steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - uses: msys2/setup-msys2@v2 with: msystem: ${{matrix.sys}} @@ -43,4 +43,4 @@ jobs: install: git mingw-w64-${{matrix.env}}-${{matrix.cc}} - name: Build - run: NO_MATLAB=1 ./build.sh + run: ${{matrix.cc}} -march=native -O3 build.c -Iexternal/include -o build && ./build diff --git a/.gitignore b/.gitignore @@ -1,11 +1,11 @@ *.dll *.exe -*.mexa64 +*.old *.pdb *.rdi *.so* +build external/include/r*.h -external/lib -helpers/helper ogl +out x64 diff --git a/build.c b/build.c @@ -0,0 +1,570 @@ +/* See LICENSE for license details. */ +/* NOTE: inspired by nob: https://github.com/tsoding/nob.h */ + +#define BASE_CFLAGS "-march=native", "-std=c11", "-Wall", "-Iexternal/include" + +#define BUILD_DEPS __FILE__, "os_win32.c", "os_linux.c", "util.c", "util.h" + +#include "util.h" + +#include <stdarg.h> +#include <stdio.h> + +#define is_unix 0 +#define is_w32 0 +#define is_clang 0 + +#if defined(__linux__) + #undef is_unix + #define is_unix 1 + + #include <errno.h> + #include <string.h> + #include <sys/select.h> + #include <sys/wait.h> + + #include "os_linux.c" + + #define OS_MAIN "main_linux.c" + #define OS_LIB_EXT ".so" + +#elif defined(_WIN32) + #undef is_w32 + #define is_w32 1 + + #include "os_win32.c" + + #define OS_MAIN "main_w32.c" + #define OS_LIB_EXT ".dll" + +#else + #error Unsupported Platform +#endif + +#ifdef __clang__ +#undef is_clang +#define is_clang 1 +#define BUILD_COMMAND(output, input) "clang", BASE_CFLAGS, "-o", output, input +#else +#define BUILD_COMMAND(output, input) "cc", BASE_CFLAGS, "-o", output, input +#endif + +#define shift(list, count) ((count)--, *(list)++) + +#define da_append_count(a, s, items, item_count) do { \ + da_reserve((a), (s), (s)->count + (item_count)); \ + mem_copy((s)->data + (s)->count, (items), sizeof(*(items)) * (item_count)); \ + (s)->count += (item_count); \ +} while (0) + +#define cmd_append_count da_append_count +#define cmd_append(a, s, ...) da_append_count(a, s, ((char *[]){__VA_ARGS__}), \ + (sizeof((char *[]){__VA_ARGS__}) / sizeof(char *))) + +typedef struct { + char **data; + iz count; + iz capacity; +} CommandList; + +typedef struct { + b32 debug; + b32 report; + b32 sanitize; +} Options; + +#define die(fmt, ...) die_("%s: " fmt, __FUNCTION__, ##__VA_ARGS__) +function void __attribute__((noreturn)) +die_(char *format, ...) +{ + va_list ap; + va_start(ap, format); + /* TODO(rnp): proper log */ + vfprintf(stderr, format, ap); + va_end(ap); + os_fatal(s8("")); +} + +function b32 +s8_contains(s8 s, u8 byte) +{ + b32 result = 0; + for (iz i = 0 ; !result && i < s.len; i++) + result |= s.data[i] == byte; + return result; +} + +function void +stream_push_command(Stream *s, CommandList *c) +{ + if (!s->errors) { + for (iz i = 0; i < c->count; i++) { + s8 item = c_str_to_s8(c->data[i]); + if (item.len) { + b32 escape = s8_contains(item, ' ') || s8_contains(item, '"'); + if (escape) stream_append_byte(s, '\''); + stream_append_s8(s, item); + if (escape) stream_append_byte(s, '\''); + if (i != c->count - 1) stream_append_byte(s, ' '); + } + } + } +} + +#if defined(__unix__) + +function b32 +os_rename_file(char *name, char *new) +{ + b32 result = rename(name, new) != -1; + return result; +} + +function b32 +os_remove_file(char *name) +{ + b32 result = remove(name) != -1; + return result; +} + +function void +os_make_directory(char *name) +{ + mkdir(name, 0770); +} + +function u64 +os_get_filetime(char *file) +{ + struct stat sb; + u64 result = (u64)-1; + if (stat(file, &sb) != -1) + result = sb.st_mtim.tv_sec; + return result; +} + +function iptr +os_spawn_process(CommandList *cmd, Stream sb) +{ + pid_t result = fork(); + switch (result) { + case -1: die("failed to fork command: %s: %s\n", cmd->data[0], strerror(errno)); break; + case 0: { + if (execvp(cmd->data[0], cmd->data) == -1) + die("failed to exec command: %s: %s\n", cmd->data[0], strerror(errno)); + unreachable(); + } break; + } + return (iptr)result; +} + +function b32 +os_wait_close_process(iptr handle) +{ + b32 result = 0; + for (;;) { + i32 status; + iptr wait_pid = (iptr)waitpid(handle, &status, 0); + if (wait_pid == -1) + die("failed to wait on child process: %s\n", strerror(errno)); + if (wait_pid == handle) { + if (WIFEXITED(status)) { + status = WEXITSTATUS(status); + /* TODO(rnp): logging */ + result = status == 0; + break; + } + if (WIFSIGNALED(status)) { + /* TODO(rnp): logging */ + result = 0; + break; + } + } else { + /* TODO(rnp): handle multiple children */ + INVALID_CODE_PATH; + } + } + return result; +} + +#elif defined(_WIN32) + +#define MOVEFILE_REPLACE_EXISTING 0x01 + +W32(b32) CreateDirectoryA(c8 *, void *); +W32(b32) CreateProcessA(u8 *, u8 *, iptr, iptr, b32, u32, iptr, u8 *, iptr, iptr); +W32(b32) GetExitCodeProcess(iptr handle, u32 *); +W32(b32) GetFileTime(iptr, iptr, iptr, iptr); +W32(b32) MoveFileExA(c8 *, c8 *, u32); +W32(u32) WaitForSingleObject(iptr, u32); + +function void +os_make_directory(char *name) +{ + CreateDirectoryA(name, 0); +} + +function b32 +os_rename_file(char *name, char *new) +{ + b32 result = MoveFileExA(name, new, MOVEFILE_REPLACE_EXISTING) != 0; + return result; +} + +function b32 +os_remove_file(char *name) +{ + b32 result = DeleteFileA(name); + return result; +} + +function u64 +os_get_filetime(char *file) +{ + u64 result = (u64)-1; + iptr h = CreateFileA(file, 0, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (h != INVALID_FILE) { + struct { u32 low, high; } w32_filetime; + GetFileTime(h, 0, 0, (iptr)&w32_filetime); + result = (u64)w32_filetime.high << 32ULL | w32_filetime.low; + CloseHandle(h); + } + return result; +} + +function iptr +os_spawn_process(CommandList *cmd, Stream sb) +{ + struct { + u32 cb; + u8 *reserved, *desktop, *title; + u32 x, y, x_size, y_size, x_count_chars, y_count_chars; + u32 fill_attr, flags; + u16 show_window, reserved_2; + u8 *reserved_3; + iptr std_input, std_output, std_error; + } w32_startup_info = { + .cb = sizeof(w32_startup_info), + .flags = 0x100, + .std_input = GetStdHandle(STD_INPUT_HANDLE), + .std_output = GetStdHandle(STD_OUTPUT_HANDLE), + .std_error = GetStdHandle(STD_ERROR_HANDLE), + }; + + struct { + iptr phandle, thandle; + u32 pid, tid; + } w32_process_info = {0}; + + /* TODO(rnp): warn if we need to clamp last string */ + sb.widx = MIN(sb.widx, KB(32) - 1); + if (sb.widx < sb.cap) sb.data[sb.widx] = 0; + else sb.data[sb.widx - 1] = 0; + + iptr result = INVALID_FILE; + if (CreateProcessA(0, sb.data, 0, 0, 1, 0, 0, 0, (iptr)&w32_startup_info, + (iptr)&w32_process_info)) + { + CloseHandle(w32_process_info.thandle); + result = w32_process_info.phandle; + } + return result; +} + +function b32 +os_wait_close_process(iptr handle) +{ + b32 result = WaitForSingleObject(handle, -1) != 0xFFFFFFFFUL; + if (result) { + u32 status; + GetExitCodeProcess(handle, &status); + result = status == 0; + } + CloseHandle(handle); + return result; +} + +#endif + +#define needs_rebuild(b, ...) needs_rebuild_(b, ((char *[]){__VA_ARGS__}), \ + (sizeof((char *[]){__VA_ARGS__}) / sizeof(char *))) +function b32 +needs_rebuild_(char *binary, char *deps[], iz deps_count) +{ + u64 binary_filetime = os_get_filetime(binary); + b32 result = binary_filetime == (u64)-1; + for (iz i = 0; i < deps_count; i++) { + u64 filetime = os_get_filetime(deps[i]); + result |= (filetime == (u64)-1) | (filetime > binary_filetime); + } + return result; +} + +function b32 +run_synchronous(Arena a, CommandList *command) +{ + Stream sb = arena_stream(a); + stream_push_command(&sb, command); + printf("%.*s\n", (i32)sb.widx, sb.data); + return os_wait_close_process(os_spawn_process(command, sb)); +} + +function void +check_rebuild_self(Arena arena, i32 argc, char *argv[]) +{ + char *binary = shift(argv, argc); + if (needs_rebuild(binary, BUILD_DEPS)) { + Stream name = stream_alloc(&arena, KB(1)); + stream_append_s8(&name, c_str_to_s8(binary)); + stream_append_s8(&name, s8(".old")); + stream_append_byte(&name, 0); + + if (!os_rename_file(binary, (char *)name.data)) + die("failed to move: %s -> %s\n", binary, (char *)name.data); + + CommandList c = {0}; + cmd_append(&arena, &c, BUILD_COMMAND(binary, __FILE__)); + cmd_append(&arena, &c, "-O3", "-Wno-unused-function", (void *)0); + if (!run_synchronous(arena, &c)) { + os_rename_file((char *)name.data, binary); + die("failed to rebuild self\n"); + } + os_remove_file((char *)name.data); + + c.count = 0; + cmd_append(&arena, &c, binary); + cmd_append_count(&arena, &c, argv, argc); + cmd_append(&arena, &c, (void *)0); + if (!run_synchronous(arena, &c)) + os_exit(1); + + os_exit(0); + } +} + +function b32 +s8_equal(s8 a, s8 b) +{ + b32 result = a.len == b.len; + for (iz i = 0; result && i < a.len; i++) + result = a.data[i] == b.data[i]; + return result; +} + +function void +usage(char *argv0) +{ + die("%s [--debug] [--report] [--sanitize]\n" + " --debug: dynamically link and build with debug symbols\n" + " --report: print compilation stats (clang only)\n" + " --sanitize: build with ASAN and UBSAN\n" + , argv0); +} + +function Options +parse_options(i32 argc, char *argv[]) +{ + Options result = {0}; + + char *argv0 = shift(argv, argc); + while (argc > 0) { + char *arg = shift(argv, argc); + s8 str = c_str_to_s8(arg); + if (s8_equal(str, s8("--debug"))) { + result.debug = 1; + } else if (s8_equal(str, s8("--report"))) { + result.report = 1; + } else if (s8_equal(str, s8("--sanitize"))) { + result.sanitize = 1; + } else { + usage(argv0); + } + } + + return result; +} + +function CommandList +cmd_base(Arena *a, Options *o) +{ + CommandList result = {0}; + cmd_append(a, &result, is_clang ? "clang" : "cc", BASE_CFLAGS); + if (o->debug) cmd_append(a, &result, "-O0", "-D_DEBUG", "-Wno-unused-function"); + else cmd_append(a, &result, "-O3"); + + if (o->debug && is_unix) cmd_append(a, &result, "-ggdb"); + + if (o->sanitize) cmd_append(a, &result, "-fsanitize=address,undefined"); + + if (o->report) { + if (is_clang) cmd_append(a, &result, "-fproc-stat-report"); + else printf("warning: timing not supported with this compiler\n"); + /* TODO(rnp): basic timing */ + } + + return result; +} + +/* NOTE(rnp): produce pdbs on w32 */ +function void +cmd_pdb(Arena *a, CommandList *cmd) +{ + if (is_w32 && is_clang) + cmd_append(a, cmd, "-fuse-ld=lld", "-g", "-gcodeview", "-Wl,--pdb="); +} + +function void +git_submodule_update(Arena a, char *name) +{ + CommandList git = {0}; + /* NOTE(rnp): cryptic bs needed to get a simple exit code if name is dirty */ + cmd_append(&a, &git, "git", "diff-index", "--quiet", "HEAD", "--", name, (void *)0); + if (!run_synchronous(a, &git)) { + git.count = 1; + cmd_append(&a, &git, "submodule", "update", "--init", "--depth=1", name, (void *)0); + if (!run_synchronous(a, &git)) + die("failed to clone required module: %s\n", name); + } +} + +function b32 +build_shared_library(Arena a, CommandList cc, char *name, char **deps, iz deps_count) +{ + b32 result = 0; + cmd_append(&a, &cc, "-fPIC", "-shared"); + cmd_append_count(&a, &cc, deps, deps_count); + cmd_append(&a, &cc, "-o", name, (void *)0); + result = run_synchronous(a, &cc); + return result; +} + +function b32 +build_static_library(Arena a, CommandList cc, char *name, char **deps, char **outputs, iz count) +{ + /* TODO(rnp): refactor to not need outputs */ + b32 result = 0; + b32 all_success = 1; + cmd_append(&a, &cc, "-static"); + for (iz i = 0; i < count; i++) { + cmd_append(&a, &cc, "-c", deps[i], "-o", outputs[i], (void *)0); + all_success &= run_synchronous(a, &cc); + cc.count -= 5; + } + if (all_success) { + CommandList ar = {0}; + cmd_append(&a, &ar, "ar", "rc", name); + cmd_append_count(&a, &ar, outputs, count); + cmd_append(&a, &ar, (void *)0); + result = run_synchronous(a, &ar); + } + return result; +} + +function void +check_build_raylib(Arena a, CommandList cc, b32 shared) +{ + iz cc_count_start = cc.count; + char *libraylib[] = {"out/libraylib.a", "libraylib" OS_LIB_EXT}; + char *libglfw[] = {"out/libglfw.a", "libglfw" OS_LIB_EXT}; + + b32 rebuild_raylib = needs_rebuild(libraylib[shared], __FILE__, "external/include/rlgl.h", + "external/raylib"); + b32 rebuild_glfw = needs_rebuild(libglfw[shared], __FILE__, "external/include/rlgl.h", + "external/raylib"); + if (rebuild_glfw || rebuild_raylib) { + git_submodule_update(a, "external/raylib"); + os_copy_file("external/raylib/src/rlgl.h", "external/include/rlgl.h"); + if (!shared) os_make_directory("out"); + } + + if (rebuild_raylib) { + cc.count = cc_count_start; + cmd_append(&a, &cc, "-Wno-unused-but-set-variable"); + cmd_append(&a, &cc, "-DPLATFORM_DESKTOP_GLFW", "-DGRAPHICS_API_OPENGL_43"); + cmd_append(&a, &cc, "-Iexternal/raylib/src", "-Iexternal/raylib/src/external/glfw/include"); + + #define RAYLIB_SOURCES \ + X(rshapes) \ + X(rtext) \ + X(rtextures) \ + X(utils) + #define X(name) "external/raylib/src/" #name ".c", + char *srcs[] = {"external/rcore_extended.c", RAYLIB_SOURCES}; + #undef X + #define X(name) "out/" #name ".o", + char *outs[] = {"out/rcore_extended.o", RAYLIB_SOURCES}; + #undef X + + b32 success; + if (shared) { + cmd_pdb(&a, &cc); + cmd_append(&a, &cc, "-DBUILD_LIBTYPE_SHARED"); + success = build_shared_library(a, cc, libraylib[shared], srcs, countof(srcs)); + cc.count--; + } else { + success = build_static_library(a, cc, libraylib[shared], srcs, outs, countof(srcs)); + } + if (!success) die("failed to build libary: %s\n", libraylib[shared]); + } + + if (rebuild_glfw) { + cc.count = cc_count_start; + if (is_unix) cmd_append(&a, &cc, "-D_GLFW_X11"); + char *srcs[] = {"external/raylib/src/rglfw.c"}; + char *outs[] = {"out/rglfw.o"}; + + b32 success; + if (shared) { + cmd_pdb(&a, &cc); + if (is_w32) cmd_append(&a, &cc, "-lgdi32", "-lwinmm"); + success = build_shared_library(a, cc, libglfw[shared], srcs, countof(srcs)); + } else { + success = build_static_library(a, cc, libglfw[shared], srcs, outs, countof(srcs)); + } + if (!success) die("failed to build libary: %s\n", libglfw[shared]); + } +} + +/* NOTE(rnp): gcc requires these to appear at the end for no reason at all */ +function void +cmd_append_ldflags(Arena *a, CommandList *cc, b32 shared) +{ + cmd_pdb(a, cc); + cmd_append(a, cc, "-lm"); + if (shared && !is_w32) cmd_append(a, cc, "-Wl,-rpath,."); + if (shared) cmd_append(a, cc, "-L.", "-lglfw", "-lraylib"); + if (is_w32) cmd_append(a, cc, "-lgdi32", "-lwinmm", "-lSynchronization"); +} + +i32 +main(i32 argc, char *argv[]) +{ + Arena arena = os_alloc_arena((Arena){0}, MB(2)); + check_rebuild_self(arena, argc, argv); + + Options options = parse_options(argc, argv); + + CommandList c = cmd_base(&arena, &options); + check_build_raylib(arena, c, options.debug); + + cmd_append(&arena, &c, "-Wno-unused-function"); + if (!build_shared_library(arena, c, "helpers/ogl_beamformer_lib" OS_LIB_EXT, + (char *[]){"helpers/ogl_beamformer_lib.c"}, 1)) + { + die("failed to build: helpers/ogl_beamformer_lib" OS_LIB_EXT "\n"); + } + c.count--; + + if (options.debug && !build_shared_library(arena, c, "beamformer" OS_LIB_EXT, + (char *[]){"beamformer.c"}, 1)) + { + die("failed to build: beamfomer" OS_LIB_EXT "\n"); + } + + cmd_append(&arena, &c, "-o", "ogl", OS_MAIN); + if (!options.debug) cmd_append(&arena, &c, "out/libglfw.a", "out/libraylib.a"); + cmd_append_ldflags(&arena, &c, options.debug); + cmd_append(&arena, &c, (void *)0); + + return !run_synchronous(arena, &c); +} diff --git a/build.sh b/build.sh @@ -1,137 +0,0 @@ -#!/bin/sh - -# NOTE(rnp): to rebuild raylib run `touch build.sh` (or delete the so/dll) - -cflags="-march=native -std=c11 -Wall -I./external/include" -#cflags="${cflags} -fsanitize=address,undefined" -#cflags="${cflags} -fproc-stat-report" -#cflags="${cflags} -Rpass-missed=.*" -libcflags="${cflags} -fPIC -shared -Wno-unused-function -Wno-unused-variable" -ldflags="-lm" - -cc=${CC:-cc} -build=release - -for arg in $@; do - case "$arg" in - clang) cc=clang ;; - gcc) cc=gcc ;; - debug) build=debug ;; - release) build=release ;; - *) echo "usage: $0 [release|debug] [gcc|clang]"; exit 1;; - esac -done - -case $(uname -sm) in -MINGW64*) - win32=1 - glfw="libglfw.dll" - glfw_flags="-lgdi32 -lwinmm" - raylib="libraylib.dll" - main="main_w32.c" - libname="beamformer.dll" - ldflags="${ldflags} -lgdi32 -lwinmm -lSynchronization" - extra_ldflags="-lSynchronization" - if [ ! ${NO_MATLAB} ]; then - libcflags="${libcflags} -DMATLAB_CONSOLE" - extra_ldflags="${extra_ldflags} -llibmat -llibmex" - fi - ${cc} ${libcflags} -O3 helpers/ogl_beamformer_lib.c -o helpers/ogl_beamformer_lib.dll \ - -L'C:/Program Files/MATLAB/R2022a/extern/lib/win64/microsoft' \ - ${extra_ldflags} - ;; -Linux*) - glfw="libglfw.so" - glfw_flags="-D_GLFW_X11" - raylib="libraylib.so" - main="main_linux.c" - libname="beamformer.so" - cflags="${cflags} -D_DEFAULT_SOURCE" - - ${cc} ${libcflags} -O3 helpers/ogl_beamformer_lib.c -o helpers/ogl_beamformer_lib.so - ;; -esac - -if [ ! -f external/raylib/README.md ] || [ "$(git status --short external/raylib)" ]; then - git submodule update --init --depth=1 external/raylib -fi - -mkdir -p external/lib - -build_raylib() -{ - cp external/raylib/src/rlgl.h external/include/ - cppflags="${2} -DPLATFORM_DESKTOP_GLFW -DGRAPHICS_API_OPENGL_43" - cppflags="${cppflags} -Iexternal/raylib/src -Iexternal/raylib/src/external/glfw/include" - - case ${1} in - shared) - ${cc} ${cflags} ${cppflags} -fPIC -shared -DBUILD_LIBTYPE_SHARED \ - external/rcore_extended.c \ - external/raylib/src/rshapes.c external/raylib/src/rtext.c \ - external/raylib/src/rtextures.c external/raylib/src/utils.c \ - -o ${raylib} - ;; - static) - ${cc} ${cflags} ${cppflags} -c external/rcore_extended.c -o external/lib/rcore.c.o - ${cc} ${cflags} ${cppflags} -c external/raylib/src/rshapes.c -o external/lib/rshapes.c.o - ${cc} ${cflags} ${cppflags} -c external/raylib/src/rtext.c -o external/lib/rtext.c.o - ${cc} ${cflags} ${cppflags} -c external/raylib/src/rtextures.c -o external/lib/rtextures.c.o - ${cc} ${cflags} ${cppflags} -c external/raylib/src/utils.c -o external/lib/utils.c.o - ar rc external/lib/libraylib.a external/lib/rcore.c.o external/lib/rshapes.c.o \ - external/lib/rtext.c.o external/lib/rtextures.c.o external/lib/rtextures.c.o \ - external/lib/utils.c.o - ;; - esac -} - -check_and_rebuild_libs() -{ - # NOTE(rnp): we need to build glfw separately so that we can use functions from - # glfw directly - raylib doesn't let us open multiple opengl contexts even if - # we never plan on using them with raylib - case "${1}" in - static) - if [ "./build.sh" -nt "${glfw}" ] || [ ! -f ${glfw} ]; then - ${cc} ${cflags} ${glfw_flags} -static \ - -c external/raylib/src/rglfw.c -o external/lib/rglfw.o - ar rc ${glfw} external/lib/rglfw.o - fi - ;; - shared) - if [ "./build.sh" -nt "${glfw}" ] || [ ! -f "${glfw}" ]; then - [ "${win32}" ] && glfw_flags="${glfw_flags} -D_GLFW_BUILD_DLL" - ${cc} ${cflags} ${glfw_flags} -fPIC -shared \ - external/raylib/src/rglfw.c -o ${glfw} - fi - ;; - esac - if [ "./build.sh" -nt "${raylib}" ] || [ ! -f "${raylib}" ]; then - [ ${1} = "static" ] && build_raylib ${1} "-static" - [ ${1} = "shared" ] && build_raylib ${1} "-L. -lglfw ${ldflags}" - fi -} - -case "${build}" in -debug) - cflags="${cflags} -O0 -D_DEBUG -Wno-unused-function" - if [ "${win32}" ]; then - # NOTE(rnp): export pdb on win32; requires clang - cflags="${cflags} -fuse-ld=lld -g -gcodeview -Wl,--pdb=" - else - cflags="${cflags} -ggdb -Wl,-rpath,." - fi - check_and_rebuild_libs "shared" - ldflags="-L. -lglfw -lraylib ${ldflags}" - ${cc} ${cflags} -fPIC -shared beamformer.c -o ${libname} ${ldflags} - ;; -release) - cflags="${cflags} -O3" - raylib="external/lib/libraylib.a" - glfw="external/lib/libglfw.a" - ldflags="${raylib} ${glfw} ${ldflags}" - check_and_rebuild_libs "static" - ;; -esac - -${cc} ${cflags} -o ogl ${main} ${ldflags} diff --git a/main_linux.c b/main_linux.c @@ -74,7 +74,7 @@ main(void) OS_FNS #undef X - ctx.os.file_watch_context.handle = inotify_init1(O_NONBLOCK|O_CLOEXEC); + ctx.os.file_watch_context.handle = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); ctx.os.compute_worker.asleep = 1; ctx.os.stderr = STDERR_FILENO; diff --git a/main_w32.c b/main_w32.c @@ -5,20 +5,6 @@ #include "beamformer.h" -typedef struct { - iptr io_completion_handle; -} w32_context; - -enum w32_io_events { - W32_IO_FILE_WATCH, - W32_IO_PIPE, -}; - -typedef struct { - u64 tag; - iptr context; -} w32_io_completion_event; - #include "os_win32.c" #define OS_DEBUG_LIB_NAME ".\\beamformer.dll" diff --git a/os_linux.c b/os_linux.c @@ -16,6 +16,8 @@ #include <sys/syscall.h> #include <unistd.h> +/* NOTE(rnp): hidden behind feature flags -> screw compiler/standards idiots */ +i32 ftruncate(i32, i64); i64 syscall(i64, ...); #ifdef _DEBUG @@ -42,15 +44,22 @@ static OS_WRITE_FILE_FN(os_write_file) return 1; } -static void __attribute__((noreturn)) +function void __attribute__((noreturn)) +os_exit(i32 code) +{ + _exit(code); + unreachable(); +} + +function void __attribute__((noreturn)) os_fatal(s8 msg) { os_write_file(STDERR_FILENO, msg); - _exit(1); + os_exit(1); unreachable(); } -static OS_ALLOC_ARENA_FN(os_alloc_arena) +function OS_ALLOC_ARENA_FN(os_alloc_arena) { Arena result; iz pagesize = sysconf(_SC_PAGESIZE); @@ -147,36 +156,33 @@ os_open_shared_memory_area(char *name, iz cap) } /* NOTE: complete garbage because there is no standarized copyfile() in POSix */ -static b32 +function b32 os_copy_file(char *name, char *new) { b32 result = 0; struct stat sb; - if (stat(name, &sb) < 0) - return 0; - - i32 fd_old = open(name, O_RDONLY); - i32 fd_new = open(new, O_WRONLY|O_TRUNC, sb.st_mode); - - if (fd_old < 0 || fd_new < 0) - goto ret; - u8 buf[4096]; - iz copied = 0; - while (copied != sb.st_size) { - iz r = read(fd_old, buf, ARRAY_COUNT(buf)); - if (r < 0) goto ret; - iz w = write(fd_new, buf, r); - if (w < 0) goto ret; - copied += w; + if (stat(name, &sb) == 0) { + i32 fd_old = open(name, O_RDONLY); + i32 fd_new = open(new, O_WRONLY|O_CREAT, sb.st_mode); + if (fd_old >= 0 && fd_new >= 0) { + u8 buf[4096]; + iz copied = 0; + while (copied != sb.st_size) { + iz r = read(fd_old, buf, countof(buf)); + if (r < 0) break; + iz w = write(fd_new, buf, r); + if (w < 0) break; + copied += w; + } + result = copied == sb.st_size; + } + if (fd_old != -1) close(fd_old); + if (fd_new != -1) close(fd_new); } - result = 1; -ret: - if (fd_old != -1) close(fd_old); - if (fd_new != -1) close(fd_new); return result; } -static void * +function void * os_load_library(char *name, char *temp_name, Stream *e) { if (temp_name) { diff --git a/os_win32.c b/os_win32.c @@ -1,6 +1,7 @@ /* See LICENSE for license details. */ #include "util.h" +#define STD_INPUT_HANDLE -10 #define STD_OUTPUT_HANDLE -11 #define STD_ERROR_HANDLE -12 @@ -73,6 +74,22 @@ typedef struct { iptr event_handle; } w32_overlapped; +typedef struct { + iptr io_completion_handle; + u64 timer_start_time; + u64 timer_frequency; +} w32_context; + +typedef enum { + W32_IO_FILE_WATCH, + W32_IO_PIPE, +} W32_IO_Event; + +typedef struct { + u64 tag; + iptr context; +} w32_io_completion_event; + #define W32(r) __declspec(dllimport) r __stdcall W32(b32) CloseHandle(iptr); W32(b32) CopyFileA(c8 *, c8 *, b32); @@ -125,15 +142,22 @@ static OS_WRITE_FILE_FN(os_write_file) return raw.len == wlen; } -static void __attribute__((noreturn)) +function void __attribute__((noreturn)) +os_exit(i32 code) +{ + ExitProcess(1); + unreachable(); +} + +function void __attribute__((noreturn)) os_fatal(s8 msg) { os_write_file(GetStdHandle(STD_ERROR_HANDLE), msg); - ExitProcess(1); + os_exit(1); unreachable(); } -static OS_ALLOC_ARENA_FN(os_alloc_arena) +function OS_ALLOC_ARENA_FN(os_alloc_arena) { Arena result; w32_sys_info Info; @@ -231,13 +255,17 @@ os_open_shared_memory_area(char *name, iz cap) return result; } -static void * +function b32 +os_copy_file(char *name, char *new) +{ + return CopyFileA(name, new, 0); +} + +function void * os_load_library(char *name, char *temp_name, Stream *e) { - if (temp_name) { - if (CopyFileA(name, temp_name, 0)) - name = temp_name; - } + if (temp_name && os_copy_file(name, temp_name)) + name = temp_name; void *result = LoadLibraryA(name); if (!result && e) {