概述
参考文档:
PKGBUILD 是
makepkg读取的构建脚本:声明元信息、源码与依赖,再用几个函数把源码构建并装进伪根目录,产物是可直接安装的.pkg.tar.zst全流程:
flowchart LR A["PKGBUILD"] --> B["makepkg"] B --> C["下载 source 并校验"] C --> D["prepare / build / check"] D --> E["package() 装进 pkgdir"] E --> F[".pkg.tar.zst"] F --> G["pacman -U 或提交 AUR"]
包管理器侧的背景见Linux 发行版与包管理器
快速开始
一个 PKGBUILD 文件独占一个目录,源码与产物都落在这里:
console$ sudo pacman -S base-devel # 构建工具链与依赖安装工具 $ cd hello # 目录里只有一个 PKGBUILD $ makepkg -si # 补依赖、构建、装包一次完成
变量
最小可用的 PKGBUILD:
bashpkgname=hello pkgver=1.0 pkgrel=1 pkgdesc="简单的示例包" arch=(x86_64) url="https://example.com/hello" license=(GPL-3.0-only) depends=(glibc) source=("https://example.com/hello-$pkgver.tar.gz") sha256sums=('SKIP') build() { cd "$pkgname-$pkgver" ./configure --prefix=/usr make } package() { cd "$pkgname-$pkgver" make DESTDIR="$pkgdir" install }版本三元组决定升级判定:
pkgver: 上游版本pkgrel: 同一版本的构建序号,改了 PKGBUILD 重打就加它epoch: 前缀权重,只在版本号比较逻辑倒退时用(如1.0到0.9),写成epoch=1后包版本变成1:0.9
其余高频变量:
pkgdesc一句话描述、arch=(any)表示架构无关(脚本与数据包)、groups把包归组、install=指定.install维护脚本数组既能写成
depends=(a b),也能多行续写,元素含空格或版本约束时必须整体引号
依赖与关系
- 四种依赖按阶段分:
depends: 运行时依赖,装包时一并安装makedepends: 仅构建期需要,makepkg -s临时装上checkdepends: 仅check()测试需要optdepends: 可选功能,格式是"包名: 用途说明",pacman 装包时会展示
- 关系三元组决定与其他包的交互:
provides: 本包等价于哪些包,如provides=(libfoo)让依赖libfoo的包得到满足conflicts: 不能共存的包replaces: 安装时替换掉的历史包
- 版本约束用比较符写在元素里:
depends=("gcc>=13"),约束的是"包版本"而非上游源码版本
构建函数
四个函数按序执行,只有
package()必写:prepare(): 源码整备,最典型是打补丁:bashprepare() { cd "$pkgname-$pkgver" patch -Np1 < ../fix-path.patch # 补丁列进 source,自动落在 src/ 里 }build(): 编译,禁止在这里执行 install,产物只留在src/里check(): 跑测试套件,makepkg --nocheck可跳过package(): 把文件装进$pkgdir,这是唯一允许写文件的目录:bashpackage() { cd "$pkgname-$pkgver" make DESTDIR="$pkgdir" install # 惯用的伪根安装 install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md" }
铁律:所有安装路径必须以
$pkgdir开头,碰/usr真路径等于污染构建机目录约定:
$srcdir是解包与构建的工作区,$pkgdir映射为目标系统根,引用时一律带双引号防空格属主与权限:打包时统一按 root 收编,不需要也不应该 chown
源与校验和
source数组支持混排:- 远程 URL:
makepkg自动下载 - 本地文件:与 PKGBUILD 同目录,补丁必须列进来才会出现在
$srcdir - 重命名:
新名::url避免多个同名文件互相覆盖 - git 源:
git+https://...#tag=v1.0,可用tag=、branch=、commit=锚定
- 远程 URL:
校验数组与
source一一对应:sha256sums最常用,不确定的先写SKIP再补补齐校验和的姿势:
console$ updpkgsums # 自动下载并更新 PKGBUILD 里的值 $ makepkg -g >> PKGBUILD # 等价的手动办法git 源的版本号靠
pkgver()在构建时推导:bashpkgver() { cd "$pkgname" git describe --long --tags | sed 's/^v//;s/-/.r/;s/-/./' }- 产出形如
1.2.3.r4.5abcde6的版本,配合pkgrel=1使用,每次提交变化版本自动前进
- 产出形如
打包细节
backup=(etc/hello.conf): 标记配置文件,升级时保留旧文件,冲突内容落成.pacnewoptions=(): 开关打包行为,常见!strip保留调试符号、emptydirs保留空目录、zipman压缩 man 手册.install脚本挂在install=上,可用钩子:pre_install、post_install、pre_upgrade、post_upgrade、pre_remove、post_remove,参数依次是新版本、旧版本- 警告信息用
post_upgrade里的printf输出,不要往 README 塞提示,用户只看得到终端
工具链
makepkg常用开关:console$ makepkg -s # 缺 makedepends 就装 $ makepkg -i # 构建完直接安装 $ makepkg -o # 只解包不构建,调试 prepare 用 $ makepkg -R # 不重新构建,仅重跑打包阶段 $ makepkg --printsrcinfo > .SRCINFO # 生成 AUR 需要的元数据namcap PKGBUILD与namcap *.pkg.tar.zst: 静态检查缺失依赖、冗余依赖与权限问题,提交 AUR 前必跑pkgctl(devtools): 官方仓库维护者的工具链,pkgctl build在干净 chroot 里构建,消除"我这能编"的环境差异AUR 提交形态是 git 仓库:PKGBUILD 与
.SRCINFO必须成对提交,CachyOS 之类衍生发行版的仓库同样消费这套格式,见CachyOS 相比 Arch 的变化