#!/usr/bin/env bash # crossMacFull.sh -- cross-build the FULL calog CLI as macOS Mach-O executables for BOTH # x86_64 (Intel) and arm64 (Apple Silicon) with a single zig toolchain on Linux. No Apple # SDK: zig ships a libSystem stub (libc/pthreads/BSD sockets/getaddrinfo/dlopen/iconv), which # is everything calog's OS surface needs. # # It is the Darwin sibling of tools/crossWinFull.sh. The Windows-isms are dropped: macOS has # native pthreads in libSystem (no vendored winpthreads, no -DWINPTHREAD_STATIC), the C++ # engine (Squirrel) links against zig's libc++ via the c++ driver, there is no -ldl, no Win32 # import libs, and no libpq pthread-symbol patch (libpq uses libSystem pthreads directly). The # compression/archive stack is built here per the crossArchive.sh MUSL xar recipe -- macOS is # like musl for xar: iconv is in libSystem (empty-dir ICONV_INCLUDE_DIR pin), and there is no # CommonCrypto without the Apple SDK, so xar's MD5/SHA1 come from the pinned OpenSSL. # # Per arch under build/cross// the heavy deps -- openssl-src (+openssl-repack), # libxml2, pcre2, libssh2, mariadb, tcl, mruby, postgres-build, the codecs, xz, libarchive -- are # PINNED (not rebuilt here). Rebuild them reproducibly from vendor/ source with # `./tools/crossDeps.sh mac-x64` (or mac-arm64) before running this script; that is what makes the # full cross build reproducible from a clean checkout. # This script still builds: sqlite, enet (unix.c backend), the engine VMs (lua/quickjs/squirrel/ # my-basic/berry/s7/wren/janet), and all of calog's own source, then links the complete runner. set -eu cd /home/scott/claude/calog R=/home/scott/claude/calog 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 AR="$R/build/cross/bin/zar" # macOS Keychain trust for the HTTPS client (calogHttp httpLoadMacRoots). It needs the real Apple SDK # framework headers (Security, CoreFoundation, libDER), which zig does NOT ship. When an SDK is # present, calogHttp is compiled with -DCALOG_MAC_KEYCHAIN_TRUST against those headers and linked # against the minimal tools/macStubs/*.tbd (zig's Mach-O linker segfaults on the real multi-target # SDK .tbd, so we link tiny hand-written stubs that export only the few symbols we call; the binary # still imports the real system frameworks by install-name at runtime). Without an SDK the build # omits Keychain trust and HTTPS falls back to SSL_CERT_FILE / CALOG_CA_BUNDLE. Set CALOG_MACSDK to # point at a MacOSX*.sdk directory (default: a permanent install alongside zig). MACSDK="${CALOG_MACSDK:-/home/scott/macos-sdk/MacOSX13.3.sdk}" MACTRUST="" MACTRUSTLINK="" if [ -d "$MACSDK/System/Library/Frameworks/Security.framework" ]; then MACTRUST="-DCALOG_MAC_KEYCHAIN_TRUST -F$MACSDK/System/Library/Frameworks -isystem $MACSDK/usr/include" # Link stubs (resolved to the real system libraries by install-name at runtime): the Keychain-trust # frameworks, plus libiconv, which the SDK-built libarchive references for its xar support. MACTRUSTLINK="$R/tools/macStubs/CoreFoundation.tbd $R/tools/macStubs/Security.tbd $R/tools/macStubs/libiconv.tbd" echo "[sdk] macOS Keychain trust + libarchive xar ENABLED (SDK: $MACSDK)" else echo "[sdk] macOS SDK not found at $MACSDK -- Keychain trust DISABLED (HTTPS needs SSL_CERT_FILE/CALOG_CA_BUNDLE); set CALOG_MACSDK to enable" fi # --------------------------------------------------------------------------------------------- # Helpers (compile a directory of sources into one static archive). # --------------------------------------------------------------------------------------------- mklib(){ local out=$1 cc=$2 vo=$3; shift 3; 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 "$out" "${objs[@]}"; echo " [lib] $(basename "$out")"; } # build_codecs -- zlib/bzip2/lz4/zstd object-rule codecs (zlib needs # -DHAVE_UNISTD_H for lseek, as in crossArchive.sh). build_codecs(){ local CC=$1 O=$2 c mkdir -p "$O/obj" "$O/lib" for c in vendor/zlib/*.c; do "$CC" -std=c11 -D_GNU_SOURCE -DHAVE_UNISTD_H -w -O2 -Ivendor/zlib -c "$c" -o "$O/obj/z_$(basename "$c" .c).o"; done "$AR" rcs "$O/lib/libz.a" "$O"/obj/z_*.o for c in vendor/bzip2/*.c; do "$CC" -std=c11 -D_GNU_SOURCE -w -O2 -Ivendor/bzip2 -c "$c" -o "$O/obj/bz_$(basename "$c" .c).o"; done "$AR" rcs "$O/lib/libbz2.a" "$O"/obj/bz_*.o for c in vendor/lz4/*.c; do "$CC" -std=c11 -D_GNU_SOURCE -w -O2 -Ivendor/lz4 -c "$c" -o "$O/obj/l4_$(basename "$c" .c).o"; done "$AR" rcs "$O/lib/liblz4.a" "$O"/obj/l4_*.o for c in vendor/zstd/common/*.c vendor/zstd/compress/*.c vendor/zstd/decompress/*.c; do "$CC" -std=c11 -D_GNU_SOURCE -w -O2 -DZSTD_DISABLE_ASM -Ivendor/zstd -c "$c" -o "$O/obj/zs_$(basename "$c" .c).o"; done "$AR" rcs "$O/lib/libzstd.a" "$O"/obj/zs_*.o echo " [lib] libz/libbz2/liblz4/libzstd.a"; } # build_xz -- vendored xz/liblzma via its own CMake, out of tree. build_xz(){ cmake -S vendor/xz -B "$2/xz" -DCMAKE_TOOLCHAIN_FILE="$1" \ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \ -DENABLE_THREADS=OFF -DENABLE_NLS=OFF -DENABLE_DOXYGEN=OFF >"$2/xz-cfg.log" 2>&1 cmake --build "$2/xz" --target liblzma -j >"$2/xz-build.log" 2>&1 echo " [lib] liblzma.a"; } # build_libarchive_xar -- libarchive WITH xar, exactly the crossArchive.sh # MUSL recipe but with the PINNED mac OpenSSL + libxml2. iconv comes from libSystem (empty-dir # ICONV_INCLUDE_DIR pin so FIND_PATH does not grab host glibc headers; zig resolves iconv.h). # CommonCrypto is unavailable (no Apple SDK), so OpenSSL supplies xar's MD5/SHA1. build_libarchive_xar(){ local TC=$1 O=$2 mkdir -p "$O/noinc" cmake -S vendor/libarchive -B "$O/libarchive-xar" -DCMAKE_TOOLCHAIN_FILE="$TC" \ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DENABLE_TEST=OFF -DENABLE_INSTALL=OFF \ -DENABLE_TAR=OFF -DENABLE_CPIO=OFF -DENABLE_CAT=OFF -DENABLE_UNZIP=OFF \ -DENABLE_ACL=OFF -DENABLE_XATTR=OFF -DENABLE_LIBB2=OFF \ -DENABLE_LZO=OFF -DENABLE_NETTLE=OFF -DENABLE_MBEDTLS=OFF -DENABLE_PCREPOSIX=OFF -DENABLE_PCRE2POSIX=OFF \ -DENABLE_EXPAT=OFF -DPOSIX_REGEX_LIB=NONE \ -DENABLE_ICONV=ON -DICONV_INCLUDE_DIR="$O/noinc" \ -DENABLE_LIBXML2=ON "-DLIBXML2_INCLUDE_DIR=$R/vendor/libxml2/include;$O/libxml2" -DLIBXML2_LIBRARY="$O/libxml2/libxml2.a" \ -DENABLE_OPENSSL=ON -DOPENSSL_ROOT_DIR="$O/openssl-src" -DOPENSSL_INCLUDE_DIR="$O/openssl-src/include" \ -DOPENSSL_SSL_LIBRARY="$O/openssl-repack/libssl.a" -DOPENSSL_CRYPTO_LIBRARY="$O/openssl-repack/libcrypto.a" \ -DENABLE_ZLIB=ON -DZLIB_INCLUDE_DIR="$R/vendor/zlib" -DZLIB_LIBRARY="$O/lib/libz.a" \ -DENABLE_BZip2=ON -DBZIP2_INCLUDE_DIR="$R/vendor/bzip2" -DBZIP2_LIBRARIES="$O/lib/libbz2.a" \ -DENABLE_LZMA=ON -DLIBLZMA_INCLUDE_DIR="$R/vendor/xz/src/liblzma/api" -DLIBLZMA_LIBRARY="$O/xz/liblzma.a" \ -DENABLE_ZSTD=ON -DZSTD_INCLUDE_DIR="$R/vendor/zstd" -DZSTD_LIBRARY="$O/lib/libzstd.a" \ -DENABLE_LZ4=ON -DLZ4_INCLUDE_DIR="$R/vendor/lz4" -DLZ4_LIBRARY="$O/lib/liblz4.a" \ >"$O/la-xar-cfg.log" 2>&1 cmake --build "$O/libarchive-xar" --target archive_static -j >"$O/la-xar-build.log" 2>&1 echo " [lib] libarchive.a (+xar via libxml2/openssl)"; } # ============================================================================================= # build_arch # ============================================================================================= build_arch(){ local A=$1 local CC="$R/build/cross/bin/zcc-$A" local CXX="$R/build/cross/bin/zcxx-$A" local TC="$R/build/cross/toolchain-$A.cmake" local M="$R/build/cross/$A" local LIB="$M/lib" VO="$M/vmobj" CO="$M/cobj" mkdir -p "$LIB" "$VO" "$CO" echo "==================== $A ====================" # --- 1. compression / archive stack ------------------------------------------------------- build_codecs "$CC" "$M" build_xz "$TC" "$M" build_libarchive_xar "$TC" "$M" # --- 2. engine VMs + sqlite + enet (unix.c backend on macOS, native HAS_* defines) -------- mklib "$LIB/liblua.a" "$CC" "$VO" -std=c99 -w -O2 -DLUA_USE_MACOSX -Ivendor/lua/src -- $(ls vendor/lua/src/*.c | grep -vE '/(lua|luac)\.c$') mklib "$LIB/libquickjs.a" "$CC" "$VO" -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 "$LIB/libsquirrel.a" "$CXX" "$VO" -std=c++11 -w -O1 -D_SQ64 -DSQUSEDOUBLE -Ivendor/squirrel-src/include -Ivendor/squirrel-src/squirrel -- $(ls vendor/squirrel-src/squirrel/*.cpp) mklib "$LIB/libmybasic.a" "$CC" "$VO" -std=gnu11 -w -O1 -DMB_DOUBLE_FLOAT -- vendor/ourbasic/ourBasic.c mklib "$LIB/libberry.a" "$CC" "$VO" -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 "$LIB/libs7.a" "$CC" "$VO" -std=c99 -w -O1 -D_GNU_SOURCE -Ivendor/s7 -- vendor/s7/s7.c mklib "$LIB/libwren.a" "$CC" "$VO" -std=c99 -w -O1 -Ivendor/wren -- vendor/wren/wren.c mklib "$LIB/libjanet.a" "$CC" "$VO" -std=c11 -w -O2 -DJANET_NO_NET -DJANET_NO_PROCESSES -DJANET_NO_DYNAMIC_MODULES -Ivendor/janet -- vendor/janet/janet.c mklib "$LIB/libsqlite3.a" "$CC" "$VO" -std=c11 -w -O2 -DSQLITE_THREADSAFE=1 -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_OMIT_LOAD_EXTENSION -Ivendor/sqlite -- vendor/sqlite/sqlite3.c mklib "$LIB/libenet.a" "$CC" "$VO" -std=c11 -w -O2 -D_GNU_SOURCE -DHAS_FCNTL=1 -DHAS_POLL=1 -DHAS_GETADDRINFO=1 -DHAS_GETNAMEINFO=1 -DHAS_GETHOSTBYNAME_R=1 -DHAS_GETHOSTBYADDR_R=1 -DHAS_INET_PTON=1 -DHAS_INET_NTOP=1 -DHAS_MSGHDR_FLAGS=1 -DHAS_SOCKLEN_T=1 -Ivendor/enet/include -- $(ls vendor/enet/*.c | grep -vE '/win32\.c$') # --- 3. compile calog's own objects (core + 10 engine adapters/engines + 19 libs + main) -- local INC="-Isrc -Isrc/lua -Isrc/mybasic -Isrc/squirrel -Isrc/js -Isrc/berry -Isrc/s7 -Isrc/wren -Isrc/mruby -Isrc/tcl -Isrc/janet -Ilibs" # -Wall -Wextra (not -Werror: vendored headers under clang-cross are not warning-clean) so the # macOS-only #ifdef branches of calog's own sources get compiler scrutiny they never get on Linux. local BASE="-std=c11 -Wall -Wextra -O1 -g -pthread $INC" local 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" $BASE "$@" -c "$src" -o "$CO/$out.o"; } cc broker src/broker.c cc value src/value.c cc context src/context.c cc luaEngine src/lua/luaEngine.c; cc jsEngine src/js/jsEngine.c cc squirrelEngine src/squirrel/squirrelEngine.c; cc mybasicEngine src/mybasic/mybasicEngine.c cc berryEngine src/berry/berryEngine.c; cc s7Engine src/s7/s7Engine.c cc wrenEngine src/wren/wrenEngine.c; cc mrubyEngine src/mruby/mrubyEngine.c cc tclEngine src/tcl/tclEngine.c; cc janetEngine src/janet/janetEngine.c cc luaAdapter src/lua/luaAdapter.c -Ivendor/lua/src cc jsAdapter src/js/jsAdapter.c -Ivendor/quickjs cc squirrelAdapter src/squirrel/squirrelAdapter.c -D_SQ64 -DSQUSEDOUBLE -Ivendor/squirrel-src/include cc mybasicAdapter src/mybasic/mybasicAdapter.c -Ivendor/ourbasic -DMB_DOUBLE_FLOAT cc berryAdapter src/berry/berryAdapter.c -Ivendor/berry/src -Ivendor/berry cc s7Adapter src/s7/s7Adapter.c -Ivendor/s7 cc wrenAdapter src/wren/wrenAdapter.c -Ivendor/wren cc mrubyAdapter src/mruby/mrubyAdapter.c -Ivendor/mruby/include -Ivendor/mruby/build/cross-$A/include cc tclAdapter src/tcl/tclAdapter.c -Ivendor/tcl/generic -DSTATIC_BUILD cc janetAdapter src/janet/janetAdapter.c -Ivendor/janet cc calogMain src/calogMain.c $ENGDEF cc calogArchive libs/calogArchive.c -Ivendor/libarchive/libarchive cc calogCrypto libs/calogCrypto.c -I"$M/openssl-src/include" cc calogCsv libs/calogCsv.c cc calogDbFull libs/calogDb.c -Ivendor/sqlite -Ivendor/postgres/src/interfaces/libpq -Ivendor/postgres/src/include -I"$M/postgres-build/src/include" -Ivendor/mariadb/include -I"$M/mariadb/include" -DCALOG_WITH_SQLITE -DCALOG_WITH_PG -DCALOG_WITH_MYSQL cc calogExport libs/calogExport.c cc calogFs libs/calogFs.c cc calogHttp libs/calogHttp.c -I"$M/openssl-src/include" $MACTRUST cc calogJson libs/calogJson.c cc calogKv libs/calogKv.c cc calogNet libs/calogNet.c -Ivendor/enet/include -I"$M/openssl-src/include" cc calogProc libs/calogProc.c cc calogPubsub libs/calogPubsub.c cc calogRegex libs/calogRegex.c -I"$M/pcre2" -DPCRE2_STATIC cc calogSsh libs/calogSsh.c -Ivendor/libssh2/include cc calogTask libs/calogTask.c $ENGDEF cc calogTime libs/calogTime.c cc calogTimer libs/calogTimer.c cc calogXml libs/calogXml.c -Ivendor/libxml2/include -I"$M/libxml2" -DLIBXML_STATIC cc calogHandle libs/calogHandle.c echo " [obj] all calog objects compiled" # --- 4. link the full Mach-O. C++ driver pulls zig's libc++ (Squirrel). Native pthreads, # sockets, DNS, dlopen, iconv all resolve against libSystem -- no -ldl, no sys libs. # The PG frontend archives are circular, so they go in a --start-group with the # separately-shipped fe_memutils.o (excluded from libpgcommon_shlib.a). OpenSSL is # linked from openssl-repack/ (the BSD-format __.SYMDEF archives): OpenSSL's own build # emitted GNU-format .a files under openssl-src/, which zig's Mach-O linker cannot # parse ("unknown cpu architecture"); the repack is the same objects in BSD ar form. -- local 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 $M/mruby/libmruby.a $M/tcl/libtcl9.0.a $LIB/libsqlite3.a $LIB/libenet.a" local ARCH="$M/libarchive-xar/libarchive/libarchive.a $M/libxml2/libxml2.a $M/xz/liblzma.a $LIB/libzstd.a $LIB/liblz4.a $LIB/libbz2.a $LIB/libz.a" local PG="$M/postgres-build/src/interfaces/libpq/libpq.a $M/postgres-build/src/common/libpgcommon_shlib.a $M/postgres-build/src/port/libpgport_shlib.a $M/postgres-build/src/common/fe_memutils.o" # libssh2 is built Release (-O2, no UBSan) by tools/crossDeps.sh, so no __ubsan_handle_* symbols to # resolve and NO -fsanitize=undefined at link -- matching the Windows/Linux binaries (which never # carried the UBSan runtime). If you instead use an old UBSan-instrumented libssh2.a, add # `-fsanitize=undefined` back here to pull zig's UBSan runtime. "$CXX" -O1 -g -o "$M/calog" $CO/*.o \ $VMLIBS "$M/libssh2/_build/src/libssh2.a" $ARCH "$M/pcre2/libpcre2-8.a" \ -Wl,--start-group $PG -Wl,--end-group \ "$M/mariadb/libmariadb/libmariadbclient.a" "$M/openssl-repack/libssl.a" "$M/openssl-repack/libcrypto.a" \ $MACTRUSTLINK \ -lm echo " [BIN] $M/calog" file "$M/calog" } # Build the arch(s) named on the command line, or both by default. ARCHS=("$@") [ ${#ARCHS[@]} -eq 0 ] && ARCHS=(mac-x64 mac-arm64) for a in "${ARCHS[@]}"; do build_arch "$a"; done echo "== done =="