Commit: ea6a876212d30d4c6b91a6edb11b44ef94f5cf7e
Parent: 11de3a3a3c5f01b38610d6a673651d41e39e7672
Author: Randy Palamar
Date: Sat, 26 Apr 2025 20:04:19 -0600
build: replace build.sh with build.c
Diffstat:
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) {