6. 制作项目发布包的好经验

这一章节主要介绍你发布的项目应该具有什么样的形式,以方便其他人下载、检索和解压。

6.1. 确保tar包解压时会建一个独立的新目录

新手常犯的低级错误是制作了一个解压后把文件和目录直接解压在当前工作目录的tar包,这样做潜在地危险是会把原来已有的同名文件覆盖掉。千万记住,不要这么干。

正确的方法是,你的项目的所有档案都是存放在项目所在目录下的标准目录结构中,这样tar包就可以解压在一个特定的目录下而不是当前目录。

这里有一个Makefile文件的技巧示例展示了如何完成打包工作,这里假定你的项目所在目录名称为“foobar”,而SRC变量中是一个包含所有需要发布的文件列表:

foobar-$(VERS).tar.gz:
	@ls $(SRC) | sed s:^:foobar-$(VERS)/: >MANIFEST
	@(cd ..; ln -s foobar foobar-$(VERS))
	(cd ..; tar -czvf foobar/foobar-$(VERS).tar.gz `cat foobar/MANIFEST`)
	@(cd ..; rm foobar-$(VERS))

6.2. 制作一个README文件

应该有一个名为README或者READ.ME的文件来说明整个源码的结构信息。古老的传统告诉我们,勇猛的探索者在解开你的压缩文件包后的第一件事情就是找出README文件来阅读。

README文件中最好应该包括如下信息:

  1. 整个项目的简介

  2. 项目的WWW站点所在的URL(如果有的话)

  3. 指出开发者编译整个项目所在的系统环境,并指出项目可能潜在地移植性问题

  4. 重要文件和子目录的结构信息

  5. 编译/安装步骤说明,或者指明这些信息所在的文件名(通常是INSTALL文件)

  6. 项目主持人和参与者的名单列表,或者指出这些信息所在的文件(通常是CREDITS文件)

  7. 最近关于本项目的一些进展情况和新闻,或者指出包含此信息的文件(通常是NEWS文件)

6.3. 遵照标准文件命名规则

“勇猛的探索者”要想阅读README文件,他们就必须首先浏览解压后项目档案所在的根目录下的文件名。这些文件名本身就在向读者传达许多信息。如果你遵照标准的命名规则就可以给那些探索者有价值得线索以便他们更好的理解你的意图。

这里列出了一些标准文件名称和他们的涵义。当然并不是所有项目发布时都必须包含所有这些文件。

README 或 READ.ME

整个项目的结构信息说明,第一个需要阅读的文件

INSTALL

配置、编译和安装该项目的说明信息

CREDITS

本项目所有贡献者的列表

NEWS

本项目最近的一些新闻和进展

HISTORY

本项目的历史发展演变记录

COPYING

指出本项目采用的许可证条款(通常采用GNU)

LICENSE

本项目的许可证条款文件

MANIFEST

本项目的所有文件列表

FAQ

关于本项目的纯文本格式的常见问题解答

TAGS

为Emacs或vi准备的标记文件

我们可以看出来,全部大写的文件名一般表示该文件是给人阅读的文档,而不是项目的一个组成部分。

编撰一个FAQ文件可以帮你很多忙。如果某个问题经常被其他人问起,就把这个问题列入FAQ文件;然后指导用户在向你发文或提交出错报告前首先阅读FAQ文件。一份好的FAQ文件可以给项目维护者减轻好几个数量级的负担。

另外在每次发布时都保留一个HISTORY文件和NEWS文件,并列明时间信息非常有好处。在所有其他文件中,这两个文件可以让你在遇到一些专利侵权法律问题时有所准备(虽然这种情况至今还没有发生过,不过最好还是有备无患)。

6.4. 为项目升级做好准备

只要你打算为你的项目发布新版本,项目就必定处在不断的变化之中。有些变化是不能向前兼容的。因此你必须认真思考安装程序设计上的问题,就是说让同一项目的不同版本的代码安装后可以共存在一个系统中。这个问题对库项目的发布尤为重要,因为你不能指望所有基于这个库的应用程序都会紧跟你的API接口规范的后尘。

Emacs、Python和Qt项目有一套对付这个问题的好办法,就是让目录名中包含版本号。这里有Qt库安装后的目录结构的例子(${ver}是代表版本号的变量):

/usr/lib/qt
/usr/lib/qt-${ver}
/usr/lib/qt-${ver}/bin          # Where you find moc
/usr/lib/qt-${ver}/lib          # Where you find .so
/usr/lib/qt-${ver}/include      # Where you find header files

这样组织目录结构可以让多个不同版本的档案共存。客户的程序可以根据需要选用具有特定版本号的库,因此为了不让这些接口影响客户程序,还是需要付出一些小小代价(制定版本号)的。

6.5. 提供RPM包

安装可执行文件包(二进制包)的事实标准就是使用RedHat包管理器将可执行文件打包成 rpm 包。许多流行的Linux发行版都是这么做的,同时也有许多发行版虽然主要不是rpm包格式但是也支持rpm包(除了Debian和Slackware以外,而且Debian还支持rpm的安装)。

因此一个好的项目除了有tar包的源代码以外,最好也提供直接可安装的rpm包的下载。

如果你能把你的源代码tar包和Makefile文件中用于生成rpm包的相关信息写入rpm的spec文件中就再好不过了。spec文件是有着".spec"后缀的文件,这就是带 -t 选项的 rpm 命令如何在 tar 包中寻找它的方法。

还有一个要点是,你可以用一个脚本程序自动的从Makefile或version.h文件中找出版本号,并用这个版本号来生成你的spec文件。

注:如果你还打算提供源码的rpm包,最好用BuildRoot工具来将程序编译到/tmp或者/var/tmp目录中。如果不这么做,在安装过程中执行 make install 命令时就会直接将那些源程序直接安装到最终的目录位置下。这样就会导致即使在发生文件覆盖冲突,或者你本意并不想装那个包的时候,安装动作依然被执行。因此安装完成后,文件是被装到了系统中,但是系统的RPM数据库却并没有记录这些信息。这种愚蠢的SRPM安装动作是非常危险的,理应避免。