Difference between revisions of "Creating packages (简体中文)"

From ArchWiki
Jump to: navigation, search
(rm temporary i18n template)
m (updated link)
Line 184: Line 184:
  
 
==有用的链接==
 
==有用的链接==
* [[ABS_-_The_Arch_Build_System | ABS - The Arch Build System]]
+
* [[Arch Build System]]
 
* [http://www.archlinux.org/pacman/makepkg.8.html makepkg man page]
 
* [http://www.archlinux.org/pacman/makepkg.8.html makepkg man page]
 
* [http://bbs.archlinux.org/viewtopic.php?t=4 about dependencies]
 
* [http://bbs.archlinux.org/viewtopic.php?t=4 about dependencies]

Revision as of 02:25, 17 June 2012

Tango-preferences-desktop-locale.png本页面需要更新翻译,内容可能已经与英文脱节。要贡献翻译,请访问简体中文翻译组Tango-preferences-desktop-locale.png

附注: please use the first argument of the template to provide more detailed indications.

Template:Article summary start Template:Article summary text Template:Article summary heading Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary wiki Template:Article summary end

本文旨在帮助用户利用 Arch Linux 的类似 ports 的软件包构建系统创建自己的软件包。包含了创建 PKGBUILD – 一个包创建描述文件,由 makepkg 使用来从源代码创建二进制包。如果已经有了 PKGBUILD 文件,请参考 makepkg (简体中文).

概述

Arch Linux 中的软件包是通过 makepkg 工具以及存储在 PKGBUILD 文件中的信息编译的。当运行makepkg时,系统将自动在当前目录下搜索 PKGBUILD文件,然后根据PKGBUILD文件的指示,把软件源码重新打包。 成功编译后得到的二进制文件和可以得到的其他信息如包的版本信息和依赖关系等, 都将被打包到一个文件叫name.pkg.tar.xz 里,这样这个软件就能够被干净的通过pacman -Up <package file>安装。

一个 Arch 软件包仅仅是一个使用 xz 压缩的 tar 压缩包,或者叫 'tarball'。它包含了:

  • 要安装的二进制文件
  • .PKGINFO: 包含所有 pacman 处理软件包的元数据,依赖等等。
  • .INSTALL: 可选的文件,可以用来在安装/升级/删除操作之后运行命令。(本文件只有在 PKGBUILD 中制定才会存在。)
  • .Changelog: 一个可选的文件,保存了包管理员描述软件更新的日志。(不是所有包中都存在。)

准备文件

这个PKGBUILD文件包含所有关于打包的信息,它能够被bash直接解读 (don't worry if that little tidbit of clue doesn't help you). 这里用到的变量在 ABS 这篇文章中有所描述, 但最重要的和容易混淆的将在这里再说一次。要制作一个新的软件包,需要先建立一个空的工作文件夹,推荐命名为 /var/abs/local/<PKGNAME>,这样它就能很好的集成到ABS-tree中,同时当你同步tree时它不会受到影响。切换到这个文件夹,创建一个PKGBUILD文件,文件内容你可以从/usr/share/pacman/PKGBUILD.proto中拷贝,或者 从其他包中的 PKGBUILD 文件拷贝,如果你只是想改变一个包的编译选项而不是创建一个新包后一种方法会更方便 。

不管你怎样实现,你总是需要一个PKGBUILD 文件。

编辑变量

打开文件,根据你要打的包,设定下面每个变量:

  • pkgname: 设置软件包的名字,习惯上要求软件包名字全部使用小写字母。这个是随意的,但是如果你这个包的名字和你工作的文件夹名字以及将要下载的程序的tar.gz压缩文件名字一样,这样就很方便了。
  • pkgver: 设置软件包的版本。可以含有字母,数字,小数点但是不能含有连接符。 版本取决于你将打包的选项所选用的版本系统如(major.minor.bugfix, major.date, etc) 。一般情况下你应该使用源文件名字中的版本,这样以后的步骤就会更方便和灵活点。还有值得注意的,如果源文件的作者在他的版本中使用了连接符,你应该使用下划线代替。如('0.99-10' => '0.99_10')
  • pkgrel: 每次你发布一个包这个值都要增加,值从1开始。它的目的是区别对同一个版本的包的连续构建。有时候包的第一个发布版本可能有问题或缺失特性,当你再次发布时你就把pkgrel 的值增加,这样pacman就知道它需要重新安装。当一个包的新版本发布时,你把pkgrel 的值重新设置为1。
  • pkgdesc: 包括一个对包的简短描述,描述通常少于76个字符。通常它不需要使用项目名称,像OpenGL accelerated X server 就比 xgl is an OpenGL...要好。
  • arch:包括这个包可以运行的架构名称,一般是'i686'. 在构建过程中你可以用$arch调用这个值。
  • url: 这个填写这软件的官方网址,以便想了解更多信息的人能够方便找到.
  • license: 填写软件的授权方式,如果不知道,可以填写'unknown'。
  • depends: 包括一列需要在这个包之前安装的包的名字,它们之间用空格分开。名字可以用单引号(apostrophes) (撇号)括起来,这样可以避免可能的shell引用问题,名字列需要用小括号括起来。有时候一个程序需要一个所依赖的软件的最小版本号,这种情况下你需要使用数学中的大于等于号,同时把它们整个用引号括起来。这儿是一个例子,它依赖glibc包,同时依赖版本号最小为1.8.0的slang库: depends=('glibc' 'slang>=1.8.0')
  • makedepends: 包括一列在构建时需要的包的名字,但在安装后的使用时,这些包是不需要的。如构建时在解包一些补丁的时候需要用到unarj
  • provides:包括一列这个包可以提供的软件包(或虚拟包,如'cron'或'sh')的名字 。如果你使用了这个变量,根据依赖关系的需要,你可能需要加上所提供的软件包的版本号(pkgver and perhaps the pkgrel)。 '注意:'这个功能在pacman 3.1.0的版本中有点小缺陷,将在3.1.1版本中修复。针对3.1.1版本的该文档不久后就能获取了。
    例子:如果你提供一个qt的修改版qt-foo 3.3.8版,qt-foo提供了qt包,这样provides变量就应该像这样:provides=('qt=3.3.8')。如果只是写成provides=('qt')会导致依赖于特定版本qt的软件包出问题,但是如果没有包需要依赖qt的特定版本,这样就足够了。
    例子2:如果软件包perl-5.10.0同时提供5.2.1版的perl-foo和2.5版的perl-bar两个perl模块,provides变量像这样写: provides=('perl-foo=5.2.1' 'perl-bar=2.5').
  • conflicts: 包括一列冲突包的名字,如果和这些包一起安装会出问题。同样应该指定冲突包的"版本属性",版本格式和depends变量中的一样。
  • replaces: 包括将要被安装包所取代的一系列废弃包的名字。
  • source: 包括构建这个包所需的一系列文件,其中至少应该包括软件源代码所在的位置,这个位置通常是双引号括起来的一个完整的HTTP或FTP的URL。The prototype PKGBUILD shows how you can use the previously set variables for package name and version effectively here. 如果你需要一些不能从网上下载的支持文件,如你自己写的补丁程序,你只需将它们放在你存放PKGBUILD的文件夹中,然后将文件名加到source文件列中。文件列中的任何文件路径都是相对你存放PKGBUILD的文件夹的。在开始真正构建前,列中所有的文件都需要下载下来或者检查已经存在,只要任何一个文件缺失,构建就不会开始。
  • md5sums:一列源文件的md5值,值需用引号括起来用空格分开。当source列中的所有文件都可用后,每个文件的md5值会自动生成并以它们在source列中出现的相同顺序和列中的md5值比较。source列中的文件顺序可用任意排列,但md5列中的值则必须和它们在source列中的文件顺序同步,makepkg不会去猜测哪个md5值是哪个文件的,如果它们不匹配就会弹出错误,以防止下载或操作出错。你可以在放置PKGBUILD的文件夹中使用makepkg -g命令(在source列已经设置好后)轻松地生成文件列的md5值。makepkg -g >>PKGBUILD会生成值并将它们加到PKGBUILD文件的末端,然后你可用将它剪切到文件的合适位置。

到此你还只是设置好了这个包的基本信息(meta-information),如从哪获取源文件,软件包的名字是什么等等。下一步是编写编译和安装该软件包的指令。

使用源文件

下载源码包、解压、查看需要使用那些命令来安装这个软件包。PKGBUILD 中的 build()内容,就是这个软件包的安装脚本内容。

修改PKGBUILD的build()中的参数. 这个方法(functioin)使用根据bash语法编写的shell命令。方法的基本目的是自动编译软件并将其安装到一个创建的pkg目录中,allowing makepkg to pack it all up easily without having to pick all interesting files from your "live" filesystem.

build()函数

通常情况下build函数中,最先做的就是切换当前目录到源文件解压得到的目录中。你可以利用"$startdir"(引号可以避免由文件夹中包括空格引发的头痛问题)变量完成这个步骤(它指向包含PKGBUILD的文件夹)。你还可以使用先前设置的变量 $pkgname 和 $pkgver 。例如,根据makepkg解压源文件得到的文件夹的名字,build方法的首条命令可能为cd $startdir/src/$pkgname-$pkgver,这个是很常用的除非软件的作者是个非常,非常"邪恶"的人。如果版本号中真的包含连接符,你就需要使用"${pkgver//_/-}"来代替简单的$pkgver,这样bash就会重新使用连接符代替下划线。 编译是比较难的部分,在这我假设你已经"亲自"成功地编译过这个程序,因为任何的假设步骤在这都是行不通的。这也是为什么软件的作者要写README和INSTALL的原因。

现在你已经位于那个文件夹,你需要列出编译需要的所有指令。虽然有些需要许多指令包括ant buildgcc等命令来编译的包,但在简单的情况下,你可能只需要使用./configure; make指令就行。(In simple cases, you may simply use ./configure; make, although there are dozens of variations including ant build or issuing the actual gcc commands to compile the packages.)

好的一方面是,如果你已经成功的编译了这个包,你只需列出你在编译时使用的指令就行了。很多包默认会被安装到/usr/local目录下,而Arch Linux喜欢将包安装到 /usr目录,这样你可能就需要在配置脚本中或编译时加上一个参数去处理这个小差异。在PKGBUILD的示例文件中有处理这个问题的例子。It might work differently, though; Again, your mileage may vary.

  • 一个很好的实践是:只有从源文件手动编译安装时,才使用 --prefix=/usr/local。保留/usr给pacman处理的包用,包括那些使用ABS/makepkg编译的包。这样可以避免包冲突引发的问题。

接下来在build()方法中要做的是将编译好的文件放置到一个地方,使makepkg能将它们打包到一起。这个地方就是pkg目录。它就相当于你文件系统的跟目录,你将需要安装到文件根系统的文件按同样的结构放置到pkg目录下(如: 如果你想将myprog安装到/usr/bin目录下,它就应该被放置到$startdir/pkg/usr/bin)。幸运的是这种需要用户手工复制大量文件的软件还是很少的,通常软件都在安装过程中自动做这些事,如一般运行"make install"就行了。这一步很关键,你需要告诉安装过程不要将文件真的安装到你的文件系统中,而是将它们放在$startdir/pkg/目录下。不然你最终得到的是一个空的包文件,而它们的二进制文件已经被真实地安装到你的系统中了。通常你需要像PKGBUILD示例文件中那样在"make install"命令前面加上参数,但有时你打的包需要使用其他的方法,下面是一些值得注意的(hints):

  • 有时候 configure脚本需要一个参数告诉它将包安装到什么地方,如./configure --prefix=$startdir/pkg/usr。需要当心你用的文件夹名字是否正确,有时候解压后会得到一个和原文件名不同的文件夹如:
tar -xf foo-0.99.tar.gz

运行ls命令可能会返回:

  .
  ..
  foo-0.99.tar.gz
  foo/

而不是:

  .
  ..
  foo-0.99.tar.gz
  foo-0.99/
  • Sometimes there is a PREFIX option to append to a make install command. This is sometimes set as a variable, and sometimes set in the command. In worse cases you have to edit the Makefile(s) (or ant build/properties files if the project uses ant) with sed or a patch you'd have to create yourself.
  • 还可能存在其他的一些安装脚本,你可以在这些脚本中指定你想将软件安装到什么地方。
  • 有些软件运行只需一个文件夹,将这样的文件夹复制到$startdir/pkg/opt通常是一个不错的选择。

你或许已经感觉到了,这时候实践知识和经验是很必要的。你可以浏览位于ABS树中的 PKGBUILD文件,这些文件都经过测试的,而且有些能提供一些有价值的技巧,这将对你将很有帮助。

安装时通常需要在pkg/下创建一些子文件夹。如果你不这样做,安装时就会得到文件被复制到一个不存在的文件夹这样的错误。这时,你在运行安装过程之前,需要将合适的mkdir指令加入到build()方法中。真实的文件结构是由将安装的软件决定的,有些需要放置一些文件在/etc/usr中,有些则需用使用/bin/opt目录。大多数时候需用创建一些文件夹,你可以mkdir -p $startdir/pkg/OTHER/DIRS/AS/NEEDED命令将它们全部搞定,其中OTHER/DIRS/AS/NEEDED 代表相对根文件系统的目录。

.install 文件: 安装时的处理

如果安装后需要一些执行一些操作(比如说输出用户信息),你就需要使用.install文件。

使用.install文件,首先在要在PKGBUILD中指明.install文件名:

install=${pkgname}.install

然后创建pkgname.install文件。文件的内容可以参考下面的内容:

 # 本文件是post-install脚本范例。
 # 使用的时候,将您要使用的函数取消注释,其他内容可以删除掉
 
 #pre_install() {
   # 安装前执行的函数;参数arg 1代表新版本号
 #}
 
 #post_install() {
   # 安装后执行的函数;参数arg 1代表新版本号
 #}
 
 #pre_upgrade() {
   # 升级前执行的函数;参数arg 1代表新版本号,参数arg 2代表旧版本号
 #}
 
 #post_upgrade() {
   # 升级后执行的函数;参数arg 1代表新版本号,参数arg 2代表旧版本号
 #}
 
 #pre_remove() {
   # 卸载前执行的函数;参数arg 1代表旧版本号
 #}
  
 #post_remove() {
   # 卸载后执行的函数;参数arg 1代表旧版本号
 #}

在系统中提供了包含上面这些内容的.install文件的范例,他位于:/usr/share/pacman/proto.install

测试PKGBUILD

你在写PKGBUILDbuild()方法时,会想频繁的测试你所做的改动以确保没有bug。你可以在包含 PKGBUILD的目录下运行makepkg命令来确保没有问题。如果PKGBUILD没有错误,将会生成一个包,但是如果PKGBUILD被破坏或未完成,它将抛出一个错误。如果顺利的话就只是描述性的错误(Hopefully it will be a descriptive error!)。

如果运行makepkg 成功,在你工作的目录下将会生成一个名为$pkgname-$pkgver.pkg.tar.gz的新文件。这个文件可以使用pacman -Upacman -A安装,你也可以将它加到本地或网上的软件仓库中。注意,一个包被构建并不代表你的工作就完成了!只有当所有文件的结构都正确才能确保完成,例如你给了一个不正确的前缀就不行。你可以使用pacman的查询功能显示软件包包含的文件及依赖的文件,然后将它于你认为正确的对比。"pacman -Qlp <package file>" 和"pacman -Qip <package file>" 可以完成这项工作。

如果包看起来是正确的,那你的工作就完成了。但是如果你打算发布这个包或PKGBUILD,你就需要确认确认再确认包的依赖关系。你应该列出一列需要按顺序安装的软件包。你只需要列出第一级依赖(软件直接依赖的包)就行了,间接依赖的包会自动处理。 例如:gtk2 依赖glib2. 像其他的开源C程序一样,它同样依赖 glibc。但是你不需要列出glibc,因为glib2已经依赖它了,而glib2已经被列出了。

你可以使用一些很有名的软件来检测依赖关系,如Jason Chu有名的namcap 软件(pacman -S namcap),或者ldd软件。查看它们的man页面或本页底下的链接获取更多信息。同时你应该浏览一下软件的站点(有些很nice的开发者已经给出了依赖关系的页面)。

测试生成的软件安装包

同样要确保安装的软件确实很完美的运行!如果你释放了一个包括所有必需文件的包,但是由于一些配置选项使它不能很好的工作,这真是让人恼火。如果你只是为你自己的系统安装这个软件,你就不必做这个质量保证了,因为只有你一个人需要忍受这些错误。

总结归纳

  • 下载你希望打包的软件源代码
  • 试着编译安装包到任意目录
  • 复制PKGBUILD的文件原型 /usr/share/pacman/PKGBUILD.proto到一个临时的目录并重命名为 PKGBUILD
  • 根据具体情况修改 PKGBUILD 文件
  • 运行 makepkg 看看输出的打包结果是否正确
  • 如果不正确,重复前两个步骤

有用的链接

注意事项

  • Before you can automate the package building process, you should have done it manually at least once unless you know exactly what you're doing in advance, in which case you would not be reading this in the first place. Unfortunately, although a good bunch of program authors stick to the 3-step build cycle of "./configure; make; make install", this is not always the case, and things can get real ugly if you have to apply patches to make everything work at all. Rule of thumb: If you can't get the program to compile from the source tarball, and make it install itself to a defined, temporary subdirectory, you don't even need to try packaging it. There isn't any magic pixie dust in makepkg that makes source problems go away.
  • In a few cases, the packages are not even available as source and you have to use something like sh installer.run to get it to work. You will have to do quite a bit of research (read READMEs, INSTALL instructions, man pages, perhaps ebuilds from gentoo or other package installers, possibly even the MAKEFILEs or source code) to get it working. In some really bad cases, you have to edit the source files to get it to work at all. However, makepkg needs to be completely autonomous, with no user input. Therefore if you need to edit the Makefiles, you may have to bundle a custom patch with the PKGBUILD and install it from inside the build() function, or you might have to issue some sed commands from inside the build() function.
  • Note that just because a package file was built it doesn't mean it works! It might conceivably contain only the directory structure and no files whatsoever if, for example, you specified a prefix improperly. You can use pacman's query functions to display a list of files contained in the package and the dependencies it requires, and compare those with what you consider as correct. "pacman -Qlp <package file>" and "pacman -Qip <package file>" do the trick.

更详细的指南

Template:Package Guidelines