#!/usr/bin/env bash # # crossArchive.sh -- cross-compile calog's compression/archive stack (libarchive + its 5 codecs: # zlib, bzip2, lz4, zstd, xz/liblzma) for musl (fully static Linux, zero runtime deps) and Windows # x64, using a single zig toolchain as the cross-compiler. Companion to crossBuild.sh, which proves # the core+engines+sockets; this proves the archive library, the one CMake-heavy vendored stack. # # The musl artifact is fully static and RUNS on the build host, so this script builds AND runs a # static testArchive (real round-trip through every codec). The Windows artifact is a testArchive.exe # verified as a valid PE (running it needs a Windows host or wine). # # Scope: this cross-builds libarchive + the five codecs only. The XAR format (native builds enable it # via libxml2 + OpenSSL + iconv) is NOT included here -- cross XAR would need those three cross-built # too. So XAR is a native-only feature; the cross artifacts cover every codec and the other formats. # # Requirements: zig (https://ziglang.org/download/) and cmake. Point ZIG at the binary or PATH it: # ZIG=/path/to/zig ./tools/crossArchive.sh # # Why zig for the CMake libs: xz + libarchive build out of tree with CMake. zig is wrapped as a # single-binary compiler (bin/zcc-*) so CMake sees a normal cc. The musl toolchain deliberately does # NOT set CMAKE_SYSTEM_NAME -- musl-static binaries run on this Linux host, so the build stays # "native" and CMake's try_run feature-detection works. The Windows toolchain DOES set it, so CMake # enters cross mode and skips its run-only checks (libarchive guards its one CHECK_C_SOURCE_RUNS on # CMAKE_CROSSCOMPILING; xz has none), so nothing needs pre-seeding. set -u cd "$(dirname "$0")/.." R=$(pwd) ZIG=${ZIG:-zig} X=${OUT:-build/cross} XABS="$R/$X" if ! command -v "$ZIG" >/dev/null 2>&1; then echo "error: zig not found. Set ZIG=/path/to/zig (see https://ziglang.org/download/)." >&2 exit 1 fi command -v cmake >/dev/null 2>&1 || { echo "error: cmake not found." >&2; exit 1; } ZIGABS=$(command -v "$ZIG"); ZIGABS=$(readlink -f "$ZIGABS" 2>/dev/null || echo "$ZIGABS") echo "zig: $($ZIG version)" echo "cmake: $(cmake --version | head -1)" mkdir -p "$XABS/bin" # --- single-binary compiler/archiver wrappers with the resolved zig path baked in (ephemeral) --- gen() { printf '#!/bin/sh\nexec "%s" %s "$@"\n' "$ZIGABS" "$2" > "$XABS/bin/$1"; chmod +x "$XABS/bin/$1"; } gen zcc-musl "cc -target x86_64-linux-musl" gen zcc-win "cc -target x86_64-windows-gnu" gen zar "ar" gen zranlib "ranlib" # musl toolchain: no CMAKE_SYSTEM_NAME -> native build, try_run works with static musl on the host. cat > "$XABS/toolchain-musl.cmake" < cross mode, run-only checks auto-skipped. cat > "$XABS/toolchain-win.cmake" < -- the 4 object-rule codecs (zlib needs -DHAVE_UNISTD_H so it # includes for lseek; configure normally sets that, our object-rule build must pass it). 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" || return 1; done "$XABS/bin/zar" 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" || return 1; done "$XABS/bin/zar" 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" || return 1; done "$XABS/bin/zar" 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" || return 1; done "$XABS/bin/zar" rcs "$O/lib/libzstd.a" "$O"/obj/zs_*.o } # build_cmake_libs -- xz/liblzma then libarchive, each codec backend pinned to # the just-built cross libs (headers are arch-independent -> include dirs stay the vendored source). build_cmake_libs() { local TC=$1 O=$2 cmake -S vendor/xz -B "$O/xz" -DCMAKE_TOOLCHAIN_FILE="$TC" \ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \ -DENABLE_THREADS=OFF -DENABLE_NLS=OFF -DENABLE_DOXYGEN=OFF >"$O/xz-cfg.log" 2>&1 || { echo " xz configure FAILED (see $O/xz-cfg.log)"; return 1; } cmake --build "$O/xz" --target liblzma -j >"$O/xz-build.log" 2>&1 || { echo " xz build FAILED (see $O/xz-build.log)"; return 1; } cmake -S vendor/libarchive -B "$O/libarchive" -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_ICONV=OFF -DENABLE_LIBB2=OFF \ -DENABLE_LIBXML2=OFF -DENABLE_EXPAT=OFF -DENABLE_OPENSSL=OFF \ -DENABLE_LZO=OFF -DENABLE_NETTLE=OFF -DENABLE_MBEDTLS=OFF -DENABLE_PCREPOSIX=OFF -DENABLE_PCRE2POSIX=OFF \ -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-cfg.log" 2>&1 || { echo " libarchive configure FAILED (see $O/la-cfg.log)"; return 1; } cmake --build "$O/libarchive" --target archive_static -j >"$O/la-build.log" 2>&1 || { echo " libarchive build FAILED (see $O/la-build.log)"; return 1; } } # the compression stack link line (libarchive FIRST for static link order), per target outdir. archlibs() { echo "$1/libarchive/libarchive/libarchive.a $1/xz/liblzma.a $1/lib/libzstd.a $1/lib/liblz4.a $1/lib/libbz2.a $1/lib/libz.a"; } ARCHINC="-Isrc -Isrc/lua -Ilibs -Ivendor/lua/src -Ivendor/libarchive/libarchive" echo "== musl (fully static Linux, built AND run) ==" if build_codecs "$XABS/bin/zcc-musl" "$XABS/musl" && build_cmake_libs "$XABS/toolchain-musl.cmake" "$XABS/musl"; then if "$XABS/bin/zcc-musl" -static -O2 -pthread -w $ARCHINC -DLUA_USE_POSIX \ $CORE src/lua/luaEngine.c src/lua/luaAdapter.c libs/calogArchive.c libs/calogHandle.c tests/testArchive.c \ $LUASRC $(archlibs "$XABS/musl") -lm -o "$XABS/musl/testArchive-musl" 2>"$XABS/musl/testArchive-link.err"; then if "$XABS/musl/testArchive-musl" >/dev/null 2>&1; then echo " [musl RUN ok] testArchive (libarchive + zlib/bzip2/lz4/zstd/xz, fully static)"; pass=$((pass+1)) else echo " [musl RAN, nonzero] testArchive"; fail=$((fail+1)); fi else echo " [musl LINK FAIL] testArchive (see $XABS/musl/testArchive-link.err)"; fail=$((fail+1)); fi else fail=$((fail+1)); fi echo "== Windows x64 (.exe built against vendored winpthreads; run needs wine) ==" # testArchive uses calog's pthread actor model -> needs winpthreads (vendored), like crossBuild.sh. rm -rf "$XABS/wpobj"; mkdir -p "$XABS/wpobj" "$XABS/win" wpok=1 for c in vendor/winpthreads/src/*.c; do "$XABS/bin/zcc-win" -c -O2 -w -Ivendor/winpthreads/include -Ivendor/winpthreads/src \ -DWINPTHREAD_STATIC=1 -DIN_WINPTHREAD=1 "$c" -o "$XABS/wpobj/$(basename "$c" .c).o" || { wpok=0; break; } done "$XABS/bin/zar" rcs "$XABS/win/libwinpthreads.a" "$XABS"/wpobj/*.o 2>/dev/null # libarchive on Windows uses system libs the POSIX build does not: CNG crypto (bcrypt) for its AES/ # PBKDF2, and XmlLite + OLE (xmllite/ole32) for XAR, which auto-replaces the libxml2/expat we disable. WINSYS="-lbcrypt -lxmllite -lole32 -ladvapi32 -lcrypt32 -lshlwapi" if [ "$wpok" = 1 ] && build_codecs "$XABS/bin/zcc-win" "$XABS/win" && build_cmake_libs "$XABS/toolchain-win.cmake" "$XABS/win"; then if "$XABS/bin/zcc-win" -O2 -w $ARCHINC -Ivendor/winpthreads/include -DWINPTHREAD_STATIC=1 \ $CORE src/lua/luaEngine.c src/lua/luaAdapter.c libs/calogArchive.c libs/calogHandle.c tests/testArchive.c \ $LUASRC $(archlibs "$XABS/win") "$XABS/win/libwinpthreads.a" $WINSYS -o "$XABS/win/testArchive.exe" 2>"$XABS/win/testArchive-link.err"; then if file "$XABS/win/testArchive.exe" | grep -q 'PE32+ executable'; then echo " [win BUILT] testArchive.exe (libarchive + 5 codecs, valid PE)"; pass=$((pass+1)) else echo " [win ??] testArchive.exe (not a PE?)"; fail=$((fail+1)); fi else echo " [win LINK FAIL] testArchive.exe (see $XABS/win/testArchive-link.err)"; fail=$((fail+1)); fi else fail=$((fail+1)); fi echo echo "== crossArchive: $pass ok, $fail failed (artifacts in $X/) ==" [ "$fail" -eq 0 ]