From fc44508f9364f703d66640a7d4cb8f4ede4df752 Mon Sep 17 00:00:00 2001 From: g5fighter Date: Tue, 2 Jun 2026 11:30:28 +0200 Subject: [PATCH 1/4] ci: add diagnostics to publish workflow --- .github/workflows/publish.yml | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d6bf507..9d93037 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -142,7 +142,23 @@ jobs: echo "PKG_CONFIG_PATH_aarch64_apple_darwin=${BREW_PKGCONFIG}" >> $GITHUB_ENV echo "PKG_CONFIG_PATH_x86_64_apple_darwin=${BREW_PKGCONFIG}" >> $GITHUB_ENV + - name: Diagnostic macOS gexiv2 info + if: startsWith(matrix.platform, 'macos') + run: | + GEXIV2_PREFIX=$(brew --prefix gexiv2) + echo "=== GEXIV2 PREFIX ===" + echo "${GEXIV2_PREFIX}" + echo "=== Listing prefix contents ===" + find -L "${GEXIV2_PREFIX}" -maxdepth 3 + echo "=== File details of dylibs ===" + file ${GEXIV2_PREFIX}/lib/*.dylib + echo "=== Symbols in dylibs ===" + nm -gU ${GEXIV2_PREFIX}/lib/*.dylib || true + echo "=== pkgconfig contents ===" + cat ${GEXIV2_PREFIX}/lib/pkgconfig/*.pc || true + - name: Cache ONNX model + if: false uses: actions/cache@v4 id: model-cache with: @@ -152,13 +168,15 @@ jobs: key: convnext-onnx-${{ env.MODEL_SHA256 }} - name: Download Model Weights for Bundling - if: steps.model-cache.outputs.cache-hit != 'true' + if: false run: python download_model.py - name: Install Frontend Dependencies + if: false run: pnpm install --frozen-lockfile - name: Build & Publish Release + if: false uses: tauri-apps/tauri-action@84b9d35b5fc46c1e45415bdb6144030364f7ebc5 # v0.6.2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -169,3 +187,4 @@ jobs: releaseDraft: true prerelease: false args: ${{ matrix.args }} + From 1d2aa851ff763b2f9374a05ff7f5c19b34da0a60 Mon Sep 17 00:00:00 2001 From: g5fighter Date: Tue, 2 Jun 2026 15:39:30 +0200 Subject: [PATCH 2/4] fix(ci): define gexiv2_metadata_free shim on macOS to resolve linker error --- .github/workflows/publish.yml | 21 ++------------------- src-tauri/src/main.rs | 9 +++++++++ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9d93037..3028120 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -142,23 +142,7 @@ jobs: echo "PKG_CONFIG_PATH_aarch64_apple_darwin=${BREW_PKGCONFIG}" >> $GITHUB_ENV echo "PKG_CONFIG_PATH_x86_64_apple_darwin=${BREW_PKGCONFIG}" >> $GITHUB_ENV - - name: Diagnostic macOS gexiv2 info - if: startsWith(matrix.platform, 'macos') - run: | - GEXIV2_PREFIX=$(brew --prefix gexiv2) - echo "=== GEXIV2 PREFIX ===" - echo "${GEXIV2_PREFIX}" - echo "=== Listing prefix contents ===" - find -L "${GEXIV2_PREFIX}" -maxdepth 3 - echo "=== File details of dylibs ===" - file ${GEXIV2_PREFIX}/lib/*.dylib - echo "=== Symbols in dylibs ===" - nm -gU ${GEXIV2_PREFIX}/lib/*.dylib || true - echo "=== pkgconfig contents ===" - cat ${GEXIV2_PREFIX}/lib/pkgconfig/*.pc || true - - name: Cache ONNX model - if: false uses: actions/cache@v4 id: model-cache with: @@ -168,15 +152,13 @@ jobs: key: convnext-onnx-${{ env.MODEL_SHA256 }} - name: Download Model Weights for Bundling - if: false + if: steps.model-cache.outputs.cache-hit != 'true' run: python download_model.py - name: Install Frontend Dependencies - if: false run: pnpm install --frozen-lockfile - name: Build & Publish Release - if: false uses: tauri-apps/tauri-action@84b9d35b5fc46c1e45415bdb6144030364f7ebc5 # v0.6.2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -188,3 +170,4 @@ jobs: prerelease: false args: ${{ matrix.args }} + diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 2abccd9..491e593 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,6 +1,15 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +#[cfg(target_os = "macos")] +#[no_mangle] +pub unsafe extern "C" fn gexiv2_metadata_free(metadata: *mut std::ffi::c_void) { + extern "C" { + fn g_object_unref(object: *mut std::ffi::c_void); + } + g_object_unref(metadata); +} + fn main() { tauri_app_lib::run() } From 74bef0579276789282b4be172558e23b841a0db1 Mon Sep 17 00:00:00 2001 From: g5fighter Date: Tue, 2 Jun 2026 19:26:14 +0200 Subject: [PATCH 3/4] fix(ci): move gexiv2 shim to lib.rs and drop deprecated macos-13 runner The gexiv2_metadata_free shim must live in lib.rs, not main.rs, because Cargo builds all declared crate types (staticlib, cdylib, rlib) and macOS's linker rejects undefined symbols in cdylib targets. Placing the shim in main.rs only satisfied the final binary link, not the cdylib step. Drop macos-13 from the build matrix: Intel GitHub-hosted runners are deprecated and removed on 2026-06-16; the last run queued 24h without ever getting a runner. ARM64 binaries run on Intel Macs via Rosetta 2. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/publish.yml | 3 --- src-tauri/src/lib.rs | 11 +++++++++++ src-tauri/src/main.rs | 9 --------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3028120..1726227 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,9 +23,6 @@ jobs: - platform: 'macos-latest' # Apple Silicon (arm64) args: '--target aarch64-apple-darwin' rust_targets: 'aarch64-apple-darwin' - - platform: 'macos-13' # Intel (x86_64) — last Intel GitHub runner - args: '--target x86_64-apple-darwin' - rust_targets: 'x86_64-apple-darwin' - platform: 'ubuntu-24.04' # glibc 2.39 — required by ORT prebuilt binaries args: '' rust_targets: '' diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 534004a..47fc49e 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,5 +1,16 @@ mod tagger; +// gexiv2 0.16 (Homebrew) removed gexiv2_metadata_free; rexiv2 0.10 still calls it. +// This shim forwards to g_object_unref, which is the correct GObject cleanup path. +#[cfg(target_os = "macos")] +#[no_mangle] +pub unsafe extern "C" fn gexiv2_metadata_free(metadata: *mut std::ffi::c_void) { + extern "C" { + fn g_object_unref(object: *mut std::ffi::c_void); + } + g_object_unref(metadata); +} + use tagger::{ get_folder_depth_analysis, get_image_ai_tags, get_image_data, get_image_metadata, get_images_in_folder, get_initial_folder, get_recursive_images, get_subfolders, get_thumbnail, diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 491e593..2abccd9 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,15 +1,6 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -#[cfg(target_os = "macos")] -#[no_mangle] -pub unsafe extern "C" fn gexiv2_metadata_free(metadata: *mut std::ffi::c_void) { - extern "C" { - fn g_object_unref(object: *mut std::ffi::c_void); - } - g_object_unref(metadata); -} - fn main() { tauri_app_lib::run() } From acce5e19b05720e28d3f07306fbe39276310005f Mon Sep 17 00:00:00 2001 From: g5fighter Date: Sun, 7 Jun 2026 17:47:12 +0200 Subject: [PATCH 4/4] fix(ci): link gobject-2.0 on macOS so g_object_unref resolves The gexiv2_metadata_free shim in lib.rs calls g_object_unref, which lives in libgobject-2.0. gexiv2 lists gobject only under Requires.private, so pkg-config omits it from the dynamic link line and the symbol is left undefined at link time on macOS. Probe gobject-2.0 via pkg-config in build.rs and emit an explicit link directive, gated on the target OS. Co-Authored-By: Claude Opus 4.8 --- src-tauri/Cargo.lock | 1 + src-tauri/Cargo.toml | 1 + src-tauri/build.rs | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 38d53ff..f14fe8a 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4339,6 +4339,7 @@ dependencies = [ "image", "log", "ort", + "pkg-config", "rexiv2", "rfd", "serde", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 001243b..3af91ae 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -16,6 +16,7 @@ crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] tauri-build = { version = "2", features = [] } +pkg-config = "0.3" [dependencies] tauri = { version = "2", features = ["protocol-asset"] } diff --git a/src-tauri/build.rs b/src-tauri/build.rs index d860e1e..65c34f9 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -1,3 +1,25 @@ fn main() { + // The macOS `gexiv2_metadata_free` shim in lib.rs calls `g_object_unref`, + // which lives in libgobject-2.0. gexiv2 lists gobject only under + // Requires.private, so pkg-config omits it from the dynamic link line and + // the symbol goes unresolved. Link gobject-2.0 explicitly on macOS. + // + // Gate on the *target* OS (CARGO_CFG_TARGET_OS) rather than a cfg! attribute: + // a build script is compiled for the host, so #[cfg(target_os = ...)] here + // would reflect the host, not what we are building for. + if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("macos") { + match pkg_config::Config::new().probe("gobject-2.0") { + Ok(lib) => { + for path in lib.link_paths { + println!("cargo:rustc-link-search=native={}", path.display()); + } + } + Err(e) => { + println!("cargo:warning=pkg-config could not locate gobject-2.0: {e}"); + } + } + println!("cargo:rustc-link-lib=dylib=gobject-2.0"); + } + tauri_build::build() }