十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【Bug已解决】[Build] Minimal build with the Core ML EP fails 解决方案

【Bug已解决】[Build] Minimal build with the Core ML EP fails 解决方案 【Bug已解决】[Build] Minimal build with the Core ML EP fails 解决方案一、现象长什么样用 ONNX Runtime 的**最小化构建minimal build**配置——关闭大部分 EP、只保留需要的少量组件——但同时想保留Core ML EP在 Apple 设备上用 Core ML 加速时构建直接失败要么某个 Core ML 相关的源文件引用了被最小化配置排除的符号要么链接时缺符号。现象# 现象 A编译期未定义符号 # error: use of undeclared identifier coreml_xxx # Core ML EP 的某个 .cc 引用了被 minimal build 条件编译掉的符号 # 现象 B链接期 undefined reference # undefined reference to OrtApis::... —— Core ML EP 依赖的 API 在 # minimal build 里被剔除但 Core ML EP 代码仍引用 # 现象 C只在“minimal CoreML”组合触发 # 完整构建带 Core ML 正常纯 minimal无 CoreML正常 # 一旦 minimal CoreML 就炸 —— 说明两者条件编译边界不一致最坑的是现象 C两个单独都正常的组合叠加就失败说明“minimal build 的剔除边界”和“Core ML EP 的依赖”没有对齐——Core ML EP 假设某些符号/API 一定存在但 minimal 把它们剔了。二、背景ONNX Runtime 的 minimal build 通过 CMake 选项如ORT_MINIMAL_BUILD、关闭各 EP、剔除训练/图优化等来生成体积最小的库。它的做法是条件编译某些文件/符号只在“非 minimal”时编译。Core ML EP 是一组把图节点转到 Apple Core ML 框架执行的代码。它依赖 ORT 内部的一些工具函数/API如 graph 遍历、节点属性读取、某种 allocator。当 minimal build 剔除这些依赖时Core ML EP 的源文件如果没有 corresponding 的#if !defined(ORT_MINIMAL_BUILD)守卫就会引用到被剔除的符号编译/链接失败。这是构建系统/条件编译审查里典型的坑某 EP 依赖的符号被 minimal build 剔除但该 EP 的代码没有用条件编译守卫隔离这些依赖导致 minimal该 EP 组合失败。三、根因Core ML EP 引用被 minimal 剔除的符号Core ML EP 的某些.cc直接用了非 minimal 才存在的工具函数没加#if !defined(ORT_MINIMAL_BUILD)守卫现象 A/B。条件编译边界不一致minimal build 的剔除边界和 Core ML EP 的依赖边界没对齐导致“单独都行、叠加就挂”。缺少 minimalCoreML 的构建冒烟CI 只测“完整构建”和“纯 minimal”没测“minimalCoreML”组合失败长期存在。本质是Core ML EP 依赖的符号被 minimal build 剔除且未用条件编译守卫隔离导致 minimalCoreML 组合编译/链接失败且缺组合测试。四、最小可运行复现下面用 Python 模拟“minimal build 剔除某符号Core ML EP 未守卫地引用导致失败”MINIMAL True # minimal build 开启 # minimal build 剔除了 utility 符号 def coreml_utility(): # 这个函数在 minimal 下不被编译 return ok def build_coreml_ep_buggy(): buggy: 未守卫地引用被剔除的符号。 if MINIMAL: # 编译期这里就失败coreml_utility 不存在 return coreml_utility() # NameError 类比 undefined reference return coreml_utility() def build_coreml_ep_fixed(): fixed: 用条件编译守卫隔离 minimal 不支持的依赖。 if MINIMAL: # minimal 下 Core ML EP 走简化路径不引用被剔除符号 return minimal-coreml-stub return coreml_utility() try: build_coreml_ep_buggy() except NameError: print(REPRO A/B - undefined reference under minimal build) print(fixed:, build_coreml_ep_fixed()) # minimal 下走 stub构建通过buggy在 minimal 下引用被剔除符号失败fixed用守卫隔离。五、解决方案第一层最小直接修复最小修复Core ML EP 里引用 minimal-build 会被剔除的符号处加#if !defined(ORT_MINIMAL_BUILD)守卫或提供 minimal 下的桩实现// 修正Core ML EP 中隔离 minimal 不支持的依赖 #ifndef ORT_MINIMAL_BUILD // 引用完整构建才有的图遍历/属性工具 auto props graph.GetNodeAttribute(...); #else // minimal 下 Core ML EP 只支持预编译子图跳过动态图分析 ORT_RETURN_IF_ERROR(PrepareCoreMLPrecompiled(model_path)); #endif或把 Core ML EP 整体在 minimal 下也用桩隔离保证链接不缺符号。这一层改动最小加条件编译守卫minimalCoreML 构建恢复。但依赖“每处依赖都守卫”下看第二层。六、解决方案第二层结构性改进把“Core ML EP 在 minimal build 下必须可构建依赖隔离/桩”固化成单一事实来源。下面这个 dataclass 集中管理 minimal build 的条件编译契约from dataclasses import dataclass, field from typing import Dict, Set dataclass class OrtMinimalCoreMlPolicy: 单一事实来源minimal build Core ML EP 的可构建契约。 # 被 minimal build 剔除的符号集 _stripped_symbols: Set[str] field(default_factorylambda: { Graph::GetNodeAttribute, Optimizer::Fuse, TrainingAPI::*}) # Core ML EP 实际引用的符号 _coreml_refs: Set[str] field(default_factorylambda: { Graph::GetNodeAttribute, CoreMLModelWriter}) def check_buildable(self, minimal: bool) - None: if not minimal: return # minimal 下Core ML EP 引用的符号必须都不在被剔除集合里 offending self._coreml_refs self._stripped_symbols if offending: raise AssertionError( fCore ML EP references stripped symbols under minimal build: f{offending}; guard them with #if !defined(ORT_MINIMAL_BUILD)) def assert_guarded(self, refs: Set[str], minimal: bool) - None: if minimal and (refs self._stripped_symbols): raise AssertionError(unguarded reference to stripped symbol)这一层的关键收益依赖-剔除对齐检查check_buildable验证 minimal 下 Core ML EP 不引用被剔除符号守卫断言assert_guarded确保引用都加了条件编译守卫单一事实来源所有 minimalCoreML 构建约定收口在OrtMinimalCoreMlPolicy。七、解决方案第三层断言 / CI 守护把第二层钉成 pytest挂进 CI覆盖 minimalCoreML 组合import pytest from your_package.ort_minimal_coremll import OrtMinimalCoreMlPolicy def test_minimal_coreml_buildable_when_guarded(): # 断言 1Core ML EP 引用都被守卫时minimal 可构建 p OrtMinimalCoreMlPolicy() p._coreml_refs {CoreMLModelWriter} # 不在剔除集合 p.check_buildable(minimalTrue) # 通过 def test_offending_refs_caught(): # 断言 2Core ML EP 引用被剔除符号必须报错复现原 bug p OrtMinimalCoreMlPolicy() p._coreml_refs {Graph::GetNodeAttribute} # 在剔除集合 with pytest.raises(AssertionError): p.check_buildable(minimalTrue) def test_full_build_always_ok(): # 断言 3完整构建不受限 p OrtMinimalCoreMlPolicy() p.check_buildable(minimalFalse) def test_guard_enforced(): # 断言 4minimal 下未守卫引用报错 p OrtMinimalCoreMlPolicy() with pytest.raises(AssertionError): p.assert_guarded({Graph::GetNodeAttribute}, minimalTrue)四条断言从“守卫后可构建”“违规引用被抓”“完整构建OK”“守卫强制”四面把构建失败钉死在 CI。八、排查清单minimal build Core ML EP 构建失败时报错是 undefined reference / undeclared identifier确认 Core ML EP 引用了 minimal 剔除的符号现象 A/B。是否只在 minimalCoreML 组合触发是就确认两者条件编译边界没对齐现象 C。Core ML EP 的每个外部符号引用是否都加了#if !defined(ORT_MINIMAL_BUILD)守卫没加就是漏。用第二层OrtMinimalCoreMlPolicy依赖-剔除对齐检查 守卫断言。加第三层 pytest断言“守卫后可构建、违规引用被抓、完整构建OK、守卫强制”。任何 EP 在 minimal build 下必须保证可构建依赖符号要么守卫、要么提供桩。九、小结ORT 的 minimal build Core ML EP 失败本质是Core ML EP 引用了 minimal build 会剔除的符号但未用#if !defined(ORT_MINIMAL_BUILD)条件编译守卫隔离导致“单独都正常、叠加就崩”的组合失败且 CI 没测 minimalCoreML 组合。修复分三层——第一层在 Core ML EP 引用被剔除符号处加守卫或桩第二层用OrtMinimalCoreMlPolicy这个 dataclass 把“依赖-剔除对齐 守卫断言”收口成单一事实来源第三层用四条 pytest 把“守卫后可构建、违规引用被抓、完整构建OK、守卫强制”钉死在 CI。核心心法某 EP 在 minimal build 下必须保证可构建其引用的符号要么加条件编译守卫、要么提供桩依赖边界必须与 minimal 剔除边界对齐。
返回列表