Moteur en WebAssembly : make engine-wasm et suite de contrat

Le moteur et engine-cli sont compilés avec Emscripten (image figée
emscripten/emsdk:3.1.64), en C générique, sans threads ; les données
de build/data/ sont incluses dans engine.data. Le JavaScript appelle
engine_init une fois puis main pour chaque commande : la sortie est le
JSON d'engine-cli, sans code de mise en forme dupliqué.

tests/test_wasm_reference.sh rejoue les 32 positions de référence sous
Node avec le même comparateur (option --cli) et la même tolérance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Pierre MARTIN
2026-11-02 19:07:01 +01:00
co-authored by Claude Opus 5.5
parent 850de27e90
commit b0030521d8
9 changed files with 265 additions and 9 deletions
+24
View File
@@ -0,0 +1,24 @@
// engine-cli.mjs -- engine-cli, mais avec le moteur WebAssembly, sous Node.
//
// Copyright (C) 2026 les auteurs d'Ustagammon.
// Licence : GPLv3 ou ultérieure (voir LICENSE).
//
// Mêmes arguments, même sortie et mêmes codes de sortie que build/engine-cli
// (voir engine-cli/main.c) : c'est le même main, compilé en WebAssembly.
// Sert à rejouer la suite de contrat sur le build WebAssembly
// (tests/test_wasm_reference.sh) :
//
// node engine-wasm/engine-cli.mjs --ply 2 reference 4HPwATDgc/ABMA cIkFAAAAAAAA 31
//
// L'option --data est ignorée : les données sont incluses dans
// build/wasm/engine.data.
import { fileURLToPath } from "node:url";
import createEngineModule from "../build/wasm/engine.mjs";
import { loadEngine } from "../web/engine-wasm.mjs";
const wasmDir = fileURLToPath(new URL("../build/wasm/", import.meta.url));
const engine = await loadEngine(createEngineModule, wasmDir);
const { text, exitCode } = engine.runText(process.argv.slice(2));
console.log(text);
process.exitCode = exitCode;
+80
View File
@@ -0,0 +1,80 @@
# wasm.mk -- compilation du moteur en WebAssembly avec Emscripten.
#
# Lancé dans l'image Docker emscripten/emsdk par `make engine-wasm` (Makefile
# racine), depuis la racine du dépôt, après `make engine` qui produit les
# données dans build/data/. Tout est produit dans build/wasm/ :
#
# engine.mjs module JavaScript (ES) qui charge le WebAssembly
# engine.wasm le moteur et engine-cli compilés : mêmes sources qu'en
# natif (engine/engine.mk), en C générique, sans threads
# engine.data les données de build/data/, chargées une fois dans le
# système de fichiers virtuel d'Emscripten, sous /data
# positions.json les positions de référence, pour la page de mesure
#
# Le JavaScript appelle engine_init une fois, puis main (celui
# d'engine-cli/main.c) pour chaque commande : voir web/engine-wasm.mjs.
BUILD := build
OUT := $(BUILD)/wasm
GNUBG := engine/gnubg
COMPAT := engine/compat
CC := emcc
include engine/sources.mk
# Mêmes options que le build natif : le moteur calcule comme en natif.
OPTIMISATION := -O3 -ffast-math -DG_DISABLE_ASSERT
OUR_WARNINGS := -std=c11 -Wall -Wextra -Werror
ENGINE_INCLUDES := -I$(COMPAT) -I$(COMPAT)/glib-shim -I$(GNUBG) -I$(GNUBG)/lib -Iengine/include
# Édition des liens :
# - module ES « createEngineModule », utilisable dans un Web Worker et sous Node ;
# - main n'est pas lancé au chargement, et le programme ne s'arrête pas à sa
# sortie : le moteur reste chargé entre deux commandes ;
# - mémoire extensible : les bases de fin de partie occupent plusieurs
# mégaoctets.
LINK_FLAGS := -O3 \
-sMODULARIZE -sEXPORT_ES6 -sEXPORT_NAME=createEngineModule \
-sENVIRONMENT=web,worker,node \
-sINVOKE_RUN=0 -sEXIT_RUNTIME=0 \
-sALLOW_MEMORY_GROWTH \
-sEXPORTED_FUNCTIONS=_main,_engine_init \
-sEXPORTED_RUNTIME_METHODS=callMain,ccall,HEAPU8 \
--preload-file $(BUILD)/data@/data
DATA := $(BUILD)/data/gnubg.wd $(BUILD)/data/gnubg_os0.bd $(BUILD)/data/gnubg_ts0.bd \
$(BUILD)/data/Kazaross-XG2.xml
OBJECTS := $(GNUBG_ENGINE:%.c=$(OUT)/obj/gnubg/%.o) \
$(OUT)/obj/compat/glib-shim.o $(OUT)/obj/compat/gnubg-support.o \
$(OUT)/obj/engine.o $(OUT)/obj/engine-cli/main.o
.PHONY: all
all: $(OUT)/engine.mjs $(OUT)/positions.json
$(OUT)/obj/gnubg/%.o: $(GNUBG)/%.c
@mkdir -p $(@D)
$(CC) $(OPTIMISATION) $(ENGINE_INCLUDES) -MMD -MP -c $< -o $@
$(OUT)/obj/compat/%.o: $(COMPAT)/%.c
@mkdir -p $(@D)
$(CC) $(OPTIMISATION) $(OUR_WARNINGS) $(ENGINE_INCLUDES) -MMD -MP -c $< -o $@
$(OUT)/obj/engine.o: engine/engine.c
@mkdir -p $(@D)
$(CC) $(OPTIMISATION) $(OUR_WARNINGS) $(ENGINE_INCLUDES) -MMD -MP -c $< -o $@
$(OUT)/obj/engine-cli/%.o: engine-cli/%.c
@mkdir -p $(@D)
$(CC) $(OPTIMISATION) $(OUR_WARNINGS) -Iengine/include -MMD -MP -c $< -o $@
# engine.wasm et engine.data sont produits en même temps qu'engine.mjs.
$(OUT)/engine.mjs: $(OBJECTS) $(DATA) engine-wasm/wasm.mk
$(CC) $(OBJECTS) $(LINK_FLAGS) -o $@
$(OUT)/positions.json: tests/reference/positions.json
@mkdir -p $(@D)
cp $< $@
-include $(shell find $(OUT) -name '*.d' 2>/dev/null)