Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 5 additions & 169 deletions scripts/build-release.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail

# shellcheck source=lib/macos.sh
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/macos.sh"

# Build script for creating architecture-specific releases
# Usage: ./build-release.sh [arm64|x86_64|both]

Expand All @@ -15,171 +18,6 @@ NOTARIZE="${NOTARIZE:-false}"

echo "🏗️ Building TablePro for: $ARCH"

# Ensure libmariadb.a has correct architecture
prepare_mariadb() {
local target_arch=$1
echo "📦 Preparing libmariadb.a for $target_arch..."

# If libmariadb.a already exists with the correct architecture, skip preparation.
# CI pre-copies the architecture-specific slice from Libs via scripts/ci/prepare-libs.sh.
# Homebrew is not involved: the whole library is vendored by download-libs.sh.
if [ -f "Libs/libmariadb.a" ] && lipo -info "Libs/libmariadb.a" 2>/dev/null | grep -q "$target_arch"; then
local size
size=$(ls -lh Libs/libmariadb.a 2>/dev/null | awk '{print $5}')
echo "✅ libmariadb.a already present for $target_arch ($size), skipping"
return 0
fi

# Change to Libs directory
cd Libs || {
echo "❌ FATAL: Cannot access Libs directory"
exit 1
}

# Check if universal library exists
if [ ! -f "libmariadb_universal.a" ]; then
echo "❌ ERROR: libmariadb_universal.a not found!"
echo "Run this first to create universal library:"
echo " lipo -create libmariadb_arm64.a libmariadb_x86_64.a -output libmariadb_universal.a"
cd - > /dev/null
exit 1
fi

# Extract thin slice for target architecture
if ! lipo libmariadb_universal.a -thin "$target_arch" -output libmariadb.a; then
echo "❌ FATAL: Failed to extract $target_arch slice from universal library"
echo "Ensure the universal library contains $target_arch architecture"
cd - > /dev/null
exit 1
fi

# Verify the output file was created
if [ ! -f "libmariadb.a" ]; then
echo "❌ FATAL: libmariadb.a was not created successfully"
cd - > /dev/null
exit 1
fi

# Get and display size
local size
size=$(ls -lh libmariadb.a 2>/dev/null | awk '{print $5}')
if [ -z "$size" ]; then
size="unknown"
fi

echo "✅ libmariadb.a is now $target_arch-only ($size)"

cd - > /dev/null || exit 1
}

# Ensure libpq + OpenSSL static libraries have correct architecture
prepare_libpq() {
local target_arch=$1
echo "📦 Preparing libpq + OpenSSL static libraries for $target_arch..."

local all_ok=1
for lib in libpq libpgcommon libpgport libssl libcrypto; do
# If already present with the correct architecture, skip
if [ -f "Libs/${lib}.a" ] && lipo -info "Libs/${lib}.a" 2>/dev/null | grep -q "$target_arch"; then
continue
fi

if [ ! -f "Libs/${lib}_universal.a" ]; then
echo "❌ ERROR: Libs/${lib}_universal.a not found!"
echo "Run this first: ./scripts/build-libpq.sh both"
all_ok=0
continue
fi

if ! lipo "Libs/${lib}_universal.a" -thin "$target_arch" -output "Libs/${lib}.a"; then
echo "❌ FATAL: Failed to extract $target_arch slice from ${lib}_universal.a"
exit 1
fi
done

if [ "$all_ok" -eq 0 ]; then
exit 1
fi

echo "✅ libpq + OpenSSL libraries ready for $target_arch"
}

prepare_libmongoc() {
local target_arch=$1
echo "📦 Preparing libmongoc + libbson static libraries for $target_arch..."

local all_ok=1
for lib in libmongoc libbson; do
# If already present with the correct architecture, skip
if [ -f "Libs/${lib}.a" ] && lipo -info "Libs/${lib}.a" 2>/dev/null | grep -q "$target_arch"; then
continue
fi

# Try arch-specific file first (libmongoc_arm64.a)
if [ -f "Libs/${lib}_${target_arch}.a" ]; then
cp "Libs/${lib}_${target_arch}.a" "Libs/${lib}.a"
continue
fi

# Fall back to universal
if [ ! -f "Libs/${lib}_universal.a" ]; then
echo "❌ ERROR: Libs/${lib}_${target_arch}.a and Libs/${lib}_universal.a not found!"
echo "Run this first: ./scripts/build-libmongoc.sh both"
all_ok=0
continue
fi

if ! lipo "Libs/${lib}_universal.a" -thin "$target_arch" -output "Libs/${lib}.a"; then
echo "❌ FATAL: Failed to extract $target_arch slice from ${lib}_universal.a"
exit 1
fi
done

if [ "$all_ok" -eq 0 ]; then
exit 1
fi

echo "✅ libmongoc + libbson libraries ready for $target_arch"
}

prepare_hiredis() {
local target_arch=$1
echo "📦 Preparing hiredis static libraries for $target_arch..."

local all_ok=1
for lib in libhiredis libhiredis_ssl; do
# If already present with the correct architecture, skip
if [ -f "Libs/${lib}.a" ] && lipo -info "Libs/${lib}.a" 2>/dev/null | grep -q "$target_arch"; then
continue
fi

# Try arch-specific file first
if [ -f "Libs/${lib}_${target_arch}.a" ]; then
cp "Libs/${lib}_${target_arch}.a" "Libs/${lib}.a"
continue
fi

# Fall back to universal
if [ ! -f "Libs/${lib}_universal.a" ]; then
echo "❌ ERROR: Libs/${lib}_${target_arch}.a and Libs/${lib}_universal.a not found!"
echo "Run this first: ./scripts/build-hiredis.sh both"
all_ok=0
continue
fi

if ! lipo "Libs/${lib}_universal.a" -thin "$target_arch" -output "Libs/${lib}.a"; then
echo "❌ FATAL: Failed to extract $target_arch slice from ${lib}_universal.a"
exit 1
fi
done

if [ "$all_ok" -eq 0 ]; then
exit 1
fi

echo "✅ hiredis libraries ready for $target_arch"
}

# Bundle non-system dynamic libraries into the app bundle
# so the app runs without Homebrew on end-user machines.
bundle_dylibs() {
Expand Down Expand Up @@ -312,10 +150,8 @@ build_for_arch() {
echo "🔨 Building for $arch..."

# Prepare architecture-specific libraries
prepare_mariadb "$arch"
prepare_libpq "$arch"
prepare_libmongoc "$arch"
prepare_hiredis "$arch"
echo "📦 Preparing static libraries for $arch..."
prepare_arch_libs "$arch" libmariadb libpq libpgcommon libpgport libssl libcrypto libmongoc libbson libhiredis libhiredis_ssl

# Create OpenSSL shared dylibs for this architecture
echo "📦 Creating OpenSSL shared dylibs for $arch..."
Expand Down
44 changes: 19 additions & 25 deletions scripts/ci/prepare-libs.sh
Original file line number Diff line number Diff line change
@@ -1,32 +1,26 @@
#!/usr/bin/env bash
set -euo pipefail

ARCH="${1:-}"
# Selects the per-architecture slice of every vendored static library, so an Xcode build links the
# right one. Called by the release workflow before scripts/build-release.sh.
#
# The selection lives in scripts/lib/macos.sh and is shared with build-release.sh, which used to
# carry four near-identical copies of it. This script did a bare `cp` of the per-architecture file
# with no fallback, so the two took different sources for the same library.

# shellcheck source=../lib/macos.sh
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/macos.sh"

ARCH="${1:-}"
if [[ "$ARCH" != "arm64" && "$ARCH" != "x86_64" ]]; then
echo "Usage: $0 <arm64|x86_64>"
exit 1
echo "Usage: $0 <arm64|x86_64>" >&2
exit 1
fi

# Prepare libmariadb
echo "📦 Preparing libmariadb.a for $ARCH..."
cp "Libs/libmariadb_${ARCH}.a" "Libs/libmariadb.a"
echo "✅ libmariadb.a ready"
lipo -info Libs/libmariadb.a
ls -lh Libs/libmariadb.a

# Prepare libpq + OpenSSL
echo "📦 Preparing libpq + OpenSSL static libraries for $ARCH..."
for lib in libpq libpgcommon libpgport libssl libcrypto; do
cp "Libs/${lib}_${ARCH}.a" "Libs/${lib}.a"
done
echo "✅ libpq + OpenSSL libraries ready"
ls -lh Libs/lib{pq,pgcommon,pgport,ssl,crypto}.a

# Prepare hiredis
echo "📦 Preparing hiredis static libraries for $ARCH..."
for lib in libhiredis libhiredis_ssl; do
cp "Libs/${lib}_${ARCH}.a" "Libs/${lib}.a"
done
echo "✅ hiredis libraries ready"
ls -lh Libs/lib{hiredis,hiredis_ssl}.a
echo "📦 Preparing static libraries for $ARCH..."
prepare_arch_libs "$ARCH" \
libmariadb \
libpq libpgcommon libpgport libssl libcrypto \
libmongoc libbson \
libhiredis libhiredis_ssl
echo "✅ Static libraries ready for $ARCH"
50 changes: 50 additions & 0 deletions scripts/lib/macos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,53 @@ build_openssl() {

echo "✅ OpenSSL $arch: $(du -h "$prefix/lib/libssl.a" | cut -f1) (libssl) $(du -h "$prefix/lib/libcrypto.a" | cut -f1) (libcrypto)"
}

# Puts the named libraries in Libs/<name>.a at the requested architecture, which is what
# project.yml links.
#
# Three sources, in order: a slice that is already correct, a per-architecture file, or a thinned
# universal. This existed in five places that disagreed. build-release.sh carried four
# near-identical functions, 159 lines between them, one of which cd'd into Libs and one of which
# only ever thinned the universal; scripts/ci/prepare-libs.sh did a bare `cp` of the per-arch file
# with no fallback at all, so the two took different sources for the same library.
# The architectures in a Mach-O archive, space separated, or empty if it is not there.
current_arch() {
[ -f "$1" ] || return 0
lipo -info "$1" 2> /dev/null | sed 's/.*: //' | tr -s ' ' | sed 's/ $//'
}

prepare_arch_libs() {
local target_arch="$1"
shift
local lib unresolved=0

for lib in "$@"; do
# An exact match, not "contains". `lipo -info | grep -q arm64` also matches a universal,
# so the substring form left fat libraries in place and the release linked those instead
# of the slice it asked for.
if [ "$(current_arch "$LIBS_DIR/${lib}.a")" = "$target_arch" ]; then
continue
fi

if [ -f "$LIBS_DIR/${lib}_${target_arch}.a" ]; then
cp "$LIBS_DIR/${lib}_${target_arch}.a" "$LIBS_DIR/${lib}.a"
continue
fi

if [ ! -f "$LIBS_DIR/${lib}_universal.a" ]; then
echo "ERROR: neither $LIBS_DIR/${lib}_${target_arch}.a nor ${lib}_universal.a exists" >&2
unresolved=1
continue
fi

if ! lipo "$LIBS_DIR/${lib}_universal.a" -thin "$target_arch" -output "$LIBS_DIR/${lib}.a"; then
echo "ERROR: could not extract the $target_arch slice from ${lib}_universal.a" >&2
unresolved=1
fi
done

if [ "$unresolved" -ne 0 ]; then
echo " run scripts/download-libs.sh, or rebuild the library it names" >&2
return 1
fi
}
Loading