From f91c8a5dd02d3518d8ba35d348b93ea02e91ae56 Mon Sep 17 00:00:00 2001 From: Alex Kasko Date: Wed, 21 Oct 2026 08:15:54 +0100 Subject: [PATCH] Split macOS binary into arm64 and amd64 --- .github/workflows/Java.yml | 117 ++++++++++++++++++--- CMakeLists.txt | 12 ++- CMakeLists.txt.in | 12 ++- Makefile | 11 +- scripts/jdbc_maven_deploy.py | 8 +- scripts/jdbc_maven_deploy_s3.py | 5 +- src/main/java/org/duckdb/DuckDBNative.java | 12 +-- src/test/java/org/duckdb/TestNoLib.java | 2 +- 8 files changed, 139 insertions(+), 40 deletions(-) diff --git a/.github/workflows/Java.yml b/.github/workflows/Java.yml index fc51d5ba0..e5f065746 100644 --- a/.github/workflows/Java.yml +++ b/.github/workflows/Java.yml @@ -863,8 +863,8 @@ jobs: path: | build/release/duckdb_jdbc.jar - java-osx-universal: - name: macOS (Universal) + java-macos-aarch64: + name: macOS (aarch64) runs-on: ${{ github.repository_owner == 'duckdb' && 'namespace-profile-macos-arm64' || 'macos-latest' }} needs: java-linux-amd64 env: @@ -881,7 +881,7 @@ jobs: id: cache_key run: | DUCKDB_VERSION=$(python3 ./scripts/print_duckdb_version.py) - KEY="${{ runner.os }}-${{ runner.arch }}-$DUCKDB_VERSION" + KEY="${{ runner.os }}-${{ runner.arch }}-arm64-$DUCKDB_VERSION" echo "value=${KEY}" >> "${GITHUB_OUTPUT}" - name: Restore Cache @@ -915,15 +915,15 @@ jobs: - name: List Symbols run: | - nm -gU ./build/release/libduckdb_java.so_osx_universal + nm -gU ./build/release/libduckdb_java.so_macos_arm64 - name: Check jemalloc run: | - ! (nm ./build/release/libduckdb_java.so_osx_universal | grep jemalloc) || exit 1 + ! (nm ./build/release/libduckdb_java.so_macos_arm64 | grep jemalloc) || exit 1 - - name: See if this actually universal + - name: Check architecture shell: bash - run: lipo -archs build/release/libduckdb_java.so_osx_universal | grep "x86_64 arm64" + run: test "$(lipo -archs build/release/libduckdb_java.so_macos_arm64)" = "arm64" - name: Java Tests if: ${{ inputs.skip_tests != 'true' }} @@ -932,7 +932,81 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: java-osx-universal + name: java-macos-aarch64 + path: | + build/release/duckdb_jdbc.jar + + java-macos-amd64: + name: macOS (amd64) + runs-on: ${{ github.repository_owner == 'duckdb' && 'namespace-profile-macos-arm64' || 'macos-latest' }} + needs: java-linux-amd64 + env: + GEN: ninja + CC: 'ccache clang' + CXX: 'ccache clang++' + CCACHE_DIR: ${{ github.workspace }}/ccache + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Cache Key + id: cache_key + run: | + DUCKDB_VERSION=$(python3 ./scripts/print_duckdb_version.py) + KEY="${{ runner.os }}-${{ runner.arch }}-amd64-$DUCKDB_VERSION" + echo "value=${KEY}" >> "${GITHUB_OUTPUT}" + + - name: Restore Cache + uses: actions/cache/restore@v6 + with: + path: ${{ github.workspace }}/ccache + key: ${{ steps.cache_key.outputs.value }} + + - name: Install Dependencies + run: | + python3 ./scripts/retry.py --timeout 1m -- \ + brew install -q \ + ccache \ + ninja + + - name: Setup JDK + uses: actions/setup-java@v6 + with: + distribution: corretto + java-version: '8' + architecture: x64 + + - name: Build + shell: bash + run: OSX_BUILD_AMD64=1 make release + + - name: Save Cache + uses: actions/cache/save@v6 + with: + path: ${{ github.workspace }}/ccache + key: ${{ steps.cache_key.outputs.value }} + + - name: List Symbols + run: | + nm -gU ./build/release/libduckdb_java.so_macos_amd64 + + - name: Check jemalloc + run: | + ! (nm ./build/release/libduckdb_java.so_macos_amd64 | grep jemalloc) || exit 1 + + - name: Check architecture + shell: bash + run: test "$(lipo -archs build/release/libduckdb_java.so_macos_amd64)" = "x86_64" + + - name: Java Tests + if: ${{ inputs.skip_tests != 'true' }} + shell: bash + run: make test + + - uses: actions/upload-artifact@v4 + with: + name: java-macos-amd64 path: | build/release/duckdb_jdbc.jar @@ -952,7 +1026,8 @@ jobs: - java-linux-aarch64-musl - java-windows-amd64 - java-windows-aarch64 - - java-osx-universal + - java-macos-aarch64 + - java-macos-amd64 steps: - uses: actions/checkout@v7 @@ -994,8 +1069,13 @@ jobs: - uses: actions/download-artifact@v4 with: - name: java-osx-universal - path: jdbc-artifacts/java-osx-universal + name: java-macos-aarch64 + path: jdbc-artifacts/java-macos-aarch64 + + - uses: actions/download-artifact@v4 + with: + name: java-macos-amd64 + path: jdbc-artifacts/java-macos-amd64 - name: Combine JARs shell: bash @@ -1033,7 +1113,8 @@ jobs: - java-linux-aarch64-musl - java-windows-amd64 - java-windows-aarch64 - - java-osx-universal + - java-macos-aarch64 + - java-macos-amd64 steps: - uses: actions/checkout@v7 @@ -1075,8 +1156,13 @@ jobs: - uses: actions/download-artifact@v4 with: - name: java-osx-universal - path: jdbc-artifacts/java-osx-universal + name: java-macos-aarch64 + path: jdbc-artifacts/java-macos-aarch64 + + - uses: actions/download-artifact@v4 + with: + name: java-macos-amd64 + path: jdbc-artifacts/java-macos-amd64 - name: Deploy snapshot to S3 shell: bash @@ -1107,7 +1193,8 @@ jobs: - java-linux-aarch64-musl - java-windows-amd64 - java-windows-aarch64 - - java-osx-universal + - java-macos-aarch64 + - java-macos-amd64 runs-on: ${{ github.repository_owner == 'duckdb' && 'namespace-profile-linux-slim' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v7 diff --git a/CMakeLists.txt b/CMakeLists.txt index 910082e16..bd0a959c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -579,9 +579,15 @@ elseif(FORCE_32_BIT) endif() if(APPLE) - set(OS_NAME "osx") - set(OS_ARCH "universal") - SET(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "Build architectures for Mac OS X" FORCE) + set(OS_NAME "macos") + if(OSX_BUILD_AMD64) + set(OS_ARCH "amd64") + endif() + if(OS_ARCH STREQUAL "arm64") + SET(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "Build architectures for Mac OS X" FORCE) + else() + SET(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "Build architectures for Mac OS X" FORCE) + endif() endif() if(WIN32) set(OS_NAME "windows") diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in index 00f5eda26..b58eef1b9 100644 --- a/CMakeLists.txt.in +++ b/CMakeLists.txt.in @@ -67,9 +67,15 @@ elseif(FORCE_32_BIT) endif() if(APPLE) - set(OS_NAME "osx") - set(OS_ARCH "universal") - SET(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "Build architectures for Mac OS X" FORCE) + set(OS_NAME "macos") + if(OSX_BUILD_AMD64) + set(OS_ARCH "amd64") + endif() + if(OS_ARCH STREQUAL "arm64") + SET(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "Build architectures for Mac OS X" FORCE) + else() + SET(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "Build architectures for Mac OS X" FORCE) + endif() endif() if(WIN32) set(OS_NAME "windows") diff --git a/Makefile b/Makefile index 7720f21ff..d3514d9cd 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,11 @@ ifneq ($(OVERRIDE_JDBC_OS_ARCH),) OS_ARCH_OVERRIDE=-DOVERRIDE_JDBC_OS_ARCH=$(OVERRIDE_JDBC_OS_ARCH) endif +OSX_AMD64_FLAG= +ifneq ($(OSX_BUILD_AMD64),) + OSX_AMD64_FLAG=-DOSX_BUILD_AMD64=1 +endif + PERF_ROWS?=2000000 PERF_SAMPLES?=5 @@ -45,15 +50,15 @@ stress: debug: mkdir -p build/debug - cd build/debug && cmake -DCMAKE_BUILD_TYPE=Debug $(GENERATOR) $(OS_NAME_OVERRIDE) $(OS_ARCH_OVERRIDE) ../.. && cmake --build . --config Debug + cd build/debug && cmake -DCMAKE_BUILD_TYPE=Debug $(GENERATOR) $(OS_NAME_OVERRIDE) $(OS_ARCH_OVERRIDE) $(OSX_AMD64_FLAG) ../.. && cmake --build . --config Debug release: mkdir -p build/release - cd build/release && cmake -DCMAKE_BUILD_TYPE=Release $(GENERATOR) $(OS_NAME_OVERRIDE) $(OS_ARCH_OVERRIDE) ../.. && cmake --build . --config Release + cd build/release && cmake -DCMAKE_BUILD_TYPE=Release $(GENERATOR) $(OS_NAME_OVERRIDE) $(OS_ARCH_OVERRIDE) $(OSX_AMD64_FLAG) ../.. && cmake --build . --config Release sanitized: mkdir -p build/sanitized - cd build/sanitized && cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_ADDRESS_SANITIZER=ON $(GENERATOR) $(OS_NAME_OVERRIDE) $(OS_ARCH_OVERRIDE) ../.. && cmake --build . --config Release + cd build/sanitized && cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_ADDRESS_SANITIZER=ON $(GENERATOR) $(OS_NAME_OVERRIDE) $(OS_ARCH_OVERRIDE) $(OSX_AMD64_FLAG) ../.. && cmake --build . --config Release format: python3 scripts/format.py diff --git a/scripts/jdbc_maven_deploy.py b/scripts/jdbc_maven_deploy.py index 6259beb68..50173261a 100644 --- a/scripts/jdbc_maven_deploy.py +++ b/scripts/jdbc_maven_deploy.py @@ -58,13 +58,14 @@ def exec(cmd): jdbc_artifact_dir = sys.argv[2] jdbc_root_path = sys.argv[3] -combine_builds = ['linux-amd64', 'osx-universal', 'windows-amd64', 'linux-aarch64'] +combine_builds = ['linux-amd64', 'macos-aarch64', 'windows-amd64', 'linux-aarch64'] arch_specific_builds = [ 'linux-amd64', 'linux-aarch64', 'linux-amd64-musl', 'linux-aarch64-musl', - 'osx-universal', + 'macos-aarch64', + 'macos-amd64', 'windows-amd64', 'windows-aarch64', ] @@ -73,7 +74,8 @@ def exec(cmd): 'linux_arm64', 'linux_amd64_musl', 'linux_arm64_musl', - 'macos_universal', + 'macos_arm64', + 'macos_amd64', 'windows_amd64', 'windows_arm64', ] diff --git a/scripts/jdbc_maven_deploy_s3.py b/scripts/jdbc_maven_deploy_s3.py index 687a540d9..1a5d2bde6 100644 --- a/scripts/jdbc_maven_deploy_s3.py +++ b/scripts/jdbc_maven_deploy_s3.py @@ -31,14 +31,15 @@ 'java-linux-aarch64': 'linux_arm64', 'java-linux-amd64-musl': 'linux_amd64_musl', # Alpine Linux 'java-linux-aarch64-musl': 'linux_arm64_musl', # Alpine Linux ARM - 'java-osx-universal': 'macos_universal', # Intel + Apple Silicon + 'java-macos-aarch64': 'macos_arm64', # Apple Silicon + 'java-macos-amd64': 'macos_amd64', # Intel 'java-windows-amd64': 'windows_amd64', 'java-windows-aarch64': 'windows_arm64', } # Builds to combine into the main (fat) JAR. # The main JAR includes natives for all major platforms for convenience. -combine_builds = ['java-linux-amd64', 'java-osx-universal', 'java-windows-amd64', 'java-linux-aarch64'] +combine_builds = ['java-linux-amd64', 'java-macos-aarch64', 'java-windows-amd64', 'java-linux-aarch64'] def run_cmd(cmd, check=True, cwd=project_dir): """Execute a command and return output.""" diff --git a/src/main/java/org/duckdb/DuckDBNative.java b/src/main/java/org/duckdb/DuckDBNative.java index 8600d7792..1953406c6 100644 --- a/src/main/java/org/duckdb/DuckDBNative.java +++ b/src/main/java/org/duckdb/DuckDBNative.java @@ -21,10 +21,9 @@ final class DuckDBNative { private static final String ARCH_X86_64 = "amd64"; private static final String ARCH_AARCH64 = "arm64"; - private static final String ARCH_UNIVERSAL = "universal"; private static final String OS_WINDOWS = "windows"; - private static final String OS_MACOS = "osx"; + private static final String OS_MACOS = "macos"; private static final String OS_LINUX = "linux"; static { @@ -90,14 +89,7 @@ static String osName() { } static String nativeLibName() { - String os = osName(); - final String arch; - if (OS_MACOS.equals(os)) { - arch = ARCH_UNIVERSAL; - } else { - arch = cpuArch(); - } - return "libduckdb_java.so_" + os + "_" + arch; + return "libduckdb_java.so_" + osName() + "_" + cpuArch(); } static Path currentJarDir() throws Exception { diff --git a/src/test/java/org/duckdb/TestNoLib.java b/src/test/java/org/duckdb/TestNoLib.java index 0c3c6bc49..2df9a5fca 100644 --- a/src/test/java/org/duckdb/TestNoLib.java +++ b/src/test/java/org/duckdb/TestNoLib.java @@ -37,7 +37,7 @@ private static String platformLibName() throws Exception { switch (os) { case "windows": return "duckdb_java.dll"; - case "osx": + case "macos": return "libduckdb_java.dylib"; case "linux": return "libduckdb_java.so";