From e95580728b2587b618855d94d23134bf0f148731 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" <96995091+alinaliBQ@users.noreply.github.com> Date: Mon, 5 Oct 2026 12:06:11 -0700 Subject: [PATCH 1/4] Universal macOS PKG Installer * use lipo to merge odbc installer * Add check for archs to have both builds * Add macOS installer check --- .github/workflows/cpp_extra.yml | 104 ++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml index 45f1c01a205..800916c3c53 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -672,6 +672,13 @@ jobs: name: flight-sql-odbc-pkg-installer-${{ matrix.architecture }} path: build/cpp/ArrowFlightSQLODBC-*.pkg if-no-files-found: error + - name: Upload Intel ODBC dylib to the job + if: matrix.build-type == 'release' && matrix.architecture == 'AMD64' + uses: actions/upload-artifact@v7 + with: + name: flight-sql-odbc-dylib-${{ matrix.architecture }} + path: build/cpp/${{ matrix.build-type }}/libarrow_flight_sql_odbc.dylib + if-no-files-found: error - name: Register Flight SQL ODBC Driver run: | sudo cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh $(pwd)/build/cpp/${{ matrix.build-type }}/libarrow_flight_sql_odbc.dylib @@ -686,6 +693,101 @@ jobs: sudo chown -R $USER /Library/ODBC ci/scripts/cpp_test.sh $(pwd) $(pwd)/build + odbc-macos-universal: + needs: odbc-macos + if: needs.check-enabled.outputs.is_enabled == 'true' + name: ODBC universal macOS installer + runs-on: macos-14 + timeout-minutes: 30 + steps: + - name: Download ARM64 PKG + uses: actions/download-artifact@v8 + with: + name: flight-sql-odbc-pkg-installer-ARM64 + path: arm64-pkg + - name: Download AMD64 dylib + uses: actions/download-artifact@v8 + with: + name: flight-sql-odbc-dylib-AMD64 + path: amd64-dylib + - name: Build universal macOS installer + run: | + set -euo pipefail + + pkg_path="$(ls arm64-pkg/ArrowFlightSQLODBC-*.pkg)" + pkg_name="$(basename "${pkg_path}" .pkg)" + + # Use the ARM64 .pkg and swap in a universal ODBC dylib + # that works on ARM64 and AMD64. + pkgutil --expand-full "${pkg_path}" expanded + + dylib_path="$(find expanded -name libarrow_flight_sql_odbc.dylib)" + lipo -create "${dylib_path}" amd64-dylib/libarrow_flight_sql_odbc.dylib \ + -output "${dylib_path}" + + dylib_archs="$(lipo -archs "${dylib_path}")" + echo "Universal dylib architectures: ${dylib_archs}" + for arch in arm64 x86_64; do + if ! grep -qw "${arch}" <<< "${dylib_archs}"; then + echo "Universal dylib is missing '${arch}' (got: ${dylib_archs})" + exit 1 + fi + done + + pkgutil --flatten-full expanded "${pkg_name}.pkg" + - name: Upload universal ODBC PKG + uses: actions/upload-artifact@v7 + with: + name: flight-sql-odbc-pkg-installer-universal + path: ArrowFlightSQLODBC-*.pkg + if-no-files-found: error + + odbc-macos-universal-verify: + needs: odbc-macos-universal + if: needs.check-enabled.outputs.is_enabled == 'true' + name: ODBC universal installer verify ${{ matrix.architecture }} macOS ${{ matrix.macos-version }} + runs-on: macos-${{ matrix.macos-version }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - architecture: AMD64 + macos-version: "15-intel" + - architecture: ARM64 + macos-version: "14" + steps: + - name: Download universal PKG + uses: actions/download-artifact@v8 + with: + name: flight-sql-odbc-pkg-installer-universal + - name: Install ODBC PKG + run: | + set -euo pipefail + + pkg_path="$(ls ArrowFlightSQLODBC-*.pkg)" + sudo installer -pkg "${pkg_path}" -target / -verbose + - name: Check ODBC dylib installation + run: | + set -euo pipefail + + dylib="/Library/ODBC/arrow-odbc/lib/libarrow_flight_sql_odbc.dylib" + + if [ ! -f "${dylib}" ]; then + echo "ODBC dylib not found at ${dylib}" + exit 1 + fi + echo "Found ODBC dylib: ${dylib}" + + local_arch="$(uname -m)" + archs="$(lipo -archs "${dylib}")" + echo "Local architecture: ${local_arch}" + echo "Installed dylib architectures: ${archs}" + if ! grep -qw "${local_arch}" <<< "${archs}"; then + echo "Installed ODBC dylib does not support local architecture '${local_arch}' (got: ${archs})" + exit 1 + fi + odbc-msvc: needs: check-enabled if: needs.check-enabled.outputs.is_enabled == 'true' @@ -856,6 +958,8 @@ jobs: - msvc-arm64 - odbc-linux - odbc-macos + - odbc-macos-universal + - odbc-macos-universal-verify - odbc-msvc - odbc-nightly uses: ./.github/workflows/report_ci.yml From 63100ca311348ab895f486ee127d064d1746263e Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" <96995091+alinaliBQ@users.noreply.github.com> Date: Fri, 9 Oct 2026 13:53:34 -0700 Subject: [PATCH 2/4] Address Helder's comments - Change CI to modify the real path DYLIB file, instead of the symlink - Check all symlinks and real path for installation correctness --- .github/workflows/cpp_extra.yml | 41 +++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml index 800916c3c53..75f07d76d39 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -721,17 +721,26 @@ jobs: # that works on ARM64 and AMD64. pkgutil --expand-full "${pkg_path}" expanded - dylib_path="$(find expanded -name libarrow_flight_sql_odbc.dylib)" + # The unversioned name libarrow_flight_sql_odbc.dylib is a symlink + # to the versioned dylib that the + # install name (@rpath/libarrow_flight_sql_odbc..dylib) + # resolves to. Run lipo on the real file so the symlinks stay intact. + symlink_path="$(find expanded -name libarrow_flight_sql_odbc.dylib)" + lib_dir="$(dirname "${symlink_path}")" + dylib_path="$(realpath "${symlink_path}")" + echo "Merging into ${dylib_path} (via ${symlink_path})" lipo -create "${dylib_path}" amd64-dylib/libarrow_flight_sql_odbc.dylib \ -output "${dylib_path}" - - dylib_archs="$(lipo -archs "${dylib_path}")" - echo "Universal dylib architectures: ${dylib_archs}" - for arch in arm64 x86_64; do - if ! grep -qw "${arch}" <<< "${dylib_archs}"; then - echo "Universal dylib is missing '${arch}' (got: ${dylib_archs})" - exit 1 - fi + + for lib in "${lib_dir}"/libarrow_flight_sql_odbc*.dylib; do + dylib_archs="$(lipo -archs "${lib}")" + echo "${lib}: ${dylib_archs}" + for arch in arm64 x86_64; do + if ! grep -qw "${arch}" <<< "${dylib_archs}"; then + echo "${lib} is missing '${arch}' (got: ${dylib_archs})" + exit 1 + fi + done done pkgutil --flatten-full expanded "${pkg_name}.pkg" @@ -780,13 +789,15 @@ jobs: echo "Found ODBC dylib: ${dylib}" local_arch="$(uname -m)" - archs="$(lipo -archs "${dylib}")" echo "Local architecture: ${local_arch}" - echo "Installed dylib architectures: ${archs}" - if ! grep -qw "${local_arch}" <<< "${archs}"; then - echo "Installed ODBC dylib does not support local architecture '${local_arch}' (got: ${archs})" - exit 1 - fi + for lib in /Library/ODBC/arrow-odbc/lib/libarrow_flight_sql_odbc*.dylib; do + archs="$(lipo -archs "${lib}")" + echo "${lib}: ${archs}" + if ! grep -qw "${local_arch}" <<< "${archs}"; then + echo "${lib} does not support local architecture '${local_arch}' (got: ${archs})" + exit 1 + fi + done odbc-msvc: needs: check-enabled From 851d248aabee2c7841feb1b029a3741d9d74dc0b Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" <96995091+alinaliBQ@users.noreply.github.com> Date: Tue, 13 Oct 2026 13:24:18 -0700 Subject: [PATCH 3/4] Address Bryce's comments - bump macOS version to 26 and 26-intel Co-Authored-By: Bryce Mecum --- .github/workflows/cpp_extra.yml | 44 ++++++++++++--------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml index 75f07d76d39..1b79b8b7800 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -567,10 +567,10 @@ jobs: fail-fast: false matrix: include: - - { architecture: AMD64, macos-version: "15-intel", build-type : debug } - - { architecture: AMD64, macos-version: "15-intel", build-type : release } - - { architecture: ARM64, macos-version: "14", build-type : debug } - - { architecture: ARM64, macos-version: "14", build-type : release } + - { architecture: AMD64, macos-version: "26-intel", build-type : debug } + - { architecture: AMD64, macos-version: "26-intel", build-type : release } + - { architecture: ARM64, macos-version: "26", build-type : debug } + - { architecture: ARM64, macos-version: "26", build-type : release } env: ARROW_BUILD_TESTS: ON ARROW_BUILD_TYPE: ${{ matrix.build-type }} @@ -672,7 +672,7 @@ jobs: name: flight-sql-odbc-pkg-installer-${{ matrix.architecture }} path: build/cpp/ArrowFlightSQLODBC-*.pkg if-no-files-found: error - - name: Upload Intel ODBC dylib to the job + - name: Upload AMD64 ODBC dylib to the job if: matrix.build-type == 'release' && matrix.architecture == 'AMD64' uses: actions/upload-artifact@v7 with: @@ -695,9 +695,8 @@ jobs: odbc-macos-universal: needs: odbc-macos - if: needs.check-enabled.outputs.is_enabled == 'true' - name: ODBC universal macOS installer - runs-on: macos-14 + name: Create ODBC universal macOS installer + runs-on: macos-26 timeout-minutes: 30 steps: - name: Download ARM64 PKG @@ -731,16 +730,11 @@ jobs: echo "Merging into ${dylib_path} (via ${symlink_path})" lipo -create "${dylib_path}" amd64-dylib/libarrow_flight_sql_odbc.dylib \ -output "${dylib_path}" - + + # Verify every dylib (including the symlinks) is universal before re-packaging. for lib in "${lib_dir}"/libarrow_flight_sql_odbc*.dylib; do - dylib_archs="$(lipo -archs "${lib}")" - echo "${lib}: ${dylib_archs}" - for arch in arm64 x86_64; do - if ! grep -qw "${arch}" <<< "${dylib_archs}"; then - echo "${lib} is missing '${arch}' (got: ${dylib_archs})" - exit 1 - fi - done + echo "Checking ${lib}" + lipo "${lib}" -verify_arch arm64 x86_64 done pkgutil --flatten-full expanded "${pkg_name}.pkg" @@ -753,7 +747,6 @@ jobs: odbc-macos-universal-verify: needs: odbc-macos-universal - if: needs.check-enabled.outputs.is_enabled == 'true' name: ODBC universal installer verify ${{ matrix.architecture }} macOS ${{ matrix.macos-version }} runs-on: macos-${{ matrix.macos-version }} timeout-minutes: 30 @@ -762,9 +755,9 @@ jobs: matrix: include: - architecture: AMD64 - macos-version: "15-intel" + macos-version: "26-intel" - architecture: ARM64 - macos-version: "14" + macos-version: "26" steps: - name: Download universal PKG uses: actions/download-artifact@v8 @@ -788,15 +781,10 @@ jobs: fi echo "Found ODBC dylib: ${dylib}" - local_arch="$(uname -m)" - echo "Local architecture: ${local_arch}" + # Verify every installed dylib (including the symlinks) is universal. for lib in /Library/ODBC/arrow-odbc/lib/libarrow_flight_sql_odbc*.dylib; do - archs="$(lipo -archs "${lib}")" - echo "${lib}: ${archs}" - if ! grep -qw "${local_arch}" <<< "${archs}"; then - echo "${lib} does not support local architecture '${local_arch}' (got: ${archs})" - exit 1 - fi + echo "Checking ${lib}" + lipo "${lib}" -verify_arch arm64 x86_64 done odbc-msvc: From f5c9636e451e55dfcc34485739b254d004d54fdf Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" <96995091+alinaliBQ@users.noreply.github.com> Date: Wed, 14 Oct 2026 14:49:19 -0700 Subject: [PATCH 4/4] Verify 1 arch with lipo Verify 1 arch at a time with lipo --- .github/workflows/cpp_extra.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml index 1b79b8b7800..bf1baf022a7 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -732,9 +732,17 @@ jobs: -output "${dylib_path}" # Verify every dylib (including the symlinks) is universal before re-packaging. + # Check one architecture at a time with `lipo -archs`, + # as macOS 27 support only one architecture search at a time. for lib in "${lib_dir}"/libarrow_flight_sql_odbc*.dylib; do - echo "Checking ${lib}" - lipo "${lib}" -verify_arch arm64 x86_64 + dylib_archs="$(lipo -archs "${lib}")" + echo "${lib}: ${dylib_archs}" + for arch in arm64 x86_64; do + if ! grep -qw "${arch}" <<< "${dylib_archs}"; then + echo "${lib} is missing '${arch}' (got: ${dylib_archs})" + exit 1 + fi + done done pkgutil --flatten-full expanded "${pkg_name}.pkg" @@ -782,9 +790,15 @@ jobs: echo "Found ODBC dylib: ${dylib}" # Verify every installed dylib (including the symlinks) is universal. + local_arch="$(uname -m)" + echo "Local architecture: ${local_arch}" for lib in /Library/ODBC/arrow-odbc/lib/libarrow_flight_sql_odbc*.dylib; do - echo "Checking ${lib}" - lipo "${lib}" -verify_arch arm64 x86_64 + archs="$(lipo -archs "${lib}")" + echo "${lib}: ${archs}" + if ! grep -qw "${local_arch}" <<< "${archs}"; then + echo "${lib} does not support local architecture '${local_arch}' (got: ${archs})" + exit 1 + fi done odbc-msvc: