前言
使用 Arch, 或者基于 Arch 的 Manjaro 时,有些软件官方仓库里没有,而网上又可以下载到编译好的二进制文件,deb包,或者rpm包。二进制文件可以直接运行,deb或者rpm包解压后,找到对应的二进制文件,也可以直接运行。
但时,它们不被 pacman 包管理器管理,也不能从 app lancher 里面便捷的运行。
对于 deb 包,AUR库里有一个 debtap 脚本,可以将 deb 包转换成 pacman -U 可以直接安装的 .pkg.tar.zst 格式。这个脚本非常方便,但是由于这个脚本考虑非常全面,注意普适性,这就导致有时候转换后的 .pkg.tar.zst 包会出现一些问题,安装不上。
用 makepkg 打包软件是非常简单的事情,只是如果一点也不了解的话,会生怵。但是只要知道了它的运行机理,就会觉得非常简单,而且很多问题也就不存在了。
makepkg 简介
详细地介绍在 ArchWiki 里面都有介绍。在此按我的理解梳理一下。
makepkg 是 Arch 系统中的一个软件,它的作用是将写好的程序源代码编译好,并且打包成 .pkg.tar.zst 格式,然后发布。大家就可以下载打包好的 .pkg.tar.zst 文件在 Arch 上直接安装。
要想用 makepkg 打包一个程序,必须先写一个 PKGBUILD 文件。系统中有一些示例文件,比如 /usr/share/pacman/PKGBUILD.proto 。
写好了 PKGBUILD 文件,就可以直接在 PKGBUILD 文件所在的目录直接运行
makepkg
然后就生成了 .pkg.tar.zst 格式的软件包,然后 pacman -U 安装就可以了。
一个最简单的 PKGBUILD 文件
PKGBUILD 文件使用的是 shell 语言。最简单的 PKGBUILD 文件如下
pkgname=hello-makepkg
pkgver=1.0
pkgrel=1
arch=('x86_64')
package() {
echo "packaging..."
}
前四行定义了四个变量,是软件的名字,版本,以及运行架构。最后三行定义了一个函数,输出一行字 packaging...。
pkgname 、 pkgver 、 pkgrel 、 arch 四个变量必须定义。名为 package() 的函数会被 makepkg 自动执行。
这个最简单的 PKGBUILD 文件是 trivial 的,因为它什么也没干,只是走了个过场。
打包流程(一个不 trivial 的测试)
下面写一个不 trivial 的 PKGBUILD 文件。如下:
# This is an example PKGBUILD file. Use this as a start to creating your own,
# and remove these comments. For more information, see 'man PKGBUILD'.
# NOTE: Please fill out the license field for your package! If it is unknown,
# then please put 'unknown'.
# Maintainer: Your Name <youremail@domain.com>
pkgname=zqwtest
pkgver=1.0
pkgrel=1
arch=('x86_64')
source=("m.vsix")
md5sums=('541126551a459a74e740ac6a82875d24')
prepare() {
echo "prepare..."
}
build() {
echo "building..."
# pwd
# cd ${srcdir}
# pwd
# mkdir diraa
}
check() {
echo "checking..."
}
package() {
echo "packaging..."
mkdir ${pkgdir}/home
cp m.vsix ${pkgdir}/home/m.vsix
}
PKGBUILD 文件所在的目录结构如下:
.
├── m.vsix
└── PKGBUILD
与之前相比,多定义了两个变量,source 和 md5sums 。这两个变量有什么用处呢?那应该先说一下 makepkg 具体都做了什么。
首先,它们通过我们定义的变量,得到软件包的名字,版本号等信息。source 变量是告诉 makepkg 我们打包过程中所需要的文件,它可以是一个本地文件,也可以是一个文件网址。 makepkg 会获取这个文件,验证它的 md5,然后将它放在(链接)目录 src 下。 src 目录是 makepkg 进行一些处理,比如编译,时的工作目录。
接下来, makepkg 依次执行四个函数 prepare() 、 build() 、 check() 、 package() 。 prepare() 一般做编译前的处理,比如解压文件。 build() 进行编译。check() 检查编译结果。最后 package() 进行打包。我们这里的 prepare() 、 build() 、 check() 不进行操作,只输出一行文字提示。
最后,我在函数 package() 中,先新建了一个目录 \({pkgdir}/home` 。这里先说明一下, `makepkg` 会默认定义两个变量:`\){srcdir} 是前面提到的工作路径 src;另一个 \({pkgdir}` 是软件包的目录 `pkg/\){pkgname} 。 \({pkgdir}` 目录就是最终打包成 `.pkg.tar.zst` 的目录。在安装包时,`\){pkgdir} 会被安装对应的目录中。比如我们在这个例子中,将文件 m.vsix 放在 ${pkgdir}/home/m.vsix ,那么我们用 pacman -U 安装时,就会把 m.vsix 复制到 /home/m.vsix 。
运行
makepkg
后,目录结构如下
.
├── m.vsix
├── pkg
│ └── zqwtest
├── PKGBUILD
├── src
│ ├── [Content_Types].xml
│ ├── extension
│ ├── extension.vsixmanifest
│ └── m.vsix -> /home/zqw/pkgtest/m.vsix
└── zqwtest-1.0-1-x86_64.pkg.tar.zst
然后我们运行
sudo pacman -U zqwtest-1.0-1-x86_64.pkg.tar.zst
安装一下,就可以看到,如我们所预期,/home 目录下多了文件 m.vsix:
/home
├── m.vsix
└── zqw
然后我们运行
sudo pacman -R zqwtest
删除软件包,就发现/home 目录下的 m.vsix 被删除了:
/home
└── zqw
更加多的例子可以去 AUR 仓库里随便找一些看。比如 quickapp-ide ,可以直接 clone 下来学习。
deb 包示例:wps-office
我们提前准备好 wps-office 的 deb 格式安装包,并和 PKGBUILD 文件放在一起:
.
├── PKGBUILD
└── wps-office_11.1.0.11698.XA_amd64.deb
PKGBUILD 文件如下:
# This is an example PKGBUILD file. Use this as a start to creating your own,
# and remove these comments. For more information, see 'man PKGBUILD'.
# NOTE: Please fill out the license field for your package! If it is unknown,
# then please put 'unknown'.
# Maintainer: Your Name <youremail@domain.com>
pkgname=wps-office
pkgver=11.1.0.11698
pkgrel=1
arch=('x86_64')
source=("wps-office_11.1.0.11698.XA_amd64.deb")
md5sums=('c80a2b32604cb2a8eb0de456a062fe30')
prepare() {
mv wps-office_11.1.0.11698.XA_amd64.deb ${pkgver}_${pkgver}.deb
ar -x ${pkgver}_${pkgver}.deb
mkdir ${pkgname}-${pkgver}
tar -xf data.tar.xz --directory="${pkgname}-${pkgver}"
}
package() {
cd "$pkgname-$pkgver"
cp -r ./ ${pkgdir}/
}
这里说明一下, deb 包全部解压后会有两个文件夹,control 和 data 。control 类似于我们的 PKGBUILD ,包含了软件的信息和安装过程中进行的一些操作。 data 类似于 {pkgdir} ,包含了需要安装的所有文件。因此我们要做的就是把 deb 全部解压,然后将 data 目录打包。