Ports软件组织模式与跨平台包管理神器pkgsrc
本文探讨了软件仓库的一种架构——Ports 组织模式。这是一种以构建脚本为本体、实时定义软件生产逻辑的架构。文章详细拆解了其从源码构建到二进制“缓存”的进化过程,并重点解析了具备极致可移植性的跨平台神器 pkgsrc。
1 前言
本文是《Linux 包管理器生态漫谈》的续作。在前文中,我们拆解了 Linux 包管理器的各种设计理念;而本次,我们将目光转向这些工具背后的基础设施——软件仓库。
软件仓库对软件包的录入与存储通常有三种逻辑:
- 源码录入: 仓库维护的是软件的构建说明。
- 制品录入: 仓库直接存储编译好的二进制文件(如 .deb 或 .rpm)。
- 混合模式: 二者兼有。
我今天要介绍的是“源码录入”逻辑中极具代表性的一员:Ports 模式。
这种模式的有趣之处在于:它虽然属于源码录入,但软件仓库中并不真正存储开源软件的源码包,而是只存储了一套构建脚本。在构建过程中,构建系统会实时根据脚本指令去互联网下载源码。
2 Ports 模式的特征
在 Ports 模式下,“软件”的本体并不是编好的二进制文件,而是那一套构建脚本。
这种“以脚本定义软件,以源码为本位”的设计,导致它在逻辑上跟传统的包管理系统完全不同:
- 仓库里只存“配方”:软件源的维护者通过一个巨大的代码仓库来维护软件包。这个仓库里全是文本文件,它不存软件源码,只存“配方”:去哪下源码、下完怎么打补丁、用什么参数编译、装到哪个目录下。
- 仓库本身就是“包管理器”:在很多模式下,软件仓库(存放数据)和客户端(执行逻辑)是分离的,比如 Debian 的 apt 仓库与 apt 包管理器就是两个互相独立的存在。但在 Ports 模式里,仓库里的公共脚本配合系统自带的 make,本身就已经构成了一套完善的包管理系统。
- 二进制包只是“缓存”:虽然现在的 Ports 社区都会在源码库的基础上额外提供预编译的二进制包,能帮你省去从源码实时编译的繁琐动作,但这些包本质上只是官方替你跑了一遍脚本后的“缓存结果”。如果官方包不符合你的口味(比如你想精简功能),你完全可以无缝切换回源码模式,按自己的意愿重新编一遍。
3 Ports 模式的起源
3.1 最初的玩家
Ports 这种软件组织模式由 FreeBSD 首创。狭义上来讲,Ports 正是特指 FreeBSD 的 Ports Collection。
FreeBSD 官方对 port 的介绍是这样的:
FreeBSD port 是一组文件,旨在自动执行从源代码编译应用程序的过程。port 中包含了自动下载、提取、修补、编译和安装应用程序所需的所有信息。
3.2 FreeBSD 里面的 port
以 zsh 这个软件为例,它的 port 长这样

图上的所有文件和目录加起来,就叫做一个 port。
各个文件的作用是这样的:
- Makefile:包含指定如何编译应用程序以及在何处安装其组件的语句。
- distinfo:包含构建 port 必须下载的文件的名称和校验和。
- files/:此目录包含程序在 FreeBSD 上编译和安装所需的所有补丁。此目录还可能包含用于构建 port 的其他文件。
- pkg-descr:提供该程序的更详细描述。
- pkg-plist:port 将会安装的所有文件的列表。它还会告诉 ports 系统在卸载时需要删除哪些文件。
图上的 zsh 只是一个示例,实际上所有 port 的文件结构都要符合这个规范。这个规范有一个专门的名字,叫做 ports skeleton。
我们打开 zsh 的 Makefile 看看,注意这两个变量:MASTER_SITES 和 DISTFILES。将这两个变量进行拼接,就可以获取到源码包的下载地址了,zsh 的构建过程中就是通过这个地址去实时下载源码的。

很多个 port 放在一起,就叫做一个 Ports Collection,这是官方最正式的术语。由于它的目录结构层级分明,从顶层的分类目录一直延伸到具体的软件目录,所以开发者们也形象地称之为 Ports Tree。此外它还有另一个比较常用的简称,叫做 Ports。
Ports Collection 是一个很大的目录,里面按照类型把软件进行分类,同类的软件会放在一起。

比如 zsh 这个软件是属于“shells”这个类别,因此它的 port 就放在 shells/zsh 这个目录中。

3.3 如何使用 port
在 FreeBSD 上,我们要如何将一个 port 构建成一个软件呢?
首先,需要下载一份 Ports Collection,并把它放置到 /usr/ports 目录中
git clone https://git.FreeBSD.org/ports.git /usr/ports
下载完成之后,进入到 port 所在的目录,然后执行 make install 即可。比如我要编译安装 zsh,我就要这么做
cd /usr/ports/shells/zsh
make install
这个过程看似和我们平时编译 C 程序一样,但不同之处在于:当你执行 make install 时,由于该 port 引用了仓库内的的公共 Makefile(bsd.port.pre.mk、bsd.port.post.mk),它会自动触发一套完整的流水线——下载源码、解压、打补丁、编译。
这就是 Ports 最原始的样子:仓库即工具。只要系统有 git 和 make,你不需要安装任何额外的包管理器客户端,就能完成软件全生命周期的管理。
3.4 从 Ports 到 Packages 的进化
纯粹的 Ports 模式虽然灵活,但有一个绕不开的痛点:极其耗时,因为所有软件包都需要实时编译。
为了解决这个问题,FreeBSD 引入了 Packages 方案,作为 Ports 方案的补充。
Packages 方案是这么做的:
- 官方批量构建:社区服务器定期拉取整个 Ports Collection,按照默认配置批量构建生成二进制包(Package)。
- 建立分发仓库:将这些构建好的制品托管在二进制仓库中。官方仓库主页:http://pkg.freebsd.org/。
- 引入客户端工具:向用户提供一个叫做 pkg 的二进制包管理工具,用户通过这个工具即可便捷地下载安装这些二进制包。
比如我要直接从二进制安装 zsh,我只需要执行这样一条命令即可
pkg install zsh
4 Ports 模式的主要玩家
自 FreeBSD 首创提出 Ports 方案之后,后续出现了大量的效仿者,许多类 UNIX 系统就使用了这种方案作为软件仓库的组织模式。
虽然它们名称各不相同,具体的技术实现细节也有所差异(比如使用的构建脚本已经不局限于 Makefile 而是选择了其他的形态),但理念都是一样的,所以我这里统一也都把它们归类为 Ports 模式。
| 类别 | OS 名称 | Ports 仓库的名称 | 构建脚本 | 二进制预构建包 | 二进制下载器(命令) |
|---|---|---|---|---|---|
| BSD分支 | FreeBSD | Ports Collection | Makefile | 有 | pkg |
| BSD分支 | NetBSD | pkgsrc | Makefile | 有 | pkgin |
| BSD分支 | OpenBSD | ports tree | Makefile | 有 | pkg_add |
| BSD分支 | DragonflyBSD | DPorts | Makefile | 有 | pkg |
| Linux发行版 | Gentoo Linux | Gentoo Repository | ebuild(bash) | 有 | emerge |
| Linux发行版 | Alpine Linux | aports tree | APKBUILD(bash) | 有 | apk |
| Linux发行版 | Arch Linux | official repositories | PKGBUILD(bash) | 有 | pacman |
| Linux发行版 | NixOS | nixpkgs | nix表达式 | 有 | nix |
| 其他 | macOS | homebrew-core(第三方) | formula(ruby) | 有 | brew |
| 其他 | SmartOS | pkgsrc | Makefile | 有 | pkgin |
5 pkgsrc 框架
上述的各种 Ports 方案,大部分都是有一定的讨论度的(尤其是那几个 Linux 发行版),所以我就没必要讲了,这次我想讲讲更冷门一些的 pkgsrc,它的高度可移植性令我十分感兴趣。
官方的介绍是这样的:
pkgsrc 是一个用于在类 UNIX 系统上管理第三方软件的框架,目前包含超过 26,000 个软件包。它是 NetBSD 和 SmartOS 的默认软件包管理器,可用于在大量其他类 UNIX 平台上轻松构建免费软件。pkgsrc 生成的二进制软件包无需从源代码编译任何内容即可使用。它可以轻松地补充现有系统上的软件。
pkgsrc 功能强大且可配置,支持为任意安装前缀构建软件包,允许多个分支在一台机器上共存,提供构建选项框架、编译器转换框架以及其他高级功能。此外,它还支持非特权使用和安装。
NetBSD 已经包含使用 pkgsrc 所需的工具;在其他平台上,您需要引导 pkgsrc 来安装包管理工具。
它最大的优点就是支持的系统极广。官方称其支持 20 种类 UNIX 系统和 15 种 CPU 架构。
从它的文档中可以看出支持的平台列表
我们平时常见的 OS 基本都包括在内了,包括 Linux、macOS 以及四大 BSD 都得到了支持,甚至连 windows 上的 Cygwin 环境都能支持。
它的工作原理和使用方法,整体上和前面讲的 FreeBSD Ports 差不多,因为它本身就是从 FreeBSD Ports 这套系统 fork 出来进行演进的,可以认为它是 FreeBSD Ports 的“跨平台进化版”。
它的可移植性高,主要是出于以下原因:
- 逻辑脚本化:包管理逻辑主要靠 Makefile 实现,而纯文本脚本天然比二进制代码更容易跨平台适配。
- 工具链去耦合:它自带的一套构建工具和管理工具(bmake、pkg_install 等)设计得非常精简,具备较高的可移植性,不依赖特殊的 libc 接口,因此能在众多类 UNIX 系统上编译运行。
但需要强调一点:pkgsrc 框架本身的可移植性高,并不意味着仓库里那两万多个软件的可移植性也高。
比如 这里 有一篇邮件,里面清清楚楚地提到了这一点
But, yes, `supported platform’ does not mean that all packages will succeed
to be built on Cygwin. It’s a chance for you to fix the issue 😃
因此,即使 pkgsrc 支持了你使用的平台,你也仍可能会在安装和使用软件包的过程中遇到错误。如果你有能力修复它,这就是一个为社区做贡献的机会了。
6 参考链接
- Chapter 4. Installing Applications: Packages and Ports
- pkgsrc: The NetBSD Packages Collection
- OpenBSD Ports - Working with Ports
- DragonFlyBSD: DPortsUsage
- Portage - Gentoo Wiki
- Aports tree - Alpine Linux
- Category:Package management - ArchWiki
- NixOS/nixpkgs: Nix Packages collection & NixOS
- Homebrew — The Missing Package Manager for macOS (or Linux)
- Managing Packages - SmartOS Documentation
- pkgsrc
- 如何在 Linux 上使用 pkgsrc
- Pkgsrc on cygwin
- 几个使用类似 BSD ports 软件包管理的 Linux 发行版
- 如何把NetBSD系统的软件管理工具pkgsrc移植到龙架构,编译详情步骤
更多推荐



所有评论(0)