Go 软件包指南

出自 ArchWiki
Arch 软件包指南

32 位CLRCMakeCrossDKMSEclipseElectronFontFree PascalGNOMEGoHaskellJavaKDE内核模块LispMesonMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyRust - SecurityShellVCSWebWine

本文档涵盖了关于为 Go 编写 PKGBUILD 的标准和指南。

通用指南

软件包命名

如果软件包提供的程序与 Go 生态系统紧密耦合,请使用 go-模块名。对于其他应用程序,仅使用程序名称。

注意: 软件包名称应完全小写。

构建

依赖

Go 1.11 引入了对 go modules 的初始支持。这允许 Go 上游代码声明依赖项并将其固定到给定的项目版本。目前,我们的打包工作利用此功能来 vendor 依赖项。

不使用 go modules 的上游项目

对于不使用 Go modules 的上游代码,存在以下解决方法。考虑向上游提交 issue。

PKGBUILD
url=https://github.com/upstream_user/upstream_project

prepare() {
  cd "$pkgname-$pkgver"
  go mod init "${url#https://}" # strip https:// from canonical URL
  go mod tidy
}
注意: 任何此类 hack 都会使软件包变得不可重现,因为模块会在软件包构建之间发生变化。

标志和构建选项

大多数为 go 应用程序编写的 Makefile 不遵守构建系统提供的构建标志,并且会覆盖 GOFLAGS,这导致 Go 二进制文件在编译时没有启用 RELRO,因为我们需要为编译器设置 CGO_CFLAGSCGO_LDFLAGS。这需要修补到 Makefile 中,或者应该省略 Makefile。

export CGO_CPPFLAGS="${CPPFLAGS}"
export CGO_CFLAGS="${CFLAGS}"
export CGO_CXXFLAGS="${CXXFLAGS}"
export CGO_LDFLAGS="${LDFLAGS}"
export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"

# or alternatively you can define some of these flags from the CLI options
go build \
    -trimpath \
    -buildmode=pie \
    -mod=readonly \
    -modcacherw \
    -ldflags "-linkmode external -extldflags \"${LDFLAGS}\"" \
    .

标志含义

  • -buildmode=pie 启用 PIE 编译 以增强二进制文件的安全性。
  • -trimpath 对于 可重现构建 非常重要,这样就不会嵌入完整的构建路径和模块路径。
  • -mod=readonly 确保模块文件在任何 go 操作中都不会被更新。
  • -modcacherw 不是必需的,但它可以确保 go modules 创建一个可写的路径。默认是只读的。
提示: 当软件包源包含带有 modules.txtvendor 目录时,-mod 标志可以安全地更改为 -mod=vendor
警告: 软件包维护者有责任验证构建标志是否正确传递给编译器。如果有 Makefile,请阅读它。

支持调试包

启用带有源代码列表和正确符号查找的调试包需要对默认构建标志进行一些修改。

  • 移除 -trimpath 以确保源代码路径在二进制文件中被重写
  • -ldflags 中包含 -compressdwarf=false 以确保我们可以解析 DWARF 标头,因为当前的工具不支持压缩标头。
  • 确保 -linkmode=external,因为 go 使用的内部链接器不会将 build-id 嵌入到二进制文件中。
  • 包含 GOPATH="${srcdir}",以便 makepkg 可以包含所有模块的源代码。

以上选项应生成一个带有正确分离符号和源代码列表的调试包,然后可以被调试器拾取。

export CGO_CPPFLAGS="${CPPFLAGS}"
export CGO_CFLAGS="${CFLAGS}"
export CGO_CXXFLAGS="${CXXFLAGS}"
export CGO_LDFLAGS="${LDFLAGS}"
export GOPATH="${srcdir}"
export GOFLAGS="-buildmode=pie -mod=readonly -modcacherw"

go build -ldflags "-compressdwarf=false -linkmode external" .

输出目录

目前有几种方法可以在项目中构建所有 go 二进制文件。

build(){
    cd "$pkgname-$pkgver"
    go build -o output-binary .
}

... 是编译器递归地进入目录并查找所有二进制文件的简写。它可以与输出目录结合使用来构建所有内容。

prepare(){
    cd "$pkgname-$pkgver"
    mkdir -p build
}

build(){
    cd "$pkgname-$pkgver"
    go build -o build ./cmd/...
}

PKGBUILD 示例

pkgname=foo
pkgver=0.0.1
pkgrel=1
pkgdesc='Go PKGBUILD Example'
arch=('x86_64')
url="https://example.org/$pkgname"
license=('GPL')
makedepends=('go')
source=("$url/$pkgname-$pkgver.tar.gz")
sha256sums=('1337deadbeef')

prepare(){
  cd "$pkgname-$pkgver"
  mkdir -p build/
}

build() {
  cd "$pkgname-$pkgver"
  export CGO_CPPFLAGS="${CPPFLAGS}"
  export CGO_CFLAGS="${CFLAGS}"
  export CGO_CXXFLAGS="${CXXFLAGS}"
  export CGO_LDFLAGS="${LDFLAGS}"
  export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
  go build -o build ./cmd/...
}

check() {
  cd "$pkgname-$pkgver"
  go test ./...
}

package() {
  cd "$pkgname-$pkgver"
  install -Dm755 build/$pkgname "$pkgdir"/usr/bin/$pkgname
}

示例软件包