diff --git a/.circleci/config.yml b/.circleci/config.yml index 7079d89fde062..e36d2da9556c5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,14 +39,32 @@ jobs: 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 \ + 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 4106fe3a33187..7522550d727de 100644 --- a/.github/workflows/generate-xcframework-maccatalyst.yml +++ b/.github/workflows/generate-xcframework-maccatalyst.yml @@ -90,16 +90,28 @@ 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: + # - 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 shell: bash 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 @@ -110,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: | 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; } 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" 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..8cb539ef07c6c --- /dev/null +++ b/tools/ci_build/github/apple/goodnotes_maccatalyst_build_settings.json @@ -0,0 +1,43 @@ +{ + "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", + "--cmake_extra_defines=CMAKE_POLICY_VERSION_MINIMUM=3.5" + ], + "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" + ] + } +}