build: track static-main.c + generate FFI symbols per-platform
ober
566d83228d8a6d00def3ab0f9bb64f496ce88571
--- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Build artifacts (jerbuild build) /jerboa-edge -*-main.c +/*-main.c +support/ffi-symbols.gen *.so *.wpo *.boot --- a/.jerbuild +++ b/.jerbuild @@ -13,7 +13,7 @@ ;; the list below (the linked-in archive members would otherwise be ;; dead-stripped / unreachable via dlsym). (main-c "support/static-main.c") -(ffi-symbols "support/ffi-symbols.list") +(ffi-symbols "support/ffi-symbols.gen") (rust-crates ("@bundle/jerboa-native-rs/Cargo.toml" features: "tls,crypto,sqlite" --- a/Makefile +++ b/Makefile @@ -21,7 +21,8 @@ all: binary # platform — e.g. epoll on Linux) and relink. A static main.c sets # JERBOA_STATIC=1 so the std modules use the registered symbols, not dlopen. binary: - @test -f "$(NATIVE_A)" || $(JERBUILD) build + @touch support/ffi-symbols.gen + $(JERBUILD) build sh support/gen-ffi-symbols.sh $(JERBUILD) build deleted file mode 100644 --- a/support/ffi-symbols.list +++ /dev/null @@ -1,115 +0,0 @@ -# jerboa-native FFI symbols registered via Sforeign_symbol() (see .jerbuild). -# AUTOGENERATED by support/gen-ffi-symbols.sh from libjerboa_native.a. - -jerboa_aead_open -jerboa_aead_seal -jerboa_antidebug_check_all -jerboa_antidebug_check_breakpoint -jerboa_antidebug_check_ld_preload -jerboa_antidebug_check_tracer -jerboa_antidebug_ptrace -jerboa_antidebug_timing_check -jerboa_aproc_close -jerboa_aproc_dup -jerboa_aproc_killpg -jerboa_aproc_set_nonblock -jerboa_aproc_spawn -jerboa_aproc_spawn_pty -jerboa_aproc_wait4 -jerboa_argon2id_hash -jerboa_argon2id_verify -jerboa_chacha20_open -jerboa_chacha20_seal -jerboa_deflate -jerboa_freebsd_is_traced -jerboa_freebsd_process_count -jerboa_gunzip -jerboa_gzip -jerboa_hkdf_sha256 -jerboa_hmac_sha256 -jerboa_hmac_sha256_verify -jerboa_inflate -jerboa_integrity_hash_file -jerboa_integrity_hash_region -jerboa_integrity_hash_self -jerboa_integrity_sign_verify -jerboa_integrity_verify_hash -jerboa_kill_probe -jerboa_last_error -jerboa_md5 -jerboa_mlockall -jerboa_pbkdf2_derive -jerboa_pbkdf2_verify -jerboa_prctl_set_name -jerboa_proc_self_exe -jerboa_random_bytes -jerboa_regex_captures -jerboa_regex_compile -jerboa_regex_compile_ex -jerboa_regex_find -jerboa_regex_find_at -jerboa_regex_free -jerboa_regex_group_count -jerboa_regex_is_match -jerboa_regex_replace_all -jerboa_scrypt -jerboa_secure_alloc -jerboa_secure_free -jerboa_secure_random_fill -jerboa_secure_wipe -jerboa_setproctitle -jerboa_sha1 -jerboa_sha256 -jerboa_sha384 -jerboa_sha512 -jerboa_socks5_server_port -jerboa_socks5_server_start -jerboa_socks5_server_stats -jerboa_socks5_server_stop -jerboa_sqlite_bind_blob -jerboa_sqlite_bind_double -jerboa_sqlite_bind_int -jerboa_sqlite_bind_null -jerboa_sqlite_bind_text -jerboa_sqlite_changes -jerboa_sqlite_close -jerboa_sqlite_column_blob -jerboa_sqlite_column_count -jerboa_sqlite_column_double -jerboa_sqlite_column_int -jerboa_sqlite_column_name -jerboa_sqlite_column_text -jerboa_sqlite_column_type -jerboa_sqlite_errmsg -jerboa_sqlite_exec -jerboa_sqlite_finalize -jerboa_sqlite_last_insert_rowid -jerboa_sqlite_open -jerboa_sqlite_prepare -jerboa_sqlite_reset -jerboa_sqlite_step -jerboa_timing_safe_equal -jerboa_tls_accept -jerboa_tls_close -jerboa_tls_connect -jerboa_tls_connect_mtls -jerboa_tls_connect_mtls_mem -jerboa_tls_connect_mtls_pem_ca -jerboa_tls_connect_pinned -jerboa_tls_flush -jerboa_tls_get_fd -jerboa_tls_read -jerboa_tls_server_free -jerboa_tls_server_new -jerboa_tls_server_new_mtls -jerboa_tls_server_new_mtls_pem -jerboa_tls_server_new_pem -jerboa_tls_set_nonblock -jerboa_tls_write -jerboa_x25519_diffie_hellman -jerboa_x25519_generate_keypair -jerboa_x25519_public_from_private -jerboa_x509_cert_fingerprint -jerboa_x509_generate_self_signed -jerboa_x509_generate_self_signed_mem -jerboa_x509_generate_signed_by_ca_mem --- a/support/gen-ffi-symbols.sh +++ b/support/gen-ffi-symbols.sh @@ -1,19 +1,21 @@ #!/bin/sh -# Regenerate support/ffi-symbols.list from the jerboa-native archive that -# jerbuild cargo-builds into its bundle cache. Run before the final -# `jerbuild build` so the static binary registers exactly the jerboa_* symbols -# present for THIS platform (e.g. epoll on Linux, kqueue on macOS). +# Regenerate support/ffi-symbols.gen from the jerboa-native archive that +# jerbuild cargo-builds into its bundle cache. Run between the two `jerbuild +# build` passes so the static binary registers exactly the jerboa_* symbols +# present for THIS platform + feature set (e.g. epoll on Linux, kqueue on +# macOS). The output is .gitignored — it is a build artifact, not source. set -e JH="$(jerbuild --jerboa-home 2>/dev/null)" A="$JH/jerboa-native-rs/target/release/libjerboa_native.a" -OUT="$(dirname "$0")/ffi-symbols.list" +OUT="$(dirname "$0")/ffi-symbols.gen" if [ ! -f "$A" ]; then echo "gen-ffi-symbols: $A not found (run 'jerbuild build' once first)" >&2 + : > "$OUT" exit 0 fi { - echo "# jerboa-native FFI symbols registered via Sforeign_symbol() (see .jerbuild)." echo "# AUTOGENERATED by support/gen-ffi-symbols.sh from libjerboa_native.a." + echo "# jerboa-native FFI symbols registered via Sforeign_symbol() (see .jerbuild)." echo "" nm -gjU "$A" 2>/dev/null | sed 's/^_//' | grep -E '^jerboa_[A-Za-z0-9_]+$' | sort -u } > "$OUT" new file mode 100644 --- /dev/null +++ b/support/static-main.c @@ -0,0 +1,55 @@ +/* Custom main.c for a standalone static jerbuild binary (referenced by + * .jerbuild as main-c). Identical to jerbuild's stock template with ONE + * addition: it sets JERBOA_STATIC=1 before building the heap. + * + * The bundled std modules — (std db sqlite-native), (std crypto native-rust), + * etc. — read JERBOA_STATIC at library-load time and, when set, trust the + * jerboa-native symbols that are linked into this binary (and registered via + * register_ffi_symbols() below from the .jerbuild ffi-symbols list) instead of + * trying to dlopen a libjerboa_native.{so,dylib} that does not exist in a + * static build. + */ +#include "scheme.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> + +#include "petite_boot.h" +#include "scheme_boot.h" +#include "program_boot.h" +#include "ffi_symbols.h" + +static const char *write_program_tmpfile(void) { + static char path[] = "/tmp/jerboa-prog-XXXXXX"; + int fd = mkstemp(path); + if (fd < 0) { perror("mkstemp"); exit(1); } + ssize_t n = write(fd, program_boot_data, program_boot_size); + if (n != (ssize_t)program_boot_size) { + perror("write"); close(fd); unlink(path); exit(1); + } + close(fd); + return path; +} + +int main(int argc, const char *argv[]) { + /* Trust the linked-in jerboa-native symbols (see file header). */ + setenv("JERBOA_STATIC", "1", 1); + + Sscheme_init(NULL); + Sregister_boot_file_bytes("petite", + (void *)petite_boot_data, petite_boot_size); + Sregister_boot_file_bytes("scheme", + (void *)scheme_boot_data, scheme_boot_size); + Sbuild_heap(NULL, NULL); + register_ffi_symbols(); + + const char *prog_path = write_program_tmpfile(); + int status = Sscheme_program(prog_path, argc, argv); + unlink(prog_path); + + Sscheme_deinit(); + return status; +}