Xcode 26 編譯太慢:2026 遠端 Mac 怎麼加速?
Xcode 26 編譯太慢時,先用建置計時資料定位瓶頸,再修改專案,最後才評估硬體。Apple 的文件將建置效率、測試組織、Swift Package 持續整合分開處理;因此一次建置應至少拆成 四類紀錄:增量建置、乾淨建置、Archive 與測試,而不是只看總耗時。刪除 DerivedData 或直接租用更高規格的遠端 Mac,都不應是未診斷前的固定答案。
這篇文章適合每天多次執行增量編譯、希望縮短「修改程式碼到看到結果」時間的獨立開發者。
也適合需要在遠端 Mac 執行 Release Archive、自動測試或持續整合,卻尚未確定問題是否真的來自硬體的小型團隊。
先建立可比較的建置基線
同一個專案在不同條件下得出的時間,不能直接互相比較。首次建置可能包含 Swift Package 下載與解析;遠端工作又可能受到原始碼同步、私有套件驗證或磁碟狀態影響。測量前應固定以下輸入:
- 相同的程式碼提交版本。
- 相同的 Scheme、Build Configuration 與目標裝置。
- 相同的相依套件版本與
Package.resolved。 - 相同的簽署設定,以及是否啟用腳本。
- 相同的測試範圍與模擬器設定。
Apple 的 增量建置效能說明可用來核對建置系統與程式碼變更的關係。Xcode 26 的版本行為與已修正問題,則應直接查看 Xcode 26 Release Notes,不要把社群分享的加速比例當成官方保證。
在 Xcode 中開啟 Build Timing Summary,記錄最慢的 Swift 檔案、Target、腳本與資源處理工作。若需要在自動化環境重現,可先使用明顯的佔位名稱:
xcodebuild \
-workspace <WORKSPACE_PATH> \
-scheme <SCHEME_NAME> \
-configuration <BUILD_CONFIGURATION> \
-destination '<DESTINATION_SPECIFIER>' \
build
輸出範例只用來說明閱讀方式:
CompileSwiftSources <TARGET_NAME>
PhaseScriptExecution <SCRIPT_NAME>
Ld <PRODUCT_NAME>
ProcessInfoPlistFile <RESOURCE_PATH>
看到 CompileSwiftSources 很慢,才適合進入 Swift 程式碼與 Target 依賴分析。若最慢的是 PhaseScriptExecution,換晶片通常不會解決腳本重複執行。若輸出先長時間停在套件下載,這是依賴或網路問題,不是源碼編譯問題。
| 工作場景 | 應記錄的階段 | 首要檢查方向 | 不宜先做的事 |
|---|---|---|---|
| 日常增量建置 | 受影響 Target、Swift 檔案、腳本 | Target 依賴、符號可見性、程式碼生成 | 反覆刪除 DerivedData |
| 乾淨建置 | 套件準備、源碼編譯、連結 | 相依性是否完整、快取是否可重建 | 把首次下載算成編譯時間 |
| Release Archive | 編譯、連結、資源、簽署、腳本 | Release 設定、額外 Target、符號處理 | 只看 Archive 總時間 |
| 測試與模擬器 | App 編譯、模擬器啟動、測試案例 | 測試分組、並行度、記憶體壓力 | 無限制增加測試工作數 |
增量建置:專案側修正優先於硬體
日常編輯最在意的是增量建置。一次小修改若觸發大量無關 Target,問題多半在依賴圖,而不是遠端 Mac 的 CPU。先檢查新增 Target 是否真的需要依賴完整模組,也要確認共用程式碼是否被過度暴露,導致不必要的檔案重新編譯。
Apple 的 Target 設定文件可用於核對 Target 與建置產品的關係。對 Swift 程式碼,亦可參考 改善建置效率的程式碼實踐,再以同一提交版本的計時結果驗證修改是否有效。
建議先做一個小範圍變更,例如只改動一個畫面或一個模組,然後比較修改前後的相同增量建置。若每次都同時執行程式碼生成、資源索引與多個無關 Target,應逐項確認:
- 自訂腳本是否缺少輸入與輸出檔案宣告。
- 程式碼生成是否每次建置都重新執行。
- 某個大型模組是否被過多 Target 直接引用。
- 小型變更是否造成整個共用檔案集合重新編譯。
- Debug Scheme 是否無意間啟用了發佈階段才需要的工作。
Build Timing Summary 要怎樣查看每個建置工作的耗時?
在 Xcode 的建置報告中查看 Build Timing Summary,先按耗時排序,再追蹤最慢項目所屬的 Target 與建置階段。自動化建置則保留 xcodebuild 的完整輸出,將相同提交、Scheme 與設定的結果並列。重點不是取得一個漂亮的總時間,而是找出每次都重複出現的長任務。
DerivedData 不應被當成加速按鈕。它保存中間產物與索引,正常情況下有助於增量建置;刪除後通常需要重新產生這些內容。只有快取損壞、索引狀態異常,或切換工具鏈後出現無法解釋的錯誤,才值得清除並重新建立基線。
提醒: 如果刪除 DerivedData 後只有下一次建置變慢,這不是最佳化失敗,而是把可重用的中間產物一併移除了。應比較後續同類增量建置,不要比較清除後的首次結果。
Release Archive:把總時間拆開看
Archive 慢,與日常編譯慢,可能是兩個不同問題。Release Archive 應分別記錄相依套件準備、源碼編譯、連結、資源處理、簽署、符號檔處理與自訂腳本。Apple 的 Beta 與正式版本分發說明可用來核對分發流程,不過其中的簽署與上傳工作不能簡化成「編譯」。
若 Debug 增量建置正常,只有 Release Archive 明顯變慢,應先檢查:
- Release 是否啟用不同的最佳化與符號設定。
- Archive 是否額外包含 Extension、Widget 或其他 Target。
- 符號處理、資源壓縮與腳本是否集中在最後階段。
- 發佈腳本是否重複下載工具或重新處理相同檔案。
- 簽署憑證與 Provisioning Profile 是否需要重新尋找或驗證。
| 計時結果 | 較可能的瓶頸 | 建議決策 |
|---|---|---|
| 增量建置與 Archive 都慢在源碼編譯 | 程式碼結構或 CPU 持續飽和 | 先拆分模組;確認後再評估更高 CPU 配置 |
| 增量建置正常,Archive 慢在腳本或符號處理 | 發佈流程工作重複 | 修正腳本輸入、輸出與工具快取 |
| Archive 前長時間下載套件 | 依賴解析、下載或認證 | 固定版本並檢查套件來源,暫不升級硬體 |
| 編譯完成後連結或磁碟等待突出 | 產物規模或儲存裝置瓶頸 | 檢查產物與磁碟狀態,再決定是否擴容 |
| 總時間主要消耗在測試 | 測試案例、模擬器或並行設定 | 分開測試計時,不要把問題稱為編譯慢 |
依賴恢復:固定輸入,避免把下載當成編譯
新租期、持續整合節點或新開發機第一次執行時,Swift Package 常會同時涉及版本解析、套件下載與源碼編譯。三者要分開記錄。若 Package.resolved 沒有提交到版本控制,團隊每次恢復環境都可能得到不同的解析結果,後續時間也失去可比性。
Swift Package 每次重新解析依賴,應怎樣處理?
先確認 Package.resolved 是否已提交,並核對工作區與專案實際使用的套件版本。再區分是解析失敗、下載緩慢,還是下載完成後編譯緩慢。私有套件則要另外檢查 SSH 金鑰、存取權杖、憑證與網路路由。Apple 的 Swift Package 持續整合工作流程文件可作為 CI 環境的核對依據。
快取也要有邊界。套件下載快取可以保留,但不能用一份無法追蹤來源的舊建置產物掩蓋原始碼變更。需要從源碼重建的產物,必須在乾淨 Archive 或指定的 CI 驗收中重新確認。遠端 Mac 上的首次建置時間,應獨立標記為環境恢復成本。
測試並行:速度與失敗率一起判斷
測試總時間不等於 Xcode 編譯時間。單元測試可能主要消耗在測試案例;UI 測試還會涉及模擬器啟動、狀態準備與裝置互動。Apple 的 模擬器與實體裝置執行說明以及改善回饋速度的測試組織文件,都應與實際測試輸出一併核對。
Xcode 測試並行度越高,是否一定越快?
不一定。並行測試會增加模擬器、CPU 與記憶體的同時需求;當主機開始出現記憶體壓力、交換或磁碟等待時,總完成時間可能反而拉長,失敗重試也會增加。應使用低、中、高三組明確的工作數設定逐級比較,並同時記錄完成時間、失敗數與模擬器穩定性,而不是只取最快的一次。
對獨立開發者,快速回饋與發佈前驗證應分層:
- 快速回饋:只跑受影響模組的單元測試與必要的模擬器測試。
- 合併前驗證:跑完整單元測試,確認測試資料與環境隔離。
- Archive 前驗證:加入 Release 設定、簽署與必要的 UI 測試。
- 發佈前驗證:在固定的遠端 Mac 節點重跑完整流程,保留輸出與失敗原因。
遠端建置:先驗收工作負載,再決定擴容
遠端 Mac 的價值不只在編譯速度,也在於能否穩定執行 Archive、測試與持續整合。若本地機在建置時被長時間佔用,遠端節點可以把發佈工作拆出去;但遠端連線延遲、原始碼同步、套件來源與權限設定,仍需納入驗收。
可先用同一個脫敏提交執行以下流程:
xcodebuild \
-workspace <WORKSPACE_PATH> \
-scheme <SCHEME_NAME> \
-configuration <DEBUG_CONFIGURATION> \
-destination '<SIMULATOR_DESTINATION>' \
test
xcodebuild \
-workspace <WORKSPACE_PATH> \
-scheme <SCHEME_NAME> \
-configuration <RELEASE_CONFIGURATION> \
-archivePath <ARCHIVE_PATH> \
archive
連續執行時,觀察是否出現以下差異:
- CPU 長時間飽和,但依賴已完成下載。
- 記憶體壓力持續升高,測試並行後失敗變多。
- 磁碟等待明顯,連結、索引或產物處理成為長項目。
- 遠端工作階段本身影響互動,但非互動式 CI 建置仍然穩定。
- 每次都重新解析或下載相同套件。
-
增量建置改善,但乾淨 Archive 沒有改善。
-
[ ] 固定程式碼提交、Scheme、設定與目標裝置。
- [ ] 分開保存增量建置、乾淨 Archive、測試與依賴恢復紀錄。
- [ ] 在 Build Timing Summary 找出反覆出現的長任務。
- [ ] 檢查 Target 依賴、程式碼生成與自訂腳本輸入輸出。
- [ ] 確認
Package.resolved已提交,並測試私有套件認證。 - [ ] 逐級調整測試並行度,同時記錄總時間與失敗率。
- [ ] 只有在 CPU、記憶體或磁碟等待持續成為主因時,才比較遠端 Mac 配置。
- [ ] 用同一提交重跑驗收,確認改善可重現,而非單次偶然結果。
遠端 Mac 編譯慢,應升級晶片還是增加記憶體?
先看計時與系統資源的對應關係。源碼編譯長時間受 CPU 限制,才有理由比較更高效能的晶片;測試並行、索引或多個 Target 同時工作造成記憶體壓力,才考慮增加記憶體。若主要時間花在套件下載、腳本或錯誤的依賴關係,兩者都不是正確修復方向。
若經過上述驗收,本地仍會被增量編譯反覆佔用,而 Release Archive、測試與 CI 又需要穩定常駐環境,遠端 Mac 才具備明確的成本理由。此時可先參考 SFTPMAC 的 Mac 租用方案,再用實際專案而非規格表選擇配置;若需要特定地區的連線路徑,也可查看香港 Mac 租用環境。
本地方案與遠端 Mac 的取捨
如果目前方案是把所有工作放在一台本地 Mac,常見缺點是建置時佔用開發機、磁碟快取與模擬器互相爭用資源,團隊也缺少一台可長時間執行 Archive 與 CI 的固定節點。若改用一般雲端環境,則可能遇到無法直接執行 Xcode 的限制;若只靠臨時借用實機,版本、憑證與工作狀態又不容易固定。
在瓶頸已被確認的前提下,租用 SFTPMAC 的遠端 Mac 可把同一個專案部署到可持續使用的 macOS 環境,讓開發者分開處理日常編碼與建置、簽署、測試工作。若工作只是偶爾 Archive,短期租用較合理;若每天都有固定 CI 負載,才值得用較長租期驗證成本。需要實體 USB、長期滿載且必須完全自行維護硬體的人,則應如實比較自購 Mac,而不是為了「編譯太慢」盲目搬遷。
核心判斷很簡單:先證明瓶頸在哪裡,再決定修專案、調整測試,或擴充遠端 Mac。這樣才能避免清空 DerivedData 後反覆失去快取,也避免在真正的套件、腳本或 Target 問題尚未處理前,支付不必要的硬體成本。