2026-04-24 임대 클라우드 Mac에서 xcodebuild CI의 Swift 6 엄격 동시성, Sendable 및 @MainActor
HK / JP / KR / SG / US에서 이미 Apple Silicon 호스트를 쓰는 iOS·macOS 빌드 오너는 두 번째 부담에 직면합니다. Swift 6 언어 모델과 엄격 동시성 검사는 따뜻한 노트북과 임대 SSH Mac에서 차갑고 병렬화된 xcodebuild 잡 사이의 “내 머신에선 된다”를 측정 가능한 차이로 바꿉니다. 이 글(2026-04-24)은 언어 튜토리얼이 아니라 빌드 설정(SWIFT_STRICT_CONCURRENCY, Swift 언어 버전), DerivedData·index store 격리, 병렬과 셀프호스티드 Runner 토폴로지에서 폭발하는 Sendable / nonisolated / MainActor 노이즈의 단계적 이전을 매핑합니다. tmp DerivedData + xcresult 격리와 원격 아카이브로 교차 링크해 싱가포르의 같은 Node가 미국 샤드가 사적이라고 가정했던 공유 ModuleCache를 갈가리질하지 않게 하세요.
헤드리스 CI에서 Swift 6 엄격 동시성이 다르게 반응하는 이유
엄격 검사는 시뮬레이터가 절대 밟지 않는 데이터 레이스를 드러냅니다. UI 메인 스레드가 포착한 var 수명을 가리기 때문입니다. CI에서는 병렬 swift-frontend 잡과 whole-module 최적화가 진단 순서를 바꿉니다. 64 GB 개발 노트북에서 하룻밤 컴파일되던 같은 패키지가 증분이 꺼진 -warnings-as-errors 레인에서 실패할 수 있습니다. 엄격 동시성은 이미 다루는 아카이브 bitcode 폐기나 CLT vs 풀 Xcode 패리티처럼, 고정된 DEVELOPER_DIR를 가진 별도 파이프라인 스테이지와 리팩터 전까지 SWIFT_STRICT_CONCURRENCY=targeted로 둘 수 있는 타깃에 대한 서면 정책으로 다루세요.
인덱스 재빌드 시간도 예산에 넣으세요. 깨끗한 DerivedData에서 첫 Swift 6 풀 빌드는 App Intents나 큰 WidgetKit 익스텐션을 포함한 앱에서 ExtractAppIntentsMetadata 등에 몇 분을 더 쓸 수 있습니다. 이 벽시계 점프는 동시성 실패가 아니라 첫 SwiftPM 레지스트리 프리웜과 같은 콜드 캐시 효과로, PM에게도 같은 선에서 미리 공유하세요. 전후 p95를 대시보드에 남겨 “Swift 6 주”가 클라우드 용량 퇴행으로 읽히지 않게 합니다.
빌드 설정: 언어 버전과 엄격 동시성 모드
프로젝트 또는 xcconfig에서 세 손잡이를 맞춥니다. (1) 출하하는 Swift 6 툴체인에 SWIFT_VERSION; (2) 머지 블로킹 레인에서는 SWIFT_STRICT_CONCURRENCY를 complete로, 레거시 벤더 정적 lib는 주석이 달릴 때까지 targeted일 수 있음; (3) Swift 6의 타깃별 기본 격리에서 UIKit·SwiftUI 모듈은 명시적 @MainActor 커버리지를 원합니다. CI YAML에서는 스킴이 아직 못 담을 때만 오버라이드를 넘깁니다. 예: 권고 레인에서 OTHER_SWIFT_FLAGS=-warn-concurrency. 비트 단위 재현이 필요한 릴리스 아카이브에 몰래 섞지 마세요. 패키지 플러그인과 앱 타깃의 차이를 문서화하세요. 플러그인 빌드 로그는 중요한 바이너리에 -strict-concurrency=complete를 켜기 전까지 오류를 숨길 수 있습니다.
xcodebuild 호출: 아카이브 vs 빌드 vs 분석
호스트에서 DEVELOPER_DIR=/Applications/Xcode.app를 하나로 고정하고 명시적 -configuration·-destination으로 스킴 드리프트를 피합니다. UI 테스트 전 컴파일만의 엄격 게이트라면 xcodebuild -scheme App build -destination 'platform=iOS Simulator,name=iPhone 16'에 CODE_SIGNING_ALLOWED=NO를 붙여 컴파일러 신호만 필요할 때 쓰고—두 번째 잡에서 서명을 되돌린 시뮬레이터 테스트를 돌리며 XCTest + xcresult 가이드와 같은 분할을 취합니다. 최소 엄격 게이트:
DEVELOPER_DIR=/Applications/Xcode.app xcodebuild build -workspace App.xcworkspace -scheme App -configuration Debug -destination 'platform=iOS Simulator,name=iPhone 16' -derivedDataPath "$CI_DERIVED/Swift6Gate" OTHER_SWIFT_FLAGS='$(inherited) -warn-concurrency'
Sendable에서 두 번 연속 동일 실패는 실제 코드 결함이지 Xcode 유령이 아님.
병렬 레인, DerivedData, 인덱스 스토어
부채꼴로 펼칠 때(M4 부채꼴 참조) 자식 잡마다 비공개 -derivedDataPath를 주고 엄격 스테이지에서는 증분을 끄는 것도 검토해 HK / JP / KR / SG / US 빌더 간 진단을 결정적으로 만드세요. NFS류 마운트에서 공유 DerivedData는 재시도하면 사라지는 유령 “cannot assign through subscript: base is not a concurrent value” 오류를 만드는 가장 빠른 길입니다—바로 격리 글이 xcresult에 대해 경고한 플레이크 패턴입니다. 비용 때문에 반드시 공유한다면 최소한 Index/DataStore를 잡마다 $(CI_JOB_ID) 접두 경로로 두세요.
이전 매트릭스: 경고, 오류, 오너
| 신호 | 조치 | 오너 |
|---|---|---|
Sendable 클로저 캡처 |
값 타입으로 리팩터, 타입을 Sendable로 표시하거나 actor로 이동 | 피처 스쿼드 |
| MainActor 격리 드리프트 | UI 업데이트를 작은 퍼사드 타입으로 모음 | 클라이언트 리드 |
| Sendable 없는 서드파티 바이너리 | 모듈 경계로 감싸고 벤더 이슈를 고정하거나 포크 | 빌드 플랫폼 |
동시성 오류가 아닐 때
일부 실패는 Swift 6 문제로 위장합니다. 프로비저닝·키체인 문제는 CodeSign 중 swift-frontend 줄과 끼어듭니다. dSYM 공백은 심볼리케이션을 깨뜨릴 뿐 컴파일러는 아닙니다. dSYM 위생을 엄격 레인과 같은 주간 리뷰에 넣지 않으면 온콜이 잘못된 diff를 쫓습니다.
서명, 엔타이틀먼트, 같은 빌드의 “엄격”
컴파일러 검사를 늘리는 릴리스 트레인과 프로비저닝 로테이션을 한 번에 넣는 것은 위험합니다. 순서: (1) 일회용 카나리에서 서명이 녹색임을 증명, (2) 엄격 스테이지 활성화, (3) 그다음 기본 스킴에 SWIFT_STRICT_CONCURRENCY=complete를 강제하는 피처 플래그 머지. 같은 SSH Mac mini M4 풀이 둘 다 호스트해도 잡을 하나의 워크스페이스 폴더에서 끼워 넣지 마세요. 병렬성은 이미 아카이브와 심 문서를 따를 때만 강점입니다.
관련 MacXCode 가이드
동시성 실패가 사실은 의존성 그래프 불일치라면 SwiftPM + 레지스트리 캐시와 Ruby + CocoaPods 결정성에서 시작하세요. Xcode Cloud와 전용 호스트를 섞는 팀은 둘 다에서 언어 플래그를 맞추지 않으면 전용 엄격 레인만 Xcode Cloud가 보지 못한 머지를 거부합니다.
FAQ: 공유 빌더의 Swift 6
| 질문 | 실무적 답 |
|---|---|
| 먼저 SPM 패키지에 켜야 하나? | 종종 그렇다—경계를 매핑한 뒤 앱 타깃. 테스트 전용 코드를 나누면 패키지 trait 사용. |
| VNC가 필요한가? | 보통 아니요—시각 디버깅 브레이크 글래스는 VNC. 엄격 빌드 로그용은 아님. |
| 인덱스용 디스크는? | 큰 SwiftUI 프리뷰를 꺼도 큰 Index 트리를 남기면 1–2 TB 호스트를 고르세요. 엄격 레인이 아티팩트 churn을 3×로 만들면 요금 참조. |
동시성 부하가 큰 컴파일에 베어 메탈 Mac mini M4가 맞는 이유
엄격 검사는 CPU·I/O 집약적입니다. 컴파일러가 그래프를 다시 쓰고 index는 부풀며 index store는 아카이브용으로 이미 예산한 것과 같은 NVMe에서 이득을 봅니다. 소켓 스택이 시끄러운 이웃 없음이면 레인이 패키지 해석 중 원격 캐시나 레지스트리와 말할 때 테일 지연도 줄어듭니다. 엄격 파이프라인이 안정되면 공유 DerivedData로 레인을 접기 전에 같은 리전에서 두 번째 Mac mini M4를 스케일아웃하세요—2026 메인라인은 결정적 신호를 받을 가치가 있고 복권 빌드는 아닙니다.