「Go パッケージガイドライン」の版間の差分

提供: ArchWiki
ナビゲーションに移動 検索に移動
(翻訳)
 
(情報を更新)
2行目: 2行目:
 
[[en:Go package guidelines]]
 
[[en:Go package guidelines]]
 
{{Package Guidelines}}
 
{{Package Guidelines}}
  +
このドキュメントでは、[[Go]] の [[PKGBUILD]] の作成に関する標準とガイドラインについて説明します。
   
  +
== 一般的なガイドライン ==
[[Wikipedia:ja:Go (プログラミング言語)|Go]] は Arch Linux で十分にサポートされています。
 
   
  +
=== パッケージの命名 ===
{{Pkg|go}} パッケージには ({{Ic|go fix}}, {{Ic|go build}} などを実行するための) '''go''' ツールが含まれています。また {{Pkg|gcc-go}} は {{Ic|gccgo}} を提供します。
 
   
  +
パッケージが Go エコシステムと強く結合したプログラムを提供する場合は、{{ic|go-''modulename''}} を使用します。他のアプリケーションの場合は、プログラム名のみを使用します。
[https://github.com/seletskiy/go-makepkg go-makepkg] ツールを使うことで手動で PKGBUILD ファイルを作成しなくても簡単に Go のプログラムをパッケージ化できます。
 
   
  +
{{Note|パッケージ名は完全に小文字にする必要があります}}
== 一般的なガイドライン ==
 
   
=== 命名 ===
 
* Go で書かれたアプリケーションの場合、パッケージ名はアプリケーションの名前にしてください (小文字)。
 
** パッケージ名が既に使われている場合は何か別の名前を考案してください。
 
* Go で書かれたライブラリの場合、{{Ic|go-''modulename''}} という名前にしてください (小文字)。
 
** ライブラリの名前に {{Ic|go-}} と付いている場合は、パッケージ名を {{Ic|go-''go-modulename''}} とせず {{Ic|go-''modulename''}} としてください。
 
* パッケージをダウンロードするのに "go" ツールを使用する PKGBUILD の場合、tarball やタグ付きリリースからビルドされない場合にのみパッケージ名に "-git" を追加してください (trunk/HEAD からビルドされる場合)。
 
** mercurial のパッケージの場合でも、同じようにリリース版でないときにパッケージ名に "-hg" と追加してください。
 
** 他のバージョン管理システムでも同じようにしてください。
 
** どのブランチやタグを使用するべきか決めるときに go ツールには独自のロジックがあります。{{Ic|go get --help}} を見てください。
 
* 同じ名前のアプリケーションが複数ある場合はパッケージ名に開発者の名前を追加すると良いでしょう。例: {{AUR|dcpu16-kballard}}。
 
** 一般的には、最も人気のあるパッケージが一番短くてわかりやすい名前を使用するべきです。
 
* プロジェクトの公式リリースが存在しない場合にパッケージ名に ({{Ic|-hg}}, {{Ic|-git}}, {{Ic|-svn}} などの) 文字列を付け加えるかは任意です。VCS からパッケージがダウンロードされる場合は付けるのが普通ですが、Go のプロジェクトの多くにはリリース tarball が存在せず、''trunk'' でない場合に公式リリースとしてブランチやタグが付けられるリポジトリしかありません。また、''Go'' のモジュールをインストールするときに使用する「公式」の手段である {{Ic|go get}} はリポジトリを直接使用します。
 
   
=== パッケージ ===
+
== ビルド ==
* Go プロジェクトはライブラリファイルか実行ファイル、あるいはその両方です。適切な方法でパッケージ化してください。以下では複数の例を示します。
 
* Go アプリケーションやライブラリの中には最新バージョンの Go にあわせて更新されていないものがあります。
 
** {{Ic|go build -fix}} で大抵は動作しますが、修正は開発者が行うべきです。問題がある場合は上流に報告してください。
 
* Go プロジェクトの中にはバージョン番号やライセンスファイルを持たないものがあります。
 
** ライセンスファイルが存在しない場合は license=('unknown') を使用して開発者に問題を報告してください。
 
** バージョン番号が存在しない場合は "0.1", "1" あるいは git のリビジョン (あるいは他のバージョン管理システムの同等のバージョン) を使用してください。
 
** もしくは、バージョン番号として日付を使ってください。形式: {{Ic|YYYYMMDD}}。
 
* Go アプリケーションは基本的に静的コンパイルされるため、Go ライブラリをパッケージ化する理由はあまり多くありません。
 
   
== サンプル PKGBUILD ==
+
=== 依存関係 ===
   
  +
Go 1.11 では、[https://github.com/golang/go/wiki/Modules go modules] の初期サポートが導入されました。これにより、Go のアップストリームコードで依存関係を宣言し、特定のプロジェクトバージョンに固定できるようになります。現在、私たちのパッケージ化作業では、これをベンダー依存関係に利用しています。
=== Go で書かれたアプリケーションのサンプル PKGBUILD ===
 
   
  +
==== Go モジュールを使用しないアップストリームプロジェクト ====
{{bc|<nowiki># Maintainer: NAME <EMAIL>
 
   
  +
Go モジュールを使用しないアップストリームコードの場合は、次の回避策があります。アップストリームで問題を提出することを検討してください。
pkgname=PACKAGE NAME
 
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')
 
   
  +
{{hc|PKGBUILD|2=
build() {
 
  +
<nowiki>
  +
url=https://github.com/upstream_user/upstream_project
  +
  +
prepare() {
 
cd "$pkgname-$pkgver"
 
cd "$pkgname-$pkgver"
  +
go mod init "${url#https://}" # strip https:// from canonical URL
 
go build
+
go mod tidy
 
}
 
}
  +
</nowiki>
  +
}}
   
  +
{{Note|このようなハッキングを行うと、パッケージのビルド間でモジュールが変更されるため、パッケージが再現できなくなります。}}
package() {
 
cd "$pkgname-$pkgver"
 
   
  +
=== フラグとビルドオプション ===
install -Dm755 "$pkgname-$pkgver" "$pkgdir/usr/bin/$pkgname"
 
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
 
}
 
   
  +
go アプリケーション用に書かれたほとんどの Makefile は、{{ic|GOFLAGS}} を上書きしたり、ビルドシステムが提供するビルドフラグを尊重していません。このため、コンパイラのために {{ic|CGO_CFLAGS}} と {{ic|CGO_LDFLAGS}} が設定されている必要があるので、Go バイナリが [https://www.redhat.com/en/blog/hardening-elf-binaries-using-relocation-read-only-relro RELRO] でコンパイルされません。これを Makefile にパッチするか、Makefile を省略する必要があります。
# vim:set ts=2 sw=2 et:</nowiki>}}
 
   
  +
{{bc|1=
==== サンプルパッケージ ====
 
  +
export CGO_CPPFLAGS="${CPPFLAGS}"
* {{Pkg|gendesk}}
 
  +
export CGO_CFLAGS="${CFLAGS}"
* {{AUR|dcpu16}}
 
  +
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
=== ソースファイルがひとつしかない場合のサンプル PKGBUILD ===
 
  +
go build \
  +
-trimpath \
  +
-buildmode=pie \
  +
-mod=readonly \
  +
-modcacherw \
  +
-ldflags "-linkmode external -extldflags \"${LDFLAGS}\"" \
  +
.
  +
}}
   
  +
==== Flag meaning ====
{{bc|<nowiki># Maintainer: NAME <EMAIL>
 
   
  +
* {{ic|1=-buildmode=pie}} enables [[Wikipedia:Position-independent code|PIE compilation]] for binary harderning.
pkgname=PACKAGE NAME
 
  +
* {{ic|-trimpath}} important for [[reproducible builds]] so full build paths and module paths are not embedded.
pkgver=1.2.3
 
  +
* {{ic|1=-mod=readonly}} ensure the module files are not updated in any go actions.
pkgrel=1
 
  +
* {{ic|-modcacherw}} is not important, but it ensures that go modules creates a write-able path. Default is read-only.
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')
 
   
  +
{{Tip|When package sources include a {{ic|vendor}} directory with {{ic|modules.txt}}, the {{ic|-mod}} flag can safely be changed to {{ic|1=-mod=vendor}}.}}
build() {
 
go build -o "$pkgname"
 
}
 
   
  +
{{Warning|It is up to the packager to verify the build flags are passed correctly to the compiler. Read the {{ic|Makefile}} if there is one.}}
package() {
 
install -Dm755 "$pkgname" "$pkgdir/usr/bin/$pkgname"
 
}
 
   
  +
==== Supporting debug packages ====
# vim:set ts=2 sw=2 et:</nowiki>}}
 
   
  +
Enabling debug packages with source listing and proper symbol look ups require a few modifications to the default buildflags.
==== サンプルパッケージ ====
 
* {{AUR|gorun}}
 
   
  +
* Removal of {{ic|-trimpath}} to ensure source paths are rewritten in the binary
=== 実行ファイルも含む Go ライブラリのサンプル PKGBUILD ===
 
  +
* Include {{ic|1=-compressdwarf=false}} in {{ic|-ldflags}} to ensure we can parse the DWARF headers as current tooling does not support compressed headers.
  +
* Ensure {{ic|1=-linkmode=external}} as the internal linker go uses does not embed a build-id into the binary.
  +
* Include {{ic|1=GOPATH="${srcdir}"}} so ''makepkg'' can include the source code for all modules.
   
  +
The above options should produce a debug package with proper detached symbols and source listings which can then be picked up by the debugger.
==== ''go get'' を使う (推奨) ====
 
   
  +
{{bc|1=
以下は go get を使用する方法です。
 
  +
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" .
build() や package() 関数を修正する必要は全くありません。変数だけを修正してください (pkgname など)。
 
  +
}}
   
  +
=== Output directory ===
以下の方法が使えない場合、まずは go get をテストしてみてください。
 
   
  +
There are currently a few ways to build all go binaries in a project.
{{Note|PKGBUILD でパッケージの作成が失敗する場合は {{Ic|/...}} を削除してください。}}
 
   
  +
{{bc|
{{bc|<nowiki># Maintainer: NAME <EMAIL>
 
  +
build(){
  +
cd "$pkgname-$pkgver"
  +
go build -o output-binary .
  +
}
  +
}}
   
  +
{{ic|...}} is a shorthand for the compiler to recursively descend into the directory and find all binaries. It can be used in conjunction with a output directory to build everything.
pkgname=codesearch
 
pkgver=20120515
 
pkgrel=1
 
pkgdesc="Code indexing and search written in Go"
 
arch=('x86_64' 'i686')
 
url="https://github.com/google/codesearch"
 
license=('BSD')
 
depends=('go')
 
makedepends=('mercurial')
 
options=('!strip' '!emptydirs')
 
_gourl=github.com/google/codesearch
 
   
  +
{{bc|
build() {
 
  +
prepare(){
GOPATH="$srcdir" go get -fix -v -x ${_gourl}/...
 
  +
cd "$pkgname-$pkgver"
  +
mkdir -p build
 
}
 
}
   
check() {
+
build(){
  +
cd "$pkgname-$pkgver"
GOPATH="$GOPATH:$srcdir" go test -v -x ${_gourl}/...
 
  +
go build -o build ./cmd/...
 
}
 
}
  +
}}
   
  +
== Sample PKGBUILD ==
package() {
 
mkdir -p "$pkgdir/usr/bin"
 
install -p -m755 "$srcdir/bin/"* "$pkgdir/usr/bin"
 
   
  +
{{bc|<nowiki>
mkdir -p "$pkgdir/$GOPATH"
 
  +
pkgname=foo
cp -Rv --preserve=timestamps "$srcdir/"{src,pkg} "$pkgdir/$GOPATH"
 
  +
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(){
# Package license (if available)
 
  +
cd "$pkgname-$pkgver"
for f in LICENSE COPYING LICENSE.* COPYING.*; do
 
  +
mkdir -p build/
if [ -e "$srcdir/src/$_gourl/$f" ]; then
 
install -Dm644 "$srcdir/src/$_gourl/$f" \
 
"$pkgdir/usr/share/licenses/$pkgname/$f"
 
fi
 
done
 
 
}
 
}
 
# vim:set ts=2 sw=2 et:</nowiki>}}
 
 
上記の PKBUILD は Rémy Oudompheng‎ が作成しました。
 
 
==== ''go get'' を使う ====
 
 
build() や package() 関数を修正する必要は全くありません。変数だけを修正してください (pkgname など)。
 
 
以下の方法が使えない場合、まずは go get をテストしてみてください。
 
 
{{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() {
 
build() {
  +
cd "$pkgname-$pkgver"
export GOROOT=/usr/lib/go
 
  +
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() {
rm -rf build
 
  +
cd "$pkgname-$pkgver"
mkdir -p build/go
 
cd build/go
+
go test ./...
 
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() {
 
package() {
  +
cd "$pkgname-$pkgver"
export GOROOT="$GOPATH"
 
  +
install -Dm755 build/$pkgname "$pkgdir"/usr/bin/$pkgname
  +
}
  +
</nowiki>}}
   
  +
== Example packages ==
# 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
 
}
 
   
  +
* {{Pkg|podman}}
# vim:set ts=2 sw=2 et:</nowiki>}}
 
  +
* {{Pkg|k9s}}
  +
* {{Pkg|helm}}

2023年6月26日 (月) 21:53時点における版

このドキュメントでは、GoPKGBUILD の作成に関する標準とガイドラインについて説明します。

一般的なガイドライン

パッケージの命名

パッケージが Go エコシステムと強く結合したプログラムを提供する場合は、go-modulename を使用します。他のアプリケーションの場合は、プログラム名のみを使用します。

ノート: パッケージ名は完全に小文字にする必要があります


ビルド

依存関係

Go 1.11 では、go modules の初期サポートが導入されました。これにより、Go のアップストリームコードで依存関係を宣言し、特定のプロジェクトバージョンに固定できるようになります。現在、私たちのパッケージ化作業では、これをベンダー依存関係に利用しています。

Go モジュールを使用しないアップストリームプロジェクト

Go モジュールを使用しないアップストリームコードの場合は、次の回避策があります。アップストリームで問題を提出することを検討してください。

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 アプリケーション用に書かれたほとんどの Makefile は、GOFLAGS を上書きしたり、ビルドシステムが提供するビルドフラグを尊重していません。このため、コンパイラのために CGO_CFLAGSCGO_LDFLAGS が設定されている必要があるので、Go バイナリが RELRO でコンパイルされません。これを 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}\"" \
    .

Flag meaning

  • -buildmode=pie enables PIE compilation for binary harderning.
  • -trimpath important for reproducible builds so full build paths and module paths are not embedded.
  • -mod=readonly ensure the module files are not updated in any go actions.
  • -modcacherw is not important, but it ensures that go modules creates a write-able path. Default is read-only.
ヒント: When package sources include a vendor directory with modules.txt, the -mod flag can safely be changed to -mod=vendor.
警告: It is up to the packager to verify the build flags are passed correctly to the compiler. Read the Makefile if there is one.

Supporting debug packages

Enabling debug packages with source listing and proper symbol look ups require a few modifications to the default buildflags.

  • Removal of -trimpath to ensure source paths are rewritten in the binary
  • Include -compressdwarf=false in -ldflags to ensure we can parse the DWARF headers as current tooling does not support compressed headers.
  • Ensure -linkmode=external as the internal linker go uses does not embed a build-id into the binary.
  • Include GOPATH="${srcdir}" so makepkg can include the source code for all modules.

The above options should produce a debug package with proper detached symbols and source listings which can then be picked up by the debugger.

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" .

Output directory

There are currently a few ways to build all go binaries in a project.

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

... is a shorthand for the compiler to recursively descend into the directory and find all binaries. It can be used in conjunction with a output directory to build everything.

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

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

Sample 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
}

Example packages