Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 84 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ ifeq ($(filter $(check_goal),config defconfig),)
endif
endif

# Detect Emscripten early (before including toolchain.mk)
CC_VERSION := $(shell $(CC) --version 2>/dev/null)
ifneq ($(findstring emcc,$(CC_VERSION)),)
CC_IS_EMCC := 1
endif

# Enforce SDL backend for Emscripten builds (skip during config targets)
ifeq ($(filter $(check_goal),config defconfig),)
ifeq ($(CC_IS_EMCC),1)
ifneq ($(CONFIG_BACKEND_SDL),y)
$(error Emscripten (WebAssembly) builds require SDL backend. Please run: env CC=emcc make defconfig)
endif
endif
endif

# Target variables initialization

target-y :=
Expand All @@ -23,6 +38,8 @@ target.a-y += libtwin.a
# Core library

libtwin.a_cflags-y :=
# Emscripten size optimization
libtwin.a_cflags-$(CC_IS_EMCC) += -Oz

libtwin.a_files-y = \
src/box.c \
Expand Down Expand Up @@ -85,14 +102,26 @@ endif

ifeq ($(CONFIG_LOADER_JPEG), y)
libtwin.a_files-y += src/image-jpeg.c
ifneq ($(CC_IS_EMCC), 1)
libtwin.a_cflags-y += $(shell pkg-config --cflags libjpeg)
TARGET_LIBS += $(shell pkg-config --libs libjpeg)
else
# Emscripten libjpeg port - flags needed for both compile and link
libtwin.a_cflags-y += -sUSE_LIBJPEG=1
TARGET_LIBS += -sUSE_LIBJPEG=1
endif
endif

ifeq ($(CONFIG_LOADER_PNG), y)
libtwin.a_files-y += src/image-png.c
ifneq ($(CC_IS_EMCC), 1)
libtwin.a_cflags-y += $(shell pkg-config --cflags libpng)
TARGET_LIBS += $(shell pkg-config --libs libpng)
else
# Emscripten libpng port (includes zlib) - flags needed for both compile and link
libtwin.a_cflags-y += -sUSE_LIBPNG=1 -sUSE_ZLIB=1
TARGET_LIBS += -sUSE_LIBPNG=1 -sUSE_ZLIB=1
endif
endif

ifeq ($(CONFIG_LOADER_GIF), y)
Expand All @@ -116,6 +145,8 @@ libapps.a_files-$(CONFIG_DEMO_ANIMATION) += apps/animation.c
libapps.a_files-$(CONFIG_DEMO_IMAGE) += apps/image.c

libapps.a_includes-y := include
# Emscripten size optimization
libapps.a_cflags-$(CC_IS_EMCC) += -Oz

# Graphical backends

Expand All @@ -124,8 +155,15 @@ BACKEND := none
ifeq ($(CONFIG_BACKEND_SDL), y)
BACKEND = sdl
libtwin.a_files-y += backend/sdl.c
# Emscripten uses ports system for SDL2
ifneq ($(CC_IS_EMCC), 1)
libtwin.a_cflags-y += $(shell sdl2-config --cflags)
TARGET_LIBS += $(shell sdl2-config --libs)
else
# Emscripten SDL2 port - flags needed for both compile and link
libtwin.a_cflags-y += -sUSE_SDL=2
TARGET_LIBS += -sUSE_SDL=2
endif
endif

ifeq ($(CONFIG_BACKEND_FBDEV), y)
Expand All @@ -149,7 +187,6 @@ libtwin.a_files-y += backend/headless.c
endif

# Performance tester

ifeq ($(CONFIG_PERF_TEST), y)
target-$(CONFIG_PERF_TEST) += mado-perf
mado-perf_depends-y += $(target.a-y)
Expand All @@ -167,13 +204,34 @@ target-y += demo-$(BACKEND)
demo-$(BACKEND)_depends-y += $(target.a-y)
demo-$(BACKEND)_files-y = apps/main.c
demo-$(BACKEND)_includes-y := include
# Emscripten size optimization
demo-$(BACKEND)_cflags-$(CC_IS_EMCC) += -Oz
demo-$(BACKEND)_ldflags-y := \
$(target.a-y) \
$(TARGET_LIBS)

# Emscripten-specific linker flags for WebAssembly builds
ifeq ($(CC_IS_EMCC), 1)
demo-$(BACKEND)_ldflags-y += \
-sINITIAL_MEMORY=33554432 \
-sALLOW_MEMORY_GROWTH=1 \
-sSTACK_SIZE=1048576 \
-sUSE_SDL=2 \
-sMINIMAL_RUNTIME=0 \
-sDYNAMIC_EXECUTION=0 \
-sASSERTIONS=0 \
-sEXPORTED_FUNCTIONS=_main,_malloc,_free \
-sEXPORTED_RUNTIME_METHODS=ccall,cwrap \
-sNO_EXIT_RUNTIME=1 \
-Oz \
--preload-file assets \
--exclude-file assets/web
endif
endif

# Font editor tool

# Tools should not be built for WebAssembly
ifneq ($(CC_IS_EMCC), 1)
ifeq ($(CONFIG_TOOLS), y)
target-$(CONFIG_TOOL_FONTEDIT) += font-edit
font-edit_files-y = \
Expand All @@ -194,6 +252,7 @@ headless-ctl_files-y = tools/headless-ctl.c
headless-ctl_includes-y := include
headless-ctl_ldflags-y := # -lrt
endif
endif

# Build system integration

Expand Down Expand Up @@ -237,3 +296,26 @@ defconfig: $(KCONFIGLIB)
config: $(KCONFIGLIB) configs/Kconfig
@tools/kconfig/menuconfig.py configs/Kconfig
@tools/kconfig/genconfig.py configs/Kconfig

# WebAssembly post-build: Copy artifacts to assets/web/
.PHONY: wasm-install
wasm-install:
@if [ "$(CC_IS_EMCC)" = "1" ]; then \
echo "Installing WebAssembly artifacts to assets/web/..."; \
mkdir -p assets/web; \
cp -f .demo-$(BACKEND)/demo-$(BACKEND) .demo-$(BACKEND)/demo-$(BACKEND).wasm .demo-$(BACKEND)/demo-$(BACKEND).data assets/web/ 2>/dev/null || true; \
echo "✓ WebAssembly build artifacts copied to assets/web/"; \
echo ""; \
echo "\033[1;32m========================================\033[0m"; \
echo "\033[1;32mWebAssembly build complete!\033[0m"; \
echo "\033[1;32m========================================\033[0m"; \
echo ""; \
echo "To test in browser, run:"; \
echo " \033[1;34m./scripts/serve-wasm.py --open\033[0m"; \
echo ""; \
fi

# Override all target to add post-build hook for Emscripten
ifeq ($(CC_IS_EMCC), 1)
all: wasm-install
endif
63 changes: 35 additions & 28 deletions apps/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,39 @@ static void sigint_handler(int sig)
exit(1);
}

/* Initialize demo applications based on build configuration.
* Shared by both native and WebAssembly builds.
*/
static void init_demo_apps(twin_context_t *ctx)
{
twin_screen_t *screen = ctx->screen;
#if defined(CONFIG_DEMO_MULTI)
apps_multi_start(screen, "Demo", 100, 100, 400, 400);
#endif
#if defined(CONFIG_DEMO_HELLO)
apps_hello_start(screen, "Hello, World", 0, 0, 200, 200);
#endif
#if defined(CONFIG_DEMO_CLOCK)
apps_clock_start(screen, "Clock", 10, 10, 200, 200);
#endif
#if defined(CONFIG_DEMO_CALCULATOR)
apps_calc_start(screen, "Calculator", 100, 100, 200, 200);
#endif
#if defined(CONFIG_DEMO_LINE)
apps_line_start(screen, "Line", 0, 0, 200, 200);
#endif
#if defined(CONFIG_DEMO_SPLINE)
apps_spline_start(screen, "Spline", 20, 20, 400, 400);
#endif
#if defined(CONFIG_DEMO_ANIMATION)
apps_animation_start(screen, "Viewer", ASSET_PATH "nyancat.gif", 20, 20);
#endif
#if defined(CONFIG_DEMO_IMAGE)
apps_image_start(screen, "Viewer", 20, 20);
#endif
twin_screen_set_active(screen, screen->top);
}

int main(void)
{
tx = twin_create(WIDTH, HEIGHT);
Expand All @@ -106,34 +139,8 @@ int main(void)
twin_screen_set_background(
tx->screen, load_background(tx->screen, ASSET_PATH "/tux.png"));

#if defined(CONFIG_DEMO_MULTI)
apps_multi_start(tx->screen, "Demo", 100, 100, 400, 400);
#endif
#if defined(CONFIG_DEMO_HELLO)
apps_hello_start(tx->screen, "Hello, World", 0, 0, 200, 200);
#endif
#if defined(CONFIG_DEMO_CLOCK)
apps_clock_start(tx->screen, "Clock", 10, 10, 200, 200);
#endif
#if defined(CONFIG_DEMO_CALCULATOR)
apps_calc_start(tx->screen, "Calculator", 100, 100, 200, 200);
#endif
#if defined(CONFIG_DEMO_LINE)
apps_line_start(tx->screen, "Line", 0, 0, 200, 200);
#endif
#if defined(CONFIG_DEMO_SPLINE)
apps_spline_start(tx->screen, "Spline", 20, 20, 400, 400);
#endif
#if defined(CONFIG_DEMO_ANIMATION)
apps_animation_start(tx->screen, "Viewer", ASSET_PATH "nyancat.gif", 20,
20);
#endif
#if defined(CONFIG_DEMO_IMAGE)
apps_image_start(tx->screen, "Viewer", 20, 20);
#endif

twin_screen_set_active(tx->screen, tx->screen->top);
twin_dispatch(tx);
/* Start application with unified API (handles native and WebAssembly) */
twin_run(tx, init_demo_apps);

return 0;
}
4 changes: 4 additions & 0 deletions assets/web/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# WebAssembly runtime files (generated by build)
demo-sdl
demo-sdl.wasm
demo-sdl.data
Loading