KMP 和 Xcode 26 适配

背景
iOS 打包机升级到 Xcode 26 后,KMP(Kotlin Multiplatform)相关工程开始出现编译错误,例如头文件 not found、unresolved classifier 等。
我们当前的 Kotlin/Native 编译器基于 Kotlin 2.0.21 做了魔改(用于支持鸿蒙),主工程的 Kotlin 版本也不好随意升级,因此短期内无法直接切到官方已支持 Xcode 26 的 Kotlin 2.2.20。
目标就是在 Kotlin 2.0.21 的基础上 支持 Xcode 26。
方案一:直接用腾讯 Kuikly
Tencent Kuikly Kotlin 已经完成 Xcode 26 适配,若无特殊定制需求,可以直接采用:
- 提交参考:https://github.com/Tencent-TDS/KuiklyBase-kotlin/commit/56b5c978e857dc9bcbccd4d66055b618fda7040e
- 作者说明改动集中在 LLVM 部分,但 LLVM 的具体修改未开源。
推测是自建了一套可在 Xcode 26 所用高版本 Clang 下编译通过的 LLVM/Clang 12.0.1(该版本 LLVM 在高版本 Clang 下默认会编不过)。我之前也基于 LLVM 12.0.1 改过不少地方才在高版本 Clang 下编译通过,涉及文件较多,大致如下:

最终没有采用这套自改 LLVM,原因有两点:
- 改动的正确性没把握:动了很多底层逻辑,对 LLVM/Clang 理解有限,不少地方靠 AI 辅助,不敢直接上生产。
- 我们已有编译隔离:只有 OHOS 在用 LLVM/Clang 12,其余仍是 LLVM 11.1.0;Xcode 只影响 Apple 系。因此也可以选择在 LLVM 11.1.0 上针对 Xcode 26 做修补。
方案二:基于 LLVM 11.1.0 适配 Xcode 26
下面是在 Kotlin/Native 编译过程中遇到的具体问题及处理方式。
1. UIUtilities/UIDefines.h file not found
原因:Xcode 26 将 UIUtilities 挪到了 SubFramework。
处理:在 ClangArgs 中增加 -F path/to/SubFrameworks。
2. -lto_library library filename must be libLTO.dylib
与 toolchain 升级后 linker 行为变化有关,需按新要求指定 LTO 库。
处理:在 -lto_library 后显式传入 libLTO.dylib。工程里有多处 build.gradle 有类似配置,统一改为:
# 原写法
linkerOpts("-Xlinker", "-lto_library", "-Xlinker", "KT-69382")
# 修改为
linkerOpts("-Xlinker", "-lto_library", "-Xlinker", "$llvmDir/lib/libLTO.dylib")
3. modulemap 与 _c_standard_library_obsolete 报错
报错形如:
module '_c_standard_library_obsolete' requires feature XXXXX
同时伴随 stddef.h 等头文件里 size_t 相关问题,与 Clang 的 feature 配置有关,导致 use_clang_def 等宏或头文件引入异常。这块修改是否完全正确尚不确定。
处理:因 modulemap 里 _c_standard_library_obsolete 的 require 导致编译失败,将相关 modulemap 改回按头文件直接 include 的方式:根据 moduleName 和 modulemap 里的 header 信息拼出原始头文件路径(如 XXXModule/XXX.h),再重新拼好 includes 传给 buildNativeLibrary,从而绕过该问题。
4. Accelerate.def 问题
高版本多了一个参数定义,暂不确定如何传入或应传何值。
处理:暂时将该模块 disable,不做 interop,先绕过。
总结
Kotlin/Native 目前仍要面对不少问题:崩溃排查难、要持续跟进 Xcode 升级,国内团队还要兼顾鸿蒙适配。腾讯 Kuikly 的适配能减轻不少负担。
- 小团队、以业务逻辑为主:建议直接用 Kuikly 的 Kotlin 编译器;写 UI 可考虑 Kuikly UI 或 ovCompose(支持 Compose Multiplatform 在鸿蒙上渲染)。
- 大团队、人力充足:可以继续自研、自己卷适配。
我们团队人少又要扛这类基建,实在扛不动了,后续打算直接切到 Kuikly Kotlin 编译器。