Skip to content

Latest commit

 

History

History
239 lines (168 loc) · 17.5 KB

File metadata and controls

239 lines (168 loc) · 17.5 KB

Optimization Checks

This document describes every optimization check the agent skills perform, why each check matters for build time, and where to learn more. It is the developer-facing reference; implementation details live in the skill-level docs under skills/*/references/.

Build Settings Audit

The xcode-project-analyzer audits project-level and target-level build settings against a curated best-practices checklist. Misconfigured settings are one of the most common causes of unnecessarily slow builds, especially in projects that have been migrated across Xcode versions.

Debug configuration checks:

Setting Key Recommended Why
Compilation Mode SWIFT_COMPILATION_MODE singlefile Recompiles only changed files instead of the entire target
Swift Optimization SWIFT_OPTIMIZATION_LEVEL -Onone Optimization passes add compile time with no debug benefit
C/ObjC Optimization GCC_OPTIMIZATION_LEVEL 0 Same rationale for C-family sources
Active Arch Only ONLY_ACTIVE_ARCH YES Building all architectures doubles or triples compile and link time
Debug Info Format DEBUG_INFORMATION_FORMAT dwarf dwarf-with-dsym generates a separate dSYM bundle, adding overhead
Testability ENABLE_TESTABILITY YES Required for @testable import; minor overhead is expected
Compilation Conditions SWIFT_ACTIVE_COMPILATION_CONDITIONS includes DEBUG Guards #if DEBUG code paths
Eager Linking EAGER_LINKING YES Starts linking before all compilation finishes, reducing wall-clock time

Release configuration checks:

Setting Key Recommended Why
Compilation Mode SWIFT_COMPILATION_MODE wholemodule Produces optimized runtime code
Swift Optimization SWIFT_OPTIMIZATION_LEVEL -O or -Osize Optimized binaries for distribution
C/ObjC Optimization GCC_OPTIMIZATION_LEVEL s Optimizes for size
Active Arch Only ONLY_ACTIVE_ARCH NO Release must include all supported architectures
Debug Info Format DEBUG_INFORMATION_FORMAT dwarf-with-dsym Required for crash symbolication
Testability ENABLE_TESTABILITY NO Removes internal-symbol export overhead

General (all configurations) checks:

Setting Key Recommended Why
Compilation Caching COMPILATION_CACHE_ENABLE_CACHING YES Caches Swift and C-family compilation results; biggest wins on branch switching and clean builds
Integrated Swift Driver SWIFT_USE_INTEGRATED_DRIVER YES Eliminates inter-process overhead for compilation scheduling
Clang Modules CLANG_ENABLE_MODULES YES Caches module maps on disk instead of reprocessing headers
Explicit Modules SWIFT_ENABLE_EXPLICIT_MODULES Evaluate per-project Improves parallelism but may regress due to scanning overhead; benchmark before and after

References:

CocoaPods Projects

CocoaPods is deprecated. When a project uses CocoaPods, do not attempt CocoaPods-specific build optimizations (linkage mode changes, COCOAPODS_PARALLEL_CODE_SIGN, Podfile tweaks). These are unreliable and frequently regress build times.

Recommend migrating to Swift Package Manager as the highest-impact long-term improvement. SPM advantages for build time: compilation caching works out of the box, better build parallelism from the dependency graph, no pod install xcconfig regeneration overhead, and native Xcode integration with full support for modern features like explicit modules.

Focus analysis on first-party targets and build settings the project controls directly. Do not audit Pods.xcodeproj or the Podfile.

Script Phase Analysis

The xcode-project-analyzer inspects every Run Script phase in the project for missing metadata and unnecessary execution.

What the agent checks:

  • Scripts without declared input and output files run on every build regardless of changes. The agent flags these and recommends adding declarations or .xcfilelist files.
  • Scripts that always run (alwaysOutOfDate = 1) are flagged with a recommendation to make them conditional.
  • Debug/simulator guards: scripts that upload symbols, run release-only tools, or perform network calls should be skipped in Debug or Simulator builds.
  • Timestamp-touching tools: linters or formatters that modify file timestamps without changing content silently invalidate build inputs and force replanning of every Swift module.
  • Parallelization: scripts with correctly declared dependencies can run in parallel with compilation instead of blocking it.

References:

Compile Hotspot Detection

The xcode-compilation-analyzer identifies Swift source files and expressions that take disproportionately long to type-check.

What the agent checks:

  • Build Timing Summary categories to find targets where CompileSwiftSources dominates.
  • Compiler diagnostic flags (-warn-long-function-bodies, -warn-long-expression-type-checking) to surface specific slow expressions.
  • Optional deep diagnostics: -debug-time-compilation (per-file ranking), -debug-time-function-bodies (per-function timing), -stats-output-dir (compiler statistics as JSON).
  • Patterns that commonly cause slow type-checking:
    • Complex chained or nested expressions without intermediate type annotations
    • Nested ternaries or overloaded generic chains
    • Long method chains (.map().flatMap().filter().reduce()) without typed intermediates
    • Closures passed to generic functions without explicit return types

References:

Zero-Change Build Overhead

The xcode-project-analyzer measures and diagnoses the fixed cost of rebuilding when nothing has changed.

What the agent checks:

Even with no source edits, incremental builds incur fixed overhead. The agent measures zero-change build time and investigates these categories from the Build Timing Summary:

Category What it does Why it matters
PhaseScriptExecution Script phases with alwaysOutOfDate or missing I/O Runs on every build regardless of changes
CodeSign Signs the app and embedded frameworks Runs unconditionally; scales with signed binary count
ValidateEmbeddedBinary Validates against provisioning profile Runs unconditionally
CopySwiftLibs Copies Swift standard libraries Runs even when nothing changed
RegisterWithLaunchServices Registers the built app Fast but always present
ProcessInfoPlistFile Re-processes Info.plist files Scales with target count
ExtractAppIntentsMetadata Extracts App Intents metadata from all targets including third-party dependencies Driven by Xcode, not by per-target project settings; unnecessary overhead if the project does not use App Intents but not cleanly suppressible from the repo (classify as xcode-behavior)

A zero-change build above 5 seconds on Apple Silicon typically indicates script phase overhead or excessive codesigning.

References:

Target Dependency Review

The xcode-project-analyzer audits target dependencies and scheme configuration for correctness and parallelism.

What the agent checks:

  • Target dependencies are explicit and accurate. Missing dependencies cause build failures; inflated dependencies block parallel work.
  • Removed or stale dependencies that no longer reflect real build requirements.
  • Scheme builds targets in Dependency Order (not manual order).
  • Oversized monolithic targets that serialize compilation when the work could be split across parallel targets.
  • DEFINES_MODULE is enabled for custom frameworks that should benefit from module maps.
  • Public headers are self-contained enough to compile as a module.

References:

Module Variant Detection

The xcode-project-analyzer and spm-build-analysis skills check for configuration drift that causes the same module to be built multiple times with different options.

What the agent checks:

  • Targets that import the same SPM package but compile with different Swift compiler options produce separate module variants, inflating SwiftEmitModule task counts.
  • Drift in SWIFT_OPTIMIZATION_LEVEL, SWIFT_COMPILATION_MODE, OTHER_SWIFT_FLAGS, and target-level overrides.
  • Project-level vs target-level build setting overrides: settings should be at the project level unless a target has a specific reason to override.
  • Preprocessor macros or other build options that differ across sibling targets importing the same modules.

References:

SPM Graph Analysis

The spm-build-analysis skill inspects Swift Package Manager dependencies for graph structure issues, plugin overhead, and dependency hygiene.

What the agent checks:

  • Large umbrella packages that trigger widespread rebuilds.
  • Dependency layering violations: features depending on features instead of flowing inward (Common/Core → Services → Features/UI).
  • Circular dependencies (target-level cycles must be refactored; extract shared contracts into a separate module).
  • Build-tool and command plugins that run during incremental builds even when no input changed.
  • Branch-pinned packages (branch:) that force network checks on every fresh resolve; recommends pinning to tags or revision: hashes.
  • Package reference verification: confirms packages listed in recommendations actually appear in project.pbxproj as linked dependencies.
  • Transitive dependency minimization: flags @_exported import umbrella modules that create hidden rebuild chains.
  • Interface/implementation separation opportunities for modules with heavy dependencies.
  • Test target isolation: test targets should depend on the module under test, not the entire app target.

References:

Swift Macro Impact

The spm-build-analysis skill checks for incremental build cascading caused by heavy Swift macro usage.

What the agent checks:

  • Projects using macro-heavy libraries (e.g., TCA, swift-syntax-based tools) are susceptible to cascading where a trivial change rebuilds most of the app.
  • Macro expansion can invalidate downstream modules even when the expanded output has not changed.
  • swift-syntax building universally (all architectures) when no prebuilt binary is available adds significant overhead to clean builds and CI.
  • Recommends isolating macro-using code into fewer, more stable modules to limit the invalidation blast radius.

References:

SwiftUI View Decomposition

The xcode-compilation-analyzer checks for SwiftUI view bodies that are expensive to type-check.

What the agent checks:

  • Monolithic body properties (roughly 50+ lines) that force the type-checker to resolve a single large result-builder expression.
  • @ViewBuilder helper properties instead of separate struct View types -- separate structs reduce the type-checker scope per body.
  • Deeply nested Group/VStack/HStack hierarchies within a single body.
  • Recommends extracting subviews into dedicated struct View types.

References:

Asset Catalog Parallelism

The xcode-project-analyzer checks asset catalog compilation for single-threaded bottlenecks.

What the agent checks:

  • CompileAssetCatalog is single-threaded per target. Multiple catalogs within the same target compile sequentially in a single process.
  • If asset catalog compilation appears as a significant timing category, recommends splitting assets into separate resource bundles across separate targets for parallel compilation.
  • Asset catalog compilation is not cacheable by the Xcode compilation cache (CompileAssetCatalogVariant is non-cacheable).
  • Checks whether asset catalogs rebuild during incremental builds even when no assets changed.

References:

Access Control Optimization

The xcode-compilation-analyzer checks for access control patterns that inflate compiler work.

What the agent checks:

  • Classes not intended for subclassing should be marked final. This eliminates virtual dispatch overhead and lets the compiler de-virtualize method calls.
  • Properties and methods not used outside their declaration or file should use private or fileprivate. Narrower visibility reduces the compiler's symbol search space.
  • internal (the default) is preferred over public unless the symbol genuinely crosses module boundaries.
  • struct and enum are preferred over class when reference semantics are not needed. Value types are simpler for the compiler to reason about.
  • Objective-C bridging surfaces should be kept narrow. Swift members marked private do not need Objective-C visibility.

References:

Incremental Build Diagnostics

The xcode-compilation-analyzer and xcode-project-analyzer investigate categories that disproportionately inflate incremental builds.

What the agent checks:

  • Planning Swift module: Can dominate incremental builds (up to 30s per module), sometimes exceeding clean build time. If modules are replanned but no compiles are scheduled, build inputs are being invalidated unexpectedly.
  • SwiftEmitModule: Can take 60s+ after a single-line change in large modules. If it exceeds compile time for the same target, the module's public API surface may be unnecessarily wide.
  • Task Backtraces (Xcode 16.4+): Enable via Scheme Editor > Build > Build Debugging to see why each task re-ran. The agent recommends enabling this when incremental build overhead is unexplained.
  • Multi-platform build multiplication: Adding a secondary platform (e.g., watchOS) can cause shared SPM packages to build multiple times per platform/architecture combination.

References: