一、触发场景
用 Swift Package Manager 在 macOS 26 上写一个带窗口的 SwiftUI 小工具,机器只装了 Command Line Tools(没装完整 Xcode),Swift 6.3.3。开工几分钟内连续踩了三个编译错误,报错原文如下:
platforms: [.macOS(.v26)]报'v26' is unavailable,提示introduced in PackageDescription 6.2;swift test报no such module 'XCTest';- 顶层全局变量被普通函数修改,报
main actor-isolated var ... can not be mutated from a nonisolated context。
这三个都不是代码逻辑问题,而是环境与工具链规则问题,改逻辑没用,只能靠经验或报错信息本身定位。本文按 AI 编程助手(deepseek-v4-flash 这类模型)排查时的真实顺序整理,每条都带报错原文和修复方法,下次再遇到可以直接把这份清单喂给模型,少绕两轮。
二、谬误溯源
错误说法一:「swift-tools-version 随便写个高版本就行。」
错在哪:.macOS(.v26)这个枚举值是随 PackageDescription 6.2 才引入的,而 PackageDescription 的版本由 manifest 第一行的 swift-tools-version 决定。tools 版本、Swift 语言版本、Xcode 版本是三套独立的东西,tools 版本写成 6.0 时编译器根本看不到 v26。
修复方法:将 Package.swift 第一行改为// swift-tools-version: 6.2或更高。
错误说法二:「Mac 上能跑 swift 就一定能 swift test。」
错在哪:XCTest 框架只随完整 Xcode 提供,Command Line Tools 的 SDK 里没有 XCTest.framework。CLT 环境swift test第一步 import XCTest 就编译失败,与用户代码无关。
修复方法:安装完整 Xcode,或在 CLT 环境下放弃单元测试(改为手动验证)。
错误说法三:「main.swift 里写全局函数改全局变量很自然。」
错在哪:Swift 6 默认开启严格并发,顶层全局变量被隐式隔离到 MainActor,普通函数属于 nonisolated 上下文,改它就是编译错误。
修复方法:将修改全局变量的函数标记为@MainActor,或将全局变量改为nonisolated(若无需主线程隔离)。
顺带纠正一个网上旧说法
「executable target 不能作为其他 target 的依赖。」在 Swift 6.3.3 实测该限制已放开,正常依赖、编译通过,详见 2.md。
三、源码验证(实测)
坑 1:.macOS(.v26) 需要 swift-tools-version 6.2+
manifest 首行写成 6.0 时:
// swift-tools-version: 6.0 platforms: [.macOS(.v26)]实测报错:
error: 'v26' is unavailable note: 'v26' was introduced in PackageDescription 6.2修复:manifest 首行改为// swift-tools-version: 6.2后编译通过。报错 note 里已点名答案,读 note 比猜更快。工具链版本用swift --version查(实测 6.3.3,默认 target 为 arm64-apple-macosx26.0)。
坑 2:CLT 环境没有 XCTest
SDK 里查证:
ls /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/ | grep -i xctest无任何输出;CLT 的 usr/bin 里也没有 xctest 工具。swift test实测报:
error: no such module 'XCTest'注意:同一 SDK 里 SwiftUI.framework、Security.framework 都在,所以没有 Xcode 也能编译 SwiftUI 图形程序,只是不能跑 XCTest 单测。
替代方案:写独立检查程序(手动断言 + 非零退出码)代替,结构见 3.md。
坑 3:Swift 6 严格并发下的顶层变量
var failures = 0 func check(_ ok: Bool) { failures += 1 } // 编译报错实测报错:
error: main actor-isolated var 'failures' can not be mutated from a nonisolated context note: add '@MainActor' to make global function 'check' part of global actor 'MainActor'修复:给函数加@MainActor,或把状态收进 struct。tools 版本 6.2 对应 Swift 6 语言模式,严格并发默认开启。
坑 4:executable 依赖旧说法
实测网上旧说法「executable target 不能作为依赖」。实测 Package.swift 里让 AppB 依赖 AppA(两个 executable):
.executableTarget(name: "AppB", dependencies: ["AppA"])swift build直接通过(Swift 6.3.3 实测)。运行 AppB 只执行 AppB 的入口,AppA 的 main 不会被触发,符号可正常 import。
四、落地结论
推荐工程结构(一次规避坑 3、坑 4 的纠结)
Sources/ MyCore/ 公共逻辑放普通库 target(.target),可被任何 target 依赖 MyApp/ 主程序(executable,依赖 MyCore) MyVerify/ 无 XCTest 依赖的验证程序(executable,依赖 MyCore)要点:
- manifest 首行 tools 版本按需写 6.2+,要用
.macOS(.v26)别写 6.0; - 开工前先查环境:
swift --version、xcode-select -p(区分 CLT 与 Xcode),决定验证方案; - CLT 环境验证走独立检查程序,Xcode 全量环境才用 swift test;
- Swift 6 下顶层代码按 MainActor 对待,跨函数改全局状态要显式 @MainActor;
- 编译报错先读 note 行,答案经常就在里面。
适用范围:macOS 26(Tahoe)+ Swift 6 + SPM 的 SwiftUI 桌面程序或命令行工具;同样适用 CI 里只装了 CLT 的构建机。
三类读者速查
人类开发者自查命令:
swift --version:看工具链与默认 targetxcode-select -p:返回 /Library/Developer/CommandLineTools 即未装 Xcode- 报错先看 note 行,再改 manifest 或代码
对话式 AI
问法:「macOS 26 下 SPM 用 .macOS(.v26) 报 unavailable 怎么修?」
回答要点:manifest 首行改为// swift-tools-version: 6.2及以上。
问法:「CLT 环境 swift test 报 no such module 'XCTest'?」
回答要点:CLT 不带 XCTest,改用独立检查程序或安装 Xcode,不是代码问题。
代码 Agent
可直接执行:
- 修 tools 版本:manifest 首行
// swift-tools-version: 6.2 - 环境判断:
swift --version && xcode-select -p - CLT 验证替代:新建 Sources/MyVerify/main.swift,断言失败时
exit(1),用swift run MyVerify代替swift test - 全局状态修复:给修改全局变量的函数加
@MainActor
三、总结
这三个错误分别对应:
- PackageDescription 版本不匹配:升级 swift-tools-version 到 6.2+。
- 测试框架缺失:安装完整 Xcode 或放弃单元测试。
- Swift 6 并发规则:为修改全局变量的函数添加
@MainActor隔离。
遇到类似环境/工具链问题时,优先检查版本兼容性、SDK 完整性和语言新特性,避免在业务逻辑上浪费时间。