#!/usr/bin/env bash # crossWinFull.sh -- cross-build the FULL calog CLI as a Windows PE (x86_64-windows-gnu) with zig. # # Prereqs under build/cross/win/ (pinned, NOT rebuilt here): openssl (libssl/libcrypto), libxml2, # pcre2, libssh2, mariadb, postgres (libpq+pgcommon+pgport), tcl (libtcl90), mruby (libmruby), # libarchive+codecs (xz/zstd/lz4/bz2/z), libwinpthreads. Rebuild them reproducibly from vendor/ # source with `./tools/crossDeps.sh win` before running this script -- that is what makes the full # cross build reproducible from a clean checkout. # Compilers: zcc-win / zcxx-win = `zig cc|c++ -target x86_64-windows-gnu`; zar = `zig ar`. set -eu cd /home/scott/claude/calog R=/home/scott/claude/calog CC="$R/build/cross/bin/zcc-win" CXX="$R/build/cross/bin/zcxx-win" AR="$R/build/cross/bin/zar" ZIG=${ZIG:-${CALOG_ZIG:-/home/scott/zig/current/zig}} [ -x "$ZIG" ] || { echo "error: zig not found at $ZIG. Set ZIG=/path/to/zig (a PERMANENT install, not a session/temp dir); see https://ziglang.org/download/." >&2; exit 1; } export CALOG_ZIG="$ZIG" # the build/cross/bin wrappers resolve zig via $CALOG_ZIG W=$R/build/cross/win LIB=$W/lib; VO=$W/vmobj; CO=$W/cobj mkdir -p "$LIB" "$VO" "$CO" # --------------------------------------------------------------------------------------------- # 1. Build the engine VMs + sqlite + enet (win32 backend) into static archives. # s7 needs a shim on mingw (see build/cross/win/shim/). # --------------------------------------------------------------------------------------------- mklib(){ local out=$1 cc=$2; shift 2; local fl=(); while [ "$1" != -- ]; do fl+=("$1"); shift; done; shift local objs=() s b; rm -rf "$VO/$out"; mkdir -p "$VO/$out" for s in "$@"; do b=$(basename "$s"); b=${b%.*}; "$cc" "${fl[@]}" -c "$s" -o "$VO/$out/$b.o"; objs+=("$VO/$out/$b.o"); done "$AR" rcs "$LIB/$out" "${objs[@]}"; echo " [lib] $out"; } mklib liblua.a "$CC" -std=c99 -w -O2 -Ivendor/lua/src -- $(ls vendor/lua/src/*.c | grep -vE '/(lua|luac)\.c$') mklib libquickjs.a "$CC" -std=c11 -w -O1 -D_GNU_SOURCE -Ivendor/quickjs -- vendor/quickjs/quickjs.c vendor/quickjs/libregexp.c vendor/quickjs/libunicode.c vendor/quickjs/dtoa.c mklib libsquirrel.a "$CXX" -std=c++11 -w -O1 -D_SQ64 -DSQUSEDOUBLE -Ivendor/squirrel-src/include -Ivendor/squirrel-src/squirrel -- $(ls vendor/squirrel-src/squirrel/*.cpp) mklib libmybasic.a "$CC" -std=gnu11 -w -O1 -DMB_DOUBLE_FLOAT -- vendor/ourbasic/ourBasic.c mklib libberry.a "$CC" -std=c99 -w -O1 -Ivendor/berry/src -Ivendor/berry -- $(ls vendor/berry/src/*.c) vendor/berry/default/be_port.c vendor/berry/default/be_modtab.c mklib libs7.a "$CC" -std=c99 -w -O1 -D_GNU_SOURCE -I"$W/shim" -Ivendor/s7 -- vendor/s7/s7.c mklib libwren.a "$CC" -std=c99 -w -O1 -Ivendor/wren -- vendor/wren/wren.c mklib libjanet.a "$CC" -std=c11 -w -O2 -DJANET_NO_NET -DJANET_NO_PROCESSES -DJANET_NO_DYNAMIC_MODULES -Ivendor/janet -- vendor/janet/janet.c mklib libsqlite3.a "$CC" -std=c11 -w -O2 -DSQLITE_THREADSAFE=1 -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_OMIT_LOAD_EXTENSION -Ivendor/sqlite -- vendor/sqlite/sqlite3.c mklib libenet.a "$CC" -std=c11 -w -O2 -Ivendor/enet/include -- $(ls vendor/enet/*.c | grep -vE '/unix\.c$') # --------------------------------------------------------------------------------------------- # 2. Patch the pinned libpq.a: rename its private win32 pthread emulation (pg_pthread_*) so it # stops colliding with winpthreads (ABI-incompatible pthread_mutex_t). Writes a copy; the # pinned original is left untouched. # --------------------------------------------------------------------------------------------- PW=$W/patched; rm -rf "$PW"; mkdir -p "$PW" TMP=$(mktemp -d); ( cd "$TMP" && cp "$W/postgres/lib/libpq.a" . && "$AR" x libpq.a && \ printf 'pthread_self pg_pthread_self\npthread_setspecific pg_pthread_setspecific\npthread_getspecific pg_pthread_getspecific\npthread_mutex_init pg_pthread_mutex_init\npthread_mutex_lock pg_pthread_mutex_lock\npthread_mutex_unlock pg_pthread_mutex_unlock\n' > s.txt && \ for o in *.o; do objcopy --redefine-syms=s.txt "$o" "$o.n" && mv "$o.n" "$o"; done && \ "$AR" rcs "$PW/libpq.a" *.o ); rm -rf "$TMP" echo " [patch] libpq.a pthread symbols localized -> $PW/libpq.a" # --------------------------------------------------------------------------------------------- # 3. Compile calog's own objects (core + 10 engine adapters/engines + 19 libraries + main). # --------------------------------------------------------------------------------------------- INC="-Isrc -Isrc/lua -Isrc/mybasic -Isrc/squirrel -Isrc/js -Isrc/berry -Isrc/s7 -Isrc/wren -Isrc/mruby -Isrc/tcl -Isrc/janet -Ilibs" WP="-Ivendor/winpthreads/include -DWINPTHREAD_STATIC=1" # -Wall -Wextra (not -Werror: vendored headers under clang-cross are not warning-clean) so the # Windows-only #ifdef branches of calog's own sources get compiler scrutiny they never get on Linux. BASE="-std=c11 -Wall -Wextra -O1 -g -pthread $INC $WP" ENGDEF="-DCALOG_WITH_LUA -DCALOG_WITH_JS -DCALOG_WITH_SQUIRREL -DCALOG_WITH_MYBASIC -DCALOG_WITH_BERRY -DCALOG_WITH_S7 -DCALOG_WITH_WREN -DCALOG_WITH_MRUBY -DCALOG_WITH_TCL -DCALOG_WITH_JANET" cc(){ local out=$1 src=$2; shift 2; "$CC" "$@" -c "$src" -o "$CO/$out.o"; } for f in broker value context; do cc $f src/$f.c $BASE; done cc luaEngine src/lua/luaEngine.c $BASE; cc jsEngine src/js/jsEngine.c $BASE cc squirrelEngine src/squirrel/squirrelEngine.c $BASE; cc mybasicEngine src/mybasic/mybasicEngine.c $BASE cc berryEngine src/berry/berryEngine.c $BASE; cc s7Engine src/s7/s7Engine.c $BASE cc wrenEngine src/wren/wrenEngine.c $BASE; cc mrubyEngine src/mruby/mrubyEngine.c $BASE cc tclEngine src/tcl/tclEngine.c $BASE; cc janetEngine src/janet/janetEngine.c $BASE cc luaAdapter src/lua/luaAdapter.c $BASE -Ivendor/lua/src cc jsAdapter src/js/jsAdapter.c $BASE -Ivendor/quickjs cc squirrelAdapter src/squirrel/squirrelAdapter.c $BASE -D_SQ64 -DSQUSEDOUBLE -Ivendor/squirrel-src/include cc mybasicAdapter src/mybasic/mybasicAdapter.c $BASE -Ivendor/ourbasic -DMB_DOUBLE_FLOAT cc berryAdapter src/berry/berryAdapter.c $BASE -Ivendor/berry/src -Ivendor/berry cc s7Adapter src/s7/s7Adapter.c $BASE -Ivendor/s7 cc wrenAdapter src/wren/wrenAdapter.c $BASE -Ivendor/wren cc mrubyAdapter src/mruby/mrubyAdapter.c $BASE -Ivendor/mruby/include -Ivendor/mruby/build/cross-mingw/include cc tclAdapter src/tcl/tclAdapter.c $BASE -Ivendor/tcl/generic -DSTATIC_BUILD cc janetAdapter src/janet/janetAdapter.c $BASE -Ivendor/janet cc calogMain src/calogMain.c $BASE $ENGDEF cc calogArchive libs/calogArchive.c $BASE -Ivendor/libarchive/libarchive cc calogCrypto libs/calogCrypto.c $BASE -I"$W/openssl-src/include" cc calogCsv libs/calogCsv.c $BASE cc calogDbFull libs/calogDb.c $BASE -Ivendor/sqlite -I"$W/postgres/include" -Ivendor/mariadb/include -I"$W/mariadb/include" -DCALOG_WITH_SQLITE -DCALOG_WITH_PG -DCALOG_WITH_MYSQL cc calogExport libs/calogExport.c $BASE cc calogFs libs/calogFs.c $BASE cc calogHttp libs/calogHttp.c $BASE -I"$W/openssl-src/include" cc calogJson libs/calogJson.c $BASE cc calogKv libs/calogKv.c $BASE cc calogNet libs/calogNet.c $BASE -Ivendor/enet/include -I"$W/openssl-src/include" cc calogProc libs/calogProc.c $BASE cc calogPubsub libs/calogPubsub.c $BASE cc calogRegex libs/calogRegex.c $BASE -I"$W/pcre2" -DPCRE2_STATIC cc calogSsh libs/calogSsh.c $BASE -Ivendor/libssh2/include cc calogTask libs/calogTask.c $BASE $ENGDEF cc calogTime libs/calogTime.c $BASE cc calogTimer libs/calogTimer.c $BASE cc calogXml libs/calogXml.c $BASE -Ivendor/libxml2/include -I"$W/libxml2" -DLIBXML_STATIC cc calogHandle libs/calogHandle.c $BASE echo " [obj] all calog objects compiled" # --------------------------------------------------------------------------------------------- # 4. Link the full PE. C++ driver (Squirrel) pulls zig's libc++; winpthreads static; the PG # frontend archives (+ fe_memutils.o) go in a --start-group; Win32 import libs at the end. # --------------------------------------------------------------------------------------------- VMLIBS="$LIB/liblua.a $LIB/libquickjs.a $LIB/libsquirrel.a $LIB/libmybasic.a $LIB/libberry.a $LIB/libs7.a $LIB/libwren.a $LIB/libjanet.a $W/mruby/libmruby.a $W/tcl/libtcl90.a $LIB/libsqlite3.a $LIB/libenet.a" ARCH="$W/libarchive/libarchive/libarchive.a $W/libxml2/libxml2.a $W/xz/liblzma.a $LIB/libzstd.a $LIB/liblz4.a $LIB/libbz2.a $LIB/libz.a" PG="$PW/libpq.a $W/postgres/lib/libpgcommon_shlib.a $W/postgres/lib/libpgport_shlib.a $W/postgres-build/src/common/fe_memutils.o" SYS="-lws2_32 -lwinmm -lbcrypt -lxmllite -lole32 -loleaut32 -luuid -lcrypt32 -lsecur32 -ladvapi32 -lshlwapi -luserenv -lnetapi32 -liphlpapi -luser32 -lgdi32 -lshell32 -lwldap32 -ldnsapi -lkernel32" "$CXX" -O1 -g -o "$W/calog.exe" $CO/*.o \ $VMLIBS "$W/libssh2/libssh2.a" $ARCH "$W/pcre2/libpcre2-8.a" \ -Wl,--start-group $PG -Wl,--end-group \ "$W/mariadb/libmariadb/libmariadbclient.a" "$W/openssl-src/libssl.a" "$W/openssl-src/libcrypto.a" \ "$W/libwinpthreads.a" -lm $SYS file "$W/calog.exe"