MacPorts打包过程简介

1,456 阅读5分钟
本文主要为大家介绍一下MacPorts的打包过程。

MacPorts 与 Homebrew

Homebrew 相信很多人都听说过,它是 macOS 上用户最多的包管理软件。但 macOS 上的包管理软件并非只有 Homebrew 一家,MacPorts、Nix 也是各有其独特之处的 macOS 包管理器。

MacPorts 与 Homebrew 相比有什么优点呢?

首先,MacPorts 的包数量特别多

根据 repology 统计,Homebrew 的官方源大约有四千六百个包,与之相比 MacPorts 社区维护了足足一万一千多个官方包。不过由于包数量过多和缺少维护者,MacPorts 在软件更新速度上要比 Homebrew 慢不少。

其次,MacPorts 对于老版本的 macOS 提供了良好的支持。

Homebrew 现在已经要求 macOS 10.12 及以上版本的系统才可以正常安装使用,而 MacPorts 在社区成员的支持下至今仍在提供低至 Mac OS X 10.5 系统的支持,很多常用的包例如 curl、perl 都可以直接安装二进制包。

最后,MacPorts 和传统包管理软件一样要求使用 root 权限执行包的安装、卸载等操作。

或许对于很多人来说,每次安装包都要加上 sudo 并输一次密码比较繁琐,但只有这样才能确保 MacPorts 管理的文件只有 root 用户有权限修改。笔者认为,保护好包管理目录,对于管理大量 Mac 设备的系统管理员来说十分重要。

如果任何程序都能随意在包管理的路径下创建、删除文件,就有可能因第三方程序的修改,出现包不可用或安装包时文件被覆盖的情况。

说了这么多,让我们回归正题介绍一下 MacPorts 是怎么从源码编译出一个传统的使用 autoconf 的上游项目的吧。

包“配方”(Portfile)

在 MacPorts 每个包都必须有一个对应的 Portfile 文件。这个文件说明了包的源码从哪里获取、编译需要哪些工具、依赖的库、编译参数等等。接下来我会以 getdns 这个包为例介绍一下从源码的下载到执行配置脚本、编译、打包和安装的全过程和对应的 Portfile 写法。

下载和解压源码

Portfile 只是一个配方,包的源码还是需要从网上下载。下面这两行代码指定了包的主页和源码 tar 包的下载位置。

homepage            https://getdnsapi.net/master_sites        ${homepage}dist/

name                getdnsversion             1.5.1

MacPorts 默认会下载 ${name}-${version}.tar.gz 文件,包名和包版本由上面两行代码定义。使用 port distfiles getdns 命令可以查看要下载的文件名、保存路径、Portfile 中记录的哈希值、文件大小和下载文件的 URL。哈希值和文件大小是为了保证上游或第三方没有修改包的内容,这样可以避免网站被黑客攻击后文件被恶意替换的问题。

--->  Distfiles for getdns[getdns-1.5.1.tar.gz] /opt/local/var/macports/distfiles/getdns/getdns-1.5.1.tar.gz rmd160: 94aa50f60099fdb001da4903bba2be538d109c15 sha256: 5686e61100599c309ce03535f9899a5a3d94a82cc08d10718e2cd73ad3dc28af size: 1075728  https://getdnsapi.net/dist/getdns-1.5.1.tar.gz  https://distfiles.macports.org/getdns/getdns-1.5.1.tar.gz

以 getdns 为例,MacPorts 会从软件的官网或 MacPorts 的官方镜像(有两个在中国哦)下载这个 tar 包到 /opt/local/var/macports/distfiles/getdns/ 目录下。下载成功后会用 Portfile 中记录的 checksums 校验文件,通过后才会解压下载的 tar 包。解压成功的话进入下一步执行配置脚本。

checksums           rmd160  94aa50f60099fdb001da4903bba2be538d109c15 \                    sha256  5686e61100599c309ce03535f9899a5a3d94a82cc08d10718e2cd73ad3dc28af \                    size    1075728

使用了 autoconf 框架的软件在编译时需要运行 ./configure 命令才能开始用 make 编译。但 MacPorts 并没有使用默认的 /usr/local 目录,而是为了和用户自行安装的软件隔离开使用了 /opt/local 前缀。所以 MacPorts 在执行这个脚本时会默认加上 --prefix=/opt/local 参数来调整安装目录。同时为了让编译器能找到依赖库的头文件和库文件,MacPorts 会配好 CPPFLAGS、LDFLAGS 等环境变量。最后,MacPorts 会将 Portfile 中指定的配置参数加到 --prefix 之后,这可以用来开启或关闭一些功能。

configure.args      --enable-stub-only \                    --with-libevent \                    --without-libidn

编译

编译在这个例子里非常简单,只要在源码目录下执行 make 命令,MacPorts 就会默认开启并行编译,即添加 -jN 参数,N 为 port 命令根据 CPU 和内存自动判断的并行任务数。

make -j2

打包与安装

编译成功后进入 destroot 阶段,这个阶段 MacPorts 仍然执行 make 命令,但带上了 install 和 DESTDIR 两个参数。make install 用于把编译好的文件安装到指定的目录。DESTDIR=... 则表示不要直接把文件安装到之前配置的 prefix 下,而是安装到 MacPorts 临时创建的目录下。

make -w install DESTDIR=/opt/local/var/macports/build/...

通过指定临时创建的 DESTDIR 目录,MacPorts 在“安装”成功后可以直接用 tar 命令把二进制包打到 /opt/local/var/macports/software/getdns/getdns-1.4.2_1.darwin_17.x86_64.tbz2 里。MacPorts 官方提供的二进制包就是用这种方式生成并在符合协议规范的前提下上传到镜像站上供用户下载的。

最后,MacPorts 会将打好的二进制包解压到 /opt/local 下,并清理打包过程中产生的临时文件。这样就完成了 getdns 的安装。

—end—

排版/许晔

文/SRE

本文首发于小米运维微信公众号,原文请戳链接MacPorts打包过程简介