截至 2026 年 8 月 27 日,SwiftPM 官方文件已說明 Swift Build 成為預設建置系統,並建議使用 --show-bin-path 取得輸出目錄,而不是繼續猜測 .build 內的層級;官方 Swift Build 遷移文件是這項判斷的依據。

症狀 → 最快解法: 建置指令成功,但後續上傳找不到二進位檔或測試產物 → 讓建置參數與 swift build --show-bin-path 完全一致,將查詢結果當作本次任務的真實輸出路徑。只有先證明是 Swift Build 行為差異,才用官方支援的 native 回退參數做診斷;不要把回退直接當成永久修復。

這篇適合三類人:

  • 維護 Shell、Fastlane、Makefile 或 CI 程式碼,升級後遇到「建置成功但找不到產物」的開發者。
  • 負責 Swift Package、建置外掛或多套件儲存庫交付流程的維護者。
  • 管理遠端 Mac 節點、快取、工具鏈版本與回滾策略的 DevOps 及發布工程師。

先判斷故障屬於哪一層

不要先刪除整個工作區,也不要先把問題歸咎於遠端 Mac 權限。你需要把一次失敗拆成三個互不相同的階段:

  1. 編譯階段swift build 本身失敗,通常應先保留完整錯誤輸出、工具鏈資訊與提交版本。
  2. 路徑解析階段:建置指令已完成,但腳本仍讀取舊的 .build 子目錄。
  3. 工作目錄階段:查詢路徑與實際建置不在同一個儲存庫、組態、架構或 destination 下。
SwiftPM 6.4 的關鍵改變,不是單純把檔案「搬到另一個固定資料夾」,而是舊有目錄假設不再適合作為 CI 介面。Swift Build 官方儲存庫與相關討論均把預設建置系統變更列為遷移重點;[SwiftPM 官方說明](https://github.com/swiftlang/swift-package-manager)與[預設建置系統變更討論](https://forums.swift.org/t/swiftpm-development-update-default-build-system-change/85548)可供你核對。

因此,排查紀錄至少要包含:

  • 完整建置命令及其工作目錄。
  • SwiftPM、Swift Build 與 Xcode 工具鏈版本。
  • configurationarchitecture、destination 及依賴鎖定檔。
  • 實際執行的路徑查詢命令與輸出。
  • 上傳、複製或封裝步驟所使用的來源路徑。
截至上述核實日期,Swift Evolution 頁面尚未把 Swift 6.4 標記為獨立穩定版發布;[Swift Evolution 發布狀態](https://github.com/swiftlang/swift-evolution)與[Apple Developer 的 Swift 6.4 資料](https://developer.apple.com/wwdc26/guides/swift/)應在 Swift 6.4 正式發布、Xcode 27 進入 RC 或正式版時重新確認。不要把媒體推測當作 Xcode 27 或 Swift 6.4 的正式相容性結論。

腳本維護者:把路徑查詢改成建置介面

Swift Build 產物路徑查詢

Swift Build 的輸出目錄應由同一組建置條件查詢,而不是由腳本拼接。以下示例使用占位符,查詢參數必須與真正建置時保持一致:
set -eu

REPO_DIR="/path/to/<repository>"
CONFIGURATION="<configuration>"
ARCH="<architecture>"
DESTINATION="<destination>"

cd "$REPO_DIR"

swift build \
  --configuration "$CONFIGURATION" \
  --arch "$ARCH" \
  --destination "$DESTINATION"

BIN_PATH="$(swift build \
  --configuration "$CONFIGURATION" \
  --arch "$ARCH" \
  --destination "$DESTINATION" \
  --show-bin-path)"

printf 'Binary path: %s\n' "$BIN_PATH"

如果你的工具鏈不接受某個 destination 參數組合,應以該工具鏈實際支援的形式調整;重點不是複製這段命令,而是確保「建置」和「查詢」使用相同條件。不要一次用 release、另一次用 debug;不要建置 arm64,卻用未指定架構的查詢結果;也不要在一個工作目錄執行建置、在另一個工作目錄讀取路徑。

在 Shell、Makefile、Fastlane 或自訂發布程式中搜尋以下風險:

grep -R "\.build" fastlane Makefile Scripts 2>/dev/null || true

找到硬編碼後,將它改為讀取查詢結果,再由產物名稱、Target 或檔案類型完成下一步定位。公開的命令介面可以作為 CI 合約;Swift Build 的內部資料夾結構則不應直接成為合約。官方輔助程式也展示了以工具輸出協助定位建置資料的做法,可參考官方 build-script-helper.py 實作

五步驗收順序

  1. 在全新工作區 checkout 指定提交,避免舊 .build 內容掩蓋問題。
  2. 設定明確的 configuration、architecture、destination 與工具鏈選擇。
  3. 執行建置,保存終端輸出,不要只保存最後一個退出狀態。
  4. 用完全相同的參數執行 swift build --show-bin-path,記錄回傳的絕對路徑。
  5. 從該路徑複製、封裝或上傳產物,並在工作區清理後重新執行一次。
最後一步很重要:如果全新工作區可以成功,但熱快取才成功,代表你的快取鍵或清理流程仍然依賴舊路徑。這不是「偶發網路問題」,而是可重現的流程缺陷。

Swift Package 維護者:檢查外掛與資源輸出

Package 作者消費的產物不一定是單一二進位檔。你需要分開驗證建置工具外掛、二進位 Target、資源處理以及腳本外掛,因為它們可能各自保存輸出路徑假設。

外掛輸入與輸出證據

逐項檢查:

  • 建置工具外掛是否自行拼接 .build 路徑。
  • 二進位 Target 是否以固定檔名推算輸出位置。
  • 資源處理是否假設所有資源位於同一個產物目錄。
  • 腳本外掛是否明確宣告輸入與輸出,或只依賴目前工作目錄。
  • 失敗日誌是否同時記錄外掛收到的輸入、產生的輸出與執行目錄。
外掛若只在某一台遠端 Mac 失敗,先比較節點上的工具鏈、登入帳戶及工作區位置;若在相同條件下每個節點都失敗,才把問題縮小到 Swift Build 或外掛本身。Swift Build 官方問題追蹤中已有輸出目錄差異的紀錄,應將[輸出目錄差異問題單](https://github.com/swiftlang/swift-build/issues/1363)獨立建檔,不要把已知工具鏈問題誤判成權限故障。

停止條件

當你無法提供以下任一證據時,不應直接修改 Package 的路徑邏輯:

  • 實際建置命令。
  • --show-bin-path 的輸出。
  • 外掛的輸入與輸出紀錄。
  • 同一提交在另一種建置系統下的對照結果。
這些資料能區分「外掛使用了不公開目錄」和「Swift Build 本身存在已知問題」。前者應修正外掛,後者應保留最小重現並依官方問題單追蹤。

測試工程師:重新定義測試產物收集

本地 Swift Build 成功,但遠端 Mac CI 無法上傳產物時,測試階段尤其容易被誤判。測試啟動器、覆蓋率檔案、測試日誌與失敗用例資訊,未必共享單一固定目錄或單一執行器。

你應分別確認:

  • swift test 的退出狀態是否代表測試成功。
  • 測試報告究竟來自測試執行器、日誌聚合器還是外部轉換程式。
  • 覆蓋率資料的產生條件及實際來源。
  • 失敗用例是否仍可由報告定位,而不是只檢查某個檔案存在。
  • 上傳步驟讀取的是查詢後的實際路徑,而非預設 .build 子目錄。
測試收集器可以先列出查詢結果,再對指定類型檔案做存在性驗證;不要用「找不到單一檔案」代替測試結果判定。遷移期間保留 Swift Build 與 native 的對照任務,使用相同提交、相同測試範圍及相同上傳規則,才能知道差異來自建置系統還是測試腳本。

CI 平台團隊:隔離快取與遠端 Mac 節點

快取身份

新的快取身份至少應反映以下條件:

  • SwiftPM / Swift Build 工具鏈版本。
  • 建置系統選擇。
  • 架構與 configuration。
  • destination。
  • Package.resolved 或其他依賴鎖定檔內容。
  • 建置腳本與外掛版本。
如果快取只以儲存庫提交或分支命名,新舊產物便可能互相復用;即使當次建置顯示成功,後續複製步驟仍可能讀到不屬於本次任務的檔案。對 .build 的清理也要配合快取策略,避免「清理了工作區,卻恢復了舊快取」的假乾淨狀態。

遠端 Mac 節點檢查

在遠端 Mac 上逐一記錄:

  1. 執行帳戶及其 HOME 目錄。
  2. 實際工作區的絕對路徑。
  3. xcode-select 指向的工具鏈。
  4. SSH 工作階段與非互動式 CI 工作階段的環境差異。
  5. 節點重啟後工作區、快取掛載及權限是否恢復。
  6. 冷快取、熱快取與重啟後任務的產物查詢結果。
這也是遠端 Mac 與本地 Mac 差異最常見的邊界:本地工作目錄可能固定,CI 節點則可能由暫存路徑建立;本地登入 Shell 可能載入完整環境,SSH 或服務帳戶卻未載入相同設定。若你需要先鎖定工具鏈與遠端工作區,可參考[MACGPU 的遠端 Mac 方案](https://macgpu.com/zh-Hant/index.html);若要進一步安排隔離、可重置的測試節點,也可以查看[MACGPU 的 Mac 租用方案](https://macgpu.com/zh-Hant/m4-dinggou.html),但仍應以自己的 CI 日誌完成驗收。

發布負責人:用雙軌矩陣決定回退

Swift Build 和 native 建置系統的輸出路徑不能只用「哪個看起來比較熟悉」判斷。比較時要觀察路徑取得方式、測試收集、簽名及最終交付,而不只是建置命令是否結束。

<
驗收面向Swift Build 軌native 軌通過條件
建置使用實際參數查詢輸出目錄使用官方回退參數診斷產物位置可追溯
測試分別驗證退出狀態與報告來源使用相同提交及測試集合失敗用例可定位
快取工具鏈、系統、架構及鎖定檔納入身份不與 Swift Build 快取混用冷、熱快取結果一致
簽名從查詢後路徑取用檔案以同一套簽名規則驗證驗證值與交付檔一致
重啟節點重啟後重新執行保留對照記錄不依賴人工登入或舊工作區
官方遷移文件列出的回退方式可用於診斷,但不要在尚未完成對照前把生產流程永久切回 native。若 Swift Build 成功、測試和簽名也成功,應繼續修正收集腳本;若只有 Swift Build 失敗,則保留最小重現、完整錯誤與環境資料,再依官方已知問題決定暫緩、隔離試跑或回報缺陷。

路徑修復決策表

<
觀察結果應採取的動作不應採取的動作評分
建置成功,--show-bin-path 可取得正確路徑修正產物收集與快取鍵,留在 Swift Build繼續猜測 .build 層級**5/5**
建置失敗,錯誤可由最小 Package 重現保存環境並對照 native,必要時追蹤官方問題先清除所有節點資料**4/5**
冷快取失敗、熱快取成功重建快取身份及清理流程把熱快取成功視為修復完成**2/5**
只有遠端 Mac 失敗比對帳戶、工作區、工具鏈與 SSH 環境直接判定是 SwiftPM 6.4 缺陷**3/5**
native 成功、Swift Build 失敗暫時隔離或診斷回退,保留最小重現未驗收便切換全部生產節點**3/5**

上線前可勾選驗收清單

  • [ ] 全新工作區已使用指定提交重新執行。
  • [ ] 建置與 --show-bin-path 使用相同 configuration。
  • [ ] 建置與路徑查詢使用相同 architecture。
  • [ ] destination、工作目錄與工具鏈選擇已記錄。
  • [ ] Shell、Fastlane、Makefile 及發布腳本不再硬編碼舊 .build 層級。
  • [ ] 二進位 Target、資源及腳本外掛的輸入輸出均有紀錄。
  • [ ] swift test 退出狀態、測試報告與失敗用例已分開驗證。
  • [ ] 冷快取、熱快取及節點重啟後任務均已執行。
  • [ ] Swift Build 與 native 使用同一提交完成對照。
  • [ ] 若回退,已寫明再次切回 Swift Build 的觸發條件。
若你目前使用固定的雲端 Linux 主機或本地舊 Mac,常見缺點是無法直接提供相同的 macOS 工具鏈、快取容易和單一工作區綁定,而且重啟或權限變更後不容易重現問題;虛擬 macOS 也可能讓架構、簽名或工具鏈行為與真實主機不同。路徑修復完成後,用一台可隔離、可重置的遠端 Mac 執行冷快取與重啟驗收,通常比直接在既有生產節點冒險升級更容易保留證據。若你只需要短期遷移、回歸測試或暫時性的 CI 容量,租用 MACGPU 的遠端 Mac 會比購置一台只為這次驗證的實機更靈活;若是長期穩定重負載或必須接觸實體周邊,則應先評估自購 Mac 與硬體維護成本。