5.5 使用 Ports 以源代码方式安装软件
Ports 与 Port 概述
Ports 历史
Ports 是一种简单的从源代码(也支持闭源的二进制包)构建软件的框架。由 Jordan K. Hubbard([email protected])创建,最初在公众面前出现于 1994 年 8 月。
root@ykla:/usr/ports # git log --reverse --max-parents=0 --pretty=format:"commit: %h%nAuthor: %an%nDate: %ci%n%n%B" # 打印第一次提交
commit: d27f048e966a
Author: Jordan K. Hubbard
Date: 1994-08-21 13:12:57 +0000
Commit my new ports make macros. Still not 100% complete yet by any means
but fairly usable at this stage.
Submitted by: jkh“提交了我为 ports 编写的新 Make 宏。虽然还远未完全完善,但目前已经可以较为正常的使用了。”
技巧
我们可以看到:对于一个开源项目,无论使用的何种版本控制系统,保留完整的提交记录,是多么地重要。读者慢慢就会发现,这不仅仅是考古上的意义。
NetBSD 和 OpenBSD 也使用 Ports(不通用)。
参考文献
[FreeBSD-Ports-Announce] Happy 20th birthday FreeBSD ports tree!,2014 庆祝 Ports 20 年,文中还有个庆祝视频。
Ports 与 Port 释义
一款软件的相关文件或文件夹的(补丁文件、校验码、Makefile 等)集合(表现为一个文件夹)为一个 Port,所有 Port(移植软件)的集合即 Ports Collection 或 Ports Tree,即 Ports。
ykla@ykla: $ cd /usr/ports # 切换到 /usr/ports
ykla@ykla:/usr/ports $ ls # 列出此目录下所有文件 ①
accessibility COPYRIGHT GIDs misc README www
arabic databases graphics Mk russian x11
archivers deskutils hebrew MOVED science x11-clocks
astro devel hungarian multimedia security x11-drivers
audio dns irc net shells x11-fm
benchmarks editors japanese net-im sysutils x11-fonts
biology emulators java net-mgmt Templates x11-servers
cad filesystems Keywords net-p2p textproc x11-themes
CHANGES finance korean news Tools x11-toolkits
chinese french lang polish UIDs x11-wm
comms ftp mail ports-mgmt ukrainian
CONTRIBUTING.md games Makefile portuguese UPDATING
converters german math print vietnamese
ykla@ykla:/usr/ports $ ls databases/ # 切换到 databases 数据库分类目录下
adminer php-xapian
adodb5 php81-dba
……省略一部分……
mongodb60 py-apache-arrow
mongodb70 py-apsw
mongodb80 py-asyncmy
mongosh py-asyncpg
ykla@ykla:/usr/ports/databases $ cd databases/postgresql18-server/ # 切换到 postgresql18-server 目录
ykla@ykla:/usr/ports/databases/postgresql18-server $ ls ②
distinfo pkg-descr pkg-plist-contrib pkg-plist-pltcl
files pkg-install-server pkg-plist-plperl pkg-plist-server
Makefile pkg-plist-client pkg-plist-plpython①
/usr/ports这个文件夹整体称作 Ports,包括几十种不同的分类目录,每个目录下有若干 Port。②
/usr/ports/databases/postgresql18-server这个文件夹整体称作一个 Port,由distinfo(校验和文件)、pkg-descr(软件描述文件)、Makefile(主文件,里面有构建方法和版本号及下载方式等)pkg-plist(安装的每个文件的列表清单文件及文件权限属组等)files(一般是补丁,该 Port 下为安装后的说明文件pkg-message)等文件构成。
之所以叫做“Ports Collection”,移植集合(不应理解为端口集合,参见 What does 'port' mean in 'develop a port of BSD'?,注:此来源不可信,请求其他来源)是因为这些软件绝大部分都不由 FreeBSD 控制、管理、和维护,Port 提交者主要做的事情是将 FreeBSD 上 Port 更新到上游开发者提供的最新版本,删除上游不再维护的软件 Port。在上游不接受 BSD 特有的 PR 补丁或难以直接通过既有 Ports 框架实现构建的情况下,Port 维护者也需要自行复刻一个分支出来维护(如 editors/vscode)。
Ports 构建 pkg 软件包的流程
注意
ports 和 pkg 可以同时使用,而且大部分人也是这么用的。但是要注意 pkg 的源必须是 latest,否则会存在一些依赖上的问题(比如 ssl)。latest 的源也比 main 上的 ports 要出来的晚(是从 main 编译出来的),因此即使是 latset 源也可能会出现上述问题,总之有问题出现时就卸载那个 pkg 安装的包,重新使用 ports 编译即可。
警告
需要对上面的“注意”进行补充说明的是:一旦你使用了
make config修改了 Port 的默认构建参数(进行了自定义),那么如果你仍然想保留该设置,后续的软件更新是不能通过 pkg 进行管理的,否则通过 pkg 安装的软件包会完全取代之前自定义的 Port(即 Port 开发者默认设定的构建参数将覆盖你自定义的 Port 参数)。

技巧
ports 下载路径是
/usr/ports/distfiles/。
使用 ports 压缩包
使用压缩包成功地规避了先有鸡还是先有蛋的哲学问题(要安装 Git 但是没有 Ports 也不想用 pkg 的话)。
下载 ports 压缩包
NJU:
# fetch https://mirrors.nju.edu.cn/freebsd-ports/ports.tar.gz或 USTC
# fetch https://mirrors.ustc.edu.cn/freebsd-ports/ports.tar.gz又或 FreeBSD 官方
# fetch https://download.freebsd.org/ftp/ports/ports/ports.tar.gz解压 ports 压缩包
# tar -zxvf ports.tar.gz -C /usr/ # 解压至路径
# rm ports.tar.gz # 删除存档使用 Git 获取 Ports
安装 Git
使用 pkg 安装:
# pkg install git拉取 Ports 存储库(USTC)浅克隆
# git clone --filter=tree:0 https://mirrors.ustc.edu.cn/freebsd-ports/ports.git /usr/ports拉取 Ports 存储库(FreeBSD 官方)浅克隆
# git clone --filter=tree:0 https://git.FreeBSD.org/ports.git /usr/ports完全拉取 Ports 存储库(FreeBSD 官方)并指定分支
# git clone https://git.FreeBSD.org/ports.git /usr/ports查看所有分支:
# cd /usr/ports/ # 切换到 git 项目
# git branch -a
* main # * 代表当前分支
remotes/origin/2014Q1
……省略…………
remotes/origin/2025Q1
remotes/origin/HEAD -> origin/main
remotes/origin/main切换到 2025Q1 分支:
root@ykla:/usr/ports # git switch 2025Q1
正在更新文件: 100% (14323/14323), 完成.
分支 '2025Q1' 设置为跟踪 'origin/2025Q1'。
切换到一个新分支 '2025Q1'查看本地分支:
root@ykla:/usr/ports # git branch
* 2025Q1
main已经切换成功。
同步更新 Ports Git
root@ykla:/ # cd /usr/ports/ # 切换目标目录
root@ykla:/usr/ports # git pull # 同步更新上游 Ports如果提示本地已经修改,放弃本地修改,再更新:
root@ykla:/usr/ports # git checkout . # 放弃本地修改
root@ykla:/usr/ports # git pull附录:时间错误导致的证书无效
fatal: unable to access 'https://mirrors.ustc.edu.cn/freebsd-ports/ports.git/': SSL certificate problem: certificate is not yet valid先检查时间:
# date
Fri May 31 12:09:26 UTC 2024时间错误。校对时间:
# ntpdate -u pool.ntp.org
5 Oct 08:39:16 ntpdate[3276]: step time server 202.112.29.82 offset +10960053.088901 sec检查时间:
# date
Sat Oct 5 08:39:21 UTC 2024使用 whereis 查询软件路径
whereis 查询软件路径如
# whereis python将输出
python: /usr/ports/lang/python查看依赖
已经安装:
root@ykla:~ # pkg info -d screen
screen-4.9.0_6:
indexinfo-0.3.1未安装:
root@ykla:/usr/ports/sysutils/htop # make all-depends-list
/usr/ports/ports-mgmt/pkg
/usr/ports/devel/pkgconf
/usr/ports/devel/kyua
……省略一部分……看看 python 的 ports 在哪
# whereis python
# python: /usr/ports/lang/python安装 python3
# cd /usr/ports/lang/python
# make BATCH=yes clean其中 BATCH=yes 意味着使用默认参数进行构建。
如何设置全部所需的依赖
# make config-recursive如何使用 pkg 安装依赖
不使用 Ports 来编译依赖,仅使用 Ports 来编译软件包本体:
# make install-missing-packages以 chinese/fcitx 为示例:
root@ykla:~ # cd /usr/ports/chinese/fcitx
root@ykla:/usr/ports/chinese/fcitx # make install-missing-packages
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
Updating FreeBSD-base repository catalogue...
FreeBSD-base repository is up to date.
All repositories are up to date.
Updating database digests format: 100%
The following 2 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
e2fsprogs-libuuid: 1.47.1 [FreeBSD]
enchant2: 2.2.15_5 [FreeBSD]
Number of packages to be installed: 2
94 KiB to be downloaded.
Proceed with this action? [y/N]: 如何删除当前 port 及其依赖的配置文件
# make rmconfig-recursive如何一次性下载所有需要的软件包
# make BATCH=yes fetch-recursiveports 编译的软件也可以转换为 pkg 包
# pkg create nginx更新 FreeBSD 软件包/Port
先同步更新 Ports Git。
然后列出过时 Port 软件:
root@ykla:/usr/ports # pkg version -l '<'
chromium-127.0.6533.99 <
curl-8.9.1_1 <
ffmpeg-6.1.2,1 <
vlc-3.0.21_4,4 <
w3m-0.5.3.20230718_1 <下边分别列出 2 种 FreeBSD 手册中提及的升级工具:
① portmaster(推荐)
更新:
# cd /usr/ports/ports-mgmt/portmaster && make install clean
# portmaster -a #自动升级所有软件
# portmaster screen #升级单个软件如果不想回答问题解决依赖,可使用类似 BATCH=yes 的选项 -a -G --no-confirm:
# portmaster -a -G --no-confirm查看依赖关系
root@ykla:/usr/ports/ports-mgmt/portmaster # portmaster sysutils/htop --show-work
===>>> Port directory: /usr/ports/sysutils/htop
===>>> Starting check for all dependencies
===>>> Gathering dependency list for sysutils/htop from ports
===>>> Installed devel/autoconf
===>>> Installed devel/automake
===>>> NOT INSTALLED devel/libtool
===>>> NOT INSTALLED devel/pkgconf
===>>> NOT INSTALLED lang/python311
===>>> Installed ports-mgmt/pkg② portupgrade
# cd /usr/ports/ports-mgmt/portupgrade && make install clean
# portupgrade -ai #自动升级所有软件,i 会挨个确认
# portupgrade -R screen #升级单个软件
# portupgrade -a --batch #不要问,只做,等同于 BATCH=yes参考资料
FreeBSD USE
如何全局屏蔽 mysql
# echo "OPTION_UNSET+= MYSQL" >> /etc/make.conf完整的列表见 https://cgit.freebsd.org/ports/tree/Mk/bsd.default-versions.mk
FreeBSD ports 多线程编译
将以下内容写入 /etc/make.conf,没有就 touch 新建一个。
FORCE_MAKE_JOBS=yes
MAKE_JOBS_NUMBER=4Linux 如 Gentoo 上一般是直接 -jx 或者 jx+1, x 为核心数。
4 是处理器核心数(还是线程数?)。
可以通过命令查询:
root@ykla:/home/ykla # sysctl kern.smp.cpus
kern.smp.cpus: 16或者:
root@ykla:/home/ykla # sysctl hw.ncpu
hw.ncpu: 16输出值即为 MAKE_JOBS_NUMBER 值。
英特尔的处理器搜索 CPU 型号+ARK 转跳英特尔官网可查询线程数。
个别情况下可以设置别名加速编译:(非永久设置,FreeBSD 14 无须设置默认即生效)
# alias ninja='ninja -j4'参考资料
Easy way to get cpu features,获取 CPU 线程数量的命令来自此处。
设置内存为 tmp
tmp# ee /etc/fstab写入:
tmpfs /tmp tmpfs rw 0 0reboot 重启即可。
参考资料
ccache
警告
使用 ccache 可能会导致编译失败!只在重复编译时起效果,首次编译不仅不会加速还会慢上一些。是一种以空间换时间的行为。
ccache3
使用 pkg 安装:
root@ykla:~ # pkg install ccache使用 Ports 安装:
# cd /usr/ports/devel/ccache/
# make install clean查看软链接情况:
root@ykla: # ls -al /usr/local/libexec/ccache
total 56
drwxr-xr-x 3 root wheel 15 Sep 20 02:02 .
drwxr-xr-x 18 root wheel 49 Sep 20 01:39 ..
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 CC -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 c++ -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 cc -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 clang -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 clang++ -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 clang++15 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 02:02 clang++18 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 clang15 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 02:02 clang18 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 cpp13 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 g++13 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 Sep 20 00:29 gcc13 -> /usr/local/bin/ccache
drwxr-xr-x 2 root wheel 15 Sep 20 02:02 world修改
/etc/make.conf,加入下面一行:
WITH_CCACHE_BUILD=yes设置编译缓存最大为 10GB:
root@ykla:/usr/ports/devel/ccache4 # ccache -M 10G
Set cache size limit to 10.0 GB
root@ykla:/usr/ports/www/chromium # ccache -s
cache directory /root/.ccache
primary config /root/.ccache/ccache.conf
secondary config (readonly) /usr/local/etc/ccache.conf
cache hit (direct) 0
cache hit (preprocessed) 0
cache miss 0
cache hit rate 0.00 %
cleanups performed 0
files in cache 0
cache size 0.0 kB
max cache size 10.0 GB在 Ports 编译一段时间后:
root@ykla:~ # ccache -s
cache directory /root/.ccache
primary config /root/.ccache/ccache.conf
secondary config (readonly) /usr/local/etc/ccache.conf
stats updated Fri Sep 20 02:05:35 2024
cache hit (direct) 20
cache hit (preprocessed) 17
cache miss 918
cache hit rate 3.87 %
called for link 121
called for preprocessing 26
compile failed 115
preprocessor error 66
bad compiler arguments 15
autoconf compile/link 523
no input file 71
cleanups performed 0
files in cache 2305
cache size 0.0 kB
max cache size 10.0 GBccache4
目前最新版本是 ccache4:
使用 pkg 安装:
# pkg install ccache4或使用 Ports 安装:
# cd /usr/ports/devel/ccache4/
# make install clean查看软链接情况:
root@ykla:~ # ls -al /usr/local/libexec/ccache total 55
drwxr-xr-x 3 root wheel 13 9月 20 02:29 .
drwxr-xr-x 20 root wheel 54 9月 20 02:29 ..
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 c++ -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 cc -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 CC -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 clang -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 clang++ -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 clang++15 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 clang15 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 cpp13 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 g++13 -> /usr/local/bin/ccache
lrwxr-xr-x 1 root wheel 21 9月 20 02:29 gcc13 -> /usr/local/bin/ccache
drwxr-xr-x 2 root wheel 13 9月 20 02:29 world修改
/etc/make.conf,加入下面一行:
WITH_CCACHE_BUILD=yes设置编译缓存最大为 20GB:
root@ykla: # ccache -M 20G
Set cache size limit to 20.0 GB在 Ports 编译一段时间后,查看编译缓存:
root@ykla:/ # ccache -s
Cacheable calls: 558 / 579 (96.37%)
Hits: 110 / 558 (19.71%)
Direct: 110 / 110 (100.0%)
Preprocessed: 0 / 110 ( 0.00%)
Misses: 448 / 558 (80.29%)
Uncacheable calls: 21 / 579 ( 3.63%)
Local storage:
Cache size (GB): 0.0 / 20.0 ( 0.11%)
Hits: 110 / 558 (19.71%)
Misses: 448 / 558 (80.29%)查看当前配置文件:
root@ykla:~ # ccache -p
(default) absolute_paths_in_stderr = false
(default) base_dir =
(default) cache_dir = /root/.cache/ccache
……省略一部分……参考文献
多线程下载
axel
安装:
# pkg install axel或者
# cd /usr/ports/ftp/axel/
# make install clean新建或者编辑 /etc/make.conf 文件,写入以下几行:
FETCH_CMD=axel
FETCH_BEFORE_ARGS= -n 10 -a
FETCH_AFTER_ARGS=
DISABLE_SIZE=yeswget2
# cd /usr/ports/www/wget2/ && make install clean新建或者编辑 /etc/make.conf 文件,写入以下几行:
FETCH_CMD=wget2
FETCH_BEFORE_ARGS= -c -t 3 -o 10
FETCH_AFTER_ARGS=
DISABLE_SIZE=yes-c断点续传;-t 3重试次数 3;-o 10启用 10 个线程进行下载。
技巧
10这个参数可能过于保守。但是要注意很多服务器不支持较多线程同时下载。同时会给服务器带来较大压力。
参考文献
ports --contributed applications,
FETCH_CMD的出处,同时也是参数BATCH的出处。
故障排除与未竟事宜
autoconf-2.72 Invalid perl5 version 5.42.
autoconf-2.72 Invalid perl5 version 5.42.也可以理解为“xxx-yy Invalid zz version aa”式报错。
实例,在使用 Ports 安装 openjdk21 时报错如下:
[root@Server /usr/ports/java/openjdk21]# make install clean
===> openjdk21-21.0.4+7.1 depends on executable: zip - found
===> openjdk21-21.0.4+7.1 depends on package: autoconf>0 - not found ①
===> autoconf-2.72 Invalid perl5 version 5.42. ②
*** Error code 1
Stop.
make[1]: stopped in /usr/ports/devel/autoconf
*** Error code 1
Stop.
make: stopped in /usr/ports/java/openjdk21观察整个流程可以发现,openjdk21 依赖 autoconf,但系统中没有。于是递归查找 autoconf 的依赖,发现 autoconf 依赖 perl5;结合 ② 可以发现系统中已有 perl5,但是报错“Invalid version”,即 perl5 的版本不对。
此问题,一般需要先更新 Ports,然后再通过 pkg install -f perl5 或 pkg upgrade 来更新一下 perl5 的版本即可解决。
参考文献
最后更新于
这有帮助吗?