From a7af73988c7a964ca7afd4b5dfb52c0317cab354 Mon Sep 17 00:00:00 2001 From: GoodNotesCI Date: Wed, 15 Jul 2026 19:52:12 +0800 Subject: [PATCH 1/8] Fix XCFramework CI build after upstream merge Two changes to restore CI compatibility after the upstream merge brought in a refactored build_apple_framework.py: 1. Replace `pip install -r requirements-dev.txt` with `pip install -r ios_packaging/requirements.txt` (just flatbuffers). The full dev requirements include clang-format and other heavy packages that are not needed for framework builds and can fail on newer macOS runners. 2. Introduce goodnotes_maccatalyst_build_settings.json, a GoodNotes-specific settings file separate from the upstream default_full_ios_framework_build_settings.json. This lets us maintain our own settings (e.g. FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER for macabi to prevent CMake from picking up incompatible Homebrew packages on GitHub-hosted runners) without conflicting with future upstream merges. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../generate-xcframework-maccatalyst.yml | 4 +- .../goodnotes_maccatalyst_build_settings.json | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json diff --git a/.github/workflows/generate-xcframework-maccatalyst.yml b/.github/workflows/generate-xcframework-maccatalyst.yml index 4106fe3a33187..07f46229cd22d 100644 --- a/.github/workflows/generate-xcframework-maccatalyst.yml +++ b/.github/workflows/generate-xcframework-maccatalyst.yml @@ -95,11 +95,11 @@ jobs: run: | set -euxo pipefail export PYTHONPATH="${{ github.workspace }}/tools/python:${PYTHONPATH:-}" - pip install -r ${{ github.workspace }}/requirements-dev.txt + pip install -r ${{ github.workspace }}/tools/ci_build/github/apple/ios_packaging/requirements.txt for attempt in 1 2 3; do if python3 ${{ github.workspace }}/tools/ci_build/github/apple/build_apple_framework.py --config Release ${{ matrix.build_dynamic_flag }} --build_dir=$HOME/onnxlibrary/${{ matrix.build_dir_name }} \ --include_ops_by_config=${{ github.workspace }}/tools/ci_build/github/apple/hws_mobile_package.required_operators.config \ - ${{ github.workspace }}/tools/ci_build/github/apple/default_full_ios_framework_build_settings.json; then + ${{ github.workspace }}/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json; then break fi diff --git a/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json b/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json new file mode 100644 index 0000000000000..7ef80cc2e9333 --- /dev/null +++ b/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json @@ -0,0 +1,42 @@ +{ + "build_osx_archs": { + "iphoneos": [ + "arm64" + ], + "iphonesimulator": [ + "arm64", + "x86_64" + ], + "macabi": [ + "arm64", + "x86_64" + ] + }, + "build_params": { + "base": [ + "--parallel", + "--build_apple_framework", + "--use_coreml", + "--skip_tests", + "--no_kleidiai", + "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF" + ], + "iphoneos": [ + "--ios", + "--use_xcode", + "--use_xnnpack", + "--apple_deploy_target=15.1" + ], + "iphonesimulator": [ + "--ios", + "--use_xcode", + "--use_xnnpack", + "--apple_deploy_target=15.1" + ], + "macabi": [ + "--macos=Catalyst", + "--apple_deploy_target=14.0", + "--cmake_extra_defines=FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER" + ] + } +} From d30cf6439644122adfcee61a6fdc476812640ed8 Mon Sep 17 00:00:00 2001 From: GoodNotesCI Date: Wed, 15 Jul 2026 20:05:07 +0800 Subject: [PATCH 2/8] Add maintenance comment for goodnotes_maccatalyst_build_settings.json Explains why the file exists and what to check when syncing upstream changes to default_full_ios_framework_build_settings.json. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .github/workflows/generate-xcframework-maccatalyst.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/generate-xcframework-maccatalyst.yml b/.github/workflows/generate-xcframework-maccatalyst.yml index 07f46229cd22d..27293b7676484 100644 --- a/.github/workflows/generate-xcframework-maccatalyst.yml +++ b/.github/workflows/generate-xcframework-maccatalyst.yml @@ -90,6 +90,15 @@ jobs: # --include_ops_by_config=${{ github.workspace }}/tools/ci_build/github/apple/hws_mobile_package.required_operators.config \ # --path_to_protoc_exe=/usr/local/bin/protoc-3.21.12.0 ${{ github.workspace }}/tools/ci_build/github/apple/hws_mobile_package.required_operators.config + # goodnotes_maccatalyst_build_settings.json is a GoodNotes-owned file that + # extends the upstream default_full_ios_framework_build_settings.json. + # It is kept separate to avoid merge conflicts on every upstream sync. + # + # When syncing upstream, check if default_full_ios_framework_build_settings.json + # changed (e.g. new platforms, updated deploy targets, new flags) and mirror + # those changes here, preserving the GoodNotes-specific additions: + # - macabi: FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER + # (prevents CMake from using incompatible Homebrew packages on GitHub runners) - name: create ${{ matrix.variant }} release build shell: bash run: | From f6e5d2b12398d7f1a9068a85ab02636a52fa15fa Mon Sep 17 00:00:00 2001 From: GoodNotesCI Date: Wed, 15 Jul 2026 20:21:05 +0800 Subject: [PATCH 3/8] Add CMAKE_POLICY_VERSION_MINIMUM=3.5 to fix CMake 4.x compat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GitHub-hosted macOS runners have CMake 4.x installed via Homebrew. CMake 4 removed compatibility with cmake_minimum_required values < 3.5, so the psimd dependency (pulled in transitively by XNNPACK → pthreadpool) fails with: Compatibility with CMake < 3.5 has been removed from CMake. Adding CMAKE_POLICY_VERSION_MINIMUM=3.5 tells CMake to accept these old sub-project declarations, which is what the original GoodNotes settings had before the upstream merge overwrote the file. Also document this flag (and the macabi FETCHCONTENT flag) in the workflow comment so future syncs know to preserve both. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .github/workflows/generate-xcframework-maccatalyst.yml | 3 +++ .../github/apple/goodnotes_maccatalyst_build_settings.json | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/generate-xcframework-maccatalyst.yml b/.github/workflows/generate-xcframework-maccatalyst.yml index 27293b7676484..509dcc88600a3 100644 --- a/.github/workflows/generate-xcframework-maccatalyst.yml +++ b/.github/workflows/generate-xcframework-maccatalyst.yml @@ -97,6 +97,9 @@ jobs: # When syncing upstream, check if default_full_ios_framework_build_settings.json # changed (e.g. new platforms, updated deploy targets, new flags) and mirror # those changes here, preserving the GoodNotes-specific additions: + # - base: CMAKE_POLICY_VERSION_MINIMUM=3.5 + # (GitHub runners have CMake 4.x from Homebrew; some transitive deps such as + # psimd have cmake_minimum_required < 3.5 which CMake 4 rejects without this) # - macabi: FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER # (prevents CMake from using incompatible Homebrew packages on GitHub runners) - name: create ${{ matrix.variant }} release build diff --git a/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json b/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json index 7ef80cc2e9333..8cb539ef07c6c 100644 --- a/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json +++ b/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json @@ -19,7 +19,8 @@ "--use_coreml", "--skip_tests", "--no_kleidiai", - "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF" + "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF", + "--cmake_extra_defines=CMAKE_POLICY_VERSION_MINIMUM=3.5" ], "iphoneos": [ "--ios", From a42b5266c76df5d38adf651353d2340c1f37e4e5 Mon Sep 17 00:00:00 2001 From: GoodNotesCI Date: Wed, 15 Jul 2026 21:02:16 +0800 Subject: [PATCH 4/8] Apply same CI fixes to CircleCI build-and-test-xcframework job Mirror the same three fixes already applied to the GitHub Actions workflow: - Drop 'brew install cmake' (was installing CMake 4.x, causing the psimd cmake_minimum_required error) and rely on the pre-installed CMake. - Use ios_packaging/requirements.txt instead of requirements-dev.txt (avoids installing heavy packages unneeded for framework builds). - Switch to goodnotes_maccatalyst_build_settings.json so that CMAKE_POLICY_VERSION_MINIMUM=3.5 and FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER are included for macabi builds. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .circleci/config.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7079d89fde062..9d85a4c51f668 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -38,15 +38,14 @@ jobs: - run: name: install tools for build command: | - brew install cmake - pip install -r ${CIRCLE_WORKING_DIRECTORY}/requirements-dev.txt + pip install -r ${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/ios_packaging/requirements.txt - run: name: build with build_apple_framework.py command: | export PYTHONPATH=${CIRCLE_WORKING_DIRECTORY}/tools/python:$PYTHONPATH python3 ${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/build_apple_framework.py --config Release --build_dynamic_framework --build_dir=$HOME/onnxlibrary/macabi_release_v20230327_2320 \ --include_ops_by_config=${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/hws_mobile_package.required_operators.config \ - ${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/default_full_ios_framework_build_settings.json + ${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json - run: name: archive the build results From b6069b53432eb3bcb58480effcc05be12bbb178f Mon Sep 17 00:00:00 2001 From: GoodNotesCI Date: Wed, 15 Jul 2026 21:16:28 +0800 Subject: [PATCH 5/8] Restore brew install cmake for CircleCI (cmake not pre-installed) CMake is not pre-installed on CircleCI macOS runners so removing it broke the build entirely. Brew installs CMake 4.x which is now safe since CMAKE_POLICY_VERSION_MINIMUM=3.5 is in the settings file. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9d85a4c51f668..f2e9aecbaaf96 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -38,6 +38,7 @@ jobs: - run: name: install tools for build command: | + brew install cmake pip install -r ${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/ios_packaging/requirements.txt - run: name: build with build_apple_framework.py From 4ac470b9847ae709c74dbd5f7c1b5137930b6cf2 Mon Sep 17 00:00:00 2001 From: GoodNotesCI Date: Wed, 15 Jul 2026 22:23:43 +0800 Subject: [PATCH 6/8] Fix CoreML macCatalyst availability for macabi builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upstream CoreML availability macros in host_utils.h only declared macOS and iOS availability — missing macCatalyst. Clang treats any API usage as unguarded when building for a macCatalyst deployment target, producing -Werror,-Wunguarded-availability-new errors for: - MLMultiArrayDataTypeFloat16 (macCatalyst 16+) - MLComputeUnitsCPUAndNeuralEngine (macCatalyst 16+) - MLOptimizationHints and related (macCatalyst 17.4/18+) Fix: 1. host_utils.h: add maccatalyst(N) to all API_AVAILABLE_COREML* and HAS_COREML*_OR_LATER macros so Clang recognises the guards. 2. model.mm: wrap the two unguarded CoreML 6 API usages with HAS_COREML6_OR_LATER; use #pragma clang diagnostic to silence the warning inside ConfigureOptimizationHints, which is only ever called from within if (HAS_COREML8_OR_LATER) at the call site. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../core/providers/coreml/model/host_utils.h | 24 +++++++++---------- .../core/providers/coreml/model/model.mm | 16 +++++++++++-- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/onnxruntime/core/providers/coreml/model/host_utils.h b/onnxruntime/core/providers/coreml/model/host_utils.h index 92eda24e5c46d..f967b697999ac 100644 --- a/onnxruntime/core/providers/coreml/model/host_utils.h +++ b/onnxruntime/core/providers/coreml/model/host_utils.h @@ -36,12 +36,12 @@ // https://developer.apple.com/documentation/swift/marking-api-availability-in-objective-c // API_AVAILABLE is used to decorate Objective-C APIs -#define API_AVAILABLE_COREML3 API_AVAILABLE(macos(10.15), ios(13)) -#define API_AVAILABLE_COREML4 API_AVAILABLE(macos(11), ios(14)) -#define API_AVAILABLE_COREML5 API_AVAILABLE(macos(12), ios(15)) -#define API_AVAILABLE_COREML6 API_AVAILABLE(macos(13), ios(16)) -#define API_AVAILABLE_COREML7 API_AVAILABLE(macos(14), ios(17)) -#define API_AVAILABLE_COREML8 API_AVAILABLE(macos(15), ios(18)) +#define API_AVAILABLE_COREML3 API_AVAILABLE(macos(10.15), ios(13), maccatalyst(13)) +#define API_AVAILABLE_COREML4 API_AVAILABLE(macos(11), ios(14), maccatalyst(14)) +#define API_AVAILABLE_COREML5 API_AVAILABLE(macos(12), ios(15), maccatalyst(15)) +#define API_AVAILABLE_COREML6 API_AVAILABLE(macos(13), ios(16), maccatalyst(16)) +#define API_AVAILABLE_COREML7 API_AVAILABLE(macos(14), ios(17), maccatalyst(17)) +#define API_AVAILABLE_COREML8 API_AVAILABLE(macos(15), ios(18), maccatalyst(18)) // The previous macros are used in header files to declare the availability of the APIs. // The following macros are used in build time checks to determine if the APIs are available. @@ -51,12 +51,12 @@ // @available is used in implementation code to check the availability of the APIs at runtime. // Base required OS to run CoreML Specification Version 4 (Core ML 3) -#define HAS_COREML3_OR_LATER @available(macOS 10.15, iOS 13, *) -#define HAS_COREML4_OR_LATER @available(macOS 11, iOS 14, *) -#define HAS_COREML5_OR_LATER @available(macOS 12, iOS 15, *) -#define HAS_COREML6_OR_LATER @available(macOS 13, iOS 16, *) -#define HAS_COREML7_OR_LATER @available(macOS 14, iOS 17, *) -#define HAS_COREML8_OR_LATER @available(macOS 15, iOS 18, *) +#define HAS_COREML3_OR_LATER @available(macOS 10.15, iOS 13, macCatalyst 13, *) +#define HAS_COREML4_OR_LATER @available(macOS 11, iOS 14, macCatalyst 14, *) +#define HAS_COREML5_OR_LATER @available(macOS 12, iOS 15, macCatalyst 15, *) +#define HAS_COREML6_OR_LATER @available(macOS 13, iOS 16, macCatalyst 16, *) +#define HAS_COREML7_OR_LATER @available(macOS 14, iOS 17, macCatalyst 17, *) +#define HAS_COREML8_OR_LATER @available(macOS 15, iOS 18, macCatalyst 18, *) #endif diff --git a/onnxruntime/core/providers/coreml/model/model.mm b/onnxruntime/core/providers/coreml/model/model.mm index 9d8a47ae7e5e9..d3f89260ec37f 100644 --- a/onnxruntime/core/providers/coreml/model/model.mm +++ b/onnxruntime/core/providers/coreml/model/model.mm @@ -122,7 +122,12 @@ Status CreateInputFeatureProvider(const std::unordered_map& inputs, } else if (coreml_compute_unit & COREML_FLAG_USE_CPU_AND_GPU) { config.computeUnits = MLComputeUnitsCPUAndGPU; } else if (coreml_compute_unit & COREML_FLAG_ONLY_ENABLE_DEVICE_WITH_ANE) { - config.computeUnits = MLComputeUnitsCPUAndNeuralEngine; // Apple Neural Engine + if (HAS_COREML6_OR_LATER) { + config.computeUnits = MLComputeUnitsCPUAndNeuralEngine; // Apple Neural Engine + } else { + config.computeUnits = MLComputeUnitsAll; + } } else { config.computeUnits = MLComputeUnitsAll; } From 59160693509f3f8d8dfbc1908fb94699deb5d3f9 Mon Sep 17 00:00:00 2001 From: GoodNotesCI Date: Wed, 15 Jul 2026 22:57:01 +0800 Subject: [PATCH 7/8] Upload build error logs as artifacts on failure GitHub Actions: add an 'upload build error logs' step that runs only on failure and uploads CMakeError.log / CMakeOutput.log from all intermediate build directories. Keyed per matrix variant so static and dynamic logs are separate artifacts. CircleCI: pipe build output to /tmp/build_output.log (always uploaded) and collect CMake error logs into /tmp/cmake_logs on failure. Both are stored as job artifacts for easy download. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .circleci/config.yml | 20 ++++++++++++++++++- .../generate-xcframework-maccatalyst.yml | 8 ++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f2e9aecbaaf96..e36d2da9556c5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -46,7 +46,25 @@ jobs: export PYTHONPATH=${CIRCLE_WORKING_DIRECTORY}/tools/python:$PYTHONPATH python3 ${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/build_apple_framework.py --config Release --build_dynamic_framework --build_dir=$HOME/onnxlibrary/macabi_release_v20230327_2320 \ --include_ops_by_config=${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/hws_mobile_package.required_operators.config \ - ${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json + ${CIRCLE_WORKING_DIRECTORY}/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json \ + 2>&1 | tee /tmp/build_output.log; exit ${PIPESTATUS[0]} + - run: + name: collect CMake error logs + command: | + mkdir -p /tmp/cmake_logs + find $HOME/onnxlibrary/macabi_release_v20230327_2320/intermediates \ + -name "CMakeError.log" -o -name "CMakeOutput.log" | \ + while read f; do + dest="/tmp/cmake_logs/$(echo "$f" | tr '/' '_')" + cp "$f" "$dest" + done + when: on_fail + - store_artifacts: + path: /tmp/build_output.log + destination: build_output.log + - store_artifacts: + path: /tmp/cmake_logs + destination: cmake_logs - run: name: archive the build results diff --git a/.github/workflows/generate-xcframework-maccatalyst.yml b/.github/workflows/generate-xcframework-maccatalyst.yml index 509dcc88600a3..7522550d727de 100644 --- a/.github/workflows/generate-xcframework-maccatalyst.yml +++ b/.github/workflows/generate-xcframework-maccatalyst.yml @@ -122,6 +122,14 @@ jobs: sleep $((attempt * 30)) done + - name: upload build error logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: build-error-logs-${{ matrix.variant }} + path: ${{ env.HOME }}/onnxlibrary/${{ matrix.build_dir_name }}/intermediates/**/CMakeFiles/CMake*.log + if-no-files-found: ignore + - name: archive ${{ matrix.variant }} xcframework shell: bash run: | From 46e8476032bce13be017528872e3de62c03e7592 Mon Sep 17 00:00:00 2001 From: GoodNotesCI Date: Wed, 15 Jul 2026 23:01:46 +0800 Subject: [PATCH 8/8] Fix macabi dynamic framework path for Ninja (non-Xcode) builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For macabi (Mac Catalyst) builds, the Xcode CMake generator is unsupported, so Ninja/Make is used instead. Without Xcode, CMake does not place the dynamic framework under the -macabi subdirectory — it lands directly under the config build dir as: Release/onnxruntime.framework The refactored build_apple_framework.py (upstream PR #27279) always expects the path with the subdirectory: Release/Release-macabi/onnxruntime.framework causing lipo to fail with "can't open input file" during xcframework assembly. The old script had an explicit fallback for this case; restore it as a post-build check so lipo uses the correct path. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- tools/ci_build/github/apple/build_apple_framework.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/ci_build/github/apple/build_apple_framework.py b/tools/ci_build/github/apple/build_apple_framework.py index 9b9f7f6cf234f..c1e6ce0dbf9fe 100644 --- a/tools/ci_build/github/apple/build_apple_framework.py +++ b/tools/ci_build/github/apple/build_apple_framework.py @@ -87,6 +87,15 @@ def _find_or_build_sysroot_arch_framework( ), ) + # Dynamic macabi builds use a Ninja/Make CMake generator (Xcode is unsupported + # for Catalyst). Without the Xcode generator, CMake does not place the framework + # under the - subdirectory — it lands directly under the config + # build dir. Fall back to that path when the expected one does not exist. + if build_dynamic_framework and sysroot == "macabi" and not framework_dir.exists(): + fallback = build_dir_current_arch / build_config / "onnxruntime.framework" + if fallback.exists(): + framework_dir = fallback + info_plist_file = build_dir_current_arch / build_config / "Info.plist" framework_info_file = build_dir_current_arch / build_config / "framework_info.json"