Fink

打包 - 3. 打包相关规则

3.1 软件包授权协议

Fink 中包括的软件包包括很广范围的授权协议种类。 多数都对重新发布全部源代码有限制,尤其对发布二进制版本有限制。 有些软件包因为这些授权协议而不能提供二进制发行版。因此,很重要的一点是软件包的维护者需要仔细地检查他们维护的软件包的授权协议限制。

每个以二进制包形式发布的软件都必须包含一些授权协议。 它必须被安装在 doc 目录, 也就是说:%p/share/doc/%n。 (当然,在 InstallScript 中,应该用 %i 代替 %p。DocFiles 字段会自动处理这些细节。) 如果在原始的程序中没有明确的授权协议声明,那个包含一小段文字来说明这个软件包的状态。 多数的授权协议要求在发布版中包括一份授权协议。 Fink 的规则要求总是这么做,即使软件本身没有明确要求。

为了使得二进制发行版的维护可以自动化,所有准备发布的软件包都必须有一个 License 字段。 这个字段表明授权协议的性质,并被用于决定是否为它制作二进制发行版。 按照前面解释的原因,只有在实际的授权协议条文被放进二进制包中,这个字段才会起作用。

要使得 License 字段有用,必须使用下面之一的预定义值。 如果你在打包的程序并不适合下面中的一种,请在开发者邮件列表中要求帮助。

3.2 The GPL and OpenSSL

(Policy change effective April, 2005.)

Due to the apparent incompatibilty of the OpenSSL license with the GPL and LGPL licenses, fink packages which link to openssl but are licensed under the GPL or LGPL are marked as "Restrictive." As a consequence, the Fink project will not distribute binaries of such packages, although users are free to compile them from source at their discretion.

Package maintainers are encouraged to record the original package license in the DescPackaging field.

3.3 避免干扰基本系统

Fink 是一个安装在基本系统之外的独立目录里面的外加的软件系统。 保证不要把文件安装到 Fink 的目录之外对一个软件包来说是非常重要的。

唯一的例外是没有其它的选择的情况下,比如:XFree86。 这种情况下,软件包必须在安装前检查现有的文件,如果发现可能要覆盖现有的文件,它应该拒绝安装。 软件包必须要保证它安装在 Fink 目录之外的文件要能够在删除软件包的时候同时被删除。或者留在那里保证不会造成危害(就是说,他们需要在调用它之前检查它是否在那里)。

3.4 共享函数库

Fink 对于共享库有了新的规则,它从 2002 年 2 月开始生效。 本段内容讨论的是规则的第四版,它是与 Fink's 0.5.0 一同发布的 as modified in December, 2006 to handle 64bit libraries and from January, 2008 to handle private shared libraries. (In addition, the discussion was updated in June, 2008 to eliminate obsolete references to a transitional period for implementing the shared libraries policy.) We begin with a quick summary, and then discuss things in more detail. 我们首先以一个简要的概括开始,然后讨论更多的细节问题。

任何会产生共享库的软件包,都应该使得他们的库满足 Fink 的规则。即:

Note that a package may also install private shared libraries, which are not intended to be linked from any other package. In this case, the libraries need not go into a separate package, but a Shlibs field must still be part of the package containing shared libraries. Also, maintainers should try to avoid storing a final link from libfoo.dylib in the main library directory %i/lib (or its 64-bit equivalent), to prevent other programs from accidentally linking to this library.

如果某个维护者因为某个原因而不能遵循这个规则,没有分离软件包的话,应该在 DescPackaging 字段中说明原因。

对于一些软件,可以通过一个主软件包和一个 -shlibs 软件包来组成;另外的一些情况下,你还需要第三个软件包。新的 SplitOff 字段正是为了简化这种情况。

当需要第三个软件包的时候,有两种不同的命名办法,取决于共享库是软件包的主要功能(情况一),还是可执行程序是主要功能(情况二)。对于第一种情况,使用下面的命名模式:

PackageContents
foo-shlibs

共享库

foo

头文件

foo-bin

二进制执行文件,等等

对于第二种情况,使用下面的命名模式:

PackageContents
foo-shlibs

共享库

foo-dev

头文件

foo

二进制执行文件,等等

规则细节

我们现在讨论更多的细节。我们使用 libpng,libjpeg 和 libtiff 软件包作为规则的实际例子。

已经移植到 Darwin 的软件应该尽可能编译共享库(当然,根据软件包的实际需要,维护者也可以选择编译静态库;如果他们愿意的话,也可以只提交包含静态库的版本)。 当编译共享库的时候 ,应该创建两个密切相关的 fink 软件包,分别名为 foo 和 foo-shlibs。共享库放到 foo-shlibs 中,而头文件在放到 foo 中。这两个软件包可以用同一个 .info 文件产生,象下面描述的那样,使用 SplitOff 字段(事实上,通常需要从源程序中编译出不止两个软件包,这时可以使用 SplitOff2SplitOff3…,等等)

Each software package for which public shared libraries are built must have a major version number N, which is included in the shared library's filename (for example, libbar.N.dylib). 当共享库的 API 不再后向兼容以后,才会去改变主版本号。Fink 使用下面的命名约定:如果上游的软件包叫做 bar,那么 fink 软件称为 barN 和 barN-shlibs(只有在新软件包或主版本号发生改变的软件包上,才会严格应用这个规则)。例如,现存的 libpng 软件包的主版本号是 3,但当前版本的库的主版本号是 3。所以现在有四个软件包:libpng, libpng-shlibs, libpng3, libpng3-shlibs。 在 libpng 和 libpng3 之间只能同时安装一个,但 libpng-shlibs 和 libpng3-shlibs 则可以同时安装。 (注意创建这四个软件包只需要两个 .info 文件)

共享库本身和一些相关文件会被放到 barN-shlibs 软件包中;头文件和一些其它文件会被放到 barN 的软件包。两个软件包中间没有相同的文件,放在 barN-shlibs 的文件的路径应该包含主版本号 N。多数情况下,你的软件包在运行时需要的文件原本时安装到 %i/lib/bar/%i/share/bar/ 目录中;你应该把安装路径调整到 %i/lib/bar/N/%i/share/bar/N/

所有依赖于主版本号为 N 的 bar 软件包的其它软件,需要使用依赖关系

  Depends: barN-shlibs
  BuildDepends: barN

It is not be permitted for another package to depend on barN itself. (Although there may still be a few such dependencies involving packages which were in place prior to February, 2002.) This is signaled to other developers by a boolean field

  BuildDependsOnly: True

来告诉其它开发者。

如果你的软件包包括共享库和二进制文件,而且二进制文件需要在运行时使用(而不仅仅时编译时),那么这些二进制文件应该被分离到第三个软件包中,这个软件包命名为 barN-bin。其它软件包可以依赖于 barN-shlibs 及 barN-bin。

当编译主版本号为 N 的共享库时,很重要的是要使 %p/lib/libbar.N.dylib 来作为 "install_name"。(你可以用 otool -L 或 otool64 -L for 64bit libraries 来查看你的库的 install_name)。实际的库文件应该被安装在

  %i/lib/bar.N.x.y.dylib

而你的软件包应该创建符号链接

  %i/lib/libbar.N.dylib -> %p/lib/libbar.N.x.y.dylib
  %i/lib/libbar.dylib -> %p/lib/libbar.N.x.y.dylib

from the install_name path and from the linking path to the actual library. (The first will not be needed if the library is in fact installed at the install_name path, which is becoming more common.)

如果还构建了静态库,那么它应该被安装在

  %i/lib/libbar.a

如果软件包使用 libtool,这些事情通常会被自动处理, 但无论任何情况下,你都应该检查结果时候正确。你还应该检查你的共享库是否已经定义了正确的 current_version 和 compatibility_version 值( otool -Lotool64 -L for 64bit libraries 应该也可以查询得到这些设置值)。

文件应该象下面一样分到两个文件包中

注意两个文件包都需要一些关于授权协议的文档,但包括文档文件的目录是不同的。

在实践中使用它是很容易的,这可以使用 SplitOff 字段。下面是关于如何实现上面情况的例子(部分):

Package: barN
Version: N.x.y
Revision: 1
License: GPL
Depends: barN-shlibs (= %v-%r)
BuildDependsOnly: True
DocFiles: COPYING
SplitOff: <<
  Package: barN-shlibs
  Files: lib/libbar.N.x.y.dylib lib/libbar.N.dylib lib/bar/N
  DocFiles: COPYING
<<

SplitOff 字段执行的时候,有关的文件和目录会被从主文件包的 %I 安装目录移动到剥离的文件包的 %i 目录(对于名字同样有类似的约定:%N 是主软件包的名字,%n 是当前软件包的名字)。 DocFiles 命令然后会把一份文档放到 %i/share/doc/barN-shlibs 中。

注意我们已经把当前版本的 barN-shlibs 包含为主软件包 barN( %N-shlibs (= %v-%r) 的缩写)的依赖关系。 这可以确保版本会匹配,而且保证 barN 自动继承 "inherits" barN-shlibs 的所有依赖关系。

The BuildDependsOnly field

When libraries are being upgraded over time, it is often necessary to have two versions of the header files available during a transition period, with one version used for compiling some things and the other version used for compiling others. For this reason, the packages containing header files must be constructed with some care. If both foo-dev and bar-dev contain overlapping headers, then foo-dev should declare

  Conflicts: bar-dev
  Replaces: bar-dev

and similarly bar-dev declares Conflicts/Replaces on foo-dev.

In addition, both packages should declare

  BuildDependsOnly: True

This inhibits others from writing packages which depend on foo-dev or bar-dev, since any such dependency will prevent the smooth operation of the Conflicts/Replaces method.

There are some packages containing header files for which it's not appropriate to declare BuildDependsOnly to be true. In that case, the package should declare

  BuildDependsOnly: False

and the reason must be given in the DescPackaging field.

The BuildDependsOnly field should only be mentioned in the package's .info file if the package contains header files, installed into /sw/include.

As of fink 0.20.5, "fink validate" will issue a warning for any .deb which contains header files and at least one dylib, and does not declare BuildDependsOnly to be either true or false. (It is possible that in future versions of fink, this warning will be expanded to cover the case of a .deb with header files and a static library as well.)

The goal of the Shared Library Policy is to allow assure compatibility between libraries supplied by one package and libraries or programs that use them in a different package. Some packages may have shared libraries that are not designed to be used by other packages. Common situations include a suite of programs that come with a back-end library of utility functions or a program that comes with plugins to handle various features. Because these libraries are "private" to the package that has them, they do not require being packaged with separate -shlibs or BuildDependsOnly SplitOffs.

Shlibs 字段:

除了把共享库放到合适的软件包中外,作为规则版本 4,你还需要用 Shlibs 字段声明全部共享库。 This field has one line for each shared library, which contains the -install_name of the library. If the library is public, its Shlibs entry also lists the -compatibility_version, versioned dependency information specifying the Fink package which provides this library at this compatibility version, and the library architecture. (The library architecture may either be "32", "64", or "32-64", and may be absent; the value defaults to "32" if it is absent.) 依赖关系应该用 foo (>= version-revision) 的形式指明。其中 version-revision 指提供这个与(本版本兼容)的共享库的 Fink 软件包的第一个版本。例如,这样

  Shlibs: <<
    %p/lib/libbar.1.dylib 2.1.0 bar1 (>= 1.1-2) 32
  <<

一个声明表示从 bar1 软件包的版本 1.1-2 开始,已经开始安装一个 -install_name 为 %p/lib/libbar.1.dylib,-compatibiliary_version 为 2.1.0 的函数库。另外,这个声明还表示维护者承诺这个名字及 compatibility-version 至少为 2.1.0 以上的 (32bit) 函数库可以在 bar1 软件包的以后版本中找到。

注意在库的名字中使用 %p,这使得无论他们选择什么安装路径前缀,Fink 的所有用户都可以找到正确的 -install_name 代表的函数库。

当一个软件包被更新的时候,通常 Shlibs 字段会被简单地拷贝到软件包的下一个版本/修订版中。例外的情况是如果 -compatibility_version 增加了:那种情况下,依赖信息的版本号应该改变到当前的版本号/修订版号(这是使用新兼容版本号的第一个函数库)。

The Shlibs entry for a private library uses a different syntax:

  Shlibs: <<
    !%p/lib/%N/libbar.1.dylib
  <<

The leading exclamation point indicates that this is a private library, and since the other information is not relevant in this case, it is not included.

Note that in this example, the private shared library has been placed in its own subdirectory %N of the %i/lib directory (which was named after the package). This is a recommended procedure for private libraries, as an additional safety measure, to prevent other packages from accidentally linking to this library.

当主版本号发生变化的时候应该做什么:

如果主版本号从 N 改到了 M,你需要创建两个新的软件包 barM 和 barM-shlibs。 软件包 barM-shlibs 可以不覆盖 barN-shlibs,因为许多用户会同时安装这两个版本。在软件包 barM 中,你应该使用依赖关系

  Conflicts: barN
  Replaces: barN

类似地,你应该修改 barN 来包括依赖关系

  Conflicts: barM
  Replaces: barM

用户会看到在构建其它软件包的时候,根据不同的软件的设置,会选择连接 barN 或 barM 作为共享库。这样,我们实现 barN-shlibs 和 barM-shlibs 在系统里面的共存。

Packages containing both binary files and libraries:

如果上游软件包包含二进制文件和库,那么在构建 fink 软件包的时候有些事情需要特别注意。有些情况下,那些二进制文件仅仅是一些类似 foo-config 的程序 ,它们只需要在构建的时候使用,而不需要在运行时使用。这种情况下,二进制文件可以和头文件一样包括在 foo 软件包中。

其它情况下,这些二进制文件可能需要在运行时被其它软件包使用,这时,它们需要被剥离到一个单独的文件包中,这个软件包的名字大约是 foo-binfoo-bin 软件包应该依赖于 foo-shlibs 软件包,其它软件包的维护者最好能够使用:

  Depends: foo-bin
  BuildDepends: foo

来隐式地处理 foo-shlibs。

在升级的时候会有一个问题,因为用户不会被提示安装 foo-bin。要避免这个问题,在全部其它软件包维护者象上面所说的一样修改它们的软件包之前,你的 foo 软件包可以这样声明:

  Depends: foo-shlibs (= exact.version), foo-bin

这可以强制安装 foo-bin 在多数用户的系统里面,只要有一天其它软件包维护者也升级了依赖于 foo 的软件包。

As of fink-0.28.0 (released in January 2008), the format of the Shlibs entry for a "private" shared library has changed (see earlier discussion of the difference between a public and a private shared library). Note that the Shared Library Policy has always required all shared libraries to be listed; the change here is only in the syntax of the Shlibs field. Because this type of shared library is not designed to be used by external packages, there is no need to document its compatilibity or other versioning. Instead, an exclamation-mark is used. For example, if libquux.3.dylib is the install_name of a private shared library, it would be listed as follows:

  Shlibs: <<
    !%p/lib/libquux.3.dylib
  <<

3.5 Perl 模块

Fink 从 2003 年 5 月开始实施的对 perl 模块的规则,在 2004 年 4 月进行了修改。

传统上,关于 perl 模块的 Fink 软件包具有 -pm 后缀,并使用 Type: perl 指令来构建,它把 perl 模块的文件保存在 /sw/lib/perl5 和/或 /sw/lib/perl5/darwin中。按照现行规则,这个存储位置仅允许用于那些与编译它们的 perl 程序版本无关的 perl 模块(同时也不应该依赖于那些不具备版本无关性的其它模块)。

那些版本相关的 perl 模块称为 XS 模块, 通常除了纯粹的 perl 子程序外,还包括编译好的 C 代码。有很多办法可以识别这个情况,包括存在带有 .bundle 后缀的文件等。

版本相关的 perl 模块必须使用标明版本号的 perl 程序来编译,比方说 perl5.6.0,而且必须把它的文件标准 perl 目录下面的一个标明版本号的子目录中,例如 /sw/lib/perl5/5.6.0/sw/lib/perl5/5.6.0/darwin。习惯上,使用后缀 -pm560 的命名约定来代表针对 5.6.0 的 perl 模块。类似的存储和命名约定也会用于其它版本的 perl,包括 perl 5.6.1 (仅用于 10.2 代码树), perl 5.8.0 (仅用于 10.3 代码树), perl 5.8.1, perl 5.8.4, 和 perl 5.8.6。

Type: perl 5.6.0 指令会自动使用相应标定版本的 perl 程序,并把文件存储在正确的子目录中。 (这个指令从 fink 0.13.0 版本开始提供)。

按照 2003 年 5 月的规则,可以允创建一个 -pm 软件包,它实际是去加载 -pm560 或其它存在的相应版本的"束"软件包。按照 2004 年 4 月的规则,不再鼓励这样做,而且经过一个过渡期后,将会完全放弃这种做法。(唯一的例外是 storable-pm 软件包因为自举的需要仍然需要保持这种形式)。

As of fink 0.20.2, the system-perl virtual package automatically "Provides" certain perl modules when the version of Perl present on the system is at least 5.8.0. In the case of system-perl-5.8.1-1, these are: attribute-handlers-pm581, cgi-pm581, digest-md5-pm581, file-spec-pm581, file-temp-pm581, filter-simple-pm581, filter-util-pm581, getopt-long-pm581, i18n-langtags-pm581, libnet-pm581, locale-maketext-pm581, memoize-pm581, mime-base64-pm581, scalar-list-utils-pm581, test-harness-pm581, test-simple-pm581, time-hires-pm581. (This list was slightly different in fink 0.20.1: package maintainers are encouraged to check to be sure that they are assuming the correct list.)

Users may have more than one version of perl installed at a time, so any perl-versioned module packages must be written to allow more than one version of themselves to be installed concurrently. One must use care when installing manpages and binary or other script executables in these packages in order to prevent installation conflicts due to filename collisions. You are not allowed to have any files in a package whose name ends with -pmXYZ that would have an identical pathname across different XYZ. Using Replaces to allow the same-named files to overwrite each other in different perl-versions of these perl-module packages is no longer acceptable. As a simple solution for manpages, starting in March 2005, Fink has defined alternate locations in MANPATH: %p/lib/perl5/X.Y.Z/man for each perl-X.Y.Z. You no longer need to create mutually-exclusive -man or -doc SplitOff packages. For example, to avoid conflicts between uri-pm581 and uri-pm586, the same-named URI.3pm manpage is installed as %p/lib/perl5/5.8.1/man/man3/URI.3pm and %p/lib/perl5/5.8.6/man/man3/URI.3pm, respectively. Note that the default scripts provided by Type: perl X.Y.Z have not changed, so you will have to locate the manpages here manually in your InstallScript. If you don't have a highly customized script, you can still use the default one, and then simply move the files manually:

%{default_script}
mv %i/share/man %i/lib/perl5/5.8.1

That will move all manpages. If you wish to move only one section of manpages (for example, only section 3, the module manpages, not script manpages in section 1), a similar approach works:

%{default_script}
mkdir -p %i/lib/perl5/5.8.1/man
mv %i/share/man/man3 %i/lib/perl5/5.8.1/man

If you have executables, for example, demo or utility scripts in %p/bin, you have several options. One example is to put these files (and their associated manpages and/or other related files) in a %N-bin splitoff package. Use of Conflicts and Replaces fields ensures that installation of different perl-version forms of these packages, which contain files of the same name, is mutually excluve. The user can install many different perl-versions of the runtime modules, and then choose whichever one perl-version of the scripts he wants at a given time. For example, Tk.pm comes with an executable ptksh, so the set of tk-pm* packages could be constructed as follows:

Info2: <<
Package: tk-pm%type_pkg[perl]
Type: perl (5.8.1 5.8.4 5.8.6)
InstallScript: <<
  %{default_script}
  mkdir -p %i/lib/perl5/%type_raw[perl]/man
  mv %i/share/man/man3 %i/lib/perl5/%type_raw[perl]/man
<<
SplitOff: <<
  Package: %N-bin
  Depends: %N
  Conflicts: %{Ni}5.8.1, %{Ni}5.8.4, %{Ni}5.8.6
  Replaces: %{Ni}5.8.1, %{Ni}5.8.4, %{Ni}5.8.6
  Files: bin share/man/man1
<<
<<

An alternative arrangement is to rename the scripts and their manpages to include perl-version information. This method means there is no naming conflict at all, so one does not need the mutually-exclusive %N-bin splitoffs:

Info2: <<
Package: tk-pm%type_pkg[perl]
Type: perl (5.8.1 5.8.4 5.8.6)
InstallScript: <<
  %{default_script}
  mkdir -p %i/lib/perl5/%type_raw[perl]/man
  mv %i/share/man/man3 %i/lib/perl5/%type_raw[perl]/man
  mv %i/bin/ptksh %i/bin/ptksh%type_raw[perl]
  mv %i/share/man/man1/ptksh.1 %i/share/man/man1/ptksh%type_raw[perl].1
<<
<<

The user accesses ptksh for whichever perl she wants. For convenience, one could use update-alternatives to allow users to be able to access these by their generic (no perl-version) names as well.

Also as of March 2005, the location of manpages and modules installed by fink packages for perl itself (packages perlXYZ and perlXYZ-core other than the perl-version provided by Apple) has changed. As a result of this relocation, other fink packages that supply updated versions of core perl modules should not list any perlXYZ or perlXYZ-core packages in the Replaces field.

3.6 Emacs 规则

Fink 项目选择遵循 Debian 项目针对 emacs 的规则,但稍微有些差别。 (Debian 规则文档可以在 http://www.debian.org/doc/packaging-manuals/debian-emacs-policy 找到)。 在 Fink 的规则中有两点区别。 首先,在 fink 中这个规则目前仅应用于 emacs21, emacs22emacs23 软件包,而不应用于 xemacs。(这在将来可能会有改变)。 第二,不象 Debian 的规则,Fink 软件包允许安装东西到 /sw/share/emacs/site-lisp 目录中。

3.7 Source Policy

Sources should normally be downloaded from the location(s) that the upstream developer(s) use, and any modifications for Fink should be done through the use of a PatchFile and/or a PatchScript. Do not make changes manually and use a changed source archive as a Source in your Fink packaging.

If a VCS checkout (e.g. from git or svn) is to be used, e.g. because a project doesn't do formal releases, or a fix for a particular issue has been added between releases of a package, an acceptable source can be generated via the following method:

  1. Check out the package, preferably at a definite revision of the VCS.
  2. Make an archive from the VCS checkout (e.g. zip, tar, tar.gz, or tar.bz2).

    Give the tarball a unique version. For example, you can include the VCS revision in the archive name, e.g. foo-0svn1234.tar.gz for a package that doesn't make releases, or bar-1.2.3+svn4567.tar.bz2 for a Fink package which is between upstream releases.

  3. Use the same Version in your .info file.
  4. It is also useful to put the commands that you ran to generate the source tarball in the DescPackaging field.
  5. Upload the tarball to a public download site where users can use fink to download it. If you don't have ready access to one, ask on the Fink developers mailing list or the #fink IRC channel, and someone should be able to help.

3.8 File Download Policy

Packages are not to download any files during the unpack, patch, compile, install, or build phases of the build process. Any large patches (i.e. larger than can be accommodated conveniently in a PatchFile) that need to be applied should set up as additional Sources in accordance with the Source Policy.

Packages may download data in a PostInstScript after they have been installed on the system, under some limited circumstances:

If you are unsure, contact the Fink Core Team.

Next: 4. 文件系统布局