Go 语言软件打包准则 - Arch Linux 中文维基

跳转到内容

# Go 语言软件打包准则

来自 Arch Linux 中文维基
Arch 打包准则

32 位 – 安全 – CLR – CMake – DKMS – Eclipse – Electron – Free Pascal – GNOME – Go – Haskell – Java – 交叉编译工具 – KDE – Lisp – Meson – MinGW – 内核模块 – Node.js – Nonfree – OCaml – Perl – PHP – Python – R – Ruby – Rust – Shell – VCS – Web – Wine – 字体

翻译状态：

- 本文（或部分内容）译自 Go package guidelines，最近一次同步于 2026-02-16，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

本文涵盖了为 Go 软件包编写 PKGBUILD 时须遵循的标准和指引。

## 通用准则

### 命名

如果软件包提供的程序与 Go 生态存在强关联，请使用 `go-模块名称`。对于其它应用，请仅使用程序名。

注意：软件包名称只允许使用小写字符。

## 构建

### 依赖

Go 1.11 为 go 模块提供了初步支持，使得上游的 Go 代码可以声明依赖并将其固定到特定项目版本。目前，我们的打包工作利用了这一点来满足 go 模块依赖关系。

#### 上游项目不使用 go 模块

对于不使用 Go 模块的上游代码，可以使用以下变通方法，并请考虑向上游提出 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
    }

注意：由于模块可能会在软件的各次构建期间出现变化，该方法将导致软件包的构建不具有可复现性。

#### 上游项目使用 go 模块

go 默认会使用 `GOPATH` 来下载和存放 go 模块，并导致用户的 `~/go` 目录大小增加。

为将所有 go 模块保留在构建环境中，可以在准备步骤（prepare）中配置 `GOPATH="${srcdir}"`，然后将 go 模块下载到软件包源码目录（srcdir）中：

    PKGBUILD

    prepare() {
      cd "${pkgname}-${pkgver}"
      export GOPATH="${srcdir}"
      go mod download -modcacherw
    }

### 构建标志和选项

Go 不会自动将系统的构建标志（例如 `CFLAGS` 和 `LDFLAGS`）传递给 C 工具链。为使用 RELRO 和其它加固标志构建 Go 二进制文件，需要在构建环境中显式指定 `CGO_CFLAGS` 和 `CGO_LDFLAGS` 等相关变量：

    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 \
        -trimpath \
        -buildmode=pie \
        -mod=readonly \
        -modcacherw \
        -ldflags "-linkmode external -extldflags \"${LDFLAGS}\"" \
        .

注意：大多数用于 Go 应用的 Makefile 会覆盖掉 `GOFLAGS`，不会将上述标志传递给编译器。如果上游项目使用了 Makefile，则需要通过补丁使其遵循传入的标志，或是直接调用 `go build` 来绕过该文件。

#### 标志功能

- `-buildmode=pie` 会启用 PIE 编译，用于加固二进制文件。
- `-trimpath` 用于可复现构建，可以防止嵌入完整构建路径和模块路径。
- `-mod=readonly` 可以保证模块文件不会在 go 的任何操作中被更改。
- `-modcacherw` 不重要，但是可以保证 go 模块会创建一个可写的路径。默认只会创建一个只读的路径。

提示：如果软件的 `modules.txt` 中包含了一个 `vendor` 目录，那可以将 `-mod` 标志修改为 `-mod=vendor`。
警告：包维护者需要确保构建标志被正确传递给了编译器，请务必检查源码的 `Makefile`。

#### 支持调试包

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

- 删除 `-trimpath` 来确保源码路径被写入二进制文件。
- 由于目前的工具不支持压缩的 DWARF 头，因此需要在 `-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
    }

## 软件包示例

- podman包
- k9s包
- helm包

分类：​

- Arch 打包准则

Go 语言软件打包准则
添加话题