Update files for cross compilation fixes; add dockerfiles for windows/linux/emscripten builds; add commands to makefile to build via dockerfiles
Some checks failed
Build and Deploy / build-macos (push) Failing after 29s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled

This commit is contained in:
2025-07-12 16:20:43 -05:00
parent f0afdfc7d9
commit c87f85cf6c
19 changed files with 231 additions and 54 deletions

12
.github/docker/Dockerfile.emscripten vendored Normal file
View File

@@ -0,0 +1,12 @@
# Use the official Emscripten SDK image (includes emcc, emsdk, Python, nodejs, etc)
FROM emscripten/emsdk:latest
# Install Meson & Ninja if needed (some emsdk tags already bundle them)
RUN apt-get update && \
apt-get install -y --no-install-recommends \
meson \
ninja-build \
python3-pip && \
rm -rf /var/lib/apt/lists/*
RUN pip3 install --upgrade meson>=1.4

View File

@@ -28,5 +28,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
ccache \
mingw-w64 \
wine \
npm nodejs zip && \
rm -rf /var/lib/apt/lists/*
libmimalloc-dev \
npm nodejs zip
RUN apt-get install -y libunwind-dev libblas-dev liblapacke-dev

View File

@@ -1,4 +1,6 @@
FROM ubuntu:plucky
FROM debian:trixie
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y --no-install-recommends \
@@ -11,5 +13,11 @@ RUN apt-get update && \
pkg-config \
zip \
ccache \
npm nodejs && \
npm \
nodejs \
meson \
libmimalloc-dev \
libbsd-dev \
gcc-mingw-w64-ucrt64 \
g++-mingw-w64-ucrt64 && \
rm -rf /var/lib/apt/lists/*

View File

@@ -3,6 +3,7 @@ FROM ubuntu:plucky AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-pip \
libmimalloc-dev \
libasound2-dev \
libpulse-dev \
libudev-dev \
@@ -31,7 +32,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
WORKDIR /app
RUN git clone https://gitea.pockle.world/john/prosperon.git
WORKDIR /app/prosperon
RUN git checkout jsffi_refactor
RUN git checkout master
RUN meson setup build -Dbuildtype=release -Db_lto=true -Db_lto_mode=thin -Db_ndebug=true
RUN meson compile -C build

View File

@@ -27,3 +27,43 @@ crosswin: FORCE
meson compile -C build_win
FORCE:
IMAGE_LINUX := prosperon/linux-builder:latest
IMAGE_MINGW := prosperon/mingw-builder:latest
IMAGE_EMSCRIPTEN := prosperon/emscripten-builder:latest
PWD := $(shell pwd)
ARTIFACTS_DIR := artifacts
build:
meson setup build -Dbuildtype=release -Db_lto=true -Db_lto_mode=thin -Db_ndebug=true
meson compile -C build
dockerclean:
rm -rf build build-win $(ARTIFACTS_DIR)
dockerlinux: build-linux-image run-linux
build-linux-image:
docker build -f .github/docker/Dockerfile.linux -t $(IMAGE_LINUX) .
run-linux:
@mkdir -p $(ARTIFACTS_DIR)/linux
docker run --rm -v $(PWD):/src -w /src $(IMAGE_LINUX) bash -lc 'meson setup build -Dbuildtype=release -Db_lto=true -Db_ndebug=true && meson compile -C build && cp build/cell $(ARTIFACTS_DIR)/linux/'
dockerwin: build-mingw-image run-win
build-mingw-image:
docker build -f .github/docker/Dockerfile.mingw -t $(IMAGE_MINGW) .
run-win:
@mkdir -p $(ARTIFACTS_DIR)/windows
docker run --rm -v $(PWD):/src -w /src $(IMAGE_MINGW) bash -lc 'meson setup build-win --cross-file mingw32.cross -Dbuildtype=release -Db_lto=true -Db_ndebug=true && meson compile -C build-win && cp build-win/cell.exe $(ARTIFACTS_DIR)/windows/'
dockeremc: build-emscripten-image run-emc
build-emscripten-image:
docker build -f .github/docker/Dockerfile.emscripten -t $(IMAGE_EMSCRIPTEN) .
run-emc:
@mkdir -p $(ARTIFACTS_DIR)/emscripten
docker run --rm -v $(PWD):/src -w /src $(IMAGE_EMSCRIPTEN) bash -lc 'meson setup build-emscripten --cross-file emscripten.cross -Dbuildtype=release -Db_ndebug=true -Ddefault_library=static -Dcpp_std=c++11 && meson compile -C build-emscripten && cp build-emscripten/cell.wasm build-emscripten/cell.js $(ARTIFACTS_DIR)/emscripten/'

View File

@@ -1,22 +1,22 @@
[binaries]
c = 'emcc'
cpp = 'em++'
ar = 'emar'
strip = 'emstrip'
pkg-config = 'pkg-config'
c = 'emcc'
cpp = 'em++'
ar = 'emar'
strip = 'emstrip'
pkgconfig = 'pkg-config'
exe_wrapper = 'node'
[host_machine]
system = 'emscripten'
system = 'emscripten'
cpu_family = 'wasm32'
cpu = 'wasm32'
endian = 'little'
cpu = 'wasm32'
endian = 'little'
[built-in options]
pkg_config_path = '$EMSDK/upstream/emscripten/cache/sysroot/lib/pkgconfig'
cmake_prefix_path = '$EMSDK/upstream/emscripten/cache/sysroot'
pkg_config_path = '/emsdk/upstream/emscripten/cache/sysroot/lib/pkgconfig'
cmake_prefix_path = '/emsdk/upstream/emscripten/cache/sysroot'
[properties]
needs_exe_wrapper = true
cmake_system_name = 'Emscripten'
sys_root = '@env:EMSDK@/upstream/emscripten/cache/sysroot'
needs_exe_wrapper = true
# <-- Replace with your real path to Emscripten.cmake:
cmake_toolchain_file = '/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake'

View File

@@ -107,16 +107,16 @@ sdl3_opts.add_cmake_defines({
cc = meson.get_compiler('c')
if host_machine.system() == 'darwin'
deps += dependency('appleframeworks', modules: 'accelerate')
add_project_arguments('-DACCELERATE_NEW_LAPACK=1', language:'c')
add_project_arguments('-DACCELERATE_LAPACK_ILP64=1', language:'c')
# deps += dependency('appleframeworks', modules: 'accelerate')
# add_project_arguments('-DACCELERATE_NEW_LAPACK=1', language:'c')
# add_project_arguments('-DACCELERATE_LAPACK_ILP64=1', language:'c')
endif
if host_machine.system() == 'linux'
deps += cc.find_library('asound', required:true)
deps += [dependency('x11'), dependency('xi'), dependency('xcursor'), dependency('egl'), dependency('gl')]
deps += cc.find_library('blas', required:true)
deps += cc.find_library('lapack', required:true)
# deps += cc.find_library('blas', required:true)
# deps += cc.find_library('lapacke', required:true)
endif
if host_machine.system() == 'windows'
@@ -124,11 +124,11 @@ if host_machine.system() == 'windows'
deps += cc.find_library('ws2_32', required:true)
# For Windows, you may need to install OpenBLAS or Intel MKL
# and adjust these library names accordingly
deps += cc.find_library('openblas', required:false)
if not cc.find_library('openblas', required:false).found()
deps += cc.find_library('blas', required:false)
deps += cc.find_library('lapack', required:false)
endif
# deps += cc.find_library('openblas', required:false)
# if not cc.find_library('openblas', required:false).found()
# deps += cc.find_library('blas', required:false)
# deps += cc.find_library('lapacke', required:false)
# endif
deps += cc.find_library('dbghelp')
deps += cc.find_library('winmm')
deps += cc.find_library('setupapi')
@@ -142,12 +142,43 @@ if host_machine.system() == 'windows'
endif
if host_machine.system() == 'emscripten'
link += '-sUSE_WEBGPU'
# Use the pre-installed copy
deps += dependency('sdl3',
static : true,
method : 'pkg-config', # or 'cmake' if you prefer
required : true)
message('⚙ Building SDL3 subproject for Emscripten...')
sdl3_opts.append_compile_args(
'c',
'-pthread',
'-sUSE_PTHREADS=1',
)
sdl3_opts.append_compile_args(
'cpp',
'-pthread',
'-sUSE_PTHREADS=1',
)
# 3. And into every link step
sdl3_opts.append_link_args(
'-pthread',
'-sUSE_PTHREADS=1',
'-sPTHREAD_POOL_SIZE=4',
)
sdl3_proj = cmake.subproject('sdl3', options: sdl3_opts)
deps += sdl3_proj.dependency('SDL3-static')
add_project_arguments('-DPATH_MAX=4096', language: 'c')
add_project_arguments(
'-pthread',
'-sUSE_PTHREADS=1',
'-sPTHREAD_POOL_SIZE=4',
language: ['c', 'cpp'])
add_project_link_arguments(
'--use-port=emdawnwebgpu',
'-sUSE_PTHREADS=1',
'-pthread',
'-sPTHREAD_POOL_SIZE=4',
'-sMALLOC=mimalloc',
language: ['c','cpp'])
else
# Try to find system-installed SDL3 first
sdl3_dep = dependency('sdl3', static: true, required: false)
@@ -179,7 +210,7 @@ else
endif
deps += dependency('threads')
deps += dependency('mimalloc')
# Try to find system-installed chipmunk first
chipmunk_dep = dependency('chipmunk', static: true, required: false)
@@ -200,8 +231,10 @@ if host_machine.system() != 'emscripten'
deps += enet_dep
endif
src += 'qjs_enet.c'
deps += dependency('mimalloc')
tracy_opts = ['fibers=true', 'no_exit=true', 'libunwind_backtrace=true', 'on_demand=true']
tracy_opts = ['fibers=true', 'no_exit=true', 'on_demand=true']
add_project_arguments('-DTRACY_ENABLE', language:['c','cpp'])
# Try to find system-installed tracy first
@@ -271,7 +304,7 @@ src += [
'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c',
'render.c','simplex.c','spline.c', 'transform.c','cell.c', 'wildmatch.c',
'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_input.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c',
'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c', 'qjs_num.c', 'timer.c', 'qjs_socket.c', 'qjs_kim.c', 'qjs_utf8.c', 'qjs_fit.c', 'qjs_text.c', 'qjs_layout.c'
'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c', 'timer.c', 'qjs_socket.c', 'qjs_kim.c', 'qjs_utf8.c', 'qjs_fit.c', 'qjs_text.c', 'qjs_layout.c'
]
# quirc src
src += [

View File

@@ -382,7 +382,7 @@ function format_number(num, format) {
default_separation = 0;
default_places = 1;
break;
}
}
if (separation == 0) separation = default_separation;
if (places == 0) places = default_places;

View File

@@ -20,10 +20,6 @@
#include <windows.h>
#endif
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__linux__)
#include <sys/ptrace.h>
#endif
#include <SDL3/SDL_atomic.h>
#define WOTA_IMPLEMENTATION
@@ -119,7 +115,6 @@ void actor_free(cell_rt *actor)
// Delete it out of actors first so it can no longer get messages
SDL_LockMutex(actors_mutex);
shdel(actors, actor->id);
int remaining = shlen(actors);
SDL_UnlockMutex(actors_mutex);
// If in a queue, remove it
@@ -664,7 +659,11 @@ JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *arg
// Wrapper struct to keep the array pointer stable
typedef struct {
#ifdef TRACY_ENABLE
TracyCZoneCtx *arr; // stb_ds dynamic array
#else
void *arr;
#endif
} tracy_stack_t;
// Global TLS ID for the Tracy stack
@@ -695,6 +694,7 @@ static tracy_stack_t *get_tracy_stack(void)
void tracy_call_hook(JSContext *js, JSValue fn)
{
#ifdef TRACY_ENABLE
if (!tracy_profiling_enabled)
return;
@@ -706,16 +706,19 @@ void tracy_call_hook(JSContext *js, JSValue fn)
arrput(stack->arr, ___tracy_emit_zone_begin_alloc(srcloc, 1));
free_js_debug_info(js, &debug);
#endif
}
void tracy_end_hook(JSContext *js, JSValue fn)
{
#ifdef TRACY_ENABLE
if (!tracy_profiling_enabled)
return;
tracy_stack_t *stack = get_tracy_stack();
if (arrlen(stack->arr) > 0)
___tracy_emit_zone_end(arrpop(stack->arr));
#endif
}
void actor_disrupt(cell_rt *crt)

View File

@@ -32,9 +32,9 @@
#include "qjs_blob.h"
#include "qjs_dmon.h"
#include "qjs_enet.h"
#include "qjs_nota.h"
#include "qjs_wota.h"
#include "qjs_enet.h"
#include "qjs_soloud.h"
#include "qjs_qr.h"
#include "qjs_sdl.h"
@@ -1608,7 +1608,7 @@ void ffi_load(JSContext *js)
arrput(rt->module_registry, MISTLINE(http));
arrput(rt->module_registry, MISTLINE(crypto));
arrput(rt->module_registry, MISTLINE(miniz));
arrput(rt->module_registry, MISTLINE(num));
// arrput(rt->module_registry, MISTLINE(num));
arrput(rt->module_registry, MISTLINE(kim));
arrput(rt->module_registry, MISTLINE(utf8));
arrput(rt->module_registry, MISTLINE(fit));
@@ -1619,7 +1619,11 @@ void ffi_load(JSContext *js)
// power user
arrput(rt->module_registry, MISTLINE(js));
arrput(rt->module_registry, MISTLINE(debug));
#ifndef __EMSCRIPTEN__
arrput(rt->module_registry, MISTLINE(dmon));
#endif
arrput(rt->module_registry, MISTLINE(util));
// prosperon
@@ -1672,7 +1676,10 @@ void ffi_load(JSContext *js)
JS_SetPropertyStr(js, hidden_fn, "wota", js_wota_use(js));
JS_SetPropertyStr(js, hidden_fn, "console", js_console_use(js));
JS_SetPropertyStr(js, hidden_fn, "nota", js_nota_use(js));
#ifndef __EMSCRIPTEN__
JS_SetPropertyStr(js, hidden_fn, "enet", js_enet_use(js));
#endif
// Add functions that should only be accessible to engine.js
JS_SetPropertyStr(js, hidden_fn, "use_dyn", JS_NewCFunction(js, js_os_use_dyn, "use_dyn", 1));

View File

@@ -3,14 +3,27 @@
#include "jsffi.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#include <direct.h>
#define mkdir(path, mode) _mkdir(path)
#define rmdir _rmdir
#define getcwd _getcwd
#define PATH_MAX _MAX_PATH
#define fsync(fd) _commit(fd)
#define S_ISLNK(m) 0
#define S_ISSOCK(m) 0
#else
#include <unistd.h>
#include <dirent.h>
#endif
// Helper to convert JS value to file descriptor
static int js2fd(JSContext *ctx, JSValueConst val)
{
@@ -180,8 +193,13 @@ JSC_CCALL(fd_fstat,
JS_SetPropertyStr(js, obj, "ino", JS_NewInt64(js, st.st_ino));
JS_SetPropertyStr(js, obj, "dev", JS_NewInt32(js, st.st_dev));
JS_SetPropertyStr(js, obj, "rdev", JS_NewInt32(js, st.st_rdev));
#ifndef _WIN32
JS_SetPropertyStr(js, obj, "blksize", JS_NewInt32(js, st.st_blksize));
JS_SetPropertyStr(js, obj, "blocks", JS_NewInt64(js, st.st_blocks));
#else
JS_SetPropertyStr(js, obj, "blksize", JS_NewInt32(js, 4096));
JS_SetPropertyStr(js, obj, "blocks", JS_NewInt64(js, st.st_size / 512));
#endif
// Add boolean properties for file type
JS_SetPropertyStr(js, obj, "isFile", JS_NewBool(js, S_ISREG(st.st_mode)));

View File

@@ -9,6 +9,28 @@
#include <stdlib.h>
#include <stdio.h>
#if defined(__MINGW32__) || defined(__MINGW64__)
static void *memmem(const void *hay, size_t haylen,
const void *ndl, size_t ndllen) {
const unsigned char *h = hay, *n = ndl;
if (!ndllen) return (void*)h;
haylen -= ndllen - 1;
for (size_t i = 0; i < haylen; i++)
if (memcmp(h + i, n, ndllen) == 0)
return (void*)(h + i);
return NULL;
}
static char *strndup(const char *s, size_t n) {
size_t len = strnlen(s, n);
char *d = malloc(len + 1);
if (!d) return NULL;
memcpy(d, s, len);
d[len] = '\0';
return d;
}
#endif
// Simple dynamic buffer for reading the response
typedef struct {
char *data;

View File

@@ -219,7 +219,7 @@ static JSValue js_os_rusage(JSContext *js, JSValue self, int argc, JSValue *argv
JSValue ret = JS_NULL;
ret = JS_NewObject(js);
#ifndef _WIN32
#if defined(__linux__) || defined(__APPLE__)
struct rusage jsmem;
getrusage(RUSAGE_SELF, &jsmem);
JSJMEMRET(ru_maxrss);

View File

@@ -12,6 +12,7 @@
#include <SDL3/SDL_properties.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "qjs_sdl.h"
// SDL Window free function

View File

@@ -2,12 +2,26 @@
#include "jsffi.h"
#include "qjs_blob.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
#define close closesocket
#define SHUT_RD SD_RECEIVE
#define SHUT_WR SD_SEND
#define SHUT_RDWR SD_BOTH
#ifndef AF_UNIX
#define AF_UNIX 1
#endif
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
@@ -291,7 +305,7 @@ JSC_CCALL(socket_send,
JS_FreeCString(js, data);
} else {
unsigned char *data = js_get_blob_data(js, &len, argv[1]);
sent = send(sockfd, data, len, flags);
sent = send(sockfd, (const char *)data, len, flags);
}
if (sent < 0) {
@@ -373,7 +387,7 @@ JSC_CCALL(socket_sendto,
JS_FreeCString(js, data);
} else {
unsigned char *data = js_get_blob_data(js, &len, argv[1]);
sent = sendto(sockfd, data, len, flags, to_addr, to_len);
sent = sendto(sockfd, (const char *)data, len, flags, to_addr, to_len);
}
if (sent < 0) {

View File

@@ -4,7 +4,7 @@
#include "stb_ds.h"
/* Global timer state */
static timer_t *timers = NULL;
static cell_timer_t *timers = NULL;
static Uint32 next_timer_id = 1;
static SDL_Mutex *timer_mutex = NULL;
static SDL_Condition *timer_cond = NULL;
@@ -59,7 +59,7 @@ uint64_t get_time_ns(void)
Uint32 add_timer_ns(uint64_t delay_ns, TimerCallback callback, void *param)
{
timer_t t;
cell_timer_t t;
SDL_LockMutex(timer_mutex);
t.id = next_timer_id++;
t.interval_ns = delay_ns;
@@ -90,7 +90,7 @@ void process_due_timers(void)
SDL_LockMutex(timer_mutex);
for (int i = 0; i < arrlen(timers); i++) {
if (timers[i].due_ns <= now) {
timer_t t = timers[i];
cell_timer_t t = timers[i];
arrdel(timers, i);
SDL_UnlockMutex(timer_mutex);

View File

@@ -12,7 +12,7 @@ typedef struct {
uint64_t interval_ns;
TimerCallback callback;
void *param;
} timer_t;
} cell_timer_t;
/* Initialize timer system - must be called once */
void timer_init(void);

13
subprojects/mimalloc.wrap Normal file
View File

@@ -0,0 +1,13 @@
[wrap-file]
directory = mimalloc-3.1.5
source_url = https://github.com/microsoft/mimalloc/archive/refs/tags/v3.1.5.tar.gz
source_filename = mimalloc-3.1.5.tar.gz
source_hash = 1c6949032069d5ebea438ec5cedd602d06f40a92ddf0f0d9dcff0993e5f6635c
patch_filename = mimalloc_3.1.5-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/mimalloc_3.1.5-1/get_patch
patch_hash = 321b4507c1adda5b7aa9954a5f1748e17bf30a11142b4f6c3d52929523565e80
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/mimalloc_3.1.5-1/mimalloc-3.1.5.tar.gz
wrapdb_version = 3.1.5-1
[provide]
mimalloc = mi_dep

3
tangletart.bat Normal file
View File

@@ -0,0 +1,3 @@
@echo off
"%~dp0cell.exe" prosperon accio
pause