第 7 章 高级 pkg-plist 用法

This translation may be out of date. To help with the translations please access the FreeBSD translations instance.

7.1. 根据 make 变量对 pkg-plist 进行修改

某些 port, 特别是 p5- port, 会需要根据配置选项 (或对于 p5- port 而言, perl 的版本) 来修改它们的 pkg-plist。 为简化这一工作, 在 pkg-plist 中的 %%OSREL%%%%PERL_VER%%, 以及 %%PERL_VERSION%% 将自动进行相应的替换。 其中, %%OSREL%% 的值是操作系统以数值表示的版本 (例如 4.9)。 %%PERL_VERSION%%%%PERL_VER%%perl 的完整版本号 (例如 5.8.9)。许多其它与 port 文档文件有关的 %%变量%%相应章节 中进行了介绍。

如果您还需要进行其它的替换, 可以通过将 PLIST_SUB 变量设置为一组 变量=值 对来实现。 其中, %%VAR%% 表示在 pkg-plist 中将被 替换的那些文字。

举例来说, 如果 port 需要把很多文件放到和版本有关的目录中, 可以在 Makefile 中按照类似下面的例子:

OCTAVE_VERSION= 2.0.13
PLIST_SUB=      OCTAVE_VERSION=${OCTAVE_VERSION}

并在 pkg-plist 中将具体的版本替换为 %%OCTAVE_VERSION%%。 这样, 在升级 port 时, 就不需要再到 pkg-plist 中修改那几十 (或者, 有时甚至是上百) 行的内容了。

如果您的 port 需要根据一定的配置来有条件地安装一些文件, 通常的做法是在 pkg-plist 中列出这些文件时, 在对应行的开头加上 %%TAG%%, 并将 TAG 写到 Makefile 中的 PLIST_SUB 变量中, 根据需要替换掉, 或替换为 @comment, 后者表示让打包工具忽略这行:

.if defined(WITH_X11)
PLIST_SUB+=	X11=""
.else
PLIST_SUB+=	X11="@comment "
.endif

与之对应, 在 pkg-plist 中:

%%X11%%bin/foo-gui

这一替换过程 (以及加入 联机手册 的过程), 会在 pre-installdo-install 两个 target 之间, 通过读取 PLIST 并写入 TMPPLIST (默认情况下, 是: WRKDIR/.PLIST.mktmp) 来完成。 因此, 如果您的 port 动态生成 PLIST, 就需要在 pre-install 之前完成。 另外, 如果您的 port 需要编辑所生成的文件, 则需要在 post-install 中操作名为 TMPPLIST 的那个文件。

另一种可行的修改装箱单的方法, 则是根据 PLIST_FILESPLIST_DIRS 这两个变量的设置来进行。 它们的值会作为目录名连同 PLIST 的内容一起写入 TMPPLIST。 在 PLIST_FILESPLIST_DIRS 中列出的名字, 会经历前面所介绍的 %%变量%% 替换过程。 除此之外, 在 PLIST_FILES 中列出的文件, 会不加任何修改第出现在最终的装箱单中, 而 @dirrm 将作为前缀加到 PLIST_DIRS 所列的名字之前。 为了达到目的, PLIST_FILESPLIST_DIRS 必须在写 TMPPLIST 之前, 也就是在 pre-install 或更早的阶段进行设置。

7.2. 空目录

7.2.1. 清理空目录

一定要让 port 在卸载时进行清理空目录。 通常, 可以通过为所有由 port 创建的目录增加对应的 @dirrm 行来实现。 在删除父目录之前, 需要首先删除它的子目录。

 :
lib/X11/oneko/pixmaps/cat.xpm
lib/X11/oneko/sounds/cat.au
 :
@dirrm lib/X11/oneko/pixmaps
@dirrm lib/X11/oneko/sounds
@dirrm lib/X11/oneko

然而, 有时 @dirrm 会由于其它 port 使用了同一个目录而发生错误。 利用 @dirrmtry 可以只删除那些空目录, 而避免给出警告。

@dirrmtry share/doc/gimp

按照上面的写法, 将不会显示任何错误信息, 而且,即使在 ${PREFIX}/shared/doc/gimp 由于其它 port 在其中安装了一些别的文件的时候, 也不会导致 pkg_delete(1) 异常退出。

7.2.2. 如何建立空目录

在 port 安装过程中创建的空目录需要特别留意。 安装 package 时并不会自动创建这些目录, 这是因为 package 只保存文件。 要确保安装 package 时会自动创建这些空目录, 需要在 pkg-plist 中加入与 @dirrm 对应的行:

@exec mkdir -p %D/shared/foo/templates

7.3. 配置文件

如果 port 需要把一些文件放到 PREFIX/etc不要 简单地安装它们, 并将其列入 pkg-plist, 因为这样会导致 pkg_delete(1) 删除用户精心编辑的文件, 而新安装时则又会把这些文件覆盖。

因此, 您应把配置文件的例子按其它的后缀来安装 (例如 filename.sample 就是一个不错的选择) 并显示一条 消息 告诉用户如何复制并编辑这个配置文件, 以便让软件能够正确工作。

因此, 应按其它的后缀来安装配置文件的例子 (filename.sample 就是一个不错的选择)。 如果实际的配置文件不存在, 则将其复制为实际文件的名字。 卸载时, 如果发现用户没有修改配置文件, 则将其删除。 您需要在 port 的 Makefile, 以及 pkg-plist (对于从 package 安装的情形) 进行处理。

示例的 Makefile 部分:

post-install:
	@if [ ! -f ${PREFIX}/etc/orbit.conf ]; then \
		${CP} -p ${PREFIX}/etc/orbit.conf.sample ${PREFIX}/etc/orbit.conf ; \
	fi

示例的 pkg-plist 部分:

@unexec if cmp -s %D/etc/orbit.conf.sample %D/etc/orbit.conf; then rm -f %D/etc/orbit.conf; fi
etc/orbit.conf.sample
@exec if [ ! -f %D/etc/orbit.conf ] ; then cp -p %D/%F %B/orbit.conf; fi

另外, 还应显示一条 消息 指出用户应在何处复制并编辑这个文件, 以便让软件能开始正常工作。

7.4. 动态装箱单与静态装箱单的对比

静态装箱单 是指在 Ports Collection 中以 pkg-plist 文件 (可能包含变量替换), 或以 PLIST_FILESPLIST_DIRS 的形式嵌入到 Makefile 出现的装箱单。 即使它是由工具或 Makefile 中的某个 target 在经由 committer 加入到 Ports Collection 之前 自动生成的也是如此, 因为可以在不下载或编译源代码包的前提下对其进行检视。

动态装箱单 是指在 port 编译并安装时生成的装箱单。 在下载并编译您所移植的应用程序的源代码之前, 或在执行了 make clean 之后, 就无法查看其内容了。

尽管使用动态装箱单并不被禁止, 但监护人应尽可能使用静态装箱单, 因为它能够让用户使用 grep(1)来发现所需的 ports, 例如, 它是否会安装某个特定文件。 动态列表主要应用于复杂的, 其装箱单随所选功能会发生巨变 (因而使得维护静态装箱单不再可行), 或那些随版本而改变装箱单内容的 port (例如, 使用 Javadoc 来生成文档的那些 ports)。

我们鼓励那些选择使用动态装箱单的监护人提供一个能够生成 pkg-plist 的 target, 以便于用户检视其内容。

7.5. 装箱单 (package list) 的自动化制作

首先, 请确认已经基本上完成了 port 的工作, 仅缺 pkg-plist

接下来, 建立一个用于安装您的 port 的临时目录, 并在其中安装它所依赖的所有其他软件包:

# mkdir /var/tmp/`make -V PORTNAME`
# mtree -U -f `make -V MTREE_FILE` -d -e -p /var/tmp/`make -V PORTNAME`
# make depends PREFIX=/var/tmp/`make -V PORTNAME`

将目录结构保存到一新文件中。

# (cd /var/tmp/`make -V PORTNAME` && find -d * -type d) | sort > OLD-DIRS

建立一空白 pkg-plist 文件:

# :>pkg-plist

如果您的 port 遵循 PREFIX (应该如此) 则接下来应安装该 port 并创建装箱单。

# make install PREFIX=/var/tmp/`make -V PORTNAME`
# (cd /var/tmp/`make -V PORTNAME` && find -d * \! -type d) | sort > pkg-plist

此外还应把新建立的目录加入装箱单。

# (cd /var/tmp/`make -V PORTNAME` && find -d * -type d) | sort | comm -13 OLD-DIRS - | sort -r | sed -e 's#^#@dirrm #' >> pkg-plist

最后需要手工整理 packing list; 这一过程不是 完全 自动的。 联机手册应列入 port 的 Makefile 中的 MANn, 而不是装箱单。 用户配置文件应被删除, 或以 filename.sample 这样的名字来安装。 info/dir 文件, 也不应列入, 同时应按照 info 文件 的说明来增加一些 install-info 行。 所有由 port 安装的库, 应按照 动态连接库 小节中介绍的方法处理。

另外, 也可以使用 /usr/ports/Tools/scripts/ 中的 plist 脚本来自动创建 package list。 plist 脚本是一个 Ruby 脚本, 它能够将前面介绍的手工操作自动化。

开始的步骤和上面的前三行一样, 也就是 mkdirmtreemake depends。 然后联编和安装 port:

# make install PREFIX=/var/tmp/`make -V PORTNAME`

然后让 plist 生成 pkg-plist 文件:

# /usr/ports/Tools/scripts/plist -Md -m `make -V MTREE_FILE` /var/tmp/`make -V PORTNAME` > pkg-plist

与前面类似, 如此生成的装箱单也需要手工进行一些清理工作。

另一个可以用来创建最初的 pkg-plist 的工具是 ports-mgmt/genplist。 和其他自动化工具类似, 您应对它生成的 pkg-plist 应手工检查并根据需要进行修改。


Last modified on: December 11, 2021 by Sergio Carlavilla Delgado