feat(runtime): native platform backends and UI vessels onto main
This commit is contained in:
Executable
+135
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env bash
|
||||
# build-win32.sh — Cross-compile native-hello for Windows using mingw64.
|
||||
#
|
||||
# Requirements:
|
||||
# - x86_64-w64-mingw32-gcc (brew install mingw-w64)
|
||||
# - elc in PATH or at ../../../lang/dist/platform/elc
|
||||
#
|
||||
# Output: build-win32/native-hello.exe
|
||||
#
|
||||
# Note: We use el_runtime_win32.c instead of el_runtime.c / el_seed.c because
|
||||
# those files have deep POSIX dependencies (pthread, curl, dlfcn, sys/socket,
|
||||
# etc.) that cannot be cross-compiled to Windows. el_runtime_win32.c provides
|
||||
# all the runtime symbols that native-hello and the el-native vessel actually
|
||||
# call, using only standard C11 + Win32 APIs.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
EL_LANG_ROOT="${SCRIPT_DIR}/../../../lang"
|
||||
EL_UI_ROOT="${SCRIPT_DIR}/../.."
|
||||
EL_RUNTIME="${EL_LANG_ROOT}/el-compiler/runtime"
|
||||
EL_NATIVE_VESSEL="${EL_UI_ROOT}/vessels/el-native/src/main.el"
|
||||
BUILD_DIR="${SCRIPT_DIR}/build-win32"
|
||||
|
||||
# ── Locate elc ───────────────────────────────────────────────────────────────
|
||||
if command -v elc &>/dev/null; then
|
||||
ELC="elc"
|
||||
elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then
|
||||
ELC="${EL_LANG_ROOT}/dist/platform/elc"
|
||||
else
|
||||
echo "Error: elc not found. Add it to PATH or place it at:"
|
||||
echo " ${EL_LANG_ROOT}/dist/platform/elc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CC="x86_64-w64-mingw32-gcc"
|
||||
|
||||
# -D_WIN32_IE for SetWindowSubclass (comctl32 >= IE 0x0600)
|
||||
CFLAGS=(
|
||||
-std=c11
|
||||
-DEL_TARGET_WIN32
|
||||
-D_WIN32_IE=0x0600
|
||||
-I"${EL_RUNTIME}"
|
||||
-Wall
|
||||
-Wno-unused-function
|
||||
)
|
||||
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
|
||||
# ── 1. Compile el-native vessel to C ─────────────────────────────────────────
|
||||
echo "==> Compiling el-native vessel to C..."
|
||||
"${ELC}" "${EL_NATIVE_VESSEL}" \
|
||||
> "${BUILD_DIR}/el_native_vessel.c"
|
||||
|
||||
# ── 2. Generate vessel header (declarations only) ────────────────────────────
|
||||
# elc --emit-header includes function bodies AND bare global variable definitions.
|
||||
# We extract only forward declarations with two awk passes:
|
||||
# Pass 1: stop before function bodies (same as macOS build.sh).
|
||||
# Pass 2: convert bare global variable definitions (^el_val_t NAME;) to
|
||||
# `extern el_val_t NAME;` so the app TU sees them as declarations,
|
||||
# not definitions — avoiding duplicate symbol errors at link time.
|
||||
echo "==> Generating el-native vessel header (declarations only)..."
|
||||
"${ELC}" --emit-header "${EL_NATIVE_VESSEL}" \
|
||||
| awk 'BEGIN{in_body=0} /^[a-zA-Z_].+\)[[:space:]]*\{/ {in_body=1} !in_body{print}' \
|
||||
| awk '/^el_val_t [A-Za-z_][A-Za-z0-9_]*;/{print "extern " $0; next} {print}' \
|
||||
> "${BUILD_DIR}/el_native_vessel.h"
|
||||
|
||||
# ── 3. Compile app entry to C ─────────────────────────────────────────────────
|
||||
echo "==> Compiling app entry to C..."
|
||||
EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \
|
||||
"${ELC}" "${SCRIPT_DIR}/src/main.el" \
|
||||
> "${BUILD_DIR}/native_hello.c"
|
||||
|
||||
# ── 4. Compile el_win32.c ─────────────────────────────────────────────────────
|
||||
echo "==> Compiling el_win32.c (Win32 widget bridge)..."
|
||||
${CC} "${CFLAGS[@]}" \
|
||||
-c "${EL_RUNTIME}/el_win32.c" \
|
||||
-o "${BUILD_DIR}/el_win32.o"
|
||||
|
||||
# ── 5. Compile el_runtime_win32.c ─────────────────────────────────────────────
|
||||
# This replaces el_seed.c + el_runtime.c for Win32 targets.
|
||||
echo "==> Compiling el_runtime_win32.c (Win32 runtime stub)..."
|
||||
${CC} "${CFLAGS[@]}" \
|
||||
-c "${EL_RUNTIME}/el_runtime_win32.c" \
|
||||
-o "${BUILD_DIR}/el_runtime_win32.o"
|
||||
|
||||
# ── 6. Compile el-native vessel object ───────────────────────────────────────
|
||||
echo "==> Compiling el-native vessel object..."
|
||||
${CC} "${CFLAGS[@]}" \
|
||||
-include "${EL_RUNTIME}/el_native_target.h" \
|
||||
-c "${BUILD_DIR}/el_native_vessel.c" \
|
||||
-o "${BUILD_DIR}/el_native_vessel.o"
|
||||
|
||||
echo "==> Patching el_native_vessel.o (localising vessel main + shared globals)..."
|
||||
# The vessel's compiled C has its own main(). We localize it so the linker sees
|
||||
# only the app's main(). We also localize any globals (TOKEN_*, etc.) that the
|
||||
# vessel defines but the app also declares — matching the nmedit step in
|
||||
# build.sh (macOS), using objcopy for mingw.
|
||||
VESSEL_LOCAL_SYMS=()
|
||||
# Collect all defined (T and D/B/C) symbols in the vessel object
|
||||
while IFS= read -r sym; do
|
||||
VESSEL_LOCAL_SYMS+=("--localize-symbol=${sym}")
|
||||
done < <(x86_64-w64-mingw32-nm "${BUILD_DIR}/el_native_vessel.o" 2>/dev/null \
|
||||
| awk '/^[0-9a-f]+ [TDBCt] /{print $3}' \
|
||||
| grep -E '^(main|TOKEN_)' || true)
|
||||
if [ ${#VESSEL_LOCAL_SYMS[@]} -gt 0 ]; then
|
||||
x86_64-w64-mingw32-objcopy "${VESSEL_LOCAL_SYMS[@]}" \
|
||||
"${BUILD_DIR}/el_native_vessel.o"
|
||||
fi
|
||||
|
||||
# ── 7. Compile app object ─────────────────────────────────────────────────────
|
||||
echo "==> Compiling app object..."
|
||||
${CC} "${CFLAGS[@]}" \
|
||||
-include "${EL_RUNTIME}/el_native_target.h" \
|
||||
-include "${BUILD_DIR}/el_native_vessel.h" \
|
||||
-c "${BUILD_DIR}/native_hello.c" \
|
||||
-o "${BUILD_DIR}/native_hello.o"
|
||||
|
||||
# ── 8. Link ───────────────────────────────────────────────────────────────────
|
||||
# -Wl,--export-all-symbols: make el callback functions (on_greet_click etc.)
|
||||
# visible to GetProcAddress(GetModuleHandle(NULL), fn_name) — the Win32
|
||||
# equivalent of POSIX dlsym(RTLD_DEFAULT, fn_name).
|
||||
echo "==> Linking native-hello.exe..."
|
||||
${CC} "${CFLAGS[@]}" \
|
||||
-Wl,--export-all-symbols \
|
||||
"${BUILD_DIR}/native_hello.o" \
|
||||
"${BUILD_DIR}/el_native_vessel.o" \
|
||||
"${BUILD_DIR}/el_win32.o" \
|
||||
"${BUILD_DIR}/el_runtime_win32.o" \
|
||||
-lcomctl32 -luser32 -lgdi32 -lkernel32 \
|
||||
-o "${BUILD_DIR}/native-hello.exe"
|
||||
|
||||
echo ""
|
||||
echo "==> Built: ${BUILD_DIR}/native-hello.exe"
|
||||
ls -lh "${BUILD_DIR}/native-hello.exe"
|
||||
Reference in New Issue
Block a user