跳到主要内容
知仓学习社ZHICANG

kotlin-tooling-native-build-performance

>

不碰外部(只输出文字)无严重或高危命中Kotlin/kotlin-agent-skills

它会碰到什么

扫了多少7 个文本文件,23 KB
它会碰到什么不碰外部(只输出文字)
命中总数0 处
命中统计严重 0 · 高 0 · 中 0 · 低 0

这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。

技能内容

Kotlin/Native Build Performance

Turn "the iOS build is slow" into a measured diagnosis and a small set of safe

fixes. Two rules apply throughout:

  1. Never trade away required release behavior. A faster local loop must not

change what CI publishes.

  1. Measure before and after with the same command and the same build state.

An unmeasured fix is a guess.

Step 0: Classify the Slow Scenario

Establish four facts before editing anything: where (local or CI),

what (debug feedback loop or release/distribution artifact), state

(first build, clean, warm, or no-op), and phase (which tasks dominate the

log). Then match the dominant symptom:

| Symptom in the build log | Likely cause | Read |

|---|---|---|

| linkRelease or ReleaseXCFramework tasks in a local development loop | Building distribution artifacts for development | [artifacts-and-targets](references/artifacts-and-targets.md) |

| Kotlin/Native compiler distribution downloaded on every CI run | ~/.konan not preserved between runs | [caching-and-gradle](references/caching-and-gradle.md) |

| Long pause before the first task starts | Configuration phase, no configuration cache | [caching-and-gradle](references/caching-and-gradle.md) |

| All iOS targets build when only one simulator is needed | Broad task (build, assemble, assemble*XCFramework) or unused targets | [artifacts-and-targets](references/artifacts-and-targets.md) |

| ksp tasks ahead of compileKotlinIos | Generated-code work on the native path | [exports-and-generated-code](references/exports-and-generated-code.md) |

| Small source edit recompiles and relinks everything | Compiler caches disabled, or missing incrementality | [caching-and-gradle](references/caching-and-gradle.md), [experimental](references/experimental.md) |

| Machine overloaded while several link* tasks run at once | Parallel native linking | [caching-and-gradle](references/caching-and-gradle.md), worker-limit caveat |

Step 1: Audit and Measure

  1. Run the static audit from the project root:
   scripts/audit-native-build.sh /path/to/project

It is read-only and prints file:line findings (disabled caches, broad

local tasks, transitiveExport, broad KSP configuration, missing CI

.konan cache), each pointing at the reference file with the fix.

Findings are leads, not verdicts — confirm each against project policy.

  1. Find the command the user actually waits for: a script, a CI step, or the

Gradle invocation inside an Xcode build phase. Optimize that command, not

a task you picked yourself.

  1. Run it twice when practical. The first build downloads Kotlin/Native

components and fills caches; only the second and later runs are

representative. Attribute time per task before blaming the compiler:

   kotlin.build.report.output=file   # writes build/reports/kotlin-build/

Gradle's --scan or --profile work too.

  1. If you cannot run the build (no macOS host, no Xcode), analyze logs, build

scans, or checked-in metrics instead — and state explicitly that the

conclusion is static.

Step 2: Fix in Safe Order

Apply fixes one at a time, re-measuring as you go:

  1. Restore healthy defaults — remove cache/daemon workarounds, enable

Gradle build and configuration caches, keep ~/.konan warm in CI, update

Kotlin: [references/caching-and-gradle.md](references/caching-and-gradle.md)

  1. Build only what the feedback loop needs — one specific task per loop,

correct integration method, justified target matrix:

[references/artifacts-and-targets.md](references/artifacts-and-targets.md)

  1. Cut export and generated-code cost — drop transitiveExport, narrow

export(...), scope KSP work to the native compilations that need it:

[references/exports-and-generated-code.md](references/exports-and-generated-code.md)

  1. Experimental switches last, with the user's agreement:

[references/experimental.md](references/experimental.md)

Worked Example

A developer on an Apple Silicon Mac complains that "every shared-module

change costs 12 minutes". Their loop runs ./gradlew :shared:assembleXCFramework.

A build scan of the second (warm) run shows:

:shared:linkReleaseFrameworkIosArm64             348s
:shared:linkReleaseFrameworkIosX64               341s
:shared:compileKotlinIosX64                       96s
:shared:linkDebugFrameworkIosSimulatorArm64       41s
:shared:compileKotlinIosSimulatorArm64            38s
configuration phase                               64s

Reasoning chain:

  • The loop is local + debug + warm, but ~690s goes to linkRelease*

release linking is an order of magnitude slower than debug and only CI

needs it. Replace the local command with

:shared:linkDebugFrameworkIosSimulatorArm64 (or the Xcode embed task if

Xcode drives the build). (artifacts-and-targets)

  • All iosX64 work serves Intel simulators; ask whether the team still

supports them before removing the target. (artifacts-and-targets)

  • 64s of configuration on every run disappears behind

org.gradle.configuration-cache=true once trialed. (caching-and-gradle)

  • Expected loop after the change: ~40s compile + ~40s link on warm builds —

confirm by re-running the new command twice and comparing.

  • CI keeps assembleXCFramework untouched; note that explicitly in the

report.

Verify

  • [ ] Re-run the exact baseline command; compare warm build against warm

build, not warm against cold.

  • [ ] Second run with the configuration cache reports it is being reused.
  • [ ] The local development log no longer contains linkRelease*,

*ReleaseXCFramework, or removed generator tasks.

  • [ ] CI still produces every required release artifact, unchanged.
  • [ ] Tests pass and the app still runs from Xcode.
  • [ ] scripts/audit-native-build.sh reports no findings you have not

consciously accepted and documented.

Report Your Changes

Close with a short performance note:

  • The slow scenario (local/CI, debug/release, cold/warm) and the measured

evidence — or a statement that the analysis was static.

  • Each change, and why it is safe for release behavior.
  • The before/after commands the user can run to confirm the win.
  • Remaining tradeoffs: experimental flags enabled, targets removed under a

policy assumption, worker limits, or generated-code work deferred.

  • Links to the relevant official documentation below.

Official Documentation

| Topic | Link |

|---|---|

| Improving Kotlin/Native compilation time | https://kotlinlang.org/docs/native-improving-compilation-time.html |

| Kotlin Gradle plugin compilation and caches | https://kotlinlang.org/docs/gradle-compilation-and-caches.html |

| iOS integration methods | https://kotlinlang.org/docs/multiplatform-ios-integration-overview.html |

| Direct integration with Xcode | https://kotlinlang.org/docs/multiplatform/multiplatform-direct-integration.html |

| Building final native binaries and XCFrameworks | https://kotlinlang.org/docs/multiplatform/multiplatform-build-native-binaries.html |

| Kotlin/Native binary options | https://kotlinlang.org/docs/native-binary-options.html |

| KSP with Kotlin Multiplatform | https://kotlinlang.org/docs/ksp-multiplatform.html |

想直接用这个技能?

本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。