第 7 章 高级 pkg-plist 用法
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-install
和 do-install
两个 target 之间, 通过读取 PLIST
并写入 TMPPLIST
(默认情况下, 是: WRKDIR/.PLIST.mktmp
) 来完成。 因此, 如果您的 port 动态生成 PLIST
, 就需要在 pre-install
之前完成。 另外, 如果您的 port 需要编辑所生成的文件, 则需要在 post-install
中操作名为 TMPPLIST
的那个文件。
另一种可行的修改装箱单的方法, 则是根据 PLIST_FILES
和 PLIST_DIRS
这两个变量的设置来进行。 它们的值会作为目录名连同 PLIST
的内容一起写入 TMPPLIST
。 在 PLIST_FILES
和 PLIST_DIRS
中列出的名字, 会经历前面所介绍的 %%变量%%
替换过程。 除此之外, 在 PLIST_FILES
中列出的文件, 会不加任何修改第出现在最终的装箱单中, 而 @dirrm
将作为前缀加到 PLIST_DIRS
所列的名字之前。 为了达到目的, PLIST_FILES
和 PLIST_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}/share/doc/gimp
由于其它 port 在其中安装了一些别的文件的时候, 也不会导致 pkg_delete(1) 异常退出。
7.2.2. 如何建立空目录
在 port 安装过程中创建的空目录需要特别留意。 安装 package 时并不会自动创建这些目录, 这是因为 package 只保存文件。 要确保安装 package 时会自动创建这些空目录, 需要在 pkg-plist
中加入与 @dirrm
对应的行:
@exec mkdir -p %D/share/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_FILES
和 PLIST_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
中的 MAN
, 而不是装箱单。 用户配置文件应被删除, 或以 n
filename.sample
这样的名字来安装。 info/dir
文件, 也不应列入, 同时应按照 info 文件 的说明来增加一些 install-info
行。 所有由 port 安装的库, 应按照 动态连接库 小节中介绍的方法处理。
另外, 也可以使用 /usr/ports/Tools/scripts/
中的 plist
脚本来自动创建 package list。 plist
脚本是一个 Ruby 脚本, 它能够将前面介绍的手工操作自动化。
开始的步骤和上面的前三行一样, 也就是 mkdir
, mtree
并 make 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
应手工检查并根据需要进行修改。