Go package guidelines

From ArchWiki
Jump to: navigation, search
Package creation guidelines

CLRCrossEclipseFree PascalGNOMEGoHaskellJavaKDEKernelLispMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyVCSWebWine

This document covers standards and guidelines on writing PKGBUILDs for Go.

General guidelines

Package naming

For Go library modules, use go-modulename. Also use the prefix if the package provides a program that is strongly coupled to the Go ecosystem. For other applications, use only the program name.

Note: The package name should be entirely lowercase.

Dependencies

Go packages currently use the vendor/ folder to handle dependencies in projects. These are usually managed by one of several dependency manager projects. If one is used for the package, this step should be performed in the prepare() function of the PKGBUILD.

Dependency managers in the repositories

Prepare

We create a directory $srcdir/gopath for $GOPATH and copy over the source to this directory. It should be noted that this step might not be needed if the project provides a sane Makefile for the project and sets this up.

prepare(){
  mkdir -p "gopath/src/github.com/pkgbuild-example"
  ln -rTsf "${pkgname}-${pkgver}" "gopath/src/github.com/pkgbuild-example/$pkgname"

  # the dependencies can be fetched here if needed
  cd "gopath/src/github.com/pkgbuild-example/$pkgname"
  dep ensure
}

Building

There are two go packages in the repositories that you can build towards; go and go-pie. All packages should preferably be built towards go-pie as this enables us to deliver secure binaries. However, as upstream might have bugs, building towards go should be a last resort.

Flags and build options

Most Makefiles written for go applications do not respect the LDFLAGS provided by build systems, this causes Go binaries to not be compiled with RELRO. This needs to be patched into the Makefile, or the Makefile should be omitted. If there is an Makefile involved, you have 3 options to support RELRO.

  • Patch Makefile
  • Skip Makefile completely and use go build
  • Export GOFLAGS - This is less desirable as we are dropping flags from LDFLAGS.

For reproducible builds it's important that the binaries are stripped of the build path using the -trimpath flags.

# LDFLAGS into the GOFLAGS env variable.
export GOFLAGS="-gcflags=all=-trimpath=${PWD} -asmflags=all=-trimpath=${PWD} -ldflags=-extldflags=-zrelro -ldflags=-extldflags=-znow"

# LDFLAGS defined in go build.
go build \
    -gcflags "all=-trimpath=${PWD}" \
    -asmflags "all=-trimpath=${PWD}" \
    -ldflags "-extldflags ${LDFLAGS}" \
    .
Note: For the sake of brevity, these flags are omitted in the examples below.

Pre 1.11 building

When building go packages with $GOPATH there are a few problems one can encounter. Usually the project delivers a Makefile that can be used and should be used. There are cases where you still need to setup a $GOPATH in the PKGBUILD. The following snippet sets up an appropriate GOPATH inside $srcdir/gopath one can use to build packages. A new directory is used as some go dependency managers does wierd things if it discovers the project in the root of the $GOPATH.

Note: These builds should have $GOPATH stripped from the binary.
prepare(){
  mkdir -p "gopath/src/github.com/pkgbuild-example"
  ln -rTsf "${pkgname}-${pkgver}" "gopath/src/github.com/pkgbuild-example/$pkgname"

  # the dependencies can be fetched here if needed
  cd "gopath/src/github.com/pkgbuild-example/$pkgname"
  dep ensure
}

build(){
  export GOPATH="$srcdir/gopath"
  cd "gopath/src/github.com/pkgbuild-example/$pkgname"
  go install -v .
}

Note that install and build and can do recursive builds if you have a cmd/ subdirectory with multiple binaries: go install -v github.com/pkgbuild-example/cmd/...

Post 1.11 building

Go 1.11 introduces go modules. This omits the need to setup GOPATH and we can build directly in the directory. Projects like these have a go.mod and go.sum file defined.

Note: These builds needs $PWD stripped from the binary.
build(){
  cd "$pkgname-$pkgver"
  go build .
}

Sample PKGBUILDs

Basic PKGBUILD

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

build() {
  cd "$pkgname-$pkgver"
  go build \
    -gcflags "all=-trimpath=${PWD}" \
    -asmflags "all=-trimpath=${PWD}" \
    -ldflags "-extldflags ${LDFLAGS}" \
    -o "$pkgname" .
}

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

PKGBUILD with GOPATH and dep

pkgname=foo
pkgver=0.0.1
pkgrel=1
pkgdesc="Go PKGBUILD Example"
arch=('x86_64' 'i686')
url="http://example.org/$pkgname/"
license=('GPL')
makedepends=('go-pie' 'dep')
source=("http://example.org/$pkgname/$pkgname-$pkgver.tar.gz")
sha256sums=('00112233445566778899aabbccddeeff')

prepare(){
  mkdir -p gopath/src/example.org/foo
  ln -rTsf "${pkgname}-${pkgver}" gopath/src/example.org/foo

  cd "gopath/src/example.org/foo"
  dep ensure
}

build() {
  export GOPATH="$srcdir/gopath"
  cd "$GOPATH/src/example.org/foo
  go install \
    -gcflags "all=-trimpath=${GOPATH}" \
    -asmflags "all=-trimpath=${GOPATH}" \
    -ldflags "-extldflags ${LDFLAGS}" \
    -v ./...
}

check() {
  export GOPATH="$srcdir/gopath"
  cd "$GOPATH/src/example.org/foo
  go test ./...
}

package() {
  install -Dm755 "gopath/bin/$pkgname" "$pkgdir/usr/bin/$pkgname"
}

Example Packages