axiom-build-performance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBuild Performance Optimization
构建性能优化
Overview
概述
Systematic Xcode build performance analysis and optimization. Core principle: Measure before optimizing, then optimize the critical path first.
系统化的Xcode构建性能分析与优化。核心原则:优化前先测量,优先优化关键路径。
When to Use This Skill
何时使用此技能
- Build times have increased significantly
- Incremental builds taking too long
- Want to analyze Build Timeline
- Need to identify slow-compiling Swift code
- Optimizing CI/CD build times
- Build performance regression investigation
- Enabling Xcode 26 compilation caching
- Reducing module variants in explicitly built modules
- Understanding the three-phase build process (scan → modules → compile)
- 构建时间显著增加
- 增量构建耗时过长
- 想要分析Build Timeline
- 需要识别编译缓慢的Swift代码
- 优化CI/CD构建时间
- 排查构建性能回归问题
- 启用Xcode 26编译缓存
- 减少显式构建模块中的模块变体
- 了解三阶段构建流程(扫描→模块→编译)
Quick Win: Run the Agent First
快速见效:先运行Agent
For automated scanning and quick wins:
bash
/axiom:optimize-buildThe build-optimizer agent scans for common issues and provides immediate fixes. Use this skill for deep analysis.
如需自动扫描和快速优化:
bash
/axiom:optimize-build构建优化Agent会扫描常见问题并提供即时修复方案。如需深度分析,请使用本技能。
The Build Performance Workflow
构建性能优化工作流
Step 1: Measure Baseline (Required)
步骤1:测量基准线(必填)
Why: You can't improve what you don't measure. Baseline prevents placebo optimizations.
bash
undefined原因:无法优化未测量的指标。基准线可避免“安慰剂式优化”。
bash
undefinedClean build (eliminates all caching)
清理构建(清除所有缓存)
xcodebuild clean build -scheme YourScheme
xcodebuild clean build -scheme YourScheme
Measure time
测量时间
time xcodebuild build -scheme YourScheme
time xcodebuild build -scheme YourScheme
Or use Xcode UI
或使用Xcode界面
Product → Perform Action → Build with Timing Summary
**Record**:
- Total build time
- Incremental build time (change one file, rebuild)
- Which phase takes longest (compilation vs linking vs scripts)
**Example baseline**:Clean build: 247 seconds
Incremental (1 file change): 12 seconds
Longest phase: Compile Swift sources (189s)
undefined产品 → 执行操作 → 带时间摘要的构建
**记录以下内容**:
- 总构建时间
- 增量构建时间(修改一个文件后重新构建)
- 耗时最长的阶段(编译、链接还是脚本)
**基准线示例**:清理构建:247秒
增量构建(修改1个文件):12秒
最长阶段:编译Swift源代码(189秒)
undefinedStep 2: Analyze Build Timeline (Xcode 14+)
步骤2:分析Build Timeline(Xcode 14+)
Access:
- Build your project (Cmd+B)
- Open Report Navigator (Cmd+9)
- Select latest build
- Show Assistant Editor (Cmd+Option+Return)
- Build Timeline appears alongside build log
What to look for:
访问方式:
- 构建项目(Cmd+B)
- 打开报告导航器(Cmd+9)
- 选择最新的构建记录
- 显示助理编辑器(Cmd+Option+Return)
- Build Timeline会与构建日志一同显示
需要关注的内容:
Critical Path (The Build's Speed Limit)
关键路径(构建的速度上限)
The critical path is the shortest possible build time with unlimited CPU cores. It's defined by the longest chain of dependent tasks.
┌─────────────────────────────────────────┐
│ Critical Path: A → B → C → D (120s) │
│ │
│ Task A: 30s ─────────┐ │
│ Task B: 40s ├─→ D: 20s │
│ Task C: 30s ─────────┘ │
│ │
│ Even with 100 CPUs, build takes 120s │
└─────────────────────────────────────────┘Goal: Shorten the critical path by breaking dependencies.
关键路径是拥有无限CPU核心时的最短可能构建时间,由最长的依赖任务链定义。
┌─────────────────────────────────────────┐
│ 关键路径:A → B → C → D(120秒) │
│ │
│ 任务A:30秒 ─────────┐ │
│ 任务B:40秒 ├─→ D:20秒 │
│ 任务C:30秒 ─────────┘ │
│ │
│ 即使有100个CPU,构建仍需120秒 │
└─────────────────────────────────────────┘目标:通过打破依赖关系缩短关键路径。
Timeline Red Flags
Timeline中的红色警示
Empty vertical space: Tasks waiting for inputs
Timeline:
████████░░░░░░░░████████ ← Bad: idle cores waiting
████████████████████████ ← Good: continuous workLong horizontal bars: Slow individual tasks
Task A: ████████████████████ (45 seconds) ← Investigate
Task B: ███ (3 seconds) ← FineSerial target builds: Targets waiting unnecessarily
Framework: ████████░░░░░░░░░░ ← Waiting
App: ░░░░░░░░░░████████ ← Delayed
Better (parallel):
Framework: ████████
App: ░░░░████████████垂直空白区域:任务在等待输入
Timeline:
████████░░░░░░░░████████ ← 不良:核心闲置等待
████████████████████████ ← 良好:持续工作长水平条:单个任务耗时过长
任务A:████████████████████(45秒) ← 需要排查
任务B:███(3秒) ← 正常串行目标构建:目标不必要地等待
框架:████████░░░░░░░░░░ ← 等待中
应用: ░░░░░░░░░░████████ ← 延迟
优化后(并行):
框架:████████
应用: ░░░░████████████Step 3: Identify Bottlenecks (Decision Tree)
步骤3:识别瓶颈(决策树)
Is compilation the slowest phase?
├─ YES → Check type checking performance (Step 4)
└─ NO → Is linking slow?
├─ YES → Check link dependencies (Step 5)
└─ NO → Are scripts slow?
├─ YES → Optimize build phase scripts (Step 6)
└─ NO → Check parallelization (Step 7)
编译是否是最慢的阶段?
├─ 是 → 检查类型检查性能(步骤4)
└─ 否 → 链接是否缓慢?
├─ 是 → 检查链接依赖(步骤5)
└─ 否 → 脚本是否缓慢?
├─ 是 → 优化构建阶段脚本(步骤6)
└─ 否 → 检查并行化设置(步骤7)
Optimization Patterns
优化模式
Pattern 1: Type Checking Performance (MEDIUM-HIGH IMPACT)
模式1:类型检查性能优化(中高影响)
Symptom: "Compile Swift sources" takes >50% of build time.
Diagnosis:
Enable compiler warnings to find slow functions:
swift
// Add to Debug build settings → Other Swift Flags
-warn-long-function-bodies 100
-warn-long-expression-type-checking 100Build → Xcode shows warnings:
MyView.swift:42: Function body took 247ms to type-check (limit: 100ms)
LoginViewModel.swift:18: Expression took 156ms to type-check (limit: 100ms)Fix slow type checking:
swift
// ❌ SLOW - Complex type inference (247ms)
func calculateTotal(items: [Item]) -> Double {
return items
.filter { $0.isActive }
.map { $0.price * $0.quantity }
.reduce(0, +)
}
// ✅ FAST - Explicit types (12ms)
func calculateTotal(items: [Item]) -> Double {
let activeItems: [Item] = items.filter { $0.isActive }
let prices: [Double] = activeItems.map { $0.price * $0.quantity }
let total: Double = prices.reduce(0, +)
return total
}Common slow patterns:
- Complex chained operations without intermediate types
- Deeply nested closures
- Large literals (dictionaries, arrays)
- Operator overloading in complex expressions
Expected impact: 10-30% faster compilation for affected files.
症状:“编译Swift源代码”耗时占总构建时间的50%以上。
诊断方法:
启用编译器警告来查找缓慢的函数:
swift
// 添加到Debug构建设置 → 其他Swift标志
-warn-long-function-bodies 100
-warn-long-expression-type-checking 100构建后Xcode会显示警告:
MyView.swift:42: 函数体类型检查耗时247毫秒(限制:100毫秒)
LoginViewModel.swift:18: 表达式类型检查耗时156毫秒(限制:100毫秒)修复缓慢的类型检查:
swift
// ❌ 缓慢 - 复杂类型推断(247毫秒)
func calculateTotal(items: [Item]) -> Double {
return items
.filter { $0.isActive }
.map { $0.price * $0.quantity }
.reduce(0, +)
}
// ✅ 快速 - 显式类型(12毫秒)
func calculateTotal(items: [Item]) -> Double {
let activeItems: [Item] = items.filter { $0.isActive }
let prices: [Double] = activeItems.map { $0.price * $0.quantity }
let total: Double = prices.reduce(0, +)
return total
}常见的缓慢模式:
- 没有中间类型的复杂链式操作
- 深度嵌套的闭包
- 大型字面量(字典、数组)
- 复杂表达式中的运算符重载
预期影响:受影响文件的编译速度提升10-30%。
Pattern 2: Build Phase Script Optimization (HIGH IMPACT)
模式2:构建阶段脚本优化(高影响)
Symptom: Build Timeline shows long script phases in Debug builds.
Common culprits:
- dSYM/Crashlytics uploads running in Debug
- Asset processing on every build
- Code generation scripts without caching
Fix: Make scripts conditional
bash
undefined症状:Build Timeline显示Debug构建中的脚本阶段耗时较长。
常见原因:
- Debug模式下运行dSYM/Crashlytics上传
- 每次构建都处理资源
- 未缓存的代码生成脚本
修复方案:让脚本仅在特定条件下运行
bash
undefined❌ BAD - Runs in ALL configurations (adds 6+ seconds to debug builds)
❌ 不良 - 在所有配置中运行(为Debug构建增加6秒以上耗时)
#!/bin/bash
firebase crashlytics upload-symbols
#!/bin/bash
firebase crashlytics upload-symbols
✅ GOOD - Skip in Debug
✅ 良好 - 在Debug模式下跳过
#!/bin/bash
if [ "${CONFIGURATION}" = "Release" ]; then
firebase crashlytics upload-symbols
fi
#!/bin/bash
if [ "${CONFIGURATION}" = "Release" ]; then
firebase crashlytics upload-symbols
fi
Example savings: 6.3 seconds per incremental debug build
示例节省时间:每次增量Debug构建节省6.3秒
**Script Phase Sandboxing** (Xcode 14+)
Enable to prevent data races and improve parallelization:
Build Settings → User Script Sandboxing → YES
**Why**: Forces you to declare inputs/outputs explicitly, enabling parallel execution.
```bash
**脚本阶段沙箱化**(Xcode 14+)
启用该功能可防止数据竞争并提升并行化能力:
构建设置 → 用户脚本沙箱化 → 是
**原因**:强制您显式声明输入/输出,从而支持并行执行。
```bashScript phase with proper inputs/outputs
带有正确输入/输出的脚本阶段
Input Files:
$(SRCROOT)/input.txt
$(DERIVED_FILE_DIR)/checksum.txt
Output Files:
$(DERIVED_FILE_DIR)/output.html
输入文件:
$(SRCROOT)/input.txt
$(DERIVED_FILE_DIR)/checksum.txt
输出文件:
$(DERIVED_FILE_DIR)/output.html
Now Xcode knows dependencies and can parallelize safely
现在Xcode了解依赖关系,可以安全地并行执行
**Parallel Script Execution**:
Build Settings → FUSE_BUILD_SCRIPT_PHASES → YES
**⚠️ WARNING**: Only enable if ALL scripts have correct inputs/outputs declared. Otherwise you'll get data races.
**Expected impact**: 5-10 seconds saved per incremental debug build.
---
**并行脚本执行**:
构建设置 → FUSE_BUILD_SCRIPT_PHASES → 是
**⚠️ 警告**:仅当所有脚本都正确声明了输入/输出时才启用。否则会出现数据竞争。
**预期影响**:每次增量Debug构建节省5-10秒。
---Pattern 3: Compilation Mode Settings (CRITICAL)
模式3:编译模式设置(关键)
Symptom: Incremental builds recompile entire modules.
Check current settings:
bash
undefined症状:增量构建会重新编译整个模块。
检查当前设置:
bash
undefinedIn project.pbxproj
在project.pbxproj中
grep "SWIFT_COMPILATION_MODE" project.pbxproj
**Optimal configuration**:
| Configuration | Setting | Why |
|---|---|---|
| **Debug** | `singlefile` (Incremental) | Only recompiles changed files |
| **Release** | `wholemodule` | Maximum optimization |
```swift
// ❌ BAD - Whole module in Debug
SWIFT_COMPILATION_MODE = wholemodule; // ALL configs
// ✅ GOOD - Incremental for Debug
Debug: SWIFT_COMPILATION_MODE = singlefile;
Release: SWIFT_COMPILATION_MODE = wholemodule;How to fix:
- Project → Build Settings
- Filter: "Compilation Mode"
- Set Debug to "Incremental"
- Set Release to "Whole Module"
Expected impact: 40-60% faster incremental debug builds.
grep "SWIFT_COMPILATION_MODE" project.pbxproj
**最佳配置**:
| 配置 | 设置 | 原因 |
|---|---|---|
| **Debug** | `singlefile`(增量) | 仅重新编译修改过的文件 |
| **Release** | `wholemodule` | 最大化运行时优化 |
```swift
// ❌ 不良 - Debug模式下使用全模块编译
SWIFT_COMPILATION_MODE = wholemodule; // 所有配置
// ✅ 良好 - Debug模式下使用增量编译
Debug: SWIFT_COMPILATION_MODE = singlefile;
Release: SWIFT_COMPILATION_MODE = wholemodule;修复方法:
- 项目 → 构建设置
- 筛选:“编译模式”
- 将Debug设置为“增量”
- 将Release设置为“全模块”
预期影响:增量Debug构建速度提升40-60%。
Pattern 4: Build Active Architecture Only (HIGH IMPACT)
模式4:仅构建活跃架构(高影响)
Symptom: Debug builds compile for multiple architectures (x86_64 + arm64).
Check:
bash
grep "ONLY_ACTIVE_ARCH" project.pbxprojFix:
| Configuration | Setting | Why |
|---|---|---|
| Debug | | Only build for current device (arm64 OR x86_64) |
| Release | | Build universal binary |
How to fix:
- Build Settings → "Build Active Architecture Only"
- Set Debug to YES
- Keep Release as NO
Expected impact: 40-50% faster debug builds (half the architectures).
症状:Debug构建为多个架构编译(x86_64 + arm64)。
检查方法:
bash
grep "ONLY_ACTIVE_ARCH" project.pbxproj修复方案:
| 配置 | 设置 | 原因 |
|---|---|---|
| Debug | | 仅为当前设备构建(arm64 或 x86_64) |
| Release | | 构建通用二进制文件 |
修复方法:
- 构建设置 → “仅构建活跃架构”
- 将Debug设置为YES
- 保持Release为NO
预期影响:Debug构建速度提升40-50%(只需编译一半架构)。
Pattern 5: Debug Information Format (MEDIUM IMPACT)
模式5:调试信息格式(中影响)
Symptom: Debug builds generating dSYMs unnecessarily.
Optimal configuration:
| Configuration | Setting | Why |
|---|---|---|
| Debug | | Embedded debug info, faster |
| Release | | Separate dSYM for crash reporting |
bash
undefined症状:Debug构建不必要地生成dSYM文件。
最佳配置:
| 配置 | 设置 | 原因 |
|---|---|---|
| Debug | | 嵌入式调试信息,速度更快 |
| Release | | 单独的dSYM文件用于崩溃报告 |
bash
undefinedCheck current
检查当前设置
grep "DEBUG_INFORMATION_FORMAT" project.pbxproj
**How to fix**:
1. Build Settings → "Debug Information Format"
2. Set Debug to "DWARF"
3. Set Release to "DWARF with dSYM File"
**Expected impact**: 3-5 seconds saved per debug build.
---grep "DEBUG_INFORMATION_FORMAT" project.pbxproj
**修复方法**:
1. 构建设置 → “调试信息格式”
2. 将Debug设置为“DWARF”
3. 将Release设置为“DWARF with dSYM File”
**预期影响**:每次Debug构建节省3-5秒。
---Pattern 6: Target Parallelization (WWDC 2018-408)
模式6:目标并行化(WWDC 2018-408)
Symptom: Build Timeline shows targets building sequentially when they could be parallel.
Check scheme configuration:
- Product → Scheme → Edit Scheme
- Build tab
- Check "Parallelize Build" checkbox
- Verify target order allows parallelization
Dependency graph example:
App ──┬──→ Framework A
└──→ Framework B
Framework A ──→ Utilities
Framework B ──→ UtilitiesTimeline (bad - serial):
Utilities: ████████░░░░░░░░░░░░░░
Framework A: ░░░░░░░░████████░░░░░░
Framework B: ░░░░░░░░░░░░░░░░████████
App: ░░░░░░░░░░░░░░░░░░░░░░████Timeline (good - parallel):
Utilities: ████████
Framework A: ░░░░░░░░████████
Framework B: ░░░░░░░░████████
App: ░░░░░░░░░░░░░░░░████Expected impact: Proportional to number of independent targets (e.g., 2 parallel targets = ~2x faster).
症状:Build Timeline显示本可以并行构建的目标却在串行构建。
检查方案配置:
- 产品 → Scheme → 编辑Scheme
- 构建标签页
- 勾选“并行构建”复选框
- 验证目标顺序支持并行化
依赖关系图示例:
应用 ──┬──→ 框架A
└──→ 框架B
框架A ──→ 工具库
框架B ──→ 工具库Timeline(不良 - 串行):
工具库: ████████░░░░░░░░░░░░░░
框架A: ░░░░░░░░████████░░░░░░
框架B: ░░░░░░░░░░░░░░░░████████
应用: ░░░░░░░░░░░░░░░░░░░░░░████Timeline(良好 - 并行):
工具库: ████████
框架A: ░░░░░░░░████████
框架B: ░░░░░░░░████████
应用: ░░░░░░░░░░░░░░░░████预期影响:与独立目标的数量成正比(例如,2个并行目标 ≈ 速度提升2倍)。
Pattern 7: Emit Module Optimization (Xcode 14+, Swift 5.7+)
模式7:模块输出优化(Xcode 14+, Swift 5.7+)
What it is: Swift modules are produced separately from compilation, unblocking downstream targets faster.
Before (Xcode 13):
Framework: Compile ████████████ → Emit Module █
App: ░░░░░░░░░░░░░░░░░░░░░░░░░█████████
↑
Waiting for Framework compilation to finishAfter (Xcode 14+):
Framework: Compile ████████████
Emit Module ███
App: ░░░░░░███████████
↑
Starts as soon as module emittedAutomatic: No configuration needed, works in Xcode 14+ with Swift 5.7+.
Expected impact: Reduces idle time in multi-target builds by 20-40%.
功能说明:Swift模块的生成与编译分离,下游目标可以更早开始构建。
优化前(Xcode 13):
框架: 编译 ████████████ → 输出模块 █
应用: ░░░░░░░░░░░░░░░░░░░░░░░░░█████████
↑
等待框架编译完成优化后(Xcode 14+):
框架: 编译 ████████████
输出模块 ███
应用: ░░░░░░███████████
↑
模块输出完成后立即开始自动生效:无需配置,在Xcode 14+和Swift 5.7+环境下自动生效。
预期影响:多目标构建中的闲置时间减少20-40%。
Pattern 8: Eager Linking (Xcode 14+)
模式8:提前链接(Xcode 14+)
What it is: Linking can start before all compilation finishes if the module is ready.
Impact: Further reduces critical path in dependency chains.
Automatic: Works in Xcode 14+ automatically.
功能说明:如果模块已准备就绪,链接可以在所有编译完成前开始。
影响:进一步缩短依赖链中的关键路径。
自动生效:在Xcode 14+中自动生效。
Pattern 9: Compilation Caching (Xcode 26+, CRITICAL)
模式9:编译缓存(Xcode 26+, 关键)
What it is: Xcode 26 introduces compilation caching that reuses previously compiled artifacts across clean builds.
Build Settings:
Build Settings → COMPILATION_CACHE_ENABLE_CACHING → YESHow it works:
- Caches compilation results based on input file content and compiler flags
- Works across clean builds — even after , cached artifacts can be reused
xcodebuild clean - Significantly reduces CI/CD build times where clean builds are common
When to enable:
- CI/CD pipelines with frequent clean builds
- Teams sharing build artifacts
- Projects with stable dependencies
Verification:
bash
undefined功能说明:Xcode 26引入了编译缓存,可在清理构建之间重用之前编译的产物。
构建设置:
构建设置 → COMPILATION_CACHE_ENABLE_CACHING → 是工作原理:
- 根据输入文件内容和编译器标志缓存编译结果
- 支持跨清理构建重用缓存——即使执行,仍可重用缓存产物
xcodebuild clean - 显著减少CI/CD流水线中频繁清理构建的时间
启用场景:
- 频繁执行清理构建的CI/CD流水线
- 团队共享构建产物
- 依赖稳定的项目
验证方法:
bash
undefinedBuild with caching enabled
启用缓存后构建
xcodebuild build -scheme YourScheme
COMPILATION_CACHE_ENABLE_CACHING=YES
COMPILATION_CACHE_ENABLE_CACHING=YES
xcodebuild build -scheme YourScheme
COMPILATION_CACHE_ENABLE_CACHING=YES
COMPILATION_CACHE_ENABLE_CACHING=YES
Check build log for cache information
在构建日志中检查缓存信息
**Current limitations** (Xcode 26):
- Swift Package Manager dependencies not yet cacheable
- CompileStoryboard, CompileXIB, DataModelCompile, Ld tasks not cacheable
- Cache requires time to populate on first run
**Expected impact**: 20-40% faster clean builds after initial cache population (up to 70%+ for favorable projects).
---
**当前限制**(Xcode 26):
- Swift Package Manager依赖暂不支持缓存
- CompileStoryboard、CompileXIB、DataModelCompile、Ld任务暂不支持缓存
- 首次运行需要时间填充缓存
**预期影响**:缓存填充完成后,清理构建速度提升20-40%(对合适的项目可提升70%以上)。
---Pattern 10: Explicitly Built Modules (Xcode 16+, HIGH IMPACT)
模式10:显式构建模块(Xcode 16+, 高影响)
What it is: Xcode splits module compilation into explicit build tasks instead of implicit on-demand compilation. Enabled by default for Swift in Xcode 26.
The Problem with Implicit Modules (Pre-Xcode 16):
When a compiler encounters an import, it builds the module on-demand:
Compile A.swift ─── needs UIKit ───→ (builds UIKit.pcm) ───→ continues
Compile B.swift ─── needs UIKit ───→ (waits for A to finish) ───→ uses cached
Compile C.swift ─── needs UIKit ───→ (waits) ───→ uses cachedProblems:
- One task blocks others waiting for the same module
- Non-deterministic: whoever gets there first builds it
- Build failures hard to reproduce (depends on task order)
Explicitly Built Modules Solution:
Xcode now separates compilation into three phases:
Phase 1: SCAN Phase 2: BUILD MODULES Phase 3: COMPILE
┌──────────────────┐ ┌──────────────────────┐ ┌──────────────────┐
│ Scan A.swift │ │ Build UIKit.pcm │ │ Compile A.swift │
│ Scan B.swift │ → │ Build Foundation.pcm │ → │ Compile B.swift │
│ Scan C.swift │ │ Build SwiftUI.pcm │ │ Compile C.swift │
└──────────────────┘ └──────────────────────┘ └──────────────────┘
(fast) (parallel) (parallel)Benefits:
- More reliable builds: Precise dependencies, deterministic build graphs
- More efficient scheduling: Build system knows exactly what's needed
- Better debugging: Debugger reuses built modules (no separate rebuild)
- Visible module tasks: See "Compile Clang Module" and "Compile Swift Module" in build log
Enable/Disable (if needed):
Build Settings → Explicitly Built Modules → YES (default in Xcode 26 for Swift)Module Variants (WWDC 2024-10171)
The same module may be built multiple times with different settings:
Build Log:
Compile Clang module 'UIKit' (hash: abc123) ← Variant 1
Compile Clang module 'UIKit' (hash: def456) ← Variant 2
Compile Swift module 'UIKit' (hash: ghi789) ← Variant 3Common causes of variants:
- Different preprocessor macros between targets
- Mixed C and Objective-C language modes
- Different C language versions (C11 vs C17)
- Disabling ARC on some targets
Diagnose variants:
- Build with Timing Summary:
Product → Perform Action → Build with Timing Summary - Filter build log: Type "modules report" in filter box
- View Clang and Swift module reports showing variant counts
Reduce variants (unify settings at project/workspace level):
bash
undefined功能说明:Xcode将模块编译拆分为显式构建任务,而非隐式的按需编译。在Xcode 26中默认对Swift启用。
隐式模块的问题(Xcode 16之前):
当编译器遇到导入语句时,会按需构建模块:
编译A.swift ─── 需要UIKit ───→ (构建UIKit.pcm) ───→ 继续
编译B.swift ─── 需要UIKit ───→ (等待A完成) ───→ 使用缓存
编译C.swift ─── 需要UIKit ───→ (等待) ───→ 使用缓存问题:
- 一个任务会阻塞其他等待同一模块的任务
- 非确定性:谁先执行谁就构建模块
- 构建失败难以重现(取决于任务顺序)
显式构建模块的解决方案:
Xcode现在将编译分为三个阶段:
阶段1:扫描 阶段2:构建模块 阶段3:编译
┌──────────────────┐ ┌──────────────────────┐ ┌──────────────────┐
│ 扫描A.swift │ │ 构建UIKit.pcm │ │ 编译A.swift │
│ 扫描B.swift │ → │ 构建Foundation.pcm │ → │ 编译B.swift │
│ 扫描C.swift │ │ 构建SwiftUI.pcm │ │ 编译C.swift │
└──────────────────┘ └──────────────────────┘ └──────────────────┘
(快速) (并行) (并行)优势:
- 更可靠的构建:精确的依赖关系,确定性的构建图
- 更高效的调度:构建系统准确了解所需资源
- 更好的调试体验:调试器重用已构建的模块(无需单独重新构建)
- 可见的模块任务:在构建日志中可以看到“编译Clang模块”和“编译Swift模块”
启用/禁用(如有需要):
构建设置 → 显式构建模块 → 是(Xcode 26中对Swift默认启用)模块变体(WWDC 2024-10171)
同一模块可能会使用不同的设置多次构建:
构建日志:
编译Clang模块 'UIKit'(哈希值:abc123) ← 变体1
编译Clang模块 'UIKit'(哈希值:def456) ← 变体2
编译Swift模块 'UIKit'(哈希值:ghi789) ← 变体3变体的常见原因:
- 目标之间的预处理器宏不同
- C和Objective-C语言模式混合
- C语言版本不同(C11 vs C17)
- 部分目标禁用了ARC
诊断变体:
- 使用时间摘要构建:
产品 → 执行操作 → 带时间摘要的构建 - 筛选构建日志:在筛选框中输入“modules report”
- 查看显示变体数量的Clang和Swift模块报告
减少变体(在项目/工作区级别统一设置):
bash
undefinedCheck for macro differences
检查宏定义差异
grep "GCC_PREPROCESSOR_DEFINITIONS" project.pbxproj
grep "GCC_PREPROCESSOR_DEFINITIONS" project.pbxproj
Move target-specific macros to project level where possible
尽可能将目标特定的宏定义移至项目级别
Project → Build Settings → Preprocessor Macros → [unify here]
**Example** (from WWDC 2024-10171):Before: 4 UIKit variants (2 Swift × 2 Clang)
After: 2 UIKit variants (unified settings)
Impact: Fewer module builds = faster incremental builds
**Expected impact**: 10-30% faster builds by reducing duplicate module compilation.
**Note: Swift Build** (Xcode 26+): Xcode now uses Swift Build, Apple's open-source build engine. This provides more predictable builds, better SPM integration, and cross-platform support (Linux, Windows, Android). No configuration needed.
---项目 → 构建设置 → 预处理器宏 → [在此处统一设置]
**示例**(来自WWDC 2024-10171):优化前:4个UIKit变体(2个Swift × 2个Clang)
优化后:2个UIKit变体(统一设置)
影响:减少模块构建次数 = 增量构建速度提升
**预期影响**:通过减少重复的模块编译,构建速度提升10-30%。
**注意:Swift Build**(Xcode 26+):Xcode现在使用Swift Build,这是苹果的开源构建引擎。它提供了更可预测的构建、更好的SPM集成,以及跨平台支持(Linux、Windows、Android)。无需配置。
---Measurement & Verification
测量与验证
Before and After Comparison
优化前后对比
Required steps:
-
Baseline (before changes):bash
xcodebuild clean build -scheme YourScheme 2>&1 | tee baseline.log -
Apply ONE optimization at a time
-
Measure improvement:bash
xcodebuild clean build -scheme YourScheme 2>&1 | tee optimized.log -
Compare:bash
# Extract build time from logs grep "Build succeeded" baseline.log grep "Build succeeded" optimized.log
Example:
Baseline: Build succeeded (247.3 seconds)
Optimized: Build succeeded (156.8 seconds)
Improvement: 90.5 seconds (36.6% faster)必填步骤:
-
基准线(优化前):bash
xcodebuild clean build -scheme YourScheme 2>&1 | tee baseline.log -
每次仅应用一项优化
-
测量优化效果:bash
xcodebuild clean build -scheme YourScheme 2>&1 | tee optimized.log -
对比结果:bash
# 从日志中提取构建时间 grep "Build succeeded" baseline.log grep "Build succeeded" optimized.log
示例:
基准线: Build succeeded (247.3 seconds)
优化后: Build succeeded (156.8 seconds)
提升:90.5秒(速度提升36.6%)Build Timeline Visual Verification
Build Timeline可视化验证
Before optimization:
- Look for empty vertical space (idle cores)
- Long horizontal bars (slow tasks)
- Serial target builds
After optimization:
- Timeline should be more "filled"
- Shorter horizontal bars
- Parallel target builds
Critical path: Should be visibly shorter.
优化前:
- 存在垂直空白区域(核心闲置)
- 长水平条(缓慢任务)
- 串行目标构建
优化后:
- Timeline应更“饱满”
- 水平条更短
- 并行目标构建
关键路径:应明显缩短。
Real-World Optimization Examples
实际优化案例
Example 1: Large iOS App (50+ source files)
案例1:大型iOS应用(50+源文件)
Baseline:
- Clean build: 247 seconds
- Incremental (1 file): 12 seconds
Optimizations applied:
- Debug compilation mode: singlefile (saved 89s)
- Build Active Architecture: YES (saved 45s)
- Conditional dSYM upload script (saved 6.3s per incremental)
Result:
- Clean build: 156 seconds (36% faster)
- Incremental: 5.7 seconds (52% faster)
基准线:
- 清理构建:247秒
- 增量构建(修改1个文件):12秒
应用的优化措施:
- Debug编译模式设置为singlefile(节省89秒)
- 仅构建活跃架构设置为YES(节省45秒)
- 条件化dSYM上传脚本(每次增量构建节省6.3秒)
结果:
- 清理构建:156秒(速度提升36%)
- 增量构建:5.7秒(速度提升52%)
Example 2: Multi-Framework Project
案例2:多框架项目
Baseline:
- 5 frameworks built serially
- Total: 189 seconds
Optimizations applied:
- Enabled parallel builds in scheme
- Fixed unnecessary dependencies
- Emit module optimization (automatic in Xcode 14)
Result:
- Total: 94 seconds (50% faster)
- Critical path reduced from 189s to 94s
基准线:
- 5个框架串行构建
- 总耗时:189秒
应用的优化措施:
- 在Scheme中启用并行构建
- 修复不必要的依赖关系
- 模块输出优化(Xcode 14中自动生效)
结果:
- 总耗时:94秒(速度提升50%)
- 关键路径从189秒缩短至94秒
Common Pitfalls
常见陷阱
Pitfall 1: Optimizing Without Measuring
陷阱1:未测量就优化
Mistake: "I think this will help" → make change → no measurement.
Why bad: Placebo improvements, wasted time, actual regressions unnoticed.
Fix: Always measure before → change one thing → measure after.
错误做法:“我认为这会有帮助” → 修改设置 → 不进行测量。
危害:产生“安慰剂式”提升,浪费时间,无法发现实际的性能退化。
修复方案:始终遵循“优化前测量 → 修改一项设置 → 优化后测量”的流程。
Pitfall 2: Optimizing Release Builds for Speed
陷阱2:优化Release构建的速度
Mistake: Set Release to incremental compilation for "faster builds".
Why bad: Release builds should optimize for runtime performance, not build speed. You ship Release builds to users.
Fix: Only optimize Debug builds for speed. Keep Release optimized for runtime.
错误做法:将Release设置为增量编译以“加快构建速度”。
危害:Release构建应优先优化运行时性能,而非构建速度。您交付给用户的是Release构建。
修复方案:仅优化Debug构建的速度。保持Release构建针对运行时优化。
Pitfall 3: Breaking Dependencies for Parallelization
陷阱3:为了并行化而打破依赖关系
Mistake: Remove legitimate dependencies to "make builds parallel".
Why bad: Build errors, undefined behavior, race conditions.
Fix: Only parallelize truly independent targets. Use Build Timeline to identify safe opportunities.
错误做法:移除合法的依赖关系以“实现并行构建”。
危害:构建错误、未定义行为、竞争条件。
修复方案:仅并行化真正独立的目标。使用Build Timeline识别安全的并行化机会。
Pitfall 4: Enabling FUSE_BUILD_SCRIPT_PHASES Without Sandboxing
陷阱4:未启用沙箱化就启用FUSE_BUILD_SCRIPT_PHASES
Mistake: Enable parallel scripts but don't declare inputs/outputs.
Why bad: Data races, non-deterministic build failures, incorrect builds.
Fix: First enable , fix all errors, THEN enable .
ENABLE_USER_SCRIPT_SANDBOXING = YESFUSE_BUILD_SCRIPT_PHASES错误做法:启用并行脚本但未声明输入/输出。
危害:数据竞争、非确定性构建失败、不正确的构建结果。
修复方案:先启用,修复所有错误,然后再启用。
ENABLE_USER_SCRIPT_SANDBOXING = YESFUSE_BUILD_SCRIPT_PHASESTroubleshooting
故障排除
Problem: Builds Still Slow After Optimizations
问题:优化后构建仍然缓慢
Check:
- Did you clean before measuring? ()
xcodebuild clean - Are you measuring the right build? (Debug vs Release)
- Is your machine thermal throttling? (Activity Monitor → CPU tab)
- Are other apps using CPU? (Quit Xcode, Docker, VMs during measurement)
检查项:
- 测量前是否清理了构建?()
xcodebuild clean - 您测量的是正确的构建吗?(Debug vs Release)
- 您的机器是否在热节流?(活动监视器 → CPU标签页)
- 是否有其他应用在占用CPU?(测量期间关闭Xcode、Docker、虚拟机)
Problem: Build Timeline Shows No Parallelization
问题:Build Timeline显示没有并行化
Check:
- Scheme → Parallelize Build checked?
- Are targets actually independent? (Check dependency graph)
- Do targets have unnecessary explicit dependencies?
检查项:
- Scheme中是否勾选了“并行构建”?
- 目标是否真的独立?(检查依赖关系图)
- 目标是否有不必要的显式依赖?
Problem: Type Checking Warnings Don't Appear
问题:类型检查警告不显示
Check:
- Added flags to correct configuration? (Debug, not Release)
- Syntax correct? (with hyphen)
-warn-long-function-bodies 100 - Building the right scheme?
- Clean build to force recompilation
检查项:
- 是否将标志添加到了正确的配置中?(Debug,而非Release)
- 语法是否正确?(带有连字符)
-warn-long-function-bodies 100 - 您构建的是正确的Scheme吗?
- 清理构建以强制重新编译
Advanced: Analyzing Build Logs
进阶:分析构建日志
Extract Compilation Times
提取编译时间
bash
undefinedbash
undefinedFind slowest files to compile
查找编译最慢的文件
xcodebuild -workspace YourApp.xcworkspace
-scheme YourScheme
clean build
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" 2>&1 |
grep ".[0-9]ms" |
sort -nr |
head -20
-scheme YourScheme
clean build
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" 2>&1 |
grep ".[0-9]ms" |
sort -nr |
head -20
**Output**:247.3ms MyViewModel.swift:42:1 func calculateTotal
156.8ms LoginView.swift:18:3 var body
89.2ms NetworkManager.swift:67:1 func handleResponse
...
**Action**: Add explicit types to slowest functions.
---xcodebuild -workspace YourApp.xcworkspace
-scheme YourScheme
clean build
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" 2>&1 |
grep ".[0-9]ms" |
sort -nr |
head -20
-scheme YourScheme
clean build
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" 2>&1 |
grep ".[0-9]ms" |
sort -nr |
head -20
**输出示例**:247.3ms MyViewModel.swift:42:1 func calculateTotal
156.8ms LoginView.swift:18:3 var body
89.2ms NetworkManager.swift:67:1 func handleResponse
...
**操作**:为最慢的函数添加显式类型。
---Extract Build Phase Times
提取构建阶段时间
bash
undefinedbash
undefinedFrom build log
来自构建日志
Build target 'MyApp' (project 'MyApp')
Compile Swift source files (128.4 seconds)
Link MyApp (12.3 seconds)
Run custom shell script (6.7 seconds)
**Action**: Optimize the longest phase first.
---Build target 'MyApp' (project 'MyApp')
Compile Swift source files (128.4 seconds)
Link MyApp (12.3 seconds)
Run custom shell script (6.7 seconds)
**操作**:优先优化耗时最长的阶段。
---Checklist: Build Performance Audit
清单:构建性能审计
Before considering your build optimized:
Measurement
- Measured baseline (clean + incremental)
- Verified improvement in Build Timeline
- Documented baseline → optimized comparison
Compilation Settings
- Debug uses incremental compilation
- Build Active Architecture = YES (Debug only)
- Debug uses DWARF (not dSYM)
- Type checking warnings enabled
- Fixed slow type-checking functions (>100ms)
Parallelization
- Parallelize Build enabled in scheme
- No unnecessary target dependencies
- Build phase scripts are conditional (skip in Debug when possible)
- Enabled script sandboxing if using parallel scripts
Xcode 26+ (if applicable)
- Compilation caching enabled for CI/CD ()
COMPILATION_CACHE_ENABLE_CACHING - Checked module variants (Modules Report in build log, see Pattern 10)
- Unified build settings at project level to reduce module variants
- Explicitly Built Modules enabled (default for Swift in Xcode 26)
在认为构建已优化前,请完成以下检查:
测量
- 已测量基准线(清理构建 + 增量构建)
- 已在Build Timeline中验证优化效果
- 已记录基准线 → 优化后的对比数据
编译设置
- Debug使用增量编译
- 仅构建活跃架构 = YES(仅Debug)
- Debug使用DWARF(而非dSYM)
- 已启用类型检查警告
- 已修复缓慢的类型检查函数(>100ms)
并行化
- Scheme中已启用并行构建
- 没有不必要的目标依赖
- 构建阶段脚本已条件化(可能时在Debug中跳过)
- 如果使用并行脚本,已启用脚本沙箱化
Xcode 26+(如适用)
- 已为CI/CD启用编译缓存()
COMPILATION_CACHE_ENABLE_CACHING - 已检查模块变体(构建日志中的模块报告,参见模式10)
- 已在项目级别统一构建设置以减少模块变体
- 已启用显式构建模块(Xcode 26中对Swift默认启用)
Resources
资源
WWDC: 2018-408, 2022-110364, 2024-10171, 2025-247
Docs: /xcode/improving-the-speed-of-incremental-builds, /xcode/building-your-project-with-explicit-module-dependencies
Tools: Xcode Build Timeline (Xcode 14+), Build with Timing Summary (Product → Perform Action), Modules Report (Xcode 16+), Instruments Time Profiler
Remember: Build performance optimization is about systematic measurement and targeted improvements. Optimize the critical path first, measure everything, and verify improvements in the Build Timeline.
WWDC:2018-408, 2022-110364, 2024-10171, 2025-247
文档:/xcode/improving-the-speed-of-incremental-builds, /xcode/building-your-project-with-explicit-module-dependencies
工具:Xcode Build Timeline(Xcode 14+)、带时间摘要的构建(产品 → 执行操作)、模块报告(Xcode 16+)、Instruments时间分析器
记住:构建性能优化是关于系统化测量和针对性改进的工作。优先优化关键路径,测量所有指标,并在Build Timeline中验证优化效果。