编译 Swift 5.8 源码

编译准备

首先保证硬盘空间足够,本人一套流程下来文件夹有将近 60GB 大小。接下来是相关环境的安装,因为我的环境都是最新的,所以基本安装的都是最新版的包,如果你的环境不是新版的话,请找对应版本包安装。本人环境说明:

名称 版本
芯片 Apple M2 Pro
macOS Ventura 13.3
Python 3.11.2
CMake 3.26.3
ninja 1.11.1
sccache 0.4.1
Xcode 14.3

我们可以通过 homebrew 统一安装环境:

1
$ brew install cmake ninja sccache

此文只介绍 Xcode 调试环境,如果想用 VS Code 调试的话,需要用 Ninja 编译,Ninja 的编译请移步官方文档。

项目拉取

首先我们在文稿中新建一个文件夹,然后 cd 到我们的目录:

1
2
$ mkdir ~/Documents/swift-project
$ cd ~/Documents/swift-project

然后找到你的 Xcode 所支持的 Swift 版本,因为本人的 Xcode 为 14.3 版本,所以直接下载 Swift 5.8 Release。查找 Xcode 对应的 Swift 的版本有两种方式:

  1. 去官网,查看 Xcode 的 Release Notes,在 Overview 中会有介绍。例如:Xcode 14.3 Release Notes

  2. 终端运行命令查看 xcrun swift -version

    本地环境输出如下:

    1
    2
    swift-driver version: 1.75.2 Apple Swift version 5.8 (swiftlang-5.8.0.124.2 clang-1403.0.22.11.100)
    Target: arm64-apple-macosx13.0

我们在刚才新建的目录中执行如下命令拉取对应的 Swift 源码,并 cd 到源码目录:

1
2
$ git clone --branch swift-5.8-RELEASE git@github.com:apple/swift.git
$ cd swift

拉取源码后还须拉取依赖

1
$ utils/update-checkout --tag swift-5.8-RELEASE --clone

顺便说一句,上述操作最好全程科学上网。

编译

一切准备完毕后我们将开始第一步编译,这里我们需要用到官方的脚本,在 utils 目录下的 build-script 脚本,以下是本人所使用的命令。

1
2
3
4
$ utils/build-script \
--release-debuginfo --debug-swift-stdlib \
--xcode --skip-ios --skip-watchos --skip-tvos \
--skip-early-swiftsyntax --swift-darwin-supported-archs="$(uname -m)"

编译命令的参数最好做一些简单了解,不要盲目复制粘贴,这里只展示苹果 M 系列芯片的 arm64 架构编译命令,如果你是 Intel 环境请自行查阅官方文档。或执行 utils/build-script --help 命令查阅。

我们来简单的介绍一下这里众多的参数:

  • --release-debuginfo 编译出带有 RelWithDebInfo 环境变量的工程,类似于 DebugRelease 模式,RelWithDebInfo 会优化一部分,但同时保留调试信息。

  • --debug-swift-stdlib 编译带有调试信息的 Swift标准库,如果想调试 Swift编译器,可以使用 --debug-swift

  • --xcode 使用 CMake 的 Xcode 生成器,编译完成后会生成一个 Swift.xcodeproj 工程。

  • --skip-ios --skip-watchos --skip-tvos 跳过相应平台,这里只编译 macOS 平台。

  • --swift-darwin-supported-archs="$(uname -m)" 编译相关架构,$(uname -m) 命令用于获取机器架构环境,例如本机获取的结果为 arm64

--skip-early-swiftsyntax 这个命令我们留到后面错误修复的时候再说,这里先留个悬念。

接下来我们回车执行命令,这里需要等待一段时间,编译时间长短与机器性能有关。编译结束之后,我们会在目录 ~/Documents/swift-project 下得到一个 build 文件夹,里面就是我们 build 的产物。

Xcode-RelWithDebInfoAssert+stdlib-DebugAssert。目录结构如下图:

至此第一阶段编译完成,离成功又近了一步,接下来我们进入 Xcode 编译阶段。

源码调试

进入目录 swift-macosx-arm64 双击打开 Xcode 工程,此时会有自动创建 schemes 的提示,如下图,我们选择自动创建。

创建自定义 target 用于调试

Swift.xcodeproj 工程里面,我们点击 TARGETS 下面的 + 新建一个调试的 target,我们选择 macOS 的命令行模式。如下图:

Product Name 取个自定义名字就行。接下来为我们的 target 引入依赖,如下图:

接下来我们需要在设置中关闭 Hardened Runtime 选项,如下图:

如果想了解更多关于 Hardened Runtime 的介绍,请查看官方文档:Hardened Runtime

我们还须将 target schemeBuild Configuration 修改为 ReWithDebInfo

最后我们在自定义 target 文件夹下的 main.swift 文件中添加相应的代码,并在 HeapObject.cpp 中设置断点就可以开始愉快的调试了。如下图:

问题解决

在编译源码的过程中,本人遇到了几个问题,列在这里用以记录,也方便他人。

执行脚本阶段,最开始我执行的脚本并没有添加 --skip-early-swiftsyntax 这两个参数,脚本执行不通过,报错如下:

CMake Error in lib/ASTGen/CMakeLists.txt:
Imported target “SwiftSyntax::SwiftBasicFormat” includes non-existent path

"/Users/jiafengwu/Documents/github/buildSwiftSource/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/earlyswiftsyntax-macosx-arm64/lib/swift/host"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not
    provide.

CMake Error in lib/ASTGen/CMakeLists.txt:
Imported target “SwiftSyntax::SwiftBasicFormat” includes non-existent path

"/Users/jiafengwu/Documents/github/buildSwiftSource/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/earlyswiftsyntax-macosx-arm64/lib/swift/host"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not
    provide.

CMake Error in lib/ASTGen/CMakeLists.txt:
Imported target “SwiftSyntax::SwiftBasicFormat” includes non-existent path

"/Users/jiafengwu/Documents/github/buildSwiftSource/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/earlyswiftsyntax-macosx-arm64/lib/swift/host"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not
    provide.

CMake Error in lib/ASTGen/CMakeLists.txt:
Imported target “SwiftSyntax::SwiftBasicFormat” includes non-existent path

"/Users/jiafengwu/Documents/github/buildSwiftSource/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/earlyswiftsyntax-macosx-arm64/lib/swift/host"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not
    provide.

CMake Error in lib/Parse/CMakeLists.txt:
Imported target “SwiftSyntax::SwiftBasicFormat” includes non-existent path

"/Users/jiafengwu/Documents/github/buildSwiftSource/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/earlyswiftsyntax-macosx-arm64/lib/swift/host"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not
    provide.

CMake Error in lib/Parse/CMakeLists.txt:
Imported target “SwiftSyntax::SwiftBasicFormat” includes non-existent path

"/Users/jiafengwu/Documents/github/buildSwiftSource/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/earlyswiftsyntax-macosx-arm64/lib/swift/host"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not
    provide.

CMake Error in lib/Parse/CMakeLists.txt:
Imported target “SwiftSyntax::SwiftBasicFormat” includes non-existent path

"/Users/jiafengwu/Documents/github/buildSwiftSource/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/earlyswiftsyntax-macosx-arm64/lib/swift/host"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not
    provide.

CMake Error in lib/Parse/CMakeLists.txt:
Imported target “SwiftSyntax::SwiftBasicFormat” includes non-existent path

"/Users/jiafengwu/Documents/github/buildSwiftSource/build/Xcode-RelWithDebInfoAssert+stdlib-DebugAssert/earlyswiftsyntax-macosx-arm64/lib/swift/host"

in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:

  • The path was deleted, renamed, or moved to another location.

  • An install or uninstall procedure did not complete successfully.

  • The installation package was faulty and references files it does not
    provide.

从上面的报错可看出,出错的原因是在编译 earlyswiftsyntax 的时候。要修复此问题,我们只需添加参数 --skip-early-swiftsyntax 即可,让其在执行编译命令的时候跳过 earlyswiftsyntax 的构建。因为这并不影响我们最终的源码调试。

Xcode 编译阶段,第一次执行编译的时候出现了如下的错误:

这是由于在执行 utils/build-script --xcode 的时候 cxxshim 试图创建模块目录导致。我们只需要将 swift/stdlib/public/Cxx/cxxshim/CMakeLists.txt 此文件中的如下命令删除即可:

1
2
3
4
list(APPEND outputs ${module_dir})
if(SWIFT_BUILD_STATIC_STDLIB)
list(APPEND outputs ${module_dir_static})
endif()

然后清空 build 目录,重新执行 utils/build-script 进行构建即可。

接下来一切完成后,继续 Xcode 编译又会出现如下错误:

看报错是 llvm-macosx-arm64 中的 Debug 目录下没有相应的文件。首先我们查看 swift-compatibility-symbols 这个 target 将其 Build Configuration 修改为 ReWithDebInfo 。然后我们在执行编译即可。

参考文档