几年前,我还用vapor写应用接口,但慢慢的我放弃了。很大一个阻力就是在linux编译vapor项目非常困难:
- 首先就是服务器性能比较低,构建速度非常慢
- 最痛的就是,拉取第三方库非常非常非常慢,导致得在服务器安装 vpn
- 还有就是 vapor 的 orm 不成熟
其实除去打包编译的原因,我还是很喜欢用vapor的,毕竟很多东西很原始,你的手动实现,这样也不会有很多魔法特性,至少用完之后,你知道服务器 web 开发到底都涉及了哪些技术。很多其他语言的 web开发框架很好用,但是学习不到啥东西,因为它帮你做了很多东西,节省了很多步骤。如果你是为了学习,建议用vapor,如果你是为了快速开发,还是用其他语言的框架把,比如 springboot,django 等。
很久没有跟进 vapor 这块文章,最近秒了几眼 swift 的交叉编译,就迫不及待的想尝试下 vapor 项目的构建。
实践结果是可行的,不得不说swift在跨端方面确实做了工作。那么接下来一起来看看这个构建该如何实施。
Swift Static Linux SDK
在这之前我们先了解下 Swift Static Linux SDK,它 主要解决了 Linux 上部署 Swift 应用时的依赖问题。传统上,Swift 应用需要依赖系统中的动态库(如 libSwiftCore.so 和 libc.so),这可能导致兼容性问题或复杂的部署过程。该 SDK 通过 静态链接,将所有依赖嵌入到一个独立的可执行文件中,避免了对目标系统上库的依赖。
举个例子:
假设你开发了一个 Swift 应用,并想部署到一个没有 Swift 环境的 Linux 服务器。使用 Swift Static Linux SDK 后,你可以构建一个 静态链接的可执行文件,直接在目标服务器上运行,而不需要安装任何 Swift 或系统库。
它解决的问题:
- 避免动态库依赖:应用不依赖系统动态库,因为它唯一依赖的是 Linux 系统调用接口。
- 减少兼容性问题:保证应用在不同版本的 Linux 系统上运行。
- 简化部署:只需部署单个二进制文件,简化了安装过程。
Static vs Dynamic Linking
以下是关于 静态库 与 动态库 的定义、差异、优缺点的对比表格:
| 类别 | 静态库 | 动态库 |
|---|---|---|
| 定义 | 在编译时将库文件的内容嵌入到最终的可执行文件中。 | 在运行时,程序依赖操作系统加载的外部共享库。 |
| 链接方式 | 静态链接:在编译时将所有依赖的库打包到可执行文件中。 | 动态链接:程序在运行时加载外部共享库。 |
| 文件大小 | 可执行文件较大,因为库被直接嵌入其中。 | 可执行文件较小,只包含程序的代码,库由系统加载。 |
| 内存使用 | 每个程序都包含一份库,可能造成内存浪费。 | 多个程序可以共享同一个动态库的内存,节省内存。 |
| 依赖管理 | 不依赖系统的动态库,完全独立。 | 依赖目标系统中的动态库,可能导致依赖缺失或版本不兼容。 |
| 启动时间 | 启动时无需加载外部库,因此启动较快。 | 程序启动时需要加载动态库,可能导致启动时间稍慢。 |
| 更新与维护 | 更新库时需要重新编译整个程序。 | 只需更新共享库,程序可自动加载新版本的库。 |
| 兼容性问题 | 无兼容性问题,程序与库一起打包。 | 可能会遇到版本不匹配或缺少库等兼容性问题。 |
| 部署复杂度 | 部署时只需复制单个可执行文件,简单。 | 部署时需要确保目标系统安装了正确的动态库,较复杂。 |
| 安全性 | 更安全,因为所有依赖都在程序内,不依赖外部库。 | 可能会受到外部库的安全漏洞影响。 |
优缺点总结:
| 特性 | 静态库 | 动态库 |
|---|---|---|
| 优点 | 1. 独立性强,无需依赖外部库。 2. 兼容性好,跨平台部署简单。 3. 部署简便,减少了外部环境配置的复杂性。 4. 更安全,所有依赖都被打包。 | 1. 文件小,节省磁盘空间。 2. 内存共享,多个程序共享同一库。 3. 更新库时,无需重新编译程序。 4. 程序启动较快。 |
| 缺点 | 1. 文件较大。 2. 更新麻烦,必须重新编译程序。 3. 内存浪费,每个程序都包含一份库。 | 1. 依赖外部库,可能缺失或不兼容。 2. 兼容性差,可能引发“DLL Hell”。 3. 部署复杂,需要管理系统库。 4. 启动时间稍慢。 |
安装环境
首先我们无法使用 Xcode 提供的工具链来使用 SDK 构建程序,必须安装对应版本的工具链。
1. 安装Swiftly
curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg && \
installer -pkg swiftly.pkg -target CurrentUserHomeDirectory && \
~/.swiftly/bin/swiftly init --quiet-shell-followup && \
. ~/.swiftly/env.sh && \
hash -r
Swiftly 是一个专门为 Swift 提供的工具和框架,旨在简化和加速开发者的工作流程。它可以用来帮助开发者更高效地构建、测试和调试 Swift 应用,特别是在某些特定场景下,如自动化构建、交叉编译、和使用 Swift 进行脚本化工作时。
以下是 Swiftly 的用途和适用场景的表格:
| 功能 | 说明 | 适用场景 |
|---|---|---|
| 自动化构建与管理 | 提供自动化工具,简化构建和处理输出,适用于持续集成和持续交付(CI/CD)。 | 持续集成、持续交付(CI/CD)流程 |
| 交叉编译支持 | 支持在不同平台(如 Linux、Windows)之间进行交叉编译,简化多平台构建过程。 | 跨平台开发、嵌入式设备、不同操作系统间迁移 |
| 命令行工具支持 | 允许用 Swift 编写命令行工具,提供自动化和脚本化能力,适用于处理批量任务。 | 自动化脚本、批量处理任务 |
| 开发者工具整合 | 提供库和工具,帮助开发者集成第三方服务或工具,减少配置复杂度和手动操作。 | 第三方服务集成、减少配置操作 |
| 增强的调试和测试 | 提供增强的调试功能,如跨平台调试、模拟环境等,帮助快速发现和修复错误。 | 调试跨平台应用、测试不同环境 |
安装完成后,我们可以用以下指令:
swiftly --version # 查看版本
swiftly list # 查看已安装sdk列表
swiftly install 6.1.0 # 安装指定版本swfit
swiftly use 6.1.0 # 使用指定版swift
swiftly uninstall 6.1.0 # 卸载指定版本swift
更多可以前往:www.swift.org/swiftly/doc…
2. Static Linux SDK 安装
工具链必须与您安装的 Static Linux SDK 的版本匹配。静态 Linux SDK 在其文件名中包含相应的 Swift 版本,以帮助识别 SDK 的正确版本。
可以在 www.swift.org/install/mac…,找到相应资源。
$ xattr -d -r -s com.apple.quarantine "swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz"
$ swift sdk install swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz
$ swift sdk list #获取已安装 SDK 的列表
$ swift sdk remove <name-of-SDK> # 删除指定sdk
官方的安装指南:www.swift.org/documentati…
构建可执行包
-
首先,我们创建一个vapor 项目:
vapor new hello -n -
在本地建立和运行
$ swift build $ .build/debug/hello但是安装了静态Linux SDK,您还可以为X86-64和ARM64机器构建Linux二进制文件:
$ swift build --swift-sdk x86_64-swift-linux-musl # debug 包 $ swift build --swift-sdk x86_64-swift-linux-musl -c release # release 包 $ file .build/x86_64-swift-linux-musl/debug/hello
其他
-
为了能在服务器端直接访问到项目,需要在项目配置下绑定
0.0.0.0和端口。app.http.server.configuration.hostname = "0.0.0.0" app.http.server.configuration.port = 8188 -
打包完成后,会有两个linux 文件:
x86_64-unknown-linux-gnu和x86_64-swift-linux-musl,怎么选?完全正确!你说的这句话抓住了重点:
“Static Linux SDK 不使用 Glibc;相反,它是建立在顶部的 Linux 的替代 C 库称为 musl。”
下面我帮你用一张清晰的表格总结一下相关概念,帮助你彻底理解它的意义、背景、优劣势以及使用场景:
✅
Static Linux SDK与glibcvsmusl对比项目 Static Linux SDK(musl) 普通 Linux SDK(glibc) C 标准库 muslglibc是否静态链接 ✅ 默认静态链接 ❌ 通常动态链接 可执行文件是否自包含 ✅ 是,拷贝即用,无需依赖 ❌ 否,运行时需系统已安装 glibc 兼容性 更便携,适用于 Alpine、Docker、容器环境等 只能在支持 glibc 的系统上运行 文件体积 相对小(单文件) 相对大(动态链接多个库) 适合什么场景? 跨平台分发、容器、CI/CD、嵌入式 正常部署到 Ubuntu/Debian/CentOS 构建结果目录名 x86_64-swift-linux-muslx86_64-unknown-linux-gnu📦 举个例子
假设你用
swiftly build编译出来两个版本:.build/x86_64-swift-linux-musl/MyApp # ✅ 可直接部署,无需系统安装 Swift 或 glibc .build/x86_64-unknown-linux-gnu/MyApp # ❌ 如果系统缺 glibc 可能运行失败你把
.build/x86_64-swift-linux-musl/MyApp放到任何一个 Linux(甚至很老的)系统里,大概率都能跑;它几乎不依赖任何系统的运行库。Static Linux SDK = Swift + musl + 静态链接 → 最轻便、最可移植的 Linux 可执行文件构建方案。
所以如果你在做跨平台 CLI 工具、容器部署、内网发布,推荐始终优先使用 musl 构建的版本。
toolchain 与 static linux sdk 版本不匹配
这个是我在重启电脑重新运行构建脚本的时候发生:
swift build --swift-sdk x86_64-swift-linux-musl -c release
后面再多次阅读文档:
获得结论:当你运行 swift 时,你仍然会使用 Xcode 的 Swift 版本。你需要使用 xcrun 运行安装的特定工具链
xcrun --toolchain swift swift --version
综合命令,可以将打包命令综合:
xcrun --toolchain swift swift build --swift-sdk x86_64-swift-linux-musl -c release
这才是正确的打包命令。
关注公众号:OldBird,获取最新文章推送。