Difference between revisions of "Go package guidelines"

From ArchWiki
Jump to navigation Jump to search
(-fix doesn't work for go test)
 
(113 intermediate revisions by 24 users not shown)
Line 1: Line 1:
[[Category:Package development]]
+
[[Category:Arch package guidelines]]
{{i18n|Go Package Guidelines}}
+
[[ja:Go パッケージガイドライン]]
{{Package Guidelines}}
+
[[pt:Go package guidelines]]
 +
[[zh-hans:Go package guidelines]]
 +
{{Package guidelines}}
  
[[Wikipedia:Go (programming language)|Go]] is well supported on Arch Linux. The {{Pkg|go}} package contains the '''go''' tool (for running {{Ic|go fix}}, {{Ic|go build}} etc) and there is also the {{AUR|gcc-go}} package and {{AUR|go-hg}} in [[AUR]].
+
This document covers standards and guidelines on writing [[PKGBUILD]]s for [[Go]].
  
==General guidelines==
+
== General guidelines ==
  
=== Naming ===
+
=== Package naming ===
* For applications written in Go, use the name of the application as the package name, in lowercase.
 
** Be creative if the name is already taken.
 
* For libraries written in Go, use {{Ic|go-''modulename''}}, in lowercase.
 
* If the name already starts with {{Ic|go-}}, don't call the package {{Ic|go-go-''modulename''}}, but just {{Ic|go-''modulename''}}.
 
* For PKGBUILDS that uses the "go" tool to download the package, only add "-git" to the package name if the ''_gitroot'' and ''_gitname'' variables are used.
 
** Similarly for mercurial packages, only add "-hg" to the package name if the ''_hgroot'' and ''_hgname'' variables are used.
 
** Extend this pattern for other version control systems.
 
** The go tool has its own logic for which branch or tag it should use. See {{Ic|go get --help}}.
 
* Consider adding the name of the author to the package name if there are several applications that are named the same, like {{AUR|dcpu16-kballard}}.
 
** In general, the most popular packages should be allowed to use the shortest or "best" name.
 
  
=== Packaging ===
+
For [[Go]] library modules, use {{ic|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.
* Go applications are either just library files, just executables or both. Choose an appropriate way of packaging them. There are several examples below.
 
* Some Go applications or libraries have not been updated to Go 1 yet.
 
** Running {{Ic|go build -fix}} may often work, but it may have to be fixed by the developer. Report an issue upstream if this is the case.
 
* Several Go projects doesn't have a version number or a license file.
 
** Use license=('unknown') and report an issue to the developer if a license file is missing.
 
** Use version "0.1", "1" or the git-revision (or equivivalent for other version control systems) if the version number is missing.
 
  
==Sample PKGBUILDs==
+
{{Note|The package name should be entirely lowercase.}}
  
===Sample PKGBUILD for an application written in Go===
+
=== Instructions for alternative dependency managers ===
  
{{bc|<nowiki># Maintainer: NAME <EMAIL>
+
This is not needed for Go 1.11 and later, unless an alternative dependency manager is required by the Go project you are packaging.
  
pkgname=PACKAGE NAME
+
When preparing the sources before building, the following may be needed:
pkgver=1.2.3
 
pkgrel=1
 
pkgdesc="PACKAGE DESCRIPTION"
 
arch=('x86_64' 'i686')
 
url="http://SERVER/$pkgname/"
 
license=('MIT')
 
makedepends=('go')
 
options=('!strip' '!emptydirs')
 
source=("http://SERVER/$pkgname/$pkgname-$pkgver.tar.gz")
 
sha256sums=('00112233445566778899aabbccddeeff')
 
  
build() {
+
* Create a directory {{ic|$srcdir/gopath}} for [[Go#$GOPATH|$GOPATH]] and copy over the source to this directory.
  cd "$srcdir/$pkgname-$pkgver"
+
* It should be noted that this step might not be needed if the project provides a {{ic|Makefile}} for the project that sets this up.
  
   source /etc/profile.d/go.sh
+
{{bc|<nowiki>
 +
prepare(){
 +
   mkdir -p gopath/src/github.com/pkgbuild-example
 +
  ln -rTsf $pkgname-$pkgver gopath/src/github.com/pkgbuild-example/$pkgname
  
   msg2 "Compiling..."
+
   # the dependencies can be fetched here if needed
   go build
+
  cd gopath/src/github.com/pkgbuild-example/$pkgname
 +
   dep ensure
 
}
 
}
 +
</nowiki>}}
  
package() {
+
== Building ==
  cd "$srcdir/$pkgname-$pkgver"
 
  
  install -Dm755 "$pkgname-$pkgver" "$pkgdir/usr/bin/$pkgname"
+
There are two go packages in the repositories that you can build towards; {{Pkg|go}} and {{Pkg|go-pie}}. All packages should preferably be built towards {{Pkg|go-pie}} as this enables us to deliver secure binaries. However, as upstream might have bugs, building towards {{Pkg|go}} should be a last resort.
  install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
 
}
 
  
# vim:set ts=2 sw=2 et:</nowiki>}}
+
=== Flags and build options ===
  
Sample packages:
+
Most Makefiles written for go applications do not respect the {{ic|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.
* {{Pkg|gendesk}}
 
* {{AUR|dcpu16}}
 
  
===Sample PKGBUILD for when only a single go file is available===
+
* Patch Makefile
 +
* Skip Makefile completely and use {{ic|go build}}
 +
* Export {{ic|GOFLAGS}} - This is less desirable as we are dropping flags from {{ic|LDFLAGS}}.
  
{{bc|<nowiki># Maintainer: NAME <EMAIL>
+
For [https://reproducible-builds.org/ reproducible builds] it's important that the binaries are stripped of the build path using the {{ic|-trimpath}} flags.
  
pkgname=PACKAGE NAME
+
{{bc|<nowiki>
pkgver=1.2.3
+
export CGO_LDFLAGS="${LDFLAGS}"
pkgrel=1
+
export GOFLAGS="-trimpath"
pkgdesc="PACKAGE DESCRIPTION"
 
arch=('x86_64' 'i686')
 
url="http://SERVER/$pkgname/"
 
license=('GPL3')
 
makedepends=('go')
 
options=('!strip' '!emptydirs')
 
source=("http://SERVER/$pkgname/$pkgname.go")
 
sha256sums=('00112233445566778899aabbccddeeff')
 
  
build() {
+
# or alternatively use LDFLAGS defined in go build.
  cd "$srcdir"
+
go build \
  go build -o "$pkgname"
+
    -trimpath \
}
+
    -ldflags "-extldflags ${LDFLAGS}" \
 
+
    .
package() {
+
</nowiki>}}
  cd "$srcdir"
 
  install -Dm755 "$pkgname" "$pkgdir/usr/bin/$pkgname"
 
}
 
  
# vim:set ts=2 sw=2 et:</nowiki>}}
+
{{Note|For the sake of brevity, these flags are omitted in the examples below.}}
  
Sample packages:
+
=== Modern Go projects (for Go >=1.11) ===
* {{AUR|gorun}}
 
  
===Sample PKGBUILDs for Go libraries===
+
Go 1.11 introduces [https://github.com/golang/go/wiki/Modules go modules]. This omits the need to setup {{ic|GOPATH}} and we can build directly in the directory.
  
{{Note| Not all libraries are upgraded to work with Go 1 yet! If in doubt, try installing with {{Ic|go get}} first, before packaging.}}
+
Projects like these have a {{ic|go.mod}} and a {{ic|go.sum}} file.  
  
==== Using ''go get'' '''(recommended)''' ====
+
{{Note| These builds needs {{ic|$PWD}} stripped from the binary.}}
  
Here's a way that relies on {{Ic|go get}}.
+
{{bc|<nowiki>
 
+
build(){
You probably won't need to modify the build() or package() functions at all, only the variables at the top (pkgname etc).
+
   cd "$pkgname-$pkgver"
 
+
   go build .
If this doesn't work, test with {{Ic|go get}} first.
 
 
 
{{bc|<nowiki># Maintainer: NAME <EMAIL>
 
 
 
pkgname=go-net-hg
 
pkgver=20120515
 
pkgrel=1
 
pkgdesc="Extra network libraries for Go (dict, spdy, websocket)"
 
arch=('x86_64' 'i686')
 
url="http://code.google.com/p/go"
 
license=('BSD')
 
depends=('go')
 
makedepends=('mercurial')
 
options=('!strip' '!emptydirs')
 
_gourl=code.google.com/p/go.net
 
 
 
build() {
 
   cd "$srcdir"
 
  GOPATH="$srcdir" go get -fix -v -x ${_gourl}/...
 
}
 
 
 
check() {
 
  source /etc/profile.d/go.sh
 
  GOPATH="$GOPATH:$srcdir" go test -v -x ${_gourl}/...
 
}
 
 
 
package() {
 
   source /etc/profile.d/go.sh
 
  mkdir -p "$pkgdir/$GOPATH"
 
  cp -Rv --preserve=timestamps ${srcdir}/{src,pkg} "$pkgdir/$GOPATH"
 
 
}
 
}
 +
</nowiki>}}
  
# vim:set ts=2 sw=2 et:</nowiki>}}
+
=== Old Go projects (for Go <1.11) ===
  
Thanks to Rémy Oudompheng‎ for this one.
+
When building go packages with [[Go#$GOPATH|$GOPATH]] there are a few problems one can encounter. Usually the project delivers a {{ic|Makefile}} that can be used and should be used. There are cases where you still need to setup a {{ic|$GOPATH}} in the [[PKGBUILD]]. The following snippet sets up an appropriate {{ic|GOPATH}} inside {{ic|$srcdir/gopath}} one can use to build packages. A new directory is used as some go dependency managers do weird things if they discover the project in the root of the {{ic|$GOPATH}}.
  
====Using ''go get''====
+
{{Note|These builds should have {{ic|$GOPATH}} stripped from the binary.}}
  
Here's another way that relies on {{Ic|go get}}. It can be nice to have if the {{Ic|go get}} method above doesn't work.
+
{{bc|<nowiki>
 
+
prepare(){
You probably won't need to modify the build() or package() functions at all, only the variables at the top (pkgname etc).
+
  mkdir -p gopath/src/github.com/pkgbuild-example
 +
  ln -rTsf $pkgname-$pkgver gopath/src/github.com/pkgbuild-example/$pkgname
 +
  export GOPATH="$srcdir"/gopath
  
If this doesn't work, test with {{Ic|go get}} first.
+
  # the dependencies can be fetched here if needed
 
+
   cd gopath/src/github.com/pkgbuild-example/$pkgname
{{bc|<nowiki># Maintainer: NAME <EMAIL>
+
   dep ensure
 
 
pkgname=go-PACKAGENAME
 
pkgver=1.2.3
 
pkgrel=1
 
pkgdesc="PACKAGE DESCRIPTION"
 
arch=('x86_64' 'i686')
 
url="http://SERVER/$pkgname/"
 
license=('MIT')
 
makedepends=('go' 'git')
 
options=('!strip' '!emptydirs')
 
_gourl=SERVER.NET/PATH/MODULENAME
 
 
 
build() {
 
   cd "$srcdir"
 
  export GOROOT=/usr/lib/go
 
 
 
  rm -rf build
 
  mkdir -p build/go
 
  cd build/go
 
 
 
  for f in "$GOROOT/"*; do
 
    ln -s "$f"
 
  done
 
 
 
  rm pkg
 
  mkdir pkg
 
  cd pkg
 
 
 
  for f in "$GOROOT/pkg/"*; do
 
    ln -s "$f"
 
  done
 
 
 
  platform=`for f in "$GOROOT/pkg/"*; do echo \`basename $f\`; done|grep linux`
 
 
 
   rm "$platform"
 
  mkdir "$platform"
 
  cd "$platform"
 
 
 
  for f in "$GOROOT/pkg/$platform/"*.h; do
 
    ln -s "$f"
 
  done
 
 
 
  export GOROOT="$srcdir/build/go"
 
  export GOPATH="$srcdir/build"
 
 
 
  go get -fix "$_gourl"
 
 
}
 
}
  
package() {
+
build(){
  cd "$srcdir"
+
   export GOPATH="$srcdir"/gopath
 
+
  cd gopath/src/github.com/pkgbuild-example/$pkgname
  source /etc/profile.d/go.sh
+
   go install -v .
   export GOROOT="$GOPATH"
 
 
 
  # Package go package files
 
  for f in "$srcdir/build/go/pkg/"* "$srcdir/build/pkg/"*; do
 
    # If it's a directory
 
    if [ -d "$f" ]; then
 
      cd "$f"
 
      mkdir -p "$pkgdir/$GOROOT/pkg/`basename $f`"
 
      for z in *; do
 
        # Check if the directory name matches
 
        if [ "$z" == `echo $_gourl | cut -d/ -f1` ]; then
 
          cp -r $z "$pkgdir/$GOROOT/pkg/`basename $f`"
 
        fi
 
      done
 
      cd ..
 
    fi
 
  done
 
 
 
  # Package source files
 
  if [ -d "$srcdir/build/src" ]; then
 
    mkdir -p "$pkgdir/$GOROOT/src/pkg"
 
    cp -r "$srcdir/build/src/"* "$pkgdir/$GOROOT/src/pkg/"
 
    find "$pkgdir" -depth -type d -name .git -exec rm -r {} \;
 
   fi
 
 
 
  # Package license (if available)
 
  for f in LICENSE COPYING; do
 
    if [ -e "$srcdir/build/src/$_gourl/$f" ]; then
 
      install -Dm644 "$srcdir/build/src/$_gourl/$f" \
 
        "$pkgdir/usr/share/licenses/$pkgname/$f"
 
    fi
 
  done
 
 
}
 
}
 +
</nowiki>}}
  
# vim:set ts=2 sw=2 et:</nowiki>}}
+
Note that {{ic|install}} and {{ic|build}} and can do recursive builds if you have a {{ic|cmd/}} subdirectory with multiple binaries: {{ic|go install -v github.com/pkgbuild-example/cmd/...}}
 
 
Sample packages:
 
* {{AUR|go-web}}
 
 
 
====Using ''go get'' and ''unionfs-fuse'' ====
 
 
 
Here's a way that relies on {{Ic|go get}} and {{AUR| unionfs-fuse}}.
 
  
You probably won't need to modify the build() or package() functions at all, only the variables at the top (pkgname etc).
+
=== Notes about dependencies and dependency managers ===
  
If this doesn't work, test with {{Ic|go get}} first.
+
Go packages currently use the {{ic|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 [[Creating packages#prepare()|prepare()]] function of the [[PKGBUILD]].
  
{{Note| Improvements are more than welcome, especially for how to umount the unionfs after building.}}
+
Dependencies are normally managed by the {{ic|go mod}} command, that comes with Go 1.11 or later.
  
{{Warning| This PKGBUILD may try to install .a files for libraries that are already installed, causing file conflicts, or not package libraries that are already installed.}}
+
There are also alternative dependency managers:
  
{{Note| This method is not recommended!}}
+
* {{Pkg|dep}}
 +
* {{Pkg|godep}}
 +
* {{Pkg|glide}}
  
{{Note|This way is deprecated and won't work after the latest update of Go.}}
+
== Sample PKGBUILDs ==
  
Thanks to Jens Staal for this one.
+
=== Basic PKGBUILD ===
  
 
{{bc|<nowiki>
 
{{bc|<nowiki>
# Maintainer: NAME <EMAIL>
+
pkgname=foo
 
+
pkgver=0.0.1
pkgname=go-PACKAGE NAME
 
pkgver=20120417
 
 
pkgrel=1
 
pkgrel=1
pkgdesc="PACKAGE DESCRIPTION"
+
pkgdesc='Go PKGBUILD Example'
arch=('i686' 'x86_64')
+
arch=('x86_64')
url="https://SERVER/WEBPAGE"
+
url="https://example.org/$pkgname"
license=('MIT')
+
license=('GPL')
depends=('some_random_library' 'go')
+
makedepends=('go-pie')
makedepends=('git' 'unionfs-fuse')
+
source=("$url/$pkgname-$pkgver.tar.gz")
options=('!strip' '!emptydirs')
+
sha256sums=('1337deadbeef')
_gourl=github.com/user/project
 
  
 
build() {
 
build() {
   cd "$srcdir"
+
   cd $pkgname-$pkgver
   source /etc/profile.d/go.sh
+
   go build \
 
+
    -trimpath \
  rm -rf build
+
    -ldflags "-extldflags $LDFLAGS" \
  mkdir -p build/go
+
    -o $pkgname .
  rm -rf temp
 
  mkdir -p temp
 
  #starting off fresh
 
 
 
  msg2 "Setting up union mount"
 
  unionfs -o cow -o umask=000 $srcdir/temp=RW:$GOROOT=RO $srcdir/build/go
 
 
 
  cd build/go
 
 
 
  export GOROOT="$srcdir/build/go"
 
  export GOPATH="$srcdir/build"
 
 
 
  go get -fix "$_gourl"
 
 
 
 
}
 
}
  
 
package() {
 
package() {
   cd "$srcdir"
+
   cd $pkgname-$pkgver
  source /etc/profile.d/go.sh
+
   install -Dm755 $pkgname "$pkgdir"/usr/bin/$pkgname
 
 
  # Package go package files
 
  for f in "$srcdir/build/go/pkg/"* "$srcdir/build/pkg/"*; do
 
    # If it's a directory
 
    if [ -d "$f" ]; then
 
      cd "$f"
 
      mkdir -p "$pkgdir/$GOROOT/pkg/`basename $f`"
 
      for z in *; do
 
        # Check if the directory name matches
 
        if [ "$z" == `echo $_gourl | cut -d/ -f1` ]; then
 
          cp -r $z "$pkgdir/$GOROOT/pkg/`basename $f`"
 
        fi
 
      done
 
      cd ..
 
    fi
 
   done
 
 
 
  #msg2 "Unmounting union mount"
 
  #  fusermount -u $srcdir/build/go 
 
 
 
  # Somehow fusermount -u fails, so we are now left with a mounted directory after build
 
  # scary and ugly...
 
 
 
  # Package source files
 
  if [ -d "$srcdir/build/src" ]; then
 
    mkdir -p "$pkgdir/$GOROOT/src/pkg"
 
    cp -r "$srcdir/build/src/"* "$pkgdir/$GOROOT/src/pkg/"
 
    find "$pkgdir" -depth -type d -name .git -exec rm -r {} \;
 
  fi
 
 
 
  msg2 "Package successfully built."
 
  msg "IMPORTANT: Run 'fusermount -u src/build/go' to unmount the go directory!"
 
 
}
 
}
 +
</nowiki>}}
  
# vim:set ts=2 sw=2 et:</nowiki>}}
+
=== PKGBUILD with GOPATH and dep ===
  
Temporary solution for library issue + packaging of binaries:
 
Add the following at the end of package():
 
 
{{bc|<nowiki>
 
{{bc|<nowiki>
# remove libdir in pkgdir
+
pkgname=foo
rm -rf "$pkgdir/usr/lib"
+
pkgver=0.0.1
# Package executables
 
if [ -e "$srcdir/build/bin/$pkgname" ]; then
 
  install -Dm755 "$srcdir/build/bin/$pkgname" \
 
    "$pkgdir/usr/bin/$pkgname"
 
fi
 
</nowiki>}}
 
 
 
Sample packages:
 
* {{AUR|go-tecla}}
 
* {{AUR|oh}}
 
* {{AUR|mdtwm}}
 
* {{AUR|gich}}
 
 
 
====For libraries (not executables) released as tarballs====
 
 
 
{{bc|<nowiki># Maintainer: NAME <EMAIL>
 
 
 
pkgname=go-PACKAGE NAME
 
pkgver=1.2.3
 
 
pkgrel=1
 
pkgrel=1
pkgdesc='Example library for Go package creation guidelines'
+
pkgdesc='Go PKGBUILD Example'
arch=('i686' 'x86_64')
+
arch=('x86_64')
url='http://bitbucket.org/vlasovskikh/go-aur-example'
+
url='https://example.org/$pkgname'
license=('MIT')
+
license=('GPL')
makedepends=('go' 'libSOMELIBRARY')
+
makedepends=('go-pie' 'dep')
options=('!strip')
+
source=("$url/$pkgname-$pkgver.tar.gz")
source=("https://bitbucket.org/vlasovskikh/go-aur-example/downloads/$pkgname-$pkgver.tar.gz")
+
sha256sums=('1337deadbeef')
md5sums=('810311689a73879a96bc9b29ebbfc347')
 
  
build() {
+
prepare(){
   remoteprefix="bitbucket.org/vlasovskikh/$pkgname"
+
   mkdir -p gopath/src/example.org/foo
  libname="SOMELIBRARY"
+
   ln -rTsf $pkgname-$pkgver gopath/src/example.org/foo
  cd "$srcdir"
+
   export GOPATH="$srcdir"/gopath
  install -d "src/$remoteprefix"
+
   cd gopath/src/example.org/foo
   cp -aT "$pkgname-$pkgver" "src/$remoteprefix"
+
   dep ensure
   GOPATH="$srcdir" go install "$remoteprefix/$libname"
 
   destdir="$pkgdir/usr/lib/go"
 
  install -d "$destdir" "$destdir/src/pkg"
 
  cp -aT pkg "$destdir/pkg"
 
   cp -aT src "$destdir/src/pkg"
 
 
}
 
}
 
# vim:set ts=2 sw=2 et:
 
</nowiki>}}
 
 
Thanks to Andrey Vlasovskikh for this one.
 
 
See also:
 
* https://bitbucket.org/vlasovskikh/go-aur-example
 
 
====For hg packages====
 
 
{{bc|<nowiki># Maintainer: NAME <EMAIL>
 
 
name=go-PACKAGE NAME
 
pkgname=$name-hg
 
pkgver=1.2.3
 
pkgrel=1
 
pkgdesc='Example library for Go package creation guidelines'
 
arch=('i686' 'x86_64')
 
url='http://bitbucket.org/vlasovskikh/go-aur-example'
 
license=('MIT')
 
makedepends=('go' 'libyaml')
 
options=('!strip')
 
_hgroot="https://bitbucket.org/vlasovskikh"
 
_hgrepo="$name"
 
  
 
build() {
 
build() {
   remoteprefix="bitbucket.org/vlasovskikh/$name"
+
   export GOPATH="$srcdir"/gopath
  libname="yaml"
+
   cd gopath/src/example.org/foo
   cd "$srcdir"
+
   go install \
  install -d "src/$remoteprefix"
+
    -trimpath \
  cp -aT "$name" "src/$remoteprefix"
+
    -ldflags "-extldflags $LDFLAGS" \
  GOPATH="$srcdir" go install "$remoteprefix/$libname"
+
    -v ./...
   destdir="$pkgdir/usr/lib/go"
 
  install -d "$destdir" "$destdir/src/pkg"
 
  cp -aT pkg "$destdir/pkg"
 
  cp -aT src "$destdir/src/pkg"
 
}
 
 
 
# vim:set ts=2 sw=2 et:
 
</nowiki>}}
 
 
 
Thanks to Andrey Vlasovskikh for this one. ''libyaml'' is just an example of a dependency.
 
 
 
See also:
 
* https://bitbucket.org/vlasovskikh/go-aur-example
 
 
 
===Sample PKGBUILDs for Go libraries that also includes executables===
 
 
 
====Using ''go get'' '''(recommended)''' ====
 
 
 
{{bc|<nowiki># Maintainer: NAME <EMAIL>
 
 
 
pkgname=codesearch
 
pkgver=20120515
 
pkgrel=1
 
pkgdesc="Code indexing and search written in Go"
 
arch=('x86_64' 'i686')
 
url="http://code.google.com/p/codesearch"
 
license=('BSD')
 
depends=('go')
 
makedepends=('mercurial')
 
options=('!strip' '!emptydirs')
 
_gourl=code.google.com/p/codesearch
 
 
 
build() {
 
  cd "$srcdir"
 
  GOPATH="$srcdir" go get -fix -v -x ${_gourl}/...
 
 
}
 
}
  
 
check() {
 
check() {
   source /etc/profile.d/go.sh
+
   export GOPATH="$srcdir"/gopath
   GOPATH="$GOPATH:$srcdir" go test -v -x ${_gourl}/...
+
  cd gopath/src/example.org/foo
 +
   go test ./...
 
}
 
}
  
 
package() {
 
package() {
  source /etc/profile.d/go.sh
+
   install -Dm755 gopath/bin/$pkgname "$pkgdir"/usr/bin/$pkgname
  mkdir -p "${pkgdir}/usr/bin"
 
   install -p -m755 ${srcdir}/bin/* "$pkgdir/usr/bin"
 
 
 
  mkdir -p "$pkgdir/$GOPATH"
 
  cp -Rv --preserve=timestamps ${srcdir}/{src,pkg} "$pkgdir/$GOPATH"
 
}
 
 
 
# vim:set ts=2 sw=2 et:</nowiki>}}
 
 
 
Thanks to Rémy Oudompheng‎ for this one.
 
 
 
====Using ''go get''====
 
 
 
Here's a way that relies on {{Ic|go get}}.
 
 
 
You probably won't need to modify the build() or package() functions at all, only the variables at the top (pkgname etc).
 
 
 
If this doesn't work, test with {{Ic|go get}} first.
 
 
 
{{Note|Improvements are more than welcome.}}
 
 
 
{{Note|This way is deprecated and won't work after the latest update of Go.}}
 
 
 
{{bc|<nowiki># Maintainer: NAME <EMAIL>
 
 
 
pkgname=PACKAGE NAME
 
pkgver=1.2.3
 
pkgrel=1
 
pkgdesc="PACKAGE DESCRIPTION"
 
arch=('x86_64' 'i686')
 
url="http://SERVER/$pkgname/"
 
license=('MIT')
 
makedepends=('go' 'git')
 
options=('!strip' '!emptydirs')
 
_gourl=SERVER.NET/PATH/MODULENAME
 
 
 
build() {
 
  cd "$srcdir"
 
 
 
  GOROOT=/usr/lib/go #source /etc/profile.d/go.sh
 
 
 
  rm -rf build
 
  mkdir -p build/go
 
  cd build/go
 
 
 
  for f in "$GOROOT/"*; do
 
    ln -s "$f"
 
  done
 
 
 
  rm pkg
 
  mkdir pkg
 
  cd pkg
 
 
 
  for f in "$GOROOT/pkg/"*; do
 
    ln -s "$f"
 
  done
 
 
 
  platform=`for f in "$GOROOT/pkg/"*; do echo \`basename $f\`; done|grep linux`
 
 
 
  rm "$platform"
 
  mkdir "$platform"
 
  cd "$platform"
 
 
 
  for f in "$GOROOT/pkg/$platform/"*.h; do
 
    ln -s "$f"
 
  done
 
 
 
  export GOROOT="$srcdir/build/go"
 
  export GOPATH="$srcdir/build"
 
 
 
  go get -fix "$_gourl"
 
 
 
  # Prepare executable
 
  if [ -d "$srcdir/build/src" ]; then
 
    cd "$srcdir/build/src/$_gourl"
 
    go build -o "$srcdir/build/$pkgname"
 
  else
 
    echo 'Old sources for a previous version of this package are already present!'
 
    echo 'Build in a chroot or uninstall the previous version.'
 
    return 1
 
  fi
 
}
 
 
 
package() {
 
  cd "$srcdir"
 
 
 
  GOROOT=/usr/lib/go #source /etc/profile.d/go.sh
 
 
 
  # Package go package files
 
  for f in "$srcdir/build/go/pkg/"* "$srcdir/build/pkg/"*; do
 
    # If it's a directory
 
    if [ -d "$f" ]; then
 
      cd "$f"
 
      mkdir -p "$pkgdir/$GOROOT/pkg/`basename $f`"
 
      for z in *; do
 
        # Check if the directory name matches
 
        if [ "$z" == `echo $_gourl | cut -d/ -f1` ]; then
 
          cp -r $z "$pkgdir/$GOROOT/pkg/`basename $f`"
 
        fi
 
      done
 
      cd ..
 
    fi
 
  done
 
 
 
  # Package source files
 
  if [ -d "$srcdir/build/src" ]; then
 
    mkdir -p "$pkgdir/$GOROOT/src/pkg"
 
    cp -r "$srcdir/build/src/"* "$pkgdir/$GOROOT/src/pkg/"
 
    find "$pkgdir" -depth -type d -name .git -exec rm -r {} \;
 
  fi
 
 
 
  # Package license (if available)
 
  for f in LICENSE COPYING; do
 
    if [ -e "$srcdir/build/src/$_gourl/$f" ]; then
 
      install -Dm644 "$srcdir/build/src/$_gourl/$f" \
 
        "$pkgdir/usr/share/licenses/$pkgname/$f"
 
    fi
 
  done
 
 
 
  # Package executables
 
  if [ -e "$srcdir/build/$pkgname" ]; then
 
    install -Dm755 "$srcdir/build/$pkgname" \
 
      "$pkgdir/usr/bin/$pkgname"
 
  fi
 
 
}
 
}
 +
</nowiki>}}
  
# vim:set ts=2 sw=2 et:</nowiki>}}
+
== Example packages ==
  
Sample packages:
+
* {{Pkg|dep}}
* {{AUR|dcpu16}}
+
* {{Pkg|gopass}}
 +
* {{Pkg|delve}}
 +
* {{Pkg|gitea}}
 +
* {{Pkg|git-lfs}}

Latest revision as of 17:04, 3 November 2019

Package creation guidelines

32-bitCLRCrossEclipseElectronFree PascalGNOMEGoHaskellJavaKDEKernelLispMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyRustVCSWebWine

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.

Instructions for alternative dependency managers

This is not needed for Go 1.11 and later, unless an alternative dependency manager is required by the Go project you are packaging.

When preparing the sources before building, the following may be needed:

  • 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 Makefile for the project that 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.

export CGO_LDFLAGS="${LDFLAGS}"
export GOFLAGS="-trimpath"

# or alternatively use LDFLAGS defined in go build.
go build \
    -trimpath \
    -ldflags "-extldflags ${LDFLAGS}" \
    .
Note: For the sake of brevity, these flags are omitted in the examples below.

Modern Go projects (for Go >=1.11)

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 a go.sum file.

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

Old Go projects (for Go <1.11)

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 do weird things if they discover 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
  export GOPATH="$srcdir"/gopath

  # 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/...

Notes about dependencies and dependency managers

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.

Dependencies are normally managed by the go mod command, that comes with Go 1.11 or later.

There are also alternative dependency managers:

Sample PKGBUILDs

Basic 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-pie')
source=("$url/$pkgname-$pkgver.tar.gz")
sha256sums=('1337deadbeef')

build() {
  cd $pkgname-$pkgver
  go build \
    -trimpath \
    -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')
url='https://example.org/$pkgname'
license=('GPL')
makedepends=('go-pie' 'dep')
source=("$url/$pkgname-$pkgver.tar.gz")
sha256sums=('1337deadbeef')

prepare(){
  mkdir -p gopath/src/example.org/foo
  ln -rTsf $pkgname-$pkgver gopath/src/example.org/foo
  export GOPATH="$srcdir"/gopath
  cd gopath/src/example.org/foo
  dep ensure
}

build() {
  export GOPATH="$srcdir"/gopath
  cd gopath/src/example.org/foo
  go install \
    -trimpath \
    -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