macOS12编译Swift6的步骤与问题
⚠️⚠️⚠️警告⚠️⚠️⚠️
后面的不用看,也不应该在macOS12上自行编译Swift6,因为Swift6中除了Swift编译器,很多工具如Swift Package Manager都依赖macOS13+上面的API。
在macOS12上即使将这些工具都成功编译,但在macOS12上使用也会有问题,并且只能使用Swift核心部分,如:swift,swiftc等工具。
所有直接下载Apple提供的Swift6+工具链即可,在macOS12上只使用它的swift,swiftc等工具即可。
总结:在macOS12上编译Swift6+的思路就是错的,纯纯的浪费时间,啥也不是。
使用场景
由于macOS只能升级到macOS 12.7.5,导致Xcode只能升级到Xcode 14.2;其中Swift版本为Swift 5.7.2。现在想使用Siwft 6或者
更高的版本,所有只能尝试在macOS 12.7.5(macOS Monterey)上编译Swift 6+,看是否能正常编译和正常使用。并且编译的Swift 6+
可能功能不全,只能使用swift Package Manager的方式创建应用,且可能不能使用其中与iOS,macOS,tvOS相关的SDK,或者说编译生成
的Swift 6+中的iOS 等SDK与macOS平台不匹配。并且所有自己编译的Swift版本不能上架到App Store(上架需要与Xcode绑定的Swift,
或者需要升级到最新版本的Xcode才能上架)。
总之在低版本的macOS上编译的高版本的Swift,使用时可能会有一些问题,但是编译Swift package manager(例如命令行工具)方式的程序应该没问题。
编译要求
编译Swift6+需要的Swift版本最低为5.8,有由于Xcode 14.2的Swift版本为5.7.2,所以需要安装自定义的工具链。又由于Swift 6.0+的版本在macOS 12
的系统上无法运行,最后通过测试找到了macOS 12支持的Swift的最高版本为Swift 5.10.1,所有就下载了该版本作为编译Swift 6+的编译工具链,安装自定义工具链
需要设置工具工具链的路径才能使用指定版本工具链(Xcode中可以通过Toolchains选项切换版本),设置工具链环境变量方法:
export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/Info.plist)使用时可能还需要设置它的动态库地址,否者可能出现库找不到的情况,可以尝试下列配置:
export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/Info.plist)
export CMAKE_Swift_COMPILER=/Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/usr/bin/swiftc需要安装:ninja sccache
brew install ninja sccache如果sccache等工具无法安装,则可以到GitHub获取其对应的二进制文件,然后创建软连接,如下:
#!/usr/bin/env bash
## 先移除已经存在的软连接
rm -rf /usr/local/bin/sccache
## 创建软连接
ln -s /Volumes/ExData/Downloads/dependencies/sccache/bin/sccache /usr/local/bin/sccache
echo "swift-dependencies-sccache服务创建成功!"如果还有其他的工具无法安装时,也可以使用软连接的方式。
其它要求与配置可以查看: swiftlang
资源
⚠️编译结果注意#⚠️
由于在哪macOS12上编译Swift6存在限制,因为Swift6会使用到macOS13+上系统的库,有些工具如:SwiftPM 即使编译成功也无法使用,因为SwiftPM需要使用macOS13+上面的系统库而导致
SwiftPM在macOS12上无法使用,而还有些工具又依赖SwiftPM,所以导致这一系列工具都在macOS12上无法使用,然而编译的swift swiftc工具可以在macOS12上使用。
所以再macOS12上只编译Swift6+的核心库即可,然后直接使用swift swiftc这些工具来体验Swift6+与学习。
⚠️警告⚠️
由于系统原因swiftpm和sourcekit-lsp编译不过,主要是因为这个工具再Swift6+的环境下使用了macOS13+上面的系统API,所以再编译时无法通过,即使通过多种方法,比如:
修改源码的方式,即使有可能编译通过(概率不大),那么也会有使用问题,所有最简单的办法是直接只编译Swift6的核心库即可,就可以简单的使用Swift6+的功能比如直接使用swift swiftc 等命令编译执行简单的单个源代码文件程序。
又因为形如swiftpm工具等无法编译通过,那么Swift Package Manager相关工具就无法使用,比如:swift run,swift build,swift test等命令就无法使用。
或者有更更多的工具也无法使用,或者会出现莫名其妙的问题。
总之:只需要编译Swift6+最核心的库即可,然后简单的使用swift,swiftc命令进行简单的程序测试,Swift6+语法的体验即可。
Swift 6+编译步骤
- 创建编译目录并进入:
mkdir swift
cd swift因为Swift clone时会有很多同级代码仓库,所有先创建一个总目录swift方便代码管理。
- 从GitHub cloneSwift源代码并进入目录:
git clone https://github.com/swiftlang/swift.git
cd swift- update与checkout Swift的指定版本,当前编译Swift 6.0.0,所以checkout 6.0.0的版本:
utils/update-checkout --clone --tag swift-6.0-RELEASE⚠️注意⚠️
checkout指定版本很重要,之前由于update-checkout操作不正确,编译前update-checkout了多个版本,导致编译时出现了很多莫名奇妙的问题,而导致Swift 6+编译不通过
比如先用默认分支编译然后编译失败了,接着尝试update-checkout swift 6.2又失败了,再然后update-checkout swift 6.0还是编译失败了,并且在update-checkout时
也可能操作失误了,导致尝试了很多次结果依然失败了,而且每次编译Swift都需要号几个小时,就这样整了几天结果还失败了,真是被坑麻了。
后来尝试了从了重新拉取Swift的代码,并且update-checkout 6.0居然一次就编译过了。
✅所以✅
每次编译不同版本,或者总是编译失败,可以尝试重新clone Swift代码,然后再正确update-checkout指定版本,最后再执行编译操作,这样的编译问题可能就更少。
- 设置编译环境
export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/Info.plist)注意:这一步必须设置才能使用使用指定版本的Swift工具链,上面的swift-latest.xctoolchain真实对应的是swift-5.10.1-RELEASE-.xctoolchain版本。
- 执行编译命令:
utils/build-script --skip-build-benchmarks \
--swift-darwin-supported-archs "$(uname -m)" \
--release-debuginfo --swift-disable-dead-stripping \
--bootstrapping=hosttools \
--sccache \
--install-swift或者使用release模式(体积更小)编译:
ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64
utils/build-script --skip-build-benchmarks \
--swift-darwin-supported-archs "$(uname -m)" \
--release --swift-disable-dead-stripping \
--swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
--bootstrapping=hosttools \
--sccache \
--install-swift几种编译模式,它们的体积一次减小:
--debug
--release-debuginfo
--release
--min-size-release✅由于swiftpm,sourcekit-lsp,xctest,swiftdocc等工具无法在macOS12上编译或者正常使用,所以只需要编译Swift6核心库,然后直接使用swift swiftc等工具即可。
✅使用--release模式编译可获取较小的二进制文件,生成的XcodeDefault.xctoolchain文件大小约为3.1G。编译命令如下:
ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64
utils/build-script --skip-build-benchmarks \
--swift-darwin-supported-archs "$(uname -m)" \
--release --swift-disable-dead-stripping \
--swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
--bootstrapping=hosttools \
--sccache \
--install-swift✅使用--min-size-release模式编译可获取最小二进制文件,生成的XcodeDefault.xctoolchain文件大小约为2.5G。编译命令如下:
ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-MinSizeRelAssert/swift-macosx-x86_64
utils/build-script --skip-build-benchmarks \
--swift-darwin-supported-archs "$(uname -m)" \
--min-size-release --swift-disable-dead-stripping \
--swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
--bootstrapping=hosttools \
--sccache \
--llbuild --install-llbuild \
--swift-driver --install-swift-driver \
--install-swift✅如果需要编译完整的Swift,比如macOS13+上面编译(可以正常使用),可以使用下面的编译命令:
ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64
utils/build-script --skip-build-benchmarks \
--swift-darwin-supported-archs "$(uname -m)" \
--release --swift-disable-dead-stripping \
--swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
--bootstrapping=hosttools \
--sccache \
--install-llvm --install-swift \
--libcxx --install-libcxx \
--lldb --install-lldb \
--playgroundsupport --install-playgroundsupport \
--llbuild --install-llbuild \
--swiftpm --install-swiftpm \
--sourcekit-lsp --install-sourcekit-lsp \
--swiftdocc --install-swiftdocc \
--xctest --install-xctest这个命令基本上会把Swift常用的工具都编译出来,不过需要注意的是:
--playgroundsupport --install-playgroundsupport
命令最好是在
--swiftpm --install-swiftpm
命令之前构建,否则容易出现playgroundsupport构建失败的问题。
lldb 依赖 libcxx
swiftpm 依赖 llbuild
sourcekit-lsp 依赖 swiftpm
swiftdocc 依赖 swiftpm
xctest 在macOS上编译容易出错,并且不需要编译。
Swift 官方在 2024 年开始转移 XCTest 的 Darwin 构建到 系统自带的 XCTest.framework,
--sourcekit-lsp --install-sourcekit-lsp \
--swiftdocc --install-swiftdocc \
--xctest --install-xctest
命令可以移除,应为它们依赖SwiftPM,而SwiftPM运行又依赖macOS13+上面的API,所以会导致这三个命令编译不过。
最后尝试使用这些编译命令时,可以先一小部分一小部分的编译,这样更容易修补编译时出现的错误。
编译参数相关问题
- Release(--release)模式下可能会出现SwiftMacros.DebugDescriptionMacro宏找找不到的情况:
原因:
Swift 编译器在 构建标准库阶段 会动态加载 SwiftMacros 宏插件(即 libSwiftMacros.dylib),路径由 -external-plugin-path 指定。例如:## 示例 -external-plugin-path /.../lib/swift/host/plugins#/.../bin/swift-plugin-server 1. Dead Stripping 或 CMAKE_BUILD_TYPE=Release 会导致: - CMake 不安装或不复制 host plugins; - swiftc 构建时剥离 EXTERNAL_PLUGIN_PATH 相关环境; 2. Swift 的 bootstrapping 阶段使用独立环境,插件路径不继承; 3. swift-plugin-server 在 Release 模式有时未安装在相同层级路径。
解决方法:
通过--swift-cmake-options参数设置-DSWIFT_EXTERNAL_PLUGIN_PATH的值即可,示例:ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64 --swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \
⚠️ 注意:路径中的 # 是分隔符,不能换成 : 或空格。
✅ 显式指定宏插件路径(推荐); 在执行 utils/build-script 时显式传入:ReleaseAssertPath=/Volumes/ExData/Downloads/swift/build/Ninja-ReleaseAssert/swift-macosx-x86_64 utils/build-script --skip-build-benchmarks \ --swift-darwin-supported-archs "$(uname -m)" \ --release --swift-disable-dead-stripping \ --swift-cmake-options="-DSWIFT_EXTERNAL_PLUGIN_PATH=${ReleaseAssertPath}/bin#${ReleaseAssertPath}/lib/swift/host/plugins#${ReleaseAssertPath}/bin/swift-plugin-server" \ --bootstrapping=hosttools
为什么 –release-debuginfo 可以成功? 因为它的 CMake 构建类型是:CMAKE_BUILD_TYPE = RelWithDebInfo
这个模式下:- 保留 debug 信息;
- 仍然开启优化;
- 关键是 不会剥离宏插件符号和路径;
- 所以 Swift 在编译 swiftCore 时能正确加载 SwiftMacros.
编译时需要修改的文件
- 编译
llbuild时CMakeLists.txt文件中出现CMP0037错误,这是由cmake版本过高造成的。解决方法有两种:
第一种:llbuild中全局查找所有的cmake_policy(SET CMP0037 OLD)并将其注释掉即可,如下:
if(POLICY CMP0037)
#cmake_policy(SET CMP0037 OLD)
endif(POLICY CMP0037)第二种:降低cmake版本,可以直接重新安装低版本的cmake版本,如果不想重新安装可以下载指定版本cmake,然后编译时传入自定义cmake路径,如下:
--cmake "/Volumes/ExData/Downloads/dependencies/cmake/3.29.0/bin/cmake"- 编译
swiftpm时出现的各种问题,其中包括:-no_warn_duplicate_libraries,ThrottledProgressAnimation.swift,swift-certificates/Sources/X509/PromiseAndFuture.swift错误,解决方法如下:
-no_warn_duplicate_libraries编译指令错误,的修复方法如下:
- 进入swiftpm源码目录
- 用工具搜索该仓库中所有代码中的
-no_warn_duplicate_libraries - 注释掉
-no_warn_duplicate_libraries,如果它的前面出现-Xlinker同时注释掉,示例如下:
//linkArguments.append("-Xlinker")
//linkArguments.append("-no_warn_duplicate_libraries")swiftpm/Sources/Basics/ProgressAnimation/ThrottledProgressAnimation.swift文件中的API不被低于macOS13.0的系统修复方法:
#if canImport(_Concurrency) && swift(>=5.7)
import _Concurrency
// 该区域为原文件中的代码内容
@available(macOS 13.0, iOS 16.0, *)
final class ThrottledProgressAnimation: ProgressAnimationProtocol {
....
}
@available(macOS 13.0, iOS 16.0, *)
extension ProgressAnimationProtocol {
....
}
#else
// 在老系统上禁用 throttled 功能
extension ProgressAnimationProtocol {
public func throttled(
interval: Double
) -> some ProgressAnimationProtocol {
self
}
}
#endifswift-certificates/Sources/X509/PromiseAndFuture.swift文件中不被识别的_Concurrency,只需要导入_Concurrency即可:
#if canImport(_Concurrency)
import _Concurrency
#endif
//源文件内容- ⚠️警告⚠️: 通过修改
swiftpm中的相关源码,可以编译成功,但是:即使swift package manager被编译成功的,但是它运行时依然要依赖macOS13+的系统库才能正常运行。所以再macOS12下不需要编译swiftpm,并且不能使用swift package manager的相关功能。
关于xctoolchain文件中的Info.plist文件生成
xctoolchain文件中的Info.plist文件生成,Info.plist文件用于将该工具链导入系统环境,让系统能识别swift的相关工具。
并且将该工具链导入系统的前提是需要将xxx.xctoolchain文件安装(或创建软连接)到:/Library/Developer/Toolchains/目录:
Info.plist文件内容示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Aliases</key>
<array>
<string>swift</string>
</array>
<key>CFBundleIdentifier</key>
<string>org.swift.60020251105</string>
<key>CompatibilityVersion</key>
<integer>2</integer>
<key>CompatibilityVersionDisplayString</key>
<string>Xcode 8.0</string>
<key>CreatedDate</key>
<date>2025-11-05T08:08:08Z</date>
<key>DisplayName</key>
<string>Swift 6.0 Release 2025-11-05</string>
<key>OverrideBuildSettings</key>
<dict>
<key>ENABLE_BITCODE</key>
<string>NO</string>
<key>OTHER_SWIFT_FLAGS</key>
<string>$(inherited) -plugin-path $(TOOLCHAIN_DIR)/usr/lib/swift/host/plugins</string>
<key>SWIFT_DEVELOPMENT_TOOLCHAIN</key>
<string>YES</string>
<key>SWIFT_DISABLE_REQUIRED_ARCLITE</key>
<string>YES</string>
<key>SWIFT_LINK_OBJC_RUNTIME</key>
<string>YES</string>
<key>SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME</key>
<string>YES</string>
</dict>
<key>ReportProblemURL</key>
<string>https://bugs.swift.org/</string>
<key>ShortDisplayName</key>
<string>Swift 6.0.0 Release</string>
<key>Version</key>
<string>6.0.20251105</string>
</dict>
</plist>
附加:设置动态链接库目录DYLD_LIBRARY_PATH
示例:
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/usr
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/usr/lib/
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Library/Developer/Toolchains/swift-5.10.1-RELEASE.xctoolchain/usr/lib/swift/macosx/