概述

  • 参考文档:

  • 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:

    bash
    pkgname=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(): 源码整备,最典型是打补丁:

      bash
      prepare() {
        cd "$pkgname-$pkgver"
        patch -Np1 < ../fix-path.patch   # 补丁列进 source,自动落在 src/ 里
      }
    • build(): 编译,禁止在这里执行 install,产物只留在src/里

    • check(): 跑测试套件,makepkg --nocheck可跳过

    • package(): 把文件装进$pkgdir,这是唯一允许写文件的目录:

      bash
      package() {
        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=锚定
  • 校验数组与source一一对应:sha256sums最常用,不确定的先写SKIP再补

  • 补齐校验和的姿势:

    console
    $ updpkgsums                       # 自动下载并更新 PKGBUILD 里的值
    $ makepkg -g >> PKGBUILD           # 等价的手动办法
    
  • git 源的版本号靠pkgver()在构建时推导:

    bash
    pkgver() {
      cd "$pkgname"
      git describe --long --tags | sed 's/^v//;s/-/.r/;s/-/./'
    }
    • 产出形如1.2.3.r4.5abcde6的版本,配合pkgrel=1使用,每次提交变化版本自动前进

打包细节

  • backup=(etc/hello.conf): 标记配置文件,升级时保留旧文件,冲突内容落成.pacnew
  • options=(): 开关打包行为,常见!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 的变化