Swift 编译器驱动程序

Swift 的编译器驱动程序是一个协调 Swift 源代码编译为各种编译结果的程序,包括:可执行文件、库、目标文件、Swift 模块和接口等。 它是从命令行调用以构建 Swift 代码的程序(即 swiftswiftc),并且通常由构建系统(例如 Swift Package Manager (SwiftPM) 或 Xcode 的构建系统)代表开发者调用。

swift-driver 项目是 Swift 编译器驱动程序的一个新实现,旨在取代现有驱动程序,并提供一个更具可扩展性、可维护性和健壮性的代码库。 该项目的具体目标包括:

入门指南

注意:目前,swift-driver 仅与来自 swift.org 的 trunk 开发快照兼容。

构建 swift-driver 的首选方法是使用 Swift Package Manager。

在大多数平台上,您可以使用以下命令进行构建:

$ swift build

但是,在 Windows 上,开发者必须完成一些额外的工作。

由于 Package.resolved 引用的 swift-tools-support-core 的默认版本,我们必须首先更新包依赖项。

swift package update

然后,我们可以使用以下命令构建包:

swift build -Xcc -I -Xcc "%SystemDrive%\Library\sqlite-3.38.0\usr\include" -Xlinker -L -Xlinker "%SystemDrive%\Library\sqlite-3.38.0\usr\lib" -Xlinker "%SDKROOT%\usr\lib\swift\windows\x86_64\swiftCore.lib"

由于 SQLite3 是一个系统库依赖项,并且没有唯一的头文件和库搜索路径,因此开发者必须指定该路径。 如果该库未位于指定位置,则可能需要调整 SQLite3 的路径。 此外,由于 Swift Package Manager 不区分 C/C++ 和 Swift 目标,并且使用 Swift 驱动程序作为链接器驱动程序,因此我们必须手动将 Swift 运行时链接到所有目标中。

要使用 swift-driver 代替现有的 Swift 驱动程序,请创建从 swiftswiftcswift-driver 的符号链接

ln -s /path/to/built/swift-driver $SOME_PATH/swift
ln -s /path/to/built/swift-driver $SOME_PATH/swiftc

Swift 包可以通过覆盖 SWIFT_EXEC 以引用上面创建的 swiftc 符号链接,以及覆盖 SWIFT_DRIVER_SWIFT_FRONTEND_EXEC 以引用原始的 swift-frontend 来使用新的 Swift 驱动程序构建,例如:

SWIFT_EXEC=$SOME_PATH/swiftc SWIFT_DRIVER_SWIFT_FRONTEND_EXEC=$TOOLCHAIN_PATH/bin/swift-frontend swift build

类似地,可以通过添加一个自定义构建设置(通常在项目级别)在 Xcode 中使用新的 Swift 驱动程序,该设置名为 SWIFT_EXEC,指向 $SOME_PATH/swiftc,并将 -driver-use-frontend-path $TOOLCHAIN_DIR/usr/bin/swiftc 添加到 Other Swift Flags

使用 CMake 构建

也可以使用 CMake 构建 swift-driver,这适用于 Swift Package Manager 尚未可用的环境。 这样做需要首先构建几个依赖项,所有依赖项都使用 CMake

一旦构建了这些依赖项,就可以构建 swift-driver 本身

cmake -B <swift-driver-build-dir> -G Ninja <swift-driver-source-dir> -DTSC_DIR=<swift-tools-support-core-build-dir>/cmake/modules -DLLBuild_DIR=<llbuild-build-dir>/cmake/modules -DYams_DIR=<yamls-build-dir>/cmake/modules -DArgumentParser_DIR=<swift-argument-parser-build-dir>
cmake --build <swift-driver-build-dir>

开发 swift-driver

新的 Swift 驱动程序正在开发中,有许多地方供任何对此感兴趣的人贡献力量! 本节涵盖测试、其他开发技巧和窍门,以及一个粗略的开发计划,展示了仍需要完成的工作。

驱动程序文档

有关驱动程序的概念性概述,请参阅Swift 驱动程序、编译模型和命令行体验。 要了解更多关于内部原理的信息,请参阅驱动程序设计与内部原理可解析的驱动程序输出

测试

使用命令行 SwiftPM 或 Xcode 进行测试。

$ swift test --parallel

集成测试运行成本很高,默认情况下处于禁用状态。 使用 SWIFT_DRIVER_ENABLE_INTEGRATION_TESTS 环境变量启用它们。 在 Xcode 中,您可以在 scheme 的测试操作中设置此变量。

$ SWIFT_DRIVER_ENABLE_INTEGRATION_TESTS=1 swift test --parallel

一些集成测试在 Swift 工作副本中运行 lit 测试套件。 要启用这些测试,请克隆 Swift 及其依赖项,并使用 build-script 构建它们,然后在 Xcode scheme 或命令行中设置 SWIFT_DRIVER_ENABLE_INTEGRATION_TESTSSWIFT_DRIVER_LIT_DIR

$ SWIFT_DRIVER_ENABLE_INTEGRATION_TESTS=1 \
  SWIFT_DRIVER_LIT_DIR=/path/to/build/Ninja-ReleaseAssert/swift-.../test-... \
  swift test -c release --parallel

针对 swift 编译器 trunk 进行测试

swift-driver 持续集成针对发布在 swift.org/download 上的最新 Trunk Development 快照运行。

当开发与底层 swift 编译器前端有复杂交互的补丁时,确保 swift-driver 测试也通过当前 tip-of-trunk swift 可能是明智的。 为此,请针对 github.com/apple/swift 创建一个空的 pull request,并针对您的 swift-driver pull request # 执行跨存储库测试,例如:

Using:
apple/swift-driver#208
@swift-ci smoke test

@swift-ci 跨存储库测试工具在此处进行了描述。

在 Xcode 中使用自定义工具链进行测试

安装工具链后,需要告诉 Xcode 使用它。 这可能意味着两件事:使用工具链构建驱动程序,以及告诉驱动程序在运行时使用工具链。

使用工具链进行构建很容易,在 Xcode 中设置工具链:菜单栏 > Xcode > Toolchains > 选择您的工具链

运行驱动程序需要设置 TOOLCHAINS 环境变量。 这告诉 xcrun 要使用哪个工具链 (在 darwin 上,xcrun 用于查找工具)。 此变量是工具链的名称,而不是路径 (例如: Swift Development Snapshot)。 重要提示: xcrun 查找的优先级低于 SWIFT_EXEC_*_EXEC 系列环境变量、tools 目录以及与驱动程序位于同一目录中的任何工具 (包括安装在工具链中的驱动程序)。 即使 TOOLCHAINS 不是最高优先级,它也是使用自定义工具链运行 xctest 套件的便捷方式。

准备用于调试的 Linux docker

当在没有快速访问 Linux 机器的 macOS 上进行开发时,使用 Linux Docker 通常对调试很有帮助。

要启动并运行 docker,请执行以下操作:

$ docker run -v /path/to/swift-driver:/home/swift-driver \
  --cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
  --security-opt apparmor=unconfined -it swift:latest bash
$ apt-get update
$ apt-get install libsqlite3-dev
$ apt-get install libncurses-dev

重新构建 Options.swift

Options.swift 包含驱动程序可以解析的完整选项集,它是从 Swift 编译器中的选项表 自动生成的。 如果您需要重新生成 Options.swift,您需要 构建 Swift 编译器,然后构建 makeOptions 程序,并使用 -I 来允许找到生成的 Options.inc,例如:

$ swift build -Xcc -I/path/to/build/Ninja-Release/swift-.../include -Xcc -I/path/to/build/Ninja-Release/llvm-.../include -Xcc -I/path/to/source/llvm-project/llvm/include --product makeOptions

然后,运行 makeOptions 并重定向输出以覆盖 Options.swift

$ .build/path/to/makeOptions > Sources/SwiftOptions/Options.swift

开发计划

新的 Swift 驱动程序的目标是为现有驱动程序提供一个直接替代品,这意味着在可以弃用和删除现有 Swift 驱动程序之前,需要实现一个固定的初始功能集。 以下开发计划涵盖了该功能集,并描述了许多可以改进 Swift 驱动程序的任务,从代码清理到改进测试、实现缺失的功能以及与现有系统集成。

从 SDK 构建所有 Swift 接口

基于 libSwiftDriver,swift-build-sdk-interfaces 是一种用于批量构建来自 SDK 的所有 Swift 文本接口 (.swiftinterface) 到二进制模块 (.swiftmodule) 中的工具。 例如,以下命令查找来自 MacOSX SDK 的所有 Swift 文本接口,将它们全部构建为二进制模块,并将模块特定的错误日志输出到给定的目录中。

$SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk SWIFT_EXEC=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc swift-build-sdk-interfaces -o /tmp/outputs -v -log-path /tmp/logs