Skip to content

MacOSX release build #813

MacOSX release build

MacOSX release build #813

Workflow file for this run

env:
QT_VERSION: '6.5.3'
TCL_VERSION: '8.6.17'
PYTHON_VERSION: '3.13'
ICU_VERSION: '76.1'
ICU_URL: 'https://github.com/unicode-org/icu/archive/refs/tags/release-76-1.tar.gz'
SQLITE_VERSION: '3530200'
PORTABLE_DIR: ${{ github.workspace }}/output/portable/Letos
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
name: MacOSX release build
on:
workflow_dispatch:
inputs:
use_ccache:
description: 'Use ccache (for workflow debugging only!)'
required: false
type: boolean
DEBUG:
description: 'Enable workflow debug messages'
required: false
type: boolean
default: false
debug_ssh:
description: "Open SSH tunnel at the end"
type: boolean
default: false
debug_on_failure:
description: "Open SSH tunnel if job fails"
type: boolean
default: false
schedule:
- cron: '0 3 * * 1' # run at 3 AM UTC every Monday
jobs:
build:
runs-on: macos-15
steps:
- name: Install coreutils
run: |
brew install coreutils
- name: Initial config
run: |
MACOSX_DEPLOYMENT_TARGET=11.0
echo "CFLAGS=$CFLAGS -mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET" >> $GITHUB_ENV
echo "CXXFLAGS=$CXXFLAGS -mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET" >> $GITHUB_ENV
echo "LDFLAGS=$LDFLAGS -mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET" >> $GITHUB_ENV
echo "MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET" >> $GITHUB_ENV
echo "TCL_ROOT_DIR=$(grealpath -m $GITHUB_WORKSPACE/../.cache/tcl-universal)" >> $GITHUB_ENV
echo "ICU_ROOT_DIR=$(grealpath -m $GITHUB_WORKSPACE/../.cache/icu-universal)" >> $GITHUB_ENV
- name: Cache Tcl
id: cache-tcl
uses: actions/cache@v5
with:
path: ${{ env.TCL_ROOT_DIR }}
key: tcl-${{ env.TCL_VERSION }}-macos-universal-cache-id-4
- name: Build Tcl universal
if: steps.cache-tcl.outputs.cache-hit != 'true'
run: |
if brew list tcl-tk 2>/dev/null; then
brew uninstall tcl-tk r
fi
set -euo pipefail
curl -fsSL -O https://prdownloads.sourceforge.net/tcl/tcl${TCL_VERSION}-src.tar.gz
tar xf tcl${TCL_VERSION}-src.tar.gz
cd tcl${TCL_VERSION}/unix
GLOBAL_CFLAGS=$CFLAGS
GLOBAL_LDFLAGS=$LDFLAGS
BUILD_TRIPLET="$(clang -dumpmachine)"
# arm64
CC="clang -arch arm64" \
CFLAGS="-arch arm64 $GLOBAL_CFLAGS" \
LDFLAGS="-arch arm64 $GLOBAL_LDFLAGS" \
./configure \
--build="$BUILD_TRIPLET" \
--prefix=$TCL_ROOT_DIR
make -j$(sysctl -n hw.ncpu)
make install
make distclean
# x86_64
CC="clang -arch x86_64" \
CFLAGS="-arch x86_64 $GLOBAL_CFLAGS" \
LDFLAGS="-arch x86_64 $GLOBAL_LDFLAGS" \
./configure \
--build="$BUILD_TRIPLET" \
--prefix=$PWD/build-x86_64
make -j$(sysctl -n hw.ncpu)
make install
lipo -create \
$TCL_ROOT_DIR/lib/libtcl*.dylib \
build-x86_64/lib/libtcl*.dylib \
-output $TCL_ROOT_DIR/lib/libtcl${TCL_VERSION%.*}.dylib.new
#rm $TCL_ROOT_DIR/$TCL_ROOT_DIR/lib/libtcl${TCL_VERSION%.*}.dylib
mv $TCL_ROOT_DIR/lib/libtcl${TCL_VERSION%.*}.dylib.new $TCL_ROOT_DIR/lib/libtcl${TCL_VERSION%.*}.dylib
echo "include:"
ls -l $TCL_ROOT_DIR/include
echo "lib:"
ls -l $TCL_ROOT_DIR/lib
file $TCL_ROOT_DIR/lib/libtcl*.dylib
echo "lipo archs:"
lipo -archs $TCL_ROOT_DIR/lib/libtcl*.dylib
- uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: 'arm64'
- name: Qt installation dir
id: qt-installation-dir
run: echo "DIR=$(readlink -f ${{ github.workspace }}/..)" >> $GITHUB_OUTPUT
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
cache: true
version: ${{ env.QT_VERSION }}
host: 'mac'
dir: ${{ steps.qt-installation-dir.outputs.DIR }}
setup-python: 'false'
extra: '--external 7z'
- name: Cache ICU
id: cache-icu
uses: actions/cache@v5
with:
path: ${{ env.ICU_ROOT_DIR }}
key: icu-macos-${{ env.ICU_VERSION }}-universal-cache-id-3
- name: Build ICU universal
if: steps.cache-icu.outputs.cache-hit != 'true'
shell: bash
run: |
set -euo pipefail
curl -fsSL -o icu-src.tgz "${ICU_URL}"
tar xf icu-src.tgz
cd icu-*/icu4c/source
GLOBAL_CFLAGS=$CFLAGS
GLOBAL_CXXFLAGS=$CXXFLAGS
GLOBAL_LDFLAGS=$LDFLAGS
BUILD_TRIPLET="$(clang -dumpmachine)"
echo "Triplet: $BUILD_TRIPLET"
# arm64
mkdir build-arm64 && cd build-arm64
CC="clang -arch arm64" \
CFLAGS="-arch arm64 $GLOBAL_CFLAGS" \
CXXFLAGS="-arch arm64 $GLOBAL_CXXFLAGS" \
LDFLAGS="-arch arm64 $GLOBAL_LDFLAGS" \
../configure \
--build="$BUILD_TRIPLET" \
--prefix="$PWD/install"
make -j$(sysctl -n hw.ncpu)
make install
cd ..
# x86_64
mkdir build-x86_64 && cd build-x86_64
CC="clang -arch x86_64" \
CFLAGS="-arch x86_64 $GLOBAL_CFLAGS" \
CXXFLAGS="-arch x86_64 $GLOBAL_CXXFLAGS" \
LDFLAGS="-arch x86_64 $GLOBAL_LDFLAGS" \
../configure \
--build="$BUILD_TRIPLET" \
--prefix="$PWD/install"
make -j$(sysctl -n hw.ncpu)
make install
cd ..
# assemble universal
mkdir -p "$ICU_ROOT_DIR/lib" "$ICU_ROOT_DIR/include"
cp -R build-arm64/install/include/* "$ICU_ROOT_DIR/include/"
for lib in build-arm64/install/lib/*.dylib; do
name=$(basename "$lib")
lipo -create \
"build-arm64/install/lib/$name" \
"build-x86_64/install/lib/$name" \
-output "$ICU_ROOT_DIR/lib/$name"
done
echo "ICU installed to $ICU_ROOT_DIR"
ls -l "$ICU_ROOT_DIR/include"
ls -l "$ICU_ROOT_DIR/lib"
- name: Compiler config for our source code
run: |
echo "CFLAGS=$CFLAGS -arch arm64 -arch x86_64" >> $GITHUB_ENV
echo "CXXFLAGS=$CXXFLAGS -arch arm64 -arch x86_64" >> $GITHUB_ENV
echo "LDFLAGS=-arch x86_64 -arch x86_64" >> $GITHUB_ENV
- name: Clone GH scripts
uses: actions/checkout@v6
with:
repository: pawelsalawa/gh-action-scripts
ref: main
path: gh-scripts
- name: Setup GH scripts path
shell: bash
run: |
mv gh-scripts ..
cd ..
chmod +x gh-scripts/scripts/*.sh
echo "GH_SCRIPTS=$(pwd)/gh-scripts/scripts" >> $GITHUB_ENV
echo "DEBUG=${{ inputs.DEBUG }}" >> $GITHUB_ENV
- name: Clone repo
uses: actions/checkout@v6
with:
ref: ${{ env.BRANCH_NAME }}
- name: Determine Letos version
run: |
LETOS_VERSION=$(scripts/version_from_source.sh)
echo "LETOS_VERSION=$LETOS_VERSION" >> $GITHUB_ENV
echo "PACKAGE_VERSION=${LETOS_VERSION}-macos-universal" >> $GITHUB_ENV
- name: Prepare ccache
if: inputs.use_ccache || false
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ matrix.binary_compatibility }}
max-size: "32M"
- name: Configure ccache
if: inputs.use_ccache || false
run: |
echo "PATH=/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" >> $GITHUB_ENV
- name: Install SQLite3
run: |
SQLITE_DOT_VERSION=$($GH_SCRIPTS/convert_int_ver.sh $SQLITE_VERSION)
echo "SQLITE_DOT_VERSION=$SQLITE_DOT_VERSION" >> $GITHUB_ENV
cd ..
SQLITE3_ZIP=sqlite3-macos-universal-$SQLITE_VERSION.zip
curl -L https://github.com/pawelsalawa/sqlite3-letos/releases/download/v$SQLITE_DOT_VERSION/$SQLITE3_ZIP --output $SQLITE3_ZIP
unzip $SQLITE3_ZIP libsqlite3.0.dylib sqlite3.h sqlite3ext.h -d sqlite
cd sqlite
ln -f -s libsqlite3.0.dylib libsqlite3.dylib
echo "DYLD_LIBRARY_PATH=$(pwd)" >> $GITHUB_ENV
ls -l
- name: Compile additional SQLite3 extensions
shell: bash
run: |
cd ..
mkdir ext
curl -L https://github.com/pawelsalawa/sqlite3-letos/releases/download/v$SQLITE_DOT_VERSION/sqlite3-extensions-src-$SQLITE_VERSION.zip --output sqlite3-extensions-src-$SQLITE_VERSION.zip
ls -l
mkdir ext-src
unzip sqlite3-extensions-src-$SQLITE_VERSION.zip -d ext-src
cd ext-src
ls -l
FLAGS="$CFLAGS -ldl -Os -fpic -shared -I../sqlite -L../sqlite -lsqlite3"
set -x
for f in compress sqlar; do
gcc misc/$f.c -Imisc $FLAGS -lz -o ../ext/$f.dylib
done
for f in csv decimal eval ieee754 percentile rot13 series uint uuid zorder; do
gcc misc/$f.c -Imisc $FLAGS -o ../ext/$f.dylib
done
for f in icu; do
ICU_FLAGS="-I$ICU_ROOT_DIR/include -L$ICU_ROOT_DIR/lib -licuio -licui18n -licuuc -licudata"
gcc icu/$f.c -Iicu $ICU_FLAGS $FLAGS -o ../ext/$f.dylib
done
set +x
ls -l ../ext/
- name: Prepare deps
run: |
mkdir ../lib ../include
cp $ICU_ROOT_DIR/lib/libicuio.dylib \
$ICU_ROOT_DIR/lib/libicui18n.dylib \
$ICU_ROOT_DIR/lib/libicuuc.dylib \
$ICU_ROOT_DIR/lib/libicudata.dylib \
../sqlite/libsqlite3*.dylib \
../lib
cp $TCL_ROOT_DIR/lib/libtcl*.dylib ../lib
- name: Prepare output dir
run: mkdir output output/build output/build-plugins
- name: Compile Letos
working-directory: output/build
run: |
cmake ../../Letos -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_ARCHITECTURE="x86_64;arm64" \
-DCMAKE_OSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET" \
-DCMAKE_PREFIX_PATH="$QT_ROOT_DIR" \
-DCMAKE_INSTALL_PREFIX=../Letos \
-DCUSTOM_SQLITE3=$GITHUB_WORKSPACE/../sqlite \
-DWITH_PORTABLE=1 \
-DWITH_UPDATER=1 \
-DBUILD_TESTING=0
cmake --build . --verbose
cmake --install . --verbose
- name: Compile Plugins
working-directory: output/build-plugins
run: |
cmake ../../Plugins -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_ARCHITECTURE="x86_64;arm64" \
-DCMAKE_OSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET" \
-DCMAKE_PREFIX_PATH="${{ env.QT_ROOT_DIR }}:${{ env.Python3_ROOT_DIR }}" \
-DCMAKE_INSTALL_PREFIX=../Letos \
-DCUSTOM_SQLITE3=$GITHUB_WORKSPACE/../sqlite \
-DWITH_PORTABLE=1 \
-DWITH_DYNAMIC_PYTHON=1 \
-DWITH_ALL_PLUGINS=1
cmake --build . --verbose
cmake --install . --verbose
- name: Copy SQLite extensions to output dir
shell: bash
run: |
cp -R ../ext output/Letos/Letos.app/Contents/extensions
- name: Build packages
run: |
chmod +x scripts/macos/create_macosx_bundle.sh
export DEP_LIB_DIR="$(cd ../lib && pwd)"
DEBUG_LEVEL=3 scripts/macos/create_macosx_bundle.sh output $QT_ROOT_DIR dist
- name: Determine Letos version
working-directory: output/Letos
run: |
echo "All files in boundle:"
find Letos.app
echo "Listing architecture for files."
find Letos.app -type f -name "*.dylib" -print0 | while IFS= read -r -d '' FILE; do
echo "Arch for: $FILE"
lipo -archs "$FILE"
done
echo "Arch for: Letos.app/Contents/MacOS/letos"
lipo -archs Letos.app/Contents/MacOS/letos
- name: Rename portable package
working-directory: output/Letos
run: |
mv Letos-${{ env.LETOS_VERSION }}.dmg letos-${{ env.PACKAGE_VERSION }}.dmg
- name: SHA256 checksums
shell: bash
run: |
sha256sum output/Letos/letos-${{ env.PACKAGE_VERSION }}.dmg
- name: Upload package artifact
uses: actions/upload-artifact@v7
with:
name: letos-${{ env.PACKAGE_VERSION }}.dmg
path: output/Letos/letos-${{ env.PACKAGE_VERSION }}.dmg
- name: Install Midnight Commander
if: >
${{
github.repository_owner == 'pawelsalawa'
&& (inputs.debug_ssh || (failure() && inputs.debug_on_failure))
}}
run: brew install mc
- name: Setup debugging SSH
if: >
${{
github.repository_owner == 'pawelsalawa'
&& (inputs.debug_ssh || (failure() && inputs.debug_on_failure))
}}
uses: owenthereal/action-upterm@v1
with:
wait-timeout-minutes: 10