export fn and finch build --shared: libraries a C program loads (game scripts)

export fn name(...) is a C function by that name (numbers, bool, char, pointers in and out).
--shared builds lib<name>.so / <name>.dll with no main. finch_module_on_fatal(handler) lets the
host take runtime errors over (longjmp out) instead of the process exiting.
tests/shared.sh: a C host loads one, calls it and survives an index error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-10-11 02:14:09 +02:00
commit 68637a35a7
16 changed files with 148 additions and 10 deletions

17
tests/shared.sh Executable file
View file

@ -0,0 +1,17 @@
#!/bin/sh
# finch build --shared: a library a C program loads, calls by name, and that hands runtime
# errors to the host instead of exiting.
set -e
cd "$(dirname "$0")/shared"
FINCH=${FINCH:-../../build/finch}
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
"$FINCH" build mod.fch --shared -o "$tmp/libmod.so"
${CC:-cc} host.c -rdynamic -o "$tmp/host" -ldl
out=$("$tmp/host" "$tmp/libmod.so")
expected='add 42
even 1 0
host_print: hello Rakya
caught: mod.fch:17: runtime error: index 7 is out of range (the length is 3)
still alive'
if [ "$out" = "$expected" ]; then echo "shared library: passed"; else printf 'shared library: FAILED\n%s\n' "$out"; exit 1; fi

17
tests/shared/host.c Normal file
View file

@ -0,0 +1,17 @@
#include <dlfcn.h>
#include <setjmp.h>
#include <stdio.h>
static jmp_buf jb;
void host_print(const char *s) { printf("host_print: %s\n", s); }
static void onFatal(const char *m) { printf("caught: %s\n", m); longjmp(jb, 1); }
int main(int argc, char **argv) {
void *h = dlopen(argc > 1 ? argv[1] : "./libmod.so", RTLD_NOW | RTLD_LOCAL);
if (!h) { printf("%s\n", dlerror()); return 1; }
((void (*)(void (*)(const char *)))dlsym(h, "finch_module_on_fatal"))(onFatal);
printf("add %ld\n", ((long (*)(long, long))dlsym(h, "add"))(2, 40));
printf("even %d %d\n", ((_Bool (*)(long))dlsym(h, "is_even"))(4), ((_Bool (*)(long))dlsym(h, "is_even"))(5));
((void (*)(const char *))dlsym(h, "hello"))("Rakya");
if (!setjmp(jb)) ((long (*)(long))dlsym(h, "crash"))(7);
printf("still alive\n");
return 0;
}

1
tests/shared/host.h Normal file
View file

@ -0,0 +1 @@
void host_print(const char *s);

22
tests/shared/mod.fch Normal file
View file

@ -0,0 +1,22 @@
import "host.h"
fn greet(str who) -> str {
return "hello " + who
}
export fn add(int a, int b) -> int {
return a + b
}
export fn hello(ptr[char] name) {
host_print(greet(str(name)))
}
export fn crash(int i) -> int {
xs := [1, 2, 3]
return xs[i]
}
export fn is_even(int n) -> bool {
return n % 2 == 0
}