From 887aded47684d5423afe8d1753ce38167a9c850d Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Thu, 27 Aug 2026 16:47:22 +0800 Subject: [PATCH 1/3] fix: bundling of duckdb dynlib --- .github/workflows/cli-binary.yml | 11 +++++++ .github/workflows/release.yml | 16 +++++++-- scripts/notarize-local.sh | 9 +++-- scripts/verify-macos-bundle.sh | 44 +++++++++++++++++++++++++ src-tauri/build.rs | 3 ++ src-tauri/tauri.conf.json | 5 +++ src-tauri/tauri.macos-aarch64.conf.json | 9 +++++ src-tauri/tauri.macos-x86_64.conf.json | 9 +++++ 8 files changed, 102 insertions(+), 4 deletions(-) create mode 100755 scripts/verify-macos-bundle.sh create mode 100644 src-tauri/tauri.macos-aarch64.conf.json create mode 100644 src-tauri/tauri.macos-x86_64.conf.json diff --git a/.github/workflows/cli-binary.yml b/.github/workflows/cli-binary.yml index 279224b6f..be83a19bd 100644 --- a/.github/workflows/cli-binary.yml +++ b/.github/workflows/cli-binary.yml @@ -58,3 +58,14 @@ jobs: target/release/treq --help > "$RUNNER_TEMP/treq-help.txt" grep -F "Treq - Stacking ADE" "$RUNNER_TEMP/treq-help.txt" grep -F "Usage: treq" "$RUNNER_TEMP/treq-help.txt" + + - name: Build and verify packaged app without loader overrides + run: | + npm run tauri build -- --target aarch64-apple-darwin --config src-tauri/tauri.macos-aarch64.conf.json --bundles app + codesign --force --deep --sign - target/aarch64-apple-darwin/release/bundle/macos/Treq.app + bash scripts/verify-macos-bundle.sh target/aarch64-apple-darwin/release/bundle/macos/Treq.app + loader_log="$RUNNER_TEMP/treq-app-dyld.log" + env -u DYLD_LIBRARY_PATH DYLD_PRINT_LIBRARIES=1 \ + target/aarch64-apple-darwin/release/bundle/macos/Treq.app/Contents/MacOS/treq --help \ + > /dev/null 2> "$loader_log" || true + grep -F "target/aarch64-apple-darwin/release/bundle/macos/Treq.app/Contents/Frameworks/libduckdb.dylib" "$loader_log" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a4e2f9b1b..2b7c27bc7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,10 +64,12 @@ jobs: include: - platform: "macos-latest" # for Arm based macs (M1 and above). target: "aarch64-apple-darwin" - args: "--target aarch64-apple-darwin" + args: "--target aarch64-apple-darwin --config src-tauri/tauri.macos-aarch64.conf.json" + app_bundle: "target/aarch64-apple-darwin/release/bundle/macos/Treq.app" - platform: "macos-latest" # for Intel based macs. target: "x86_64-apple-darwin" - args: "--target x86_64-apple-darwin" + args: "--target x86_64-apple-darwin --config src-tauri/tauri.macos-x86_64.conf.json" + app_bundle: "target/x86_64-apple-darwin/release/bundle/macos/Treq.app" # - platform: "macos-latest" # target: "universal-apple-darwin" # args: "--target universal-apple-darwin" @@ -151,3 +153,13 @@ jobs: prerelease: false releaseAssetNamePattern: "[name]-[version]-[platform]-[arch][ext]" args: ${{ matrix.args }} + + - name: Verify packaged macOS dependencies + if: runner.os == 'macOS' + run: | + bash scripts/verify-macos-bundle.sh "${{ matrix.app_bundle }}" + loader_log="$RUNNER_TEMP/treq-dyld.log" + env -u DYLD_LIBRARY_PATH DYLD_PRINT_LIBRARIES=1 \ + "${{ matrix.app_bundle }}/Contents/MacOS/treq" --help \ + > /dev/null 2> "$loader_log" || true + grep -F "${{ matrix.app_bundle }}/Contents/Frameworks/libduckdb.dylib" "$loader_log" diff --git a/scripts/notarize-local.sh b/scripts/notarize-local.sh index c818eca7a..6434e6de8 100755 --- a/scripts/notarize-local.sh +++ b/scripts/notarize-local.sh @@ -100,9 +100,11 @@ security set-key-partition-list -S apple-tool:,apple:,codesign: \ case "$TARGET_ARCH" in arm64|aarch64) TAURI_TARGET="aarch64-apple-darwin" + TAURI_CONFIG="src-tauri/tauri.macos-aarch64.conf.json" ;; x64|x86_64) TAURI_TARGET="x86_64-apple-darwin" + TAURI_CONFIG="src-tauri/tauri.macos-x86_64.conf.json" ;; *) echo "Error: Unknown architecture $TARGET_ARCH" @@ -116,8 +118,11 @@ cd "$PROJECT_ROOT" npm run build echo "Building and signing Tauri app for $TAURI_TARGET..." -npm run tauri build -- --target "$TAURI_TARGET" +npm run tauri build -- --target "$TAURI_TARGET" --config "$TAURI_CONFIG" + +APP_BUNDLE="target/$TAURI_TARGET/release/bundle/macos/Treq.app" +bash scripts/verify-macos-bundle.sh "$APP_BUNDLE" echo "" echo "Build complete!" -echo "Output: src-tauri/target/release/bundle/macos/" +echo "Output: $APP_BUNDLE" diff --git a/scripts/verify-macos-bundle.sh b/scripts/verify-macos-bundle.sh new file mode 100755 index 000000000..3aa685e46 --- /dev/null +++ b/scripts/verify-macos-bundle.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 /path/to/Treq.app" >&2 + exit 2 +fi + +APP_BUNDLE="$1" +EXECUTABLE="$APP_BUNDLE/Contents/MacOS/treq" +DUCKDB_DYLIB="$APP_BUNDLE/Contents/Frameworks/libduckdb.dylib" +EXPECTED_RPATH="@executable_path/../Frameworks" + +if [[ ! -f "$EXECUTABLE" ]]; then + echo "Missing app executable: $EXECUTABLE" >&2 + exit 1 +fi + +if [[ ! -f "$DUCKDB_DYLIB" ]]; then + echo "Missing bundled DuckDB library: $DUCKDB_DYLIB" >&2 + exit 1 +fi + +if ! otool -L "$EXECUTABLE" | grep -Fq '@rpath/libduckdb.dylib'; then + echo "App executable does not link to @rpath/libduckdb.dylib" >&2 + exit 1 +fi + +if ! otool -l "$EXECUTABLE" | grep -A2 LC_RPATH | grep -Fq "$EXPECTED_RPATH"; then + echo "App executable is missing LC_RPATH $EXPECTED_RPATH" >&2 + exit 1 +fi + +executable_archs="$(lipo -archs "$EXECUTABLE")" +duckdb_archs="$(lipo -archs "$DUCKDB_DYLIB")" +for arch in $executable_archs; do + if [[ " $duckdb_archs " != *" $arch "* ]]; then + echo "DuckDB architectures ($duckdb_archs) do not include executable architecture $arch" >&2 + exit 1 + fi +done + +codesign --verify --deep --strict "$APP_BUNDLE" +echo "Verified macOS bundle: $APP_BUNDLE" diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 2602caf7b..a676742a9 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -1,4 +1,7 @@ fn main() { + #[cfg(target_os = "macos")] + println!("cargo:rustc-link-arg-bin=treq=-Wl,-rpath,@executable_path/../Frameworks"); + if std::env::var_os("CARGO_FEATURE_TAURI_TEST").is_some() { napi_build::setup(); } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 6d9bb05c6..2e5d223b3 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -256,6 +256,11 @@ "bundle": { "active": true, "targets": "all", + "macOS": { + "frameworks": [ + "../target/release/deps/libduckdb.dylib" + ] + }, "icon": [ "icons/32x32.png", "icons/128x128.png", diff --git a/src-tauri/tauri.macos-aarch64.conf.json b/src-tauri/tauri.macos-aarch64.conf.json new file mode 100644 index 000000000..c0f4f309c --- /dev/null +++ b/src-tauri/tauri.macos-aarch64.conf.json @@ -0,0 +1,9 @@ +{ + "bundle": { + "macOS": { + "frameworks": [ + "../target/aarch64-apple-darwin/release/deps/libduckdb.dylib" + ] + } + } +} diff --git a/src-tauri/tauri.macos-x86_64.conf.json b/src-tauri/tauri.macos-x86_64.conf.json new file mode 100644 index 000000000..33ce7524c --- /dev/null +++ b/src-tauri/tauri.macos-x86_64.conf.json @@ -0,0 +1,9 @@ +{ + "bundle": { + "macOS": { + "frameworks": [ + "../target/x86_64-apple-darwin/release/deps/libduckdb.dylib" + ] + } + } +} From ccf122631496d5581f1343d901a0edc07d8dd44a Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Thu, 27 Aug 2026 17:54:51 +0800 Subject: [PATCH 2/3] chore: fix resolving of dynlib --- src-tauri/tauri.conf.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 2e5d223b3..6d9bb05c6 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -256,11 +256,6 @@ "bundle": { "active": true, "targets": "all", - "macOS": { - "frameworks": [ - "../target/release/deps/libduckdb.dylib" - ] - }, "icon": [ "icons/32x32.png", "icons/128x128.png", From e584093fac4f98a0a1e0326042a83ba1811baa27 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Thu, 27 Aug 2026 21:45:24 +0800 Subject: [PATCH 3/3] chore: add libduckdb.so to cache --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ebff4060..82e6f78be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,8 +85,9 @@ jobs: with: path: | target/debug/libtreq_lib.so + target/debug/deps/libduckdb.so src-tauri/target/index.js - key: napi-${{ runner.os }}-${{ hashFiles('Cargo.lock', 'Cargo.toml', 'src-tauri/Cargo.toml', 'src-tauri/build.rs', 'src-tauri/src/**', 'src-tauri/tests/**', 'src-tauri/package.json', 'crates/tauri-test-macros/**') }} + key: napi-${{ runner.os }}-${{ hashFiles('.cargo/config.toml', 'Cargo.lock', 'Cargo.toml', 'src-tauri/Cargo.toml', 'src-tauri/build.rs', 'src-tauri/src/**', 'src-tauri/tests/**', 'src-tauri/package.json', 'crates/tauri-test-macros/**') }} - name: Install Rust stable # Unit JS tests never need Rust. Integration skips the toolchain when @@ -222,6 +223,7 @@ jobs: run: | npm run build:napi test -f target/debug/libtreq_lib.so + test -f target/debug/deps/libduckdb.so test -f src-tauri/target/index.js - name: Save NAPI addon cache @@ -231,6 +233,7 @@ jobs: with: path: | target/debug/libtreq_lib.so + target/debug/deps/libduckdb.so src-tauri/target/index.js key: ${{ steps.napi-cache.outputs.cache-primary-key }}