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

From ArchWiki
Jump to navigation Jump to search
Line 74: Line 74:
 
要开始制作一个包,你应该先创建一个空工作目录,(建议{{ic|~/abs/'''pkgname'''}}),进入该目录,创建一个{{ic|PKGBUILD}}文件。你可以复制PKGBUILD模板(位于/usr/share/pacman/PKGBUILD.proto)到工作目录,或者复制一个类似包的PKGBUILD也可以。如果你只想在别人的基础上更改一些选项的话,后一种方法比较方便。
 
要开始制作一个包,你应该先创建一个空工作目录,(建议{{ic|~/abs/'''pkgname'''}}),进入该目录,创建一个{{ic|PKGBUILD}}文件。你可以复制PKGBUILD模板(位于/usr/share/pacman/PKGBUILD.proto)到工作目录,或者复制一个类似包的PKGBUILD也可以。如果你只想在别人的基础上更改一些选项的话,后一种方法比较方便。
  
== 编辑PKGBUILD变量 ==
+
== 定义PKGBUILD变量 ==
  
 
PKGBUILD文件的编写例子可以在{{Ic|/usr/share/pacman/}}处找到。PKGBUILD文件中可能用到的一些变量意义的解释可以在[[PKGBUILD]]中找到。
 
PKGBUILD文件的编写例子可以在{{Ic|/usr/share/pacman/}}处找到。PKGBUILD文件中可能用到的一些变量意义的解释可以在[[PKGBUILD]]中找到。
  
 +
''makepkg'' 定义了三个变量,你应该在编译和安装的过程中使用它们:
 +
; {{ic|startdir}}: 指向{{ic|PKGBUILD}}文件所在目录的绝对路径。这个变量过去常常和T{{ic|/src}}或{{ic|/pkg}}后缀组合使用,但现在更流行的用法是使用{{ic|srcdir}}和{{ic|pkgdir}}变量。注意,{{ic|$startdir/src}}作用效果 '''不能''' 保证等同于{{ic|$srcdir}}。这些变量的使用已经被废弃,不建议继续使用。
 +
; {{ic|srcdir}}: ''makepkg''将会把源文件解压或复制到此文件夹。
 +
; {{ic|pkgdir}}: ''makepkg''会把该文件夹当成系统根目录,并将软件安装在此文件夹下。
  
打开文件,根据你要打的包,设定下面每个变量:
+
{{Note|''makepkg'', 因此{{ic|build()}}和{{ic|package()}}函数在运行过程中都应当是非交互的。在这些函数中调用交互工具或脚本可能会中断''makepkg''的运行。(参考{{Bug|13214}})}}
<br /><br />
 
*'''pkgname:''' 设置软件包的名字,习惯上要求软件包名字全部使用小写字母。这个是随意的,但是如果你这个包的名字和你工作的文件夹名字以及将要下载的程序的tar.gz压缩文件名字一样,这样就很方便了。
 
  
*'''pkgver:''' 设置软件包的版本。可以含有字母,数字,小数点但是不能含有连接符。 版本取决于你将打包的选项所选用的版本系统如(major.minor.bugfix, major.date, etc) 。一般情况下你应该使用源文件名字中的版本,这样以后的步骤就会更方便和灵活点。还有值得注意的,如果源文件的作者在他的版本中使用了连接符,你应该使用下划线代替。如('0.99-10'  =>  '0.99_10')
+
{{Note|如果你是接手别人的包,除了把你的名字列为包维护者(Maintainers)外,你还应当把之前的维护者列为贡献者(Contributors)。}}
  
*'''pkgrel:''' 每次你发布一个包这个值都要增加,值从1开始。它的目的是区别对同一个版本的包的连续构建。有时候包的第一个发布版本可能有问题或缺失特性,当你再次发布时你就把{{ic|pkgrel}} 的值增加,这样pacman就知道它需要重新安装。当一个包的新版本发布时,你把{{ic|pkgrel}} 的值重新设置为1。
+
=== build()函数 ===
  
*'''pkgdesc:''' 包括一个对包的简短描述,描述通常少于76个字符。通常它不需要使用项目名称,像{{ic|OpenGL accelerated X server}} 就比 {{ic|xgl is an OpenGL...}}要好。
+
现在你需要执行{{ic|PKGBUILD}}文件中的{{ic|build()}}函数。这个函数使用通用的shell命令来自动编译软件并创建软件的安装目录。这允许''makepkg''无需通过你的文件系统就可以打包你的软件。
  
*'''arch:'''包括这个包可以运行的架构名称,一般是'i686'. 在构建过程中你可以用{{ic|$arch}}调用这个值。
+
{{ic|build()}}函数中第一步就是进入由解压源码包所生成的目录。大多数情况下第一条命令是这样的:
  
*'''url:''' 这个填写这软件的官方网址,以便想了解更多信息的人能够方便找到.
+
cd "$srcdir/$pkgname-$pkgver"
  
*'''license:''' 填写软件的授权方式,如果不知道,可以填写'unknown'。
+
现在,你需要把你当时手动编译软件时用到的命令一一列上。{{ic|build()}}基本上会自动运行你当时手动输入的命令并在伪root环境下编译该软件。如果你要打包的软件使用了一个配置脚本,最好在配置中加上{{ic|1=--prefix=/usr}}。许多软件都将自己安装到{{ic|/usr/local}}下,我们仅仅推荐当你手动从源码安装时这么做。所有的Arch Linux软件包都应当使用{{ic|/usr}}目录。根据示例文件{{ic|/usr/share/pacman/PKGBUILD.proto}},接下来的两行经常是这样的:
  
*'''depends:''' 包括一列需要在这个包之前安装的包的名字,它们之间用空格分开。名字可以用单引号(apostrophes) (撇号)括起来,这样可以避免可能的shell引用问题,名字列需要用小括号括起来。有时候一个程序需要一个所依赖的软件的最小版本号,这种情况下你需要使用数学中的大于等于号,同时把它们整个用引号括起来。这儿是一个例子,它依赖glibc包,同时依赖版本号最小为1.8.0的slang库: '''{{ic|1=depends=('glibc' 'slang>=1.8.0')}}'''。
+
./configure --prefix=/usr
 +
make
  
*'''makedepends:''' 包括一列在构建时需要的包的名字,但在安装后的使用时,这些包是不需要的。如构建时在解包一些补丁的时候需要用到{{ic|unarj}}。
+
=== check()函数 ===
  
*'''provides:'''包括一列这个包可以提供的软件包(或虚拟包,如'cron'或'sh')的名字 。如果你使用了这个变量,根据依赖关系的需要,你可能需要加上所提供的软件包的版本号(pkgver and perhaps the pkgrel)。 ''''注意:''''这个功能在pacman 3.1.0的版本中有点小缺陷,将在3.1.1版本中修复。针对3.1.1版本的该文档不久后就能获取了。<br/>'''例子:'''如果你提供一个qt的修改版qt-foo 3.3.8版,qt-foo提供了qt包,这样provides变量就应该像这样:'''{{ic|1=provides=('qt=3.3.8')}}'''。如果只是写成'''{{ic|1=provides=('qt')}}'''会导致依赖于特定版本qt的软件包出问题,但是如果没有包需要依赖qt的特定版本,这样就足够了。 <br/>'''例子2:'''如果软件包perl-5.10.0同时提供5.2.1版的perl-foo和2.5版的perl-bar两个perl模块,provides变量像这样写: '''{{ic|1=provides=('perl-foo=5.2.1' 'perl-bar=2.5')}}'''.
+
用来执行{{Ic|make check}}和其他一些例行测试的地方。如果不需要它可以在PKGBUILD/makepkg选项中通过{{Ic|!check}}禁用它。
  
*'''conflicts:''' 包括一列冲突包的名字,如果和这些包一起安装会出问题。同样应该指定冲突包的"版本属性",版本格式和depends变量中的一样。
+
=== package()函数 ===
  
*'''replaces:''' 包括将要被安装包所取代的一系列废弃包的名字。
+
最后一步就是把编译好的文件放到{{ic|pkg}}文件夹——一个简单的伪root环境。{{ic|pkg}}目录复制了根目录下软件安装路径的继承关系。如果你需要手动把文件放到根目录下,那么在这里你需要把文件放在{{ic|pkg}}下相同的文件层级结构中。比如,你想把一个文件安装到{{ic|/usr/bin}},那么在伪root环境中对应的路径为{{ic|$pkgdir/usr/bin}}。极少情况下的安装步骤需要用户手动复制大量的文件到某个地方。大部分软件安装时只需要调用{{ic|make install}}即可。为了将软件安装到正确的路径,最后一行一般应该这样写:
  
*'''source:''' 包括构建这个包所需的一系列文件,其中至少应该包括软件源代码所在的位置,这个位置通常是双引号括起来的一个完整的HTTP或FTP的URL。The prototype {{ic|PKGBUILD}} shows how you can use the previously set variables for package name and version effectively here. 如果你需要一些不能从网上下载的支持文件,如你自己写的补丁程序,你只需将它们放在你存放{{ic|PKGBUILD}}的文件夹中,然后将文件名加到source文件列中。文件列中的任何文件路径都是相对你存放{{ic|PKGBUILD}}的文件夹的。在开始真正构建前,列中所有的文件都需要下载下来或者检查已经存在,只要任何一个文件缺失,构建就不会开始。
+
make DESTDIR="$pkgdir/" install
  
*'''md5sums:'''一列源文件的md5值,值需用引号括起来用空格分开。当source列中的所有文件都可用后,每个文件的md5值会自动生成并'''以它们在source列中出现的相同顺序'''和列中的md5值比较。source列中的文件顺序可用任意排列,但md5列中的值则必须和它们在source列中的文件顺序同步,{{ic|makepkg}}不会去猜测哪个md5值是哪个文件的,如果它们不匹配就会弹出错误,以防止下载或操作出错。你可以在放置{{ic|PKGBUILD}}的文件夹中使用{{ic|makepkg -g}}命令(在source列已经设置好后)轻松地生成文件列的md5值。{{ic|makepkg -g >>PKGBUILD}}会生成值并将它们加到{{ic|PKGBUILD}}文件的末端,然后你可用将它剪切到文件的合适位置。
+
{{Note|有时候在{{ic|Makefile}}里没有使用{{ic|DESTDIR}};你可能需要使用{{ic|prefix}}来替代。如果软件包是用''autoconf''/''automake''来创建的,那就使用{{ic|DESTDIR}};如果{{ic|DESTDIR}}不起作用,试试{{ic|1=make prefix="$pkgdir/usr/" install}}。如果这还不起作用的话,你就需要深入检查软件的安装命令了。
  
到此你还只是设置好了这个包的基本信息(meta-information),如从哪获取源文件,软件包的名字是什么等等。下一步是编写''编译和安装''该软件包的指令。
+
在一些很罕见的情况下,软件只有安装在单一目录下时才能运行。在这种情况下你还是老老实实把它安装到{{ic|$pkgdir/opt}}下吧。
  
==使用源文件==
+
通常,软件在安装过程中会在{{ic|pkg}}目录下先创建一系列子目录。如果没有的话,''makepkg''会报错,你需要在{{ic|build()}}函数中提前手动创建这些目录。
下载源码包、解压、查看需要使用那些命令来安装这个软件包。{{ic|PKGBUILD}} 中的 {{ic|build()}}内容,就是这个软件包的安装脚本内容。
 
  
修改{{ic|PKGBUILD}}的build()中的参数. 这个方法(functioin)使用根据bash语法编写的shell命令。方法的基本目的是自动编译软件并将其安装到一个创建的{{ic|pkg}}目录中,allowing {{ic|makepkg}} to pack it all up easily without having to pick all interesting files from your "live" filesystem.
+
在过去,没有{{ic|package()}}函数。所以,复制各种文件的工作放在{{ic|build()}}函数的最后。如果{{ic|package()}}函数不存在的话,{{ic|build()}}以伪root权限运行。如果{{ic|package()}}存在的话,{{ic|build()}}以用户权限运行,{{ic|package()}}以伪root权限运行。
  
=== build()函数===
+
{{ic|makepkg --repackage}} 命令只运行{{ic|package()}}函数,它只是将文件打包成{{ic|*.pkg.*}},并不运行编译过程。如果你只是更改了PKGBUILD中的依赖,用这个命令来打包可以节省很多时间。
通常情况下build函数中,最先做的就是切换当前目录到源文件解压得到的目录中。你可以利用{{ic|"$startdir"}}(引号可以避免由文件夹中包括空格引发的头痛问题)变量完成这个步骤(它指向包含{{ic|PKGBUILD}}的文件夹)。你还可以使用先前设置的变量 $pkgname 和 $pkgver 。例如,根据{{ic|makepkg}}解压源文件得到的文件夹的名字,build方法的首条命令可能为{{ic|cd $startdir/src/$pkgname-$pkgver}},这个是很常用的除非软件的作者是个非常,非常"邪恶"的人。如果版本号中真的包含连接符,你就需要使用{{ic|"${pkgver//_/-}"}}来代替简单的{{ic|$pkgver}},这样bash就会重新使用连接符代替下划线。
 
编译是比较难的部分,在这我假设你已经"亲自"成功地编译过这个程序,因为任何的假设步骤在这都是行不通的。这也是为什么软件的作者要写README和INSTALL的原因。
 
  
现在你已经位于那个文件夹,你需要列出编译需要的所有指令。虽然有些需要许多指令包括{{ic|ant build}} 或{{ic|gcc}}等命令来编译的包,但在简单的情况下,你可能只需要使用{{ic|./configure; make}}指令就行。(In simple cases, you may simply use {{ic|./configure; make}}, although there are dozens of variations including {{ic|ant build}} or issuing the actual {{ic|gcc}} commands to compile the packages.)
+
== 测试PKGBUILD文件 ==
  
好的一方面是,如果你已经成功的编译了这个包,你只需列出你在编译时使用的指令就行了。很多包默认会被安装到{{ic|/usr/local}}目录下,而Arch Linux喜欢将包安装到 {{ic|/usr}}目录,这样你可能就需要在配置脚本中或编译时加上一个参数去处理这个小差异。在{{ic|PKGBUILD}}的示例文件中有处理这个问题的例子。It might work differently, though; Again, your mileage may vary.
+
你在写{{ic|PKGBUILD}}{{ic|build()}}方法时,会想频繁的测试你所做的改动以确保没有bug。你可以在包含 {{ic|PKGBUILD}}的目录下运行{{ic|makepkg}}命令来确保没有问题。如果{{ic|PKGBUILD}}没有错误,将会生成一个包,但是如果{{ic|PKGBUILD}}被破坏或未完成,它将抛出一个错误。
  
*''一个很好的实践是:只有从源文件手动编译安装时,才使用 --prefix=/usr/local。保留/usr给pacman处理的包用,包括那些使用ABS/makepkg编译的包。这样可以避免包冲突引发的问题。''
+
如果运行{{ic|makepkg}} 成功,在你工作的目录下将会生成一个名为$pkgname-$pkgver.pkg.tar.gz的新文件。这个文件可以使用{{ic|pacman -U}} 或 {{ic|pacman -A}}安装,你也可以将它加到本地或网上的软件仓库中。注意,一个包被构建并不代表你的工作就完成了!只有当所有文件的结构都正确才能确保完成,例如你给了一个不正确的前缀就不行。你可以使用pacman的查询功能显示软件包包含的文件及依赖的文件,然后将它于你认为正确的对比。"pacman -Qlp <package file>" 和"pacman -Qip <package file>" 可以完成这项工作。
  
接下来在{{ic|build()}}方法中要做的是将编译好的文件放置到一个地方,使{{ic|makepkg}}能将它们打包到一起。这个地方就是{{ic|pkg}}目录。它就相当于你文件系统的跟目录,你将需要安装到文件根系统的文件按同样的结构放置到{{ic|pkg}}目录下(如: 如果你想将{{ic|myprog}}安装到{{ic|/usr/bin}}目录下,它就应该被放置到{{ic|$startdir/pkg/usr/bin}})。幸运的是这种需要用户手工复制大量文件的软件还是很少的,通常软件都在安装过程中自动做这些事,如一般运行"make install"就行了。这一步很'''关键''',你需要告诉安装过程'''不要'''将文件真的安装到你的文件系统中,而是将它们放在{{ic|$startdir/pkg/}}目录下。不然你最终得到的是一个空的包文件,而它们的二进制文件已经被'''真实'''地安装到你的系统中了。通常你需要像{{ic|PKGBUILD}}示例文件中那样在"make install"命令前面加上参数,但有时你打的包需要使用其他的方法,下面是一些值得注意的(hints):
+
如果包看起来是正确的,那你的工作就完成了。但是如果你打算发布这个包或PKGBUILD,你就需要确认确认再确认包的依赖关系。
  
* 有时候 {{ic|configure}}脚本需要一个参数告诉它将包安装到什么地方,如{{ic|1=./configure --prefix=$startdir/pkg/usr}}。需要当心你用的文件夹名字是否正确,有时候解压后会得到一个和原文件名不同的文件夹如:
+
同样要确保安装的软件确实很完美的运行!如果你释放了一个包括所有必需文件的包,但是由于一些配置选项使它不能很好的工作,这真是让人恼火。如果你只是为你自己的系统安装这个软件,你就不必做这个质量保证了,因为只有你一个人需要忍受这些错误。
 
 
  <pre>tar -xf foo-0.99.tar.gz</pre>
 
 
 
运行{{ic|ls}}命令可能会返回:
 
 
 
  <pre>
 
  .
 
  ..
 
  foo-0.99.tar.gz
 
  foo/</pre>
 
 
 
而不是:
 
 
 
  <pre>
 
  .
 
  ..
 
  foo-0.99.tar.gz
 
  foo-0.99/</pre>
 
 
 
* Sometimes there is a {{ic|PREFIX}} option to append to a {{ic|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.
 
 
 
* 还可能存在其他的一些安装脚本,你可以在这些脚本中指定你想将软件安装到什么地方。
 
 
 
*有些软件运行只需一个文件夹,将这样的文件夹复制到{{ic|$startdir/pkg/opt}}通常是一个不错的选择。
 
 
 
你或许已经感觉到了,这时候实践知识和经验是很必要的。你可以浏览位于ABS树中的 {{ic|PKGBUILD}}文件,这些文件都经过测试的,而且有些能提供一些有价值的技巧,这将对你将很有帮助。
 
 
 
安装时通常需要在{{ic|pkg/}}下创建一些子文件夹。如果你不这样做,安装时就会得到文件被复制到一个不存在的文件夹这样的错误。这时,你在运行安装过程之前,需要将合适的{{ic|mkdir}}指令加入到{{ic|build()}}方法中。真实的文件结构是由将安装的软件决定的,有些需要放置一些文件在{{ic|/etc}} 或 {{ic|/usr}}中,有些则需用使用{{ic|/bin}} 或 {{ic|/opt}}目录。大多数时候需用创建一些文件夹,你可以{{ic|mkdir -p $startdir/pkg/OTHER/DIRS/AS/NEEDED}}命令将它们全部搞定,其中OTHER/DIRS/AS/NEEDED 代表相对根文件系统的目录。
 
 
 
=='''.install''' 文件: 安装时的处理==
 
 
 
如果安装后需要一些执行一些操作(比如说输出用户信息),你就需要使用'''.install'''文件。
 
 
 
使用'''.install'''文件,首先在要在PKGBUILD中指明'''.install'''文件名:
 
{{ic|1=install=${pkgname}.install}}
 
 
 
然后创建{{ic|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'''文件的范例,他位于:{{ic|/usr/share/pacman/proto.install}}。
 
  
==测试PKGBUILD==
+
=== 检查包的逻辑性 ===
  
你在写{{ic|PKGBUILD}}的 {{ic|build()}}方法时,会想频繁的测试你所做的改动以确保没有bug。你可以在包含 {{ic|PKGBUILD}}的目录下运行{{ic|makepkg}}命令来确保没有问题。如果{{ic|PKGBUILD}}没有错误,将会生成一个包,但是如果{{ic|PKGBUILD}}被破坏或未完成,它将抛出一个错误。如果顺利的话就只是描述性的错误(Hopefully it will be a descriptive error!)。
+
确定包可以正常使用后,再使用[[namcap]]来检查错误:
 +
$ namcap PKGBUILD
 +
$ namcap ''<package file name>''.pkg.tar.xz
  
如果运行{{ic|makepkg}} 成功,在你工作的目录下将会生成一个名为$pkgname-$pkgver.pkg.tar.gz的新文件。这个文件可以使用{{ic|pacman -U}} 或 {{ic|pacman -A}}安装,你也可以将它加到本地或网上的软件仓库中。注意,一个包被构建并不代表你的工作就完成了!只有当所有文件的结构都正确才能确保完成,例如你给了一个不正确的前缀就不行。你可以使用pacman的查询功能显示软件包包含的文件及依赖的文件,然后将它于你认为正确的对比。"pacman -Qlp <package file>" 和"pacman -Qip <package file>" 可以完成这项工作。
+
Namcap将会做以下工作:
 +
# 检查PKGBUILD文件里的一些常见错误
 +
# 用{{ic|ldd}}扫描包中所有的ELF文件,自动报告缺失或可去除的依赖。
 +
# 启发式搜寻缺失或冗余的依赖。
 +
要养成用namcap检查包的习惯,以避免提交包后再做修复的麻烦。
  
如果包看起来是正确的,那你的工作就完成了。但是如果你打算发布这个包或PKGBUILD,你就需要确认确认再确认包的依赖关系。你应该列出一列需要按顺序安装的软件包。你只需要列出第一级依赖(软件直接依赖的包)就行了,间接依赖的包会自动处理。
+
== 把包提交给AUR ==
例如:{{ic|gtk2}} 依赖{{ic|glib2}}. 像其他的开源C程序一样,它同样依赖 {{ic|glibc}}。但是你不需要列出{{ic|glibc}},因为{{ic|glib2}}已经依赖它了,而{{ic|glib2}}已经被列出了。
 
  
你可以使用一些很有名的软件来检测依赖关系,如Jason Chu有名的{{ic|namcap}} 软件({{ic|pacman -S namcap}}),或者{{ic|ldd}}软件。查看它们的man页面或本页底下的链接获取更多信息。同时你应该浏览一下软件的站点(有些很nice的开发者已经给出了依赖关系的页面)。
+
请参考[[AUR User Guidelines#Submitting packages]],里面详细介绍了提交流程。
  
==测试生成的软件安装包==
+
== 总结 ==
同样要确保安装的软件确实很完美的运行!如果你释放了一个包括所有必需文件的包,但是由于一些配置选项使它不能很好的工作,这真是让人恼火。如果你只是为你自己的系统安装这个软件,你就不必做这个质量保证了,因为只有你一个人需要忍受这些错误。
 
 
 
==总结归纳==
 
 
* 下载你希望打包的软件源代码
 
* 下载你希望打包的软件源代码
 
* 试着编译安装包到任意目录
 
* 试着编译安装包到任意目录
* 复制PKGBUILD的文件原型 {{ic|/usr/share/pacman/PKGBUILD.proto}}到一个临时的目录并重命名为 {{ic|PKGBUILD}}
+
* 复制PKGBUILD的文件模板 {{ic|/usr/share/pacman/PKGBUILD.proto}}到一个临时的目录并重命名为 {{ic|PKGBUILD}}
 
* 根据具体情况修改 PKGBUILD 文件
 
* 根据具体情况修改 PKGBUILD 文件
 
* 运行 {{ic|makepkg}} 看看输出的打包结果是否正确
 
* 运行 {{ic|makepkg}} 看看输出的打包结果是否正确
 
* 如果不正确,重复前两个步骤
 
* 如果不正确,重复前两个步骤
  
==有用的链接==
+
=== 注意事项 ===
* [[Arch Build System]]
 
* [http://www.archlinux.org/pacman/makepkg.8.html makepkg man page]
 
* [http://bbs.archlinux.org/viewtopic.php?t=4 about dependencies]
 
* [[Makepkg|makepkg tutorial]]
 
* [[Arch CVS & SVN PKGBUILD guidelines]]
 
  
==注意事项==
+
* 在开始自动打包之前,请确保你至少已成功手动打包一次,除非你“很清楚”你正在做什么。不幸的是,虽然大多数软件作者遵循了三步走的安装惯例:{{ic|./configure}}; {{ic|make}}; {{ic|make install}},但事情并不都是这样的,有时候你不得不自己打补丁才能安装成功。经验是:如果你手动无法编译成功或者无法将软件安装到指定子目录下,那你就不必费心打包了。{{ic|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 {{ic|makepkg}} that makes source problems go away.
+
* 在一些情况下,你可能无法直接得到包的源码,可能需要使用{{ic|sh installer.run}}这样的东西来工作。这时就需要你自己做很多工作了(比如读READMEs,安装指导,手册,或者Gentoo的ebuilds等等)。在一些很变态的情况下,你需要自己编辑源码才能正常安装。但是,{{ic|makepkg}}需要完全自主运行,不能有用户的干预。因此,如果你想修改makefiles,你需要随PKGBUILD附上一个定制的补丁,然后在{{ic|build()}}函数里安装这个补丁;或者你可以在{{ic|build()}}函数里通过{{ic|sed}}来修改。
* In a few cases, the packages are not even available as source and you have to use something like {{ic|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, {{ic|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 {{ic|PKGBUILD}} and install it from inside the {{ic|build()}} function, or you might have to issue some {{ic|sed}} commands from inside the {{ic|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.
 
  
== 更详细的指南 ==
+
== 更详细的规则 ==
 
{{Package Guidelines}}
 
{{Package Guidelines}}
 +
 +
== 参考 ==
 +
* [https://bbs.archlinux.org/viewtopic.php?id=91408 How to correctly create a patch file].

Revision as of 09:31, 14 September 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: 一个可选的文件,保存了包管理员描述软件更新的日志。(不是所有包中都存在。)

准备工作

必需的软件包

首先,确定你已安装必须的工具包。安装 base-devel应该足够了;它包含make和其它一些从源码编译时所需要的工具。

# pacman -S base-devel

创建包的一个很重要的工具是makepkg(由{{Pkg|pacman}提供),它主要做以下工作:

  1. 检查相关依赖是否安装。
  2. 从指定的服务器下载源文件。
  3. 解压源文件。
  4. 编译软件并将它安装于伪root环境下。
  5. 删除二进制文件和库文件的符号连接。
  6. 生成包的meta文件。
  7. 将伪root环境压缩成一个包文件
  8. 将生成的包文件保存到配置的文件夹中(默认为当前工作目录)。

下载并测试安装

下载你想打包的软件的源代码压缩包,解压,按照作者所说的步骤安装它。记录下在编译和安装软件过程中需要的所有命令或步骤。你将要在PKGBUILD文件中重复这些命令和步骤。

大多数软件作者遵循三步走的安装惯例:

./configure
make
make install

这个阶段是很好的确保程序能正常运行的机会。

创建PKGNUILD

当你运行makepkg时,它会在当前工作目录寻找一个PKGBUILD文件。如果找到PKGBUILD文件,它会下载该软件的源代码,根据PKGBUILD文件中的指令编译它。PKGBUILD中的指令必须能完全被Bash解释。成功完成后,最后的二进制文件和包的元信息(即包的版本、依赖)被一起打包在pkgname.pkg.tar.xz文件包中,这个文件包可以使用pacman -U <package file>来安装。

要开始制作一个包,你应该先创建一个空工作目录,(建议~/abs/pkgname),进入该目录,创建一个PKGBUILD文件。你可以复制PKGBUILD模板(位于/usr/share/pacman/PKGBUILD.proto)到工作目录,或者复制一个类似包的PKGBUILD也可以。如果你只想在别人的基础上更改一些选项的话,后一种方法比较方便。

定义PKGBUILD变量

PKGBUILD文件的编写例子可以在/usr/share/pacman/处找到。PKGBUILD文件中可能用到的一些变量意义的解释可以在PKGBUILD中找到。

makepkg 定义了三个变量,你应该在编译和安装的过程中使用它们:

startdir
指向PKGBUILD文件所在目录的绝对路径。这个变量过去常常和T/src/pkg后缀组合使用,但现在更流行的用法是使用srcdirpkgdir变量。注意,$startdir/src作用效果 不能 保证等同于$srcdir。这些变量的使用已经被废弃,不建议继续使用。
srcdir
makepkg将会把源文件解压或复制到此文件夹。
pkgdir
makepkg会把该文件夹当成系统根目录,并将软件安装在此文件夹下。
Note: makepkg, 因此build()package()函数在运行过程中都应当是非交互的。在这些函数中调用交互工具或脚本可能会中断makepkg的运行。(参考FS#13214
Note: 如果你是接手别人的包,除了把你的名字列为包维护者(Maintainers)外,你还应当把之前的维护者列为贡献者(Contributors)。

build()函数

现在你需要执行PKGBUILD文件中的build()函数。这个函数使用通用的shell命令来自动编译软件并创建软件的安装目录。这允许makepkg无需通过你的文件系统就可以打包你的软件。

build()函数中第一步就是进入由解压源码包所生成的目录。大多数情况下第一条命令是这样的:

cd "$srcdir/$pkgname-$pkgver"

现在,你需要把你当时手动编译软件时用到的命令一一列上。build()基本上会自动运行你当时手动输入的命令并在伪root环境下编译该软件。如果你要打包的软件使用了一个配置脚本,最好在配置中加上--prefix=/usr。许多软件都将自己安装到/usr/local下,我们仅仅推荐当你手动从源码安装时这么做。所有的Arch Linux软件包都应当使用/usr目录。根据示例文件/usr/share/pacman/PKGBUILD.proto,接下来的两行经常是这样的:

./configure --prefix=/usr
make

check()函数

用来执行make check和其他一些例行测试的地方。如果不需要它可以在PKGBUILD/makepkg选项中通过!check禁用它。

package()函数

最后一步就是把编译好的文件放到pkg文件夹——一个简单的伪root环境。pkg目录复制了根目录下软件安装路径的继承关系。如果你需要手动把文件放到根目录下,那么在这里你需要把文件放在pkg下相同的文件层级结构中。比如,你想把一个文件安装到/usr/bin,那么在伪root环境中对应的路径为$pkgdir/usr/bin。极少情况下的安装步骤需要用户手动复制大量的文件到某个地方。大部分软件安装时只需要调用make install即可。为了将软件安装到正确的路径,最后一行一般应该这样写:

make DESTDIR="$pkgdir/" install

{{Note|有时候在Makefile里没有使用DESTDIR;你可能需要使用prefix来替代。如果软件包是用autoconf/automake来创建的,那就使用DESTDIR;如果DESTDIR不起作用,试试make prefix="$pkgdir/usr/" install。如果这还不起作用的话,你就需要深入检查软件的安装命令了。

在一些很罕见的情况下,软件只有安装在单一目录下时才能运行。在这种情况下你还是老老实实把它安装到$pkgdir/opt下吧。

通常,软件在安装过程中会在pkg目录下先创建一系列子目录。如果没有的话,makepkg会报错,你需要在build()函数中提前手动创建这些目录。

在过去,没有package()函数。所以,复制各种文件的工作放在build()函数的最后。如果package()函数不存在的话,build()以伪root权限运行。如果package()存在的话,build()以用户权限运行,package()以伪root权限运行。

makepkg --repackage 命令只运行package()函数,它只是将文件打包成*.pkg.*,并不运行编译过程。如果你只是更改了PKGBUILD中的依赖,用这个命令来打包可以节省很多时间。

测试PKGBUILD文件

你在写PKGBUILDbuild()方法时,会想频繁的测试你所做的改动以确保没有bug。你可以在包含 PKGBUILD的目录下运行makepkg命令来确保没有问题。如果PKGBUILD没有错误,将会生成一个包,但是如果PKGBUILD被破坏或未完成,它将抛出一个错误。

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

如果包看起来是正确的,那你的工作就完成了。但是如果你打算发布这个包或PKGBUILD,你就需要确认确认再确认包的依赖关系。

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

检查包的逻辑性

确定包可以正常使用后,再使用namcap来检查错误:

$ namcap PKGBUILD
$ namcap <package file name>.pkg.tar.xz

Namcap将会做以下工作:

  1. 检查PKGBUILD文件里的一些常见错误
  2. ldd扫描包中所有的ELF文件,自动报告缺失或可去除的依赖。
  3. 启发式搜寻缺失或冗余的依赖。

要养成用namcap检查包的习惯,以避免提交包后再做修复的麻烦。

把包提交给AUR

请参考AUR User Guidelines#Submitting packages,里面详细介绍了提交流程。

总结

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

注意事项

  • 在开始自动打包之前,请确保你至少已成功手动打包一次,除非你“很清楚”你正在做什么。不幸的是,虽然大多数软件作者遵循了三步走的安装惯例:./configure; make; make install,但事情并不都是这样的,有时候你不得不自己打补丁才能安装成功。经验是:如果你手动无法编译成功或者无法将软件安装到指定子目录下,那你就不必费心打包了。makepkg没有任何魔力能消除源代码的问题让你编译成功。
  • 在一些情况下,你可能无法直接得到包的源码,可能需要使用sh installer.run这样的东西来工作。这时就需要你自己做很多工作了(比如读READMEs,安装指导,手册,或者Gentoo的ebuilds等等)。在一些很变态的情况下,你需要自己编辑源码才能正常安装。但是,makepkg需要完全自主运行,不能有用户的干预。因此,如果你想修改makefiles,你需要随PKGBUILD附上一个定制的补丁,然后在build()函数里安装这个补丁;或者你可以在build()函数里通过sed来修改。

更详细的规则

Template:Package Guidelines

参考