news 2026/9/25 2:04:24

SwiftPM 开发工具链定制指南:用 mk-toolchain 脚本构建可调试的 Manifest/Plugin API 测试环境

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SwiftPM 开发工具链定制指南:用 mk-toolchain 脚本构建可调试的 Manifest/Plugin API 测试环境
  • 开发工具
  • 构建工具

【免费下载链接】swift-package-manager

The Package Manager for the Swift Programming Language

项目地址:https://gitcode.com/gh_mirrors/sw/swift-package-manager
点击查看免费下载

导读

本指南基于 Utilities/mk-toolchain/README.md 展开,讲解 Swift Package Manager(SwiftPM)开发者如何在 macOS 上通过mk-toolchain脚本,把开发工作区(Xcode Workspace)中构建出的PackageDescription、PackagePlugin、swift-package、swift-build、swift-test、swiftpm-testing-helper、sourcekit-lsp等产物,拼装成一个自定义.xctoolchain工具链。读者完成本文后可独立搭建"改 Manifest/Plugin API → 一键重建工具链 → 在 VSCode Swift 中即时验证"的开发闭环,并用 Swift 测试与补全体验来验收 Manifest 与 Plugin API 的人机工效(ergonomics)改动。

背景:为什么要自制工具链

修改包清单(Package.swift所依赖的PackageDescriptionAPI)或插件(PackagePluginAPI)时,最自然的验证方式是在一个真实的 Swift 包工程里"边改边用",观察 API 手感是否顺畅、补全提示是否准确。但 Xcode 的XcodeDefault.xctoolchain中打包的是发布版 Manifest/Plugin 运行库,直接修改后无法立即生效。

原文档给出的最佳实践是:把开发工作区构建出的产物,通过软链接替换到一份工具链副本中,形成自定义工具链,再用TOOLCHAINS环境变量让 VSCode Swift 语言服务器与swift命令选中它。这样你在源码上做的每次改动,都能在一个真实包工程中立刻被补全、编译和测试验证,而不是停留在单元测试的抽象断言里。

前置准备:组织开发工作区

原文档推荐将 SwiftPM 开发常用的三个仓库克隆到同一目录:

git clone https://github.com/swiftlang/swift-build git clone https://github.com/swiftlang/swift-package-manager git clone https://github.com/swiftlang/sourcekit-lsp
  • swift-package-manager:SwiftPM 本体,产出swift-package、swift-build、swift-test、swiftpm-testing-helper,以及PackageDescription/PackagePlugin两个 API 框架(见 Sources/CMakeLists.txt 中的相关目标);
  • swift-build:新一代构建系统 Swift Build(仓库内以container:../../swift-build的方式被引用,见 Utilities/SwiftPM+SwiftBuild.xcworkspace/contents.xcworkspacedata),产出swift-build可执行文件与llbuild框架;
  • sourcekit-lsp:为编辑器提供索引、补全与诊断的语言服务器,负责把新 API 的补全带给 VSCode。

说明:原文档针对 macOS + Xcode 的流程,并明确欢迎其他宿主平台(如 Linux/Windows)的开发者贡献等价工具。本文严格限定在 macOS 环境下描述。

创建 xcworkspace

在同一目录下创建myNewFeature.xcworkspace,并在其中新建contents.xcworkspacedata,内容如下:

<?xml version="1.0" encoding="UTF-8"?> <Workspace version = "1.0"> <FileRef location = "group:swift-build"> </FileRef> <FileRef location = "group:swift-package-manager"> </FileRef> <FileRef location = "group:sourcekit-lsp"> </FileRef> </Workspace>

仓库中 Utilities/SwiftPM+SwiftBuild.xcworkspace/contents.xcworkspacedata 提供了一个真实范例(它以container:../../swift-build与container:../../swiftpm的相对形式引用仓库),可用于对照。这里group:前缀表示引用的是工作区内的子目录,而非绝对磁盘路径。

配置 Xcode Scheme 与构建产物

用 Xcode 打开该 xcworkspace,新建一个 Scheme,并在其 Build 阶段加入以下 Target:

PackageDescription PackagePlugin swift-package swift-build swift-test swiftpm-testing-helper sourcekit-lsp

各 Target 的职责与源码对应关系如下:

Target产物仓库源码入口
PackageDescriptionManifest API 框架/模块,Package.swift依赖它Sources/Runtimes/PackageDescription
PackagePluginPlugin API 框架/模块,插件目标依赖它Sources/Runtimes/PackagePlugin
swift-packageswift package命令Sources/swift-package/Entrypoint.swift
swift-build新一代构建系统命令swift buildSources/swift-build/Entrypoint.swift
swift-testswift test命令Sources/swift-test/Entrypoint.swift
swiftpm-testing-helper测试运行辅助程序Sources/swiftpm-testing-helper/Entrypoint.swift
sourcekit-lsp语言服务器(来自 swift-build 仓库相邻克隆)sourcekit-lsp 仓库

构建完成后,产物会落入 Xcode 的 DerivedData 目录。mk-toolchain脚本通过通配符定位它们(见下文脚本解析)。

运行 mk-toolchain 脚本生成自定义工具链

构建 Scheme 成功之后,在同时包含三个 git 仓库与 xcworkspace 文件的目录中运行本仓库的脚本:

./Utilities/mk-toolchain/mk-toolchain

脚本(Utilities/mk-toolchain/mk-toolchain,zsh 实现)按以下顺序工作:

  1. 推导名称:name=$(basename *.xcworkspace .xcworkspace),即取当前目录中唯一的.xcworkspace名(如myNewFeature);
  2. 定位源工具链:src=$(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain,即当前xcode-select指向的 Xcode 内置工具链;
  3. 定位构建产物:从~/Library/Developer/Xcode/DerivedData/${name}-*/Build/Intermediates.noindex/InstallIntermediates/macosx/Products/Debug目录读取产物;
  4. 拷贝底子:ditto $src $dest把整份XcodeDefault.xctoolchain复制到~/Library/Developer/Toolchains/${name}.xctoolchain(目标路径不存在时由脚本创建,覆盖已存在的同名工具链);
  5. 补充 llbuild:把 Swift Build 构建出的llbuild.framework拷入工具链的usr/lib/swift/pm/llbuild/,供 swift-build 运行时链接;
  6. 软链接二进制:把swift-package、swift-build、swift-test、sourcekit-lsp链接到工具链的usr/bin/;
  7. 替换 Manifest/Plugin API:清空usr/lib/swift/pm/ManifestAPI/与usr/lib/swift/pm/PluginAPI/,再分别将 DerivedData 中的PackageDescription.swiftmodule、PackageDescription.framework、PackagePlugin.swiftmodule、PackagePlugin.framework以及CompilerPluginSupport.swiftmodule软链接进去;
  8. 写入 Info.plist:删除原有ToolchainInfo.plist,生成带有别名swift、CFBundleIdentifier等于工作区名、以及OverrideBuildSettings(OTHER_SWIFT_FLAGS中追加-plugin-path $(TOOLCHAIN_DIR)/usr/lib/swift/host/plugins、SWIFT_DEVELOPMENT_TOOLCHAIN=YES、SWIFT_USE_DEVELOPMENT_TOOLCHAIN_RUNTIME=YES)的Info.plist;
  9. 冒烟自检:依次执行TOOLCHAINS=$name swift --version与TOOLCHAINS=$name swift build --version,确认新工具链可被swift命令识别。

脚本的关键校验点

脚本内含三道检查,便于排错:

  • derivedData为空时提示"请从包含 xcworkspace 的目录运行";
  • 源工具链不存在(! -d $src)时报Source toolchain not found;
  • DerivedData 目录不存在(! -d $derivedData)时报Derived data not found,此时需检查 Scheme 是否真的执行了 Install 构建(InstallIntermediates 路径),或 DerivedData 路径通配是否与实际 Xcode 布局一致。

与源码的对应关系

Manifest/Plugin API 在工具链中的位置并非随意选择。ToolchainConfiguration.swift(Sources/PackageModel/ToolchainConfiguration.swift)中的LibraryLocations在初始化时会基于swiftc路径推导lib/swift/pm/ManifestAPI与lib/swift/pm/PluginAPI;而 Sources/PackageModel/UserToolchain.swift 在查找这些框架时依次尝试"工具链内lib/swift/pm下的 ManifestAPI/PluginAPI 框架""PackageFrameworks目录""应用根目录",最终回退到基于swiftCompilerPath推导。因此mk-toolchain把框架放进usr/lib/swift/pm/正是 SwiftPM 运行时能够发现它们的标准路径。

重要提醒:Xcode 升级后需重建

原文档特别强调:每次 Xcode 升级后都要重新运行mk-toolchain。因为脚本是从"当前xcode-select选中的 Xcode"拷贝XcodeDefault.xctoolchain的,工具链副本中携带的 SDK 文件与运行时(swiftc、标准库、swift-plugin-server等,后者在 Darwin 上由 Sources/PackageModel/UserToolchain.swift 通过xcrun --find swift-plugin-server定位)必须与宿主机 Xcode 版本一致,否则会出现版本错配导致的链接或运行失败。

用新工具链验证 Manifest/Plugin API 改动

1. 初始化插件包

在任意新目录中创建 build tool 插件类型包:

swift package init --type build-tool-plugin

--type build-tool-plugin是swift package init支持的包类型之一,与empty、library、executable、tool、command-plugin、macro并列,定义于 Sources/Workspace/InitPackage.swift 的PackageType枚举中。

2. 用 TOOLCHAINS 环境变量在 VSCode 中激活

TOOLCHAINS=myNewFeature code .

TOOLCHAINS的值即你为 xcworkspace 起的名字(对应工具链Info.plist中的CFBundleIdentifier与目录名~/Library/Developer/Toolchains/myNewFeature.xctoolchain)。Swift 工具链查找机制会依据该变量在~/Library/Developer/Toolchains下按名称定位工具链,swift命令与语言服务器都会被指向新工具链。

3. 逐项验收清单

原文档给出了一个完整的功能验收顺序,逐条执行即可确认工具链可用:

  1. 包解析:确认 VSCode 能成功解析该包(无红色诊断);
  2. 构建:执行包构建并确保成功;
  3. 测试:添加测试用例,确认测试被发现并能运行(swift test经由swift-test入口,其测试运行辅助程序即swiftpm-testing-helper,实现在 Sources/swiftpm-testing-helper/Entrypoint.swift,它负责以--test-bundle-path动态加载测试包并调用其中的main);
  4. Manifest 补全:编辑Package.swift,新增一个 target,观察补全是否提示出各 target 函数——这正是验证PackageDescriptionAPI 改动的核心场景;
  5. 插件补全:编辑插件 Swift 文件,在createBuildCommands函数中对context与target参数做补全,确认PackagePluginAPI 的新增符号能被 sourcekit-lsp 索引到。

全部通过,即说明你已拥有一个"改动源码 → 重新构建 Scheme → 重跑 mk-toolchain → 在示例包中即时验证"的完整测试环境。

常见问题排查

  • Derived data not found:检查 Scheme 是否包含 Install 阶段,或 Xcode 的 DerivedData 目录名与${name}-*通配不匹配(可把~路径换成实际的DerivedData/<workspace名>-<hash>验证);
  • 补全不生效:确认 VSCode 启动时确实携带了TOOLCHAINS环境变量(在已打开窗口内用TOOLCHAINS=myNewFeature swift --version复核版本);必要时重启语言服务器,让它重新扫描工具链;
  • Xcode 升级后链接失败:重新运行mk-toolchain重建工具链副本,保证 SDK 与运行库版本一致;
  • Linux/Windows 支持:当前脚本是 macOS + Xcode 专用(zsh、ditto、xcode-select均依赖 macOS),其他平台需要等价工具,仓库欢迎此类贡献。

小结

mk-toolchain把"修改PackageDescription/PackagePluginAPI"与"在真实包工程中体验这些 API"直接连通:Xcode Scheme 产出二进制与框架,脚本将它们在XcodeDefault.xctoolchain副本中以软链接形式替换,最终通过TOOLCHAINS环境变量交付给swift与 VSCode。配合 Utilities/mk-toolchain/README.md 中约定的五项验收(解析、构建、测试、Manifest 补全、插件补全),开发者可以在迭代 API 时第一时间获得真实的使用反馈,这正是 SwiftPM 团队验证 Manifest 与 Plugin API 人机工效的标准方式。

  • 开发工具
  • 构建工具

【免费下载链接】swift-package-manager

The Package Manager for the Swift Programming Language

项目地址:https://gitcode.com/gh_mirrors/sw/swift-package-manager
点击查看免费下载
上一篇:2024最值得关注的10款笔记软件:Awesome Note-Taking权威评测
下一篇:MRPT:构建智能移动机器人的全能开发框架

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 2:03:28

企业数字化底座建设指南:从数据仓库到BI应用的全链路设计

简介&#xff1a;面向企业管理者、数字化规划人员及IT架构师的PPT资源&#xff0c;系统梳理企业数字化底座的定义、价值与总体架构&#xff0c;针对当前转型中数据分散、缺乏统一视图、风险体系缺失等问题&#xff0c;给出建设目标与分阶段规划路径。内容以综述、总体架构、规划…

作者头像 李华
网站建设 2026/9/25 2:03:11

STM32开源项目三件套:代码、原理图与仿真配套实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 2:03:07

百度之星决赛真题数据与标程:ACM/OI选手的训练利器

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 2:02:27

ESP32 -O2崩溃根源:未定义行为与编译器优化实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 2:02:19

机器学习大作业实战:从Sklearn建模到评估避坑全流程

简介&#xff1a;电子科技大学机器学习大作业的7z压缩包&#xff0c;面向该校选修机器学习课程、需要独立完成课程大作业的本科生和研究生&#xff0c;可根据自身任务需求直接参考其文件组织与实验思路。整个资源包大小约11.55MB&#xff0c;以7z格式压缩&#xff0c;体积适中便…

作者头像 李华
网站建设 2026/9/25 2:02:07

华为悦盒Q21/EC6109U免拆机刷当贝桌面实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华