
Xcode Compilation Analyzer
- 2.8k installs
- 1.2k repo stars
- Updated April 15, 2026
- avdlee/xcode-build-optimization-agent-skill
xcode-compilation-analyzer is an agent skill that analyzes Swift compile hotspots from timing summaries and diagnostics, producing ranked source-level optimization recommendations.
About
xcode-compilation-analyzer is an agent skill for diagnosing slow Swift and mixed-language compilation using build timing summaries and Swift frontend diagnostics. It starts from evidence such as recent build-benchmark artifacts or raw timing-summary output, prefers analysis-only compiler flags over persistent project edits during investigation, and ranks findings by expected wall-clock impact rather than cumulative compile time when tasks run in parallel. The workflow inspects CompileSwiftSources tasks, SwiftEmitModule spikes after small edits, Planning Swift module invalidation, and ad hoc runs with warn-long-expression-type-checking and warn-long-function-bodies thresholds plus deeper debug-time-compilation and stats-output-dir flags. A diagnose_compilation.py script surfaces ranked type-checking hotspots alongside timing categories. Apple-derived checks cover missing explicit types, complex chained expressions, AnyObject delegate typing, oversized bridging headers, missing final classes, broad access control, monolithic SwiftUI body properties, and mixed Swift-Objective-C surfaces. Reporting requires observed evidence, affected files, expected wait-time impact, confidence, and.
- Ranks recommendations by wall-clock impact when compile tasks run in parallel.
- Inspects Build Timing Summary, SwiftEmitModule, and Planning Swift module categories.
- Runs diagnose_compilation.py with warn-long thresholds to rank type-checking hotspots.
- Apple-derived checks for SwiftUI body decomposition, final classes, and bridging headers.
- Requires explicit approval before editing source or persistent build settings.
Xcode Compilation Analyzer by the numbers
- 2,832 all-time installs (skills.sh)
- +63 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #59 of 1,048 Mobile Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
xcode-compilation-analyzer capabilities & compatibility
- Capabilities
- build timing summary parsing · type checking hotspot diagnostics · wall clock impact ranking · swift and objc bridging analysis · recommendation reporting with approval gates
- Use cases
- debugging · testing
What xcode-compilation-analyzer says it does
Do not edit source or build settings without explicit developer approval.
npx skills add https://github.com/avdlee/xcode-build-optimization-agent-skill --skill xcode-compilation-analyzerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.8k |
|---|---|
| repo stars | ★ 1.2k |
| Security audit | 3 / 3 scanners passed |
| Last updated | April 15, 2026 |
| Repository | avdlee/xcode-build-optimization-agent-skill ↗ |
Why is my Xcode Swift build slow and which files or expressions dominate type-checking time?
Analyze Swift compile hotspots from build timing summaries and frontend diagnostics, then recommend source-level optimization plans ranked by wall-clock impact.
Who is it for?
iOS developers seeing slow CompileSwiftSources, warn-long-function-bodies output, or SwiftEmitModule spikes on incremental builds.
Skip if: Skip when the bottleneck is general project configuration without compile evidence; hand off to xcode-project-analyzer instead.
When should I use this skill?
User reports slow Swift compilation, type-checking warnings, expensive clean-build compile phases, or wants compile hotspot analysis.
What you get
Evidence-backed recommendation list ranked by wall-clock impact with affected modules, confidence, and approval gates before edits.
- Build timing analysis
- Script phase input/output fixes
- Module map and dependency recommendations
By the numbers
- Cites Apple documentation on improving incremental build speed
- Covers xcodebuild -showBuildTimingSummary and Build With Timing Summary measurement
Files
Xcode Compilation Analyzer
Use this skill when compile time, not just general project configuration, looks like the bottleneck.
Core Rules
- Start from evidence, ideally a recent
.build-benchmark/artifact or raw timing-summary output. - Prefer analysis-only compiler flags over persistent project edits during investigation.
- Rank findings by expected wall-clock impact, not cumulative compile-time impact. When compile tasks are heavily parallelized (sum of compile categories >> wall-clock median), note that fixing individual hotspots may improve parallel efficiency without reducing build wait time.
- When the evidence points to parallelized work rather than serial bottlenecks, label recommendations as "Reduces compiler workload (parallel)" rather than "Reduces build time."
- Do not edit source or build settings without explicit developer approval.
What To Inspect
Build Timing Summaryoutput from clean and incremental builds- long-running
CompileSwiftSourcesor per-file compilation tasks SwiftEmitModuletime -- can reach 60s+ after a single-line change in large modules; if it dominates incremental builds, the module is likely too large or macro-heavyPlanning Swift moduletime -- if this category is disproportionately large in incremental builds (up to 30s per module), it signals unexpected input invalidation or macro-related rebuild cascading- ad hoc runs with:
-Xfrontend -warn-long-expression-type-checking=<ms>-Xfrontend -warn-long-function-bodies=<ms>- deeper diagnostic flags for thorough investigation:
-Xfrontend -debug-time-compilation-- per-file compile times to rank the slowest files-Xfrontend -debug-time-function-bodies-- per-function compile times (unfiltered, complements the threshold-based warning flags)-Xswiftc -driver-time-compilation-- driver-level timing to isolate driver overhead-Xfrontend -stats-output-dir <path>-- detailed compiler statistics (JSON) per compilation unit for root-cause analysis- mixed Swift and Objective-C surfaces that increase bridging work
Analysis Workflow
1. Identify whether the main issue is broad compilation volume or a few extreme hotspots. 2. Parse timing-summary categories and rank the biggest compile contributors. 3. Run the diagnostics script to surface type-checking hotspots:
python3 scripts/diagnose_compilation.py \
--project App.xcodeproj \
--scheme MyApp \
--configuration Debug \
--destination "platform=iOS Simulator,name=iPhone 16" \
--threshold 100 \
--output-dir .build-benchmarkThis produces a ranked list of functions and expressions that exceed the millisecond threshold. Use the diagnostics artifact alongside source inspection to focus on the most expensive files first. 4. Map the evidence to a concrete recommendation list. 5. Separate code-level suggestions from project-level or module-level suggestions.
Apple-Derived Checks
Look for these patterns first:
- missing explicit type information in expensive expressions
- complex chained or nested expressions that are hard to type-check
- delegate properties typed as
AnyObjectinstead of a concrete protocol - oversized Objective-C bridging headers or generated Swift-to-Objective-C surfaces
- header imports that skip framework qualification and miss module-cache reuse
- classes missing
finalthat are never subclassed - overly broad access control (
public/open) on internal-only symbols - monolithic SwiftUI
bodyproperties that should be decomposed into subviews - long method chains or closures without intermediate type annotations
Reporting Format
For each recommendation, include:
- observed evidence
- likely affected file or module
- expected wait-time impact (e.g. "Expected to reduce your clean build by ~2s" or "Reduces parallel compile work but unlikely to reduce build wait time")
- confidence
- whether approval is required before applying it
If the evidence points to project configuration instead of source, hand off to `xcode-project-analyzer` by reading its SKILL.md and applying its workflow to the same project context.
Preferred Tactics
- Suggest ad hoc flag injection through the build command before recommending persistent build-setting changes.
- Prefer narrowing giant view builders, closures, or result-builder expressions into smaller typed units.
- Recommend explicit imports and protocol typing when they reduce compiler search space.
- Call out when mixed-language boundaries are the real issue rather than Swift syntax alone.
Additional Resources
- For the detailed audit checklist, see references/code-compilation-checks.md
- For the shared recommendation structure, see references/recommendation-format.md
- For source citations, see references/build-optimization-sources.md
Build Optimization Sources
This file stores the external sources that the README and skill docs should cite consistently.
Apple: Improving the speed of incremental builds
Source:
- <https://developer.apple.com/documentation/xcode/improving-the-speed-of-incremental-builds>
Key takeaways:
- Measure first with
Build With Timing Summaryorxcodebuild -showBuildTimingSummary. - Accurate target dependencies improve correctness and parallelism.
- Run scripts should declare inputs and outputs so Xcode can skip unnecessary work.
.xcfilelistfiles are appropriate when scripts have many inputs or outputs.- Custom frameworks and libraries benefit from module maps, typically by enabling
DEFINES_MODULE. - Module reuse is strongest when related sources compile with consistent options.
- Breaking monolithic targets into better-scoped modules can reduce unnecessary rebuilds.
Apple: Improving build efficiency with good coding practices
Source:
- <https://developer.apple.com/documentation/xcode/improving-build-efficiency-with-good-coding-practices>
Key takeaways:
- Use framework-qualified imports when module maps are available.
- Keep Objective-C bridging surfaces narrow.
- Prefer explicit type information when inference becomes expensive.
- Use explicit delegate protocols instead of overly generic delegate types.
- Simplify complex expressions that are hard for the compiler to type-check.
Apple: Building your project with explicit module dependencies
Source:
- <https://developer.apple.com/documentation/xcode/building-your-project-with-explicit-module-dependencies>
Key takeaways:
- Explicit module builds make module work visible in the build log and improve scheduling.
- Repeated builds of the same module often point to avoidable module variants.
- Inconsistent build options across targets can force duplicate module builds.
- Timing summaries can reveal option drift that prevents module reuse.
SwiftLee: Build performance analysis for speeding up Xcode builds
Source:
- <https://www.avanderlee.com/optimization/analysing-build-performance-xcode/>
Key takeaways:
- Clean and incremental builds should both be measured because they reveal different problems.
- Build Timeline and Build Timing Summary are practical starting points for build optimization.
- Build scripts often produce large incremental-build wins when guarded correctly.
-warn-long-function-bodiesand-warn-long-expression-type-checkinghelp surface compile hotspots.- Typical debug and release build setting mismatches are worth auditing, especially in older projects.
Apple: Xcode Release Notes -- Compilation Caching
Source:
- Xcode Release Notes (149700201)
Key takeaways:
- Compilation caching is an opt-in feature for Swift and C-family languages.
- It caches prior compilation results and reuses them when the same source inputs are recompiled.
- Branch switching and clean builds benefit the most.
- Can be enabled via the "Enable Compilation Caching" build setting or per-user project settings.
Apple: Demystify explicitly built modules (WWDC24)
Source:
- <https://developer.apple.com/videos/play/wwdc2024/10171/>
Key takeaways:
- Explains how explicitly built modules divide compilation into scan, module build, and source compile stages.
- Unrelated modules build in parallel, improving CPU utilization.
- Module variant duplication is a key bottleneck -- uniform compiler options across targets prevent it.
- The build log shows each module as a discrete task, making it easier to diagnose scheduling issues.
Swift Compile-Time Best Practices
Well-known Swift language patterns that reduce type-checker workload during compilation:
- Mark classes
finalwhen they are not intended for subclassing. This eliminates dynamic dispatch overhead and allows the compiler to de-virtualize method calls. - Restrict access control to the narrowest useful scope (
private,fileprivate). Fewer visible symbols reduce the compiler's search space during type resolution. - Prefer value types (
struct,enum) overclasswhen reference semantics are not needed. Value types are simpler for the compiler to reason about. - Break long method chains (
.map().flatMap().filter()) into intermediateletbindings with explicit type annotations. Even simple-looking chains can take seconds to type-check. - Provide explicit return types on closures passed to generic functions, especially in SwiftUI result-builder contexts.
- Decompose large SwiftUI
bodyproperties into smaller extracted subviews. Each subview narrows the scope of the result-builder expression the type-checker must resolve.
Bitrise: Demystifying Explicitly Built Modules for Xcode
Source:
- <https://bitrise.io/blog/post/demystifying-explicitly-built-modules-for-xcode>
Key takeaways:
- Explicit module builds give
xcodebuildvisibility into smaller compilation tasks for better parallelism. - Enabled by default for C/Objective-C in Xcode 16+; experimental for Swift.
- Minimizing module variants by aligning build options is the primary optimization lever.
- Some projects see regressions from dependency scanning overhead -- benchmark before and after.
Bitrise: Xcode Compilation Cache FAQ
Source:
- <https://docs.bitrise.io/en/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq.html>
Key takeaways:
- Granular caching is controlled by
SWIFT_ENABLE_COMPILE_CACHEandCLANG_ENABLE_COMPILE_CACHE, under the umbrellaCOMPILATION_CACHE_ENABLE_CACHINGsetting. - Non-cacheable tasks include
CompileStoryboard,CompileXIB,CompileAssetCatalogVariant,PhaseScriptExecution,DataModelCompile,CopyPNGFile,GenerateDSYMFile, andLd. - SPM dependencies are not yet cacheable as of Xcode 26 beta.
RocketSim Docs: Build Insights
Sources:
- <https://www.rocketsim.app/docs/features/build-insights/build-insights/>
- <https://www.rocketsim.app/docs/features/build-insights/team-build-insights/>
Key takeaways:
- RocketSim automatically tracks clean vs incremental builds over time without build scripts.
- It reports build counts, duration trends, and percentile-based metrics such as p75 and p95.
- Team Build Insights adds machine, Xcode, and macOS comparisons for cross-team visibility.
- This repository is best positioned as the point-in-time analyze-and-improve toolkit, while RocketSim is the monitor-over-time companion.
Swift Forums: Slow incremental builds because of planning swift module
Source:
- <https://forums.swift.org/t/slow-incremental-builds-because-of-planning-swift-module/84803>
Key takeaways:
- "Planning Swift module" can dominate incremental builds (up to 30s per module), sometimes exceeding clean build time.
- Replanning every module without scheduling compiles is a sign that build inputs are being modified unexpectedly (e.g., a misconfigured linter touching file timestamps).
- Enable Task Backtraces (Xcode 16.4+: Scheme Editor > Build > Build Debugging) to see why each task re-ran in an incremental build.
- Heavy Swift macro usage (e.g., TCA / swift-syntax) can cause trivial changes to cascade into near-full rebuilds.
swift-syntaxbuilds universally (all architectures) when no prebuilt binary is available, adding significant overhead.SwiftEmitModulecan take 60s+ after a single-line change in large modules.- Asset catalog compilation is single-threaded per target; splitting assets into separate bundles across targets enables parallel compilation.
- Multi-platform targets (e.g., adding watchOS) can cause SPM packages to build 3x (iOS arm64, iOS x86_64, watchOS arm64).
- Zero-change incremental builds still incur ~10s of fixed overhead: compute dependencies, send project description, create build description, script phases, codesigning, and validation.
- Codesigning and validation run even when output has not changed.
Code Compilation Checks
Use this reference when a build benchmark shows compilation dominating build time.
Primary Evidence Sources
xcodebuild -showBuildTimingSummary- build log compile tasks
-warn-long-function-bodies-warn-long-expression-type-checking-debug-time-compilation(per-file compile time ranking)-debug-time-function-bodies(unfiltered per-function timing)-driver-time-compilation(driver overhead)-stats-output-dir(detailed compiler statistics as JSON)
Triage Questions
1. Is one file or expression dominating compile time? 2. Is the issue mostly Swift type-checking, mixed-language bridging, or header import churn? 3. Are multiple files in the same module paying the same module-setup cost repeatedly? 4. Is SwiftEmitModule disproportionately large for any target? If a single-line change triggers 60s+ of module emission, the target is likely too large or heavily macro-dependent. 5. Does Planning Swift module dominate incremental builds? If modules are replanned but no compiles are scheduled, build inputs are being invalidated unexpectedly.
Checklist
Explicit typing
- Add explicit property or local variable types when initialization expressions are complex.
- Prefer intermediate typed variables over one giant inferred expression.
Expression simplification
- Break long chains into smaller expressions.
- Split complex result-builder code into smaller helpers or subviews.
- Replace nested ternaries or overloaded generic chains with simpler steps.
Delegate typing
- Avoid
AnyObject?or overly generic delegate surfaces. - Prefer a named delegate protocol so the compiler has a narrower lookup space.
Objective-C and Swift bridging
- Keep the Objective-C bridging header narrow.
- Move internal-only Objective-C declarations out of the bridging surface.
- Mark Swift members
privatewhen they do not need Objective-C visibility.
Framework-qualified imports
- Prefer
#import <Framework/Header.h>or module imports when a module map exists. - Watch for textual includes that defeat module-cache reuse.
Access control and dispatch optimization
- Mark classes not intended for subclassing as
final. This eliminates virtual dispatch overhead and lets the compiler de-virtualize method calls, reducing both compile and runtime cost. - Use
privateorfileprivatefor properties and methods not used outside their declaration or file. Narrower visibility reduces the compiler's symbol search space. - Prefer
internal(the default) overpublicunless the symbol genuinely crosses module boundaries. Wider access forces the compiler to consider more call sites.
Value types over reference types
- Prefer
structandenumoverclasswhen reference semantics are not needed. Value types are simpler for the compiler to reason about and do not require vtable dispatch. - When a class exists solely to group data without identity semantics, convert it to a struct.
SwiftUI view decomposition
- Extract subviews into dedicated
struct Viewtypes instead of using@ViewBuilderhelper properties. Separate structs reduce the type-checker scope perbodyproperty. - Break monolithic
bodyproperties (roughly 50+ lines) into smaller composed subviews. Large result-builder bodies are among the most expensive expressions to type-check. - Avoid deeply nested
Group/VStack/HStackhierarchies within a single body.
Closure and chain patterns
- Avoid long method chains like
.map().flatMap().filter().reduce()without intermediate type annotations. Each link in the chain multiplies the type-checker's candidate set. - Break complex closures into named functions with explicit parameter and return types.
- Add explicit return types to closures passed to generic functions so the compiler does not need to infer them from context.
Generic constraint complexity
- Minimize deeply nested generic constraints (e.g.,
where T: Collection, T.Element: Comparable, T.Element.SubSequence: ...). Each additional constraint widens the compiler's search space. - Use type aliases to flatten complex generic stacks into readable names.
- Prefer
some Protocol(opaque return types) over unconstrained generics when the concrete type does not need to be visible to callers.
Module emission and planning overhead
- Check
SwiftEmitModuletime in the Build Timing Summary. Large modules with many public symbols take longer to emit, and this cost is paid on every incremental build that touches the module. - If
SwiftEmitModuleexceeds compile time for the same target, the module's public API surface may be unnecessarily wide -- narrow access control or split the module. - Check
Planning Swift moduletime. If it is significant in incremental builds, escalate toxcode-project-analyzerto investigate unexpected input invalidation or misconfigured scripts.
Precompiled and prefix headers
- For mixed-language projects with large Objective-C codebases, verify that prefix headers are not bloated with unnecessary imports. Every import in a prefix header is parsed for every translation unit.
- Migrate away from prefix headers toward explicit module imports where possible.
Recommendation Heuristics
- High impact: repeated type-check warnings in a hot module, giant bridging headers, or a few files dominating compile time.
- Medium impact: several moderate hotspots in result builders or overloaded generic code.
- Low impact: isolated warnings without measurable benchmark impact.
Escalation Guidance
Hand findings to xcode-project-analyzer when:
- build scripts dominate instead of compilation
- module reuse is blocked by project settings
- target structure or explicit-module settings appear to be the real bottleneck
Planning Swift moduleoverhead points to input invalidation or script-related causes rather than source complexity
Recommendation Format
All optimization skills should report recommendations in a shared structure so the orchestrator can merge and prioritize them cleanly.
Required Fields
Each recommendation should include:
titlewait_time_impact-- plain-language statement of expected wall-clock impact, e.g. "Expected to reduce your clean build by ~3s", "Reduces parallel compile work but unlikely to reduce build wait time", or "Impact on wait time is uncertain -- re-benchmark to confirm"actionability-- classifies how fixable the issue is from the project (see values below)categoryobserved_evidenceestimated_impactconfidenceapproval_requiredbenchmark_verification_status
Actionability Values
Every recommendation must include an actionability classification:
repo-local-- Fix lives entirely in project files, source code, or local configuration. The developer can apply it without side effects outside the repo.package-manager-- Requires CocoaPods or SPM configuration changes that may have broad side effects (e.g., linkage mode, dependency restructuring). These should be benchmarked before and after.xcode-behavior-- Observed cost is driven by Xcode internals and is not suppressible from the project. Report the finding for awareness but do not promise a fix.upstream-- Requires changes in a third-party dependency or external tool. The developer cannot fix it locally.
Suggested Optional Fields
scopeaffected_filesaffected_targetsaffected_packagesimplementation_notesrisk_level
JSON Example
{
"recommendations": [
{
"title": "Guard a release-only symbol upload script",
"wait_time_impact": "Expected to reduce your incremental build by approximately 6 seconds.",
"actionability": "repo-local",
"category": "project",
"observed_evidence": [
"Incremental builds spend 6.3 seconds in a run script phase.",
"The script runs for Debug builds even though the output is only needed in Release."
],
"estimated_impact": "High incremental-build improvement",
"confidence": "High",
"approval_required": true,
"benchmark_verification_status": "Not yet verified",
"scope": "Target build phase",
"risk_level": "Low"
}
]
}Markdown Rendering Guidance
When rendering for human review, preserve the same field order:
1. title 2. wait-time impact 3. actionability 4. observed evidence 5. estimated impact 6. confidence 7. approval required 8. benchmark verification status
That makes it easier for the developer to approve or reject specific items quickly.
Verification Status Values
Recommended values:
Not yet verifiedQueued for verificationVerified improvementNo measurable improvementInconclusive due to benchmark noise
#!/usr/bin/env python3
"""Run a single Xcode build with -Xfrontend diagnostics to find slow type-checking."""
import argparse
import json
import re
import subprocess
import sys
import time
from datetime import datetime, timezone
from pathlib import Path
from typing import Dict, List, Optional
_TYPECHECK_RE = re.compile(
r"^(?P<file>.+?):(?P<line>\d+):(?P<col>\d+): warning: "
r"(?P<kind>instance method|global function|getter|type-check|expression) "
r"'?(?P<name>[^']*?)'?\s+took\s+(?P<ms>\d+)ms\s+to\s+type-check"
)
_EXPRESSION_RE = re.compile(
r"^(?P<file>.+?):(?P<line>\d+):(?P<col>\d+): warning: "
r"expression took\s+(?P<ms>\d+)ms\s+to\s+type-check"
)
_FILE_TIME_RE = re.compile(
r"^\s*(?P<seconds>\d+(?:\.\d+)?)\s+seconds\s+.*\s+compiling\s+(?P<file>\S+)"
)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Run an Xcode build with -Xfrontend type-checking diagnostics."
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--workspace", help="Path to the .xcworkspace file")
group.add_argument("--project", help="Path to the .xcodeproj file")
parser.add_argument("--scheme", required=True, help="Scheme to build")
parser.add_argument("--configuration", default="Debug", help="Build configuration")
parser.add_argument("--destination", help="xcodebuild destination string")
parser.add_argument("--derived-data-path", help="DerivedData path override")
parser.add_argument("--output-dir", default=".build-benchmark", help="Output directory")
parser.add_argument(
"--threshold",
type=int,
default=100,
help="Millisecond threshold for -warn-long-function-bodies and "
"-warn-long-expression-type-checking (default: 100)",
)
parser.add_argument("--skip-clean", action="store_true", help="Skip clean before build")
parser.add_argument(
"--per-file-timing",
action="store_true",
help="Add -Xfrontend -debug-time-compilation to report per-file compile times.",
)
parser.add_argument(
"--stats-output",
action="store_true",
help="Add -Xfrontend -stats-output-dir to collect detailed compiler statistics.",
)
parser.add_argument(
"--extra-arg",
action="append",
default=[],
help="Additional xcodebuild argument. Can be passed multiple times.",
)
return parser.parse_args()
def command_base(args: argparse.Namespace) -> List[str]:
command = ["xcodebuild"]
if args.workspace:
command.extend(["-workspace", args.workspace])
if args.project:
command.extend(["-project", args.project])
command.extend(["-scheme", args.scheme, "-configuration", args.configuration])
if args.destination:
command.extend(["-destination", args.destination])
if args.derived_data_path:
command.extend(["-derivedDataPath", args.derived_data_path])
command.extend(args.extra_arg)
return command
def parse_diagnostics(output: str) -> List[Dict]:
"""Extract type-checking warnings from xcodebuild output."""
warnings: List[Dict] = []
seen = set()
for raw_line in output.splitlines():
line = raw_line.strip()
match = _TYPECHECK_RE.match(line)
if match:
key = (match.group("file"), match.group("line"), match.group("col"), "function-body")
if key in seen:
continue
seen.add(key)
warnings.append(
{
"file": match.group("file"),
"line": int(match.group("line")),
"column": int(match.group("col")),
"duration_ms": int(match.group("ms")),
"kind": "function-body",
"name": match.group("name"),
}
)
continue
match = _EXPRESSION_RE.match(line)
if match:
key = (match.group("file"), match.group("line"), match.group("col"), "expression")
if key in seen:
continue
seen.add(key)
warnings.append(
{
"file": match.group("file"),
"line": int(match.group("line")),
"column": int(match.group("col")),
"duration_ms": int(match.group("ms")),
"kind": "expression",
"name": "",
}
)
warnings.sort(key=lambda w: w["duration_ms"], reverse=True)
return warnings
def parse_file_timings(output: str) -> List[Dict]:
"""Extract per-file compile times from -debug-time-compilation output."""
timings: List[Dict] = []
seen = set()
for raw_line in output.splitlines():
match = _FILE_TIME_RE.match(raw_line.strip())
if match:
filepath = match.group("file")
if filepath in seen:
continue
seen.add(filepath)
timings.append(
{
"file": filepath,
"duration_seconds": float(match.group("seconds")),
}
)
timings.sort(key=lambda t: t["duration_seconds"], reverse=True)
return timings
def main() -> int:
args = parse_args()
output_dir = Path(args.output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
scheme_slug = args.scheme.replace(" ", "-").lower()
artifact_stem = f"{timestamp}-{scheme_slug}"
base = command_base(args)
if not args.skip_clean:
print("Cleaning build products...")
clean = subprocess.run([*base, "clean"], capture_output=True, text=True)
if clean.returncode != 0:
sys.stderr.write(clean.stdout + clean.stderr)
return clean.returncode
threshold = str(args.threshold)
swift_flags = (
f"$(inherited) -Xfrontend -warn-long-function-bodies={threshold} "
f"-Xfrontend -warn-long-expression-type-checking={threshold}"
)
if args.per_file_timing:
swift_flags += " -Xfrontend -debug-time-compilation"
stats_dir: Optional[Path] = None
if args.stats_output:
stats_dir = output_dir / f"{artifact_stem}-stats"
stats_dir.mkdir(parents=True, exist_ok=True)
swift_flags += f" -Xfrontend -stats-output-dir -Xfrontend {stats_dir}"
build_command = [
*base,
"build",
"-showBuildTimingSummary",
f"OTHER_SWIFT_FLAGS={swift_flags}",
]
extras = []
if args.per_file_timing:
extras.append("per-file timing")
if args.stats_output:
extras.append("stats output")
extras_label = f" + {', '.join(extras)}" if extras else ""
print(f"Building with type-check threshold {threshold}ms{extras_label}...")
started = time.perf_counter()
result = subprocess.run(build_command, capture_output=True, text=True)
elapsed = round(time.perf_counter() - started, 3)
combined_output = result.stdout + result.stderr
log_path = output_dir / f"{artifact_stem}-diagnostics.log"
log_path.write_text(combined_output)
warnings = parse_diagnostics(combined_output)
file_timings: Optional[List[Dict]] = None
if args.per_file_timing:
file_timings = parse_file_timings(combined_output)
artifact = {
"schema_version": "1.0.0",
"created_at": datetime.now(timezone.utc).isoformat(),
"type": "compilation-diagnostics",
"build": {
"entrypoint": "workspace" if args.workspace else "project",
"path": args.workspace or args.project,
"scheme": args.scheme,
"configuration": args.configuration,
"destination": args.destination or "",
},
"threshold_ms": args.threshold,
"build_duration_seconds": elapsed,
"build_success": result.returncode == 0,
"raw_log_path": str(log_path),
"warnings": warnings,
"summary": {
"total_warnings": len(warnings),
"function_body_warnings": sum(1 for w in warnings if w["kind"] == "function-body"),
"expression_warnings": sum(1 for w in warnings if w["kind"] == "expression"),
"slowest_ms": warnings[0]["duration_ms"] if warnings else 0,
},
}
if file_timings is not None:
artifact["per_file_timings"] = file_timings
if stats_dir is not None:
artifact["stats_dir"] = str(stats_dir)
artifact_path = output_dir / f"{artifact_stem}-diagnostics.json"
artifact_path.write_text(json.dumps(artifact, indent=2) + "\n")
print(f"\nSaved diagnostics artifact: {artifact_path}")
print(f"Build {'succeeded' if result.returncode == 0 else 'failed'} in {elapsed}s")
print(f"Found {len(warnings)} type-check warnings above {threshold}ms threshold\n")
if warnings:
print(f"{'Duration':>10} {'Kind':<15} {'Location'}")
print(f"{'--------':>10} {'----':<15} {'--------'}")
for w in warnings[:20]:
loc = f"{w['file']}:{w['line']}:{w['column']}"
label = w["name"] if w["name"] else "(expression)"
print(f"{w['duration_ms']:>8}ms {w['kind']:<15} {loc} {label}")
if len(warnings) > 20:
print(f"\n ... and {len(warnings) - 20} more (see {artifact_path})")
else:
print("No type-checking hotspots found above threshold.")
if file_timings:
print(f"\nPer-file compile times (top 20):\n")
print(f"{'Duration':>12} {'File'}")
print(f"{'--------':>12} {'----'}")
for t in file_timings[:20]:
print(f"{t['duration_seconds']:>10.3f}s {t['file']}")
if len(file_timings) > 20:
print(f"\n ... and {len(file_timings) - 20} more (see {artifact_path})")
if stats_dir is not None:
stat_files = list(stats_dir.glob("*.json"))
print(f"\nCompiler statistics: {len(stat_files)} files written to {stats_dir}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Related skills
How it compares
Pick xcode-compilation-analyzer for Apple-documented incremental build diagnosis rather than generic CI caching advice.
FAQ
Should recommendations prioritize cumulative or wall-clock compile time?
Rank by expected wall-clock impact; when compile categories sum far above median wall-clock, note parallel efficiency effects separately.
Can the skill edit my source automatically?
No. It does not edit source or build settings without explicit developer approval.
What script surfaces type-checking hotspots?
python3 scripts/diagnose_compilation.py with project, scheme, configuration, destination, threshold, and output-dir flags.
Is Xcode Compilation Analyzer safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.