go1.10rc1のdebパッケージを作ってみた

はじめに

golang 1.9rc1のUbuntu 16.04用debパッケージをビルドした 以降go1.9.xのdebパッケージを git-buildpackage で作っていましたが、今回 go1.10rc1 のdebパッケージを作ってみたのでメモです。

上の記事ではよくわかっていなかったので手順に無駄がありましたが、今回は現状の私の理解での最適な手順を書きました。ビルドするところまでは。

ビルドが失敗して試行錯誤したので記録として残そうかと思ったのですが長くなったので最終的な手順だけメモしておきます。

golang-1.10のパッケージ作成

パッケージのソースのレポジトリは https://github.com/hnakamur/golang-deb です。

1.10.x用のブランチ作成

git branch ubuntu-1.10 ubuntu-1.9
git branch upstream-1.10 upstream-1.9

1.10rc1のtarballをダウンロード

mkdir -p ~/go-deb-work
cd ~/go-deb-work
curl -LO https://dl.google.com/go/go1.10rc1.src.tar.gz

ビルド対象を1.10.xに切り替え

cd ~/.ghq/github.com/hnakamur/golang-deb
git checkout ubuntu-1.10
vi debian/changelog

先頭に以下の内容を追加。

golang-1.10 (1.10~rc1-1ubuntu1~hnakamur1) xenial; urgency=medium

  * Imported Upstream version 1.10rc1

 -- Hiroaki Nakamura <hnakamur@gmail.com>  Fri, 26 Jan 2018 22:53:00 +0900

.. code-block:: console

git commit -m 'Release 1.10~rc1-1ubuntu1~hnakamur1' debian/changelog

debian/changelog の先頭のエントリの golang-1.10 の部分を元に debian/gbp.conf などのファイルを上書き生成します。

./debian/rules gencontrol

生成された debian/gbp.conf の内容を確認。

$ cat debian/gbp.conf
#
# WARNING: "debian/gbp.conf" is generated via "debian/rules gencontrol" (sourced from "debian/gbp.conf.in")
#

[DEFAULT]
debian-branch = ubuntu-1.10
debian-tag = debian/%(version)s
upstream-branch = upstream-1.10
upstream-tag = upstream/%(version)s
pristine-tar = True

[dch]
meta = 1

他に以下のファイルも生成されていました。

$ git status -s
 M debian/control
 M debian/gbp.conf
 M debian/source/lintian-overrides
 M debian/watch

変更されたファイルをコミットします。

$ git commit -m 'Switch to go1.10.x' debian/

1.10rc1のtarballをインポート

$ gbp import-orig --no-interactive -u1.10~rc1 ~/go-deb-work/go1.10rc1.src.tar.gz
gbp:info: Importing '/home/hnakamur/go-deb-work/go1.10rc1.src.tar.gz' to branch 'upstream-1.10'...
gbp:info: Source package is golang-1.10
gbp:info: Upstream version is 1.10~rc1
gbp:info: Merging to 'ubuntu-1.10'
gbp:info: Successfully imported version 1.10~rc1 of /home/hnakamur/go-deb-work/go1.10rc1.src.tar.gz

これで以下の4つが実行されていました。

1.10rc1のソースパッケージを作成

以下のコマンドでソースパッケージを作成します。

gbp buildpackage --git-export-dir=../build-area -S -sa -p/home/hnakamur/bin/gpg-passphrase

最後の -p オプションは `git-buildpackageとfreightでパスフレーズをファイルから入力させる](/blog/2017/08/28/use-passphrase-file-in-git-buildpackage-and-freight/) にメモした通りパスフレーズを自動入力するためのものです。

1.10rc1のdebパッケージをローカルでビルド

sudo pbuilder build ../build-area/golang-1.10_1.10~rc1-1ubuntu1~hnakamur1.dsc

ビルド失敗と回避策

これで無事ビルドできるかと思いきや以下のようなエラーが出てビルド失敗しました。

Building packages and commands for linux/amd64.
/build/golang-1.10-1.10~rc1/bin/go install -v -buildmode=shared \
        -ldflags '-extldflags "-Wl,-soname=libgolang-1.10-std.so.1"' \
        std
initializing cache in $GOCACHE: mkdir /nonexistent: permission denied
debian/rules:115: recipe for target 'override_dh_auto_build-arch' failed
make[1]: *** [override_dh_auto_build-arch] Error 1
make[1]: Leaving directory '/build/golang-1.10-1.10~rc1'
debian/rules:26: recipe for target 'build' failed
make: *** [build] Error 2
dpkg-buildpackage: error: debian/rules build gave error exit status 2
I: copying local configuration
E: Failed autobuilding of package
I: user script /var/cache/pbuilder/build/8740/tmp/hooks/C10shell starting

go1.10rc1のソースを見てみました。 上記の initializing cache in $GOCACHE: mkdir /nonexistent: permission denied のエラーは以下の43行目で出ているようです。

https://github.com/golang/go/blob/go1.10rc1/src/cmd/go/internal/cache/default.go#L35-L55

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// initDefaultCache does the work of finding the default cache
// the first time Default is called.
func initDefaultCache() {
    dir := DefaultDir()
    if dir == "off" {
        return
    }
    if err := os.MkdirAll(dir, 0777); err != nil {
        base.Fatalf("initializing cache in $GOCACHE: %s", err)
    }
    if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
        // Best effort.
        ioutil.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666)
    }

    c, err := Open(dir)
    if err != nil {
        base.Fatalf("initializing cache in $GOCACHE: %s", err)
    }
    defaultCache = c
}

いろいろ調べたり試行錯誤した結果、pbuilderが $HOME の指すディレクトリを書き込み不可にする一方、goのビルドとテストでは $HOME 以下にディレクトリやファイルを作ろうとするのでエラーになることがわかりました。

そこで以下のように debian/rules を書き換えて回避しました。

diff --git a/debian/rules b/debian/rules
index b6d44ae..3bc70c9 100755
--- a/debian/rules
+++ b/debian/rules
@@ -22,6 +22,14 @@ shlib_archs = $(shell GOVER=$(GOVER) perl debian/helpers/getshlibarches.pl)

 multiarch := $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)

+# NOTE: We need $HOME to be writable in order to run builds
+# and tests successfully.
+# pbuilder sets $HOME to /nonexistent and make it non-writable.
+# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=441052
+ifneq (0,$(shell test -w "$(HOME)"; echo $$?))
+        export HOME := /tmp
+endif
+
 %:
        +dh --parallel $(opt_no_act) $@

これをコミットして再度ソースパッケージとdebパッケージをビルドすると今度は成功しました。

gitタグ作成

動作確認後以下のタグを打っておきました。

git tag debian/1.10_rc1-1ubuntu1_hnakamur1

golang-defaultsのパッケージ作成

パッケージのソースのレポジトリは https://github.com/hnakamur/golang-defaults-deb です。

changelogにエントリ追加

debian/changelog の先頭に以下のエントリを追加します。

golang-defaults (2:1.10~1ubuntu1~hnakamur1) xenial; urgency=medium

  * Use Golang 1.10.

 -- Hiroaki Nakamura <hnakamur@gmail.com>  Sun, 28 Jan 2018 16:52:00 +0900

上記の変更をコミットします。

git commit -m 'Release 2:1.10~1ubuntu1~hnakamur1' debian/changelog

ソースパッケージを作成

gbp buildpackage --git-export-dir=../build-area -S -sa -p/home/hnakamur/bin/gpg-passphrase

debパッケージをローカルでビルド

sudo pbuilder build ../build-area/golang-defaults_1.10~1ubuntu1~hnakamur1.dsc

gitタグ作成

動作確認後以下のタグを打っておきました。

git tag debian/1.10_1ubuntu1_hnakamur1

golang-1.10-race-detector-runtimeのパッケージ作成

パッケージのソースのレポジトリは https://github.com/hnakamur/golang-1.10-race-detector-runtime-deb です。

ソースレポジトリを作成

1.9のrace-detector-runtimeのレポジトリをコピーして作成しました。

cp -pr ~/.ghq/github.com/hnakamur/golang-1.{9,10}-race-detector-runtime-deb

debian/control 内のパッケージ名を1.10用に書き換えます。

sed -i 's/golang-1\.9/golang-1.10/' debian/control

debian/golang-1.8-race-detector-runtime.lintian-overrides というファイルがあり、中身を見ると前回1.9用に作ったときに1.9用に書き換えてあったのですが、ファイル名は1.8のままになっていました。

ということでファイル名を1.10用に変えつつ中身も1.10用に変えます。

git mv debian/golang-1.{8,10}-race-detector-runtime.lintian-overrides
sed -i 's/golang-1\.9/golang-1.10/;s/go-1\.9/go-1.10/' debian/golang-1.10-race-detector-runtime.lintian-overrides

https://github.com/golang/go/blob/go1.10rc1/src/runtime/race/README を見ると、goのrace detectorのランタイムはLLVMプロジェクトの ThreadSanitizer race detectorがベースになっていると書いてあります。

runtime/race package contains the data race detector runtime library.
It is based on ThreadSanitizer race detector, that is currently a part of
the LLVM project (http://llvm.org/git/compiler-rt.git).

To update the .syso files use golang.org/x/build/cmd/racebuild.

Current runtime is built on rev 68e1532492f9b3fce0e9024f3c31411105965b11.

debian/changelog の先頭に以下のエントリを追加します。 バージョン番号内の +git の後の文字列は上のREADMEの最終行に書いてあるgitのコミットハッシュの先頭6桁にします。

golang-1.10-race-detector-runtime (0.0+git68e153~ubuntu16.04.1hnakamur1) xenial; urgency=medium

  * Update package name for Go 1.10.
  * Update to version used by Go 1.10.
  * Get orig source from the LLVM compiler-rt git repository.

 -- Hiroaki Nakamura <hnakamur@gmail.com>  Sun, 28 Jan 2018 17:40:00 +0900

変更内容をコミットします。

git commit -m 'Update for go1.10' debian/

オリジンのソース取得

debian/rulesget-orig-source ターゲットはgo1.9のときはLLVMのsubversionレポジトリから取得するようになっていたのですが、今回はgitなので処理を書き換えました。

diff --git a/debian/rules b/debian/rules
index b28630a..44e0ea6 100755
--- a/debian/rules
+++ b/debian/rules
@@ -35,13 +35,15 @@ override_dh_auto_build:

 PKD  = $(abspath $(dir $(MAKEFILE_LIST)))
 PKG  = $(shell dpkg-parsechangelog -l$(PKD)/changelog --show-field=Source)
-REVNO = $(shell dpkg-parsechangelog  -SVersion | sed -e 's/.*svn\([0-9]\+\)-.*/\1/')
+COMMIT = $(shell dpkg-parsechangelog -SVersion | sed -rne 's/[^+]*\+git([0-9a-f]+).*/\1/p')

 get-orig-source:
-       svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
-       cd compiler-rt && svn export -r $(REVNO) . "../$(PKG)_0.0+svn$(REVNO)"
-       tar czf $(PKG)_0.0+svn$(REVNO).orig.tar.gz $(PKG)_0.0+svn$(REVNO)
-       rm -rf compiler-rt $(PKG)_0.0+svn$(REVNO)
+       ls | grep -v '^debian$$' | xargs rm -rf
+       git clone http://llvm.org/git/compiler-rt.git
+       cd compiler-rt \
+               && echo .gitignore export-ignore > .gitattributes \
+               && git archive --worktree-attributes $(COMMIT) | tar x -C ..
+       rm -rf compiler-rt

 %:
        dh $@

以下のコマンドを実行してオリジンのソースを取得します。

./debian/rules get-orig-source

ソースの差分は以下の一か所だけで実質は変わっていませんでした。

diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh
index 812cb93..42d4790 100755
--- a/lib/tsan/go/buildgo.sh
+++ b/lib/tsan/go/buildgo.sh
@@ -125,7 +125,7 @@ if [ "$SILENT" != "1" ]; then
 fi
 $CC $DIR/gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS

-$CC $OSCFLAGS test.c $DIR/race_$SUFFIX.syso -m64 -g -o $DIR/test $OSLDFLAGS $LDFLAGS
+$CC $OSCFLAGS test.c $DIR/race_$SUFFIX.syso -m64 -g -o $DIR/test $OSLDFLAGS

 export GORACE="exitcode=0 atexit_sleep_ms=0"
 if [ "$SILENT" != "1" ]; then

取得したソースはコミットしておきます。

ソースパッケージを作成

gbp buildpackage --git-export-dir=../build-area -S -sa -p/home/hnakamur/bin/gpg-passphrase

debパッケージをローカルでビルド

sudo pbuilder build ../build-area/golang-1.10-race-detector-runtime_0.0+git68e153~ubuntu16.04.1hnakamur1.dsc

gitタグ作成

動作確認後以下のタグを打っておきました。

git tag debian/0.0+git68e153_ubuntu16.04.1hnakamur1

PPAでビルド

freightでプライベートdebレポジトリ作成 の手順でローカルのレポジトリに登録してLXDのUbuntu Xenialコンテナで動作確認して問題ないことを確認した後、PPAでビルドしました。

今回新たに https://launchpad.net/~hnakamur/+archive/ubuntu/golang-1.10 というPPAを作成しました。

作成後、画面右の Change details リンクをクリックして以下のように変更しました。

以下のコマンドを実行してPPAでビルドしました。

dput ppa:hnakamur/golang-1.10 ../build-area/golang-1.10_1.10~rc1-1ubuntu1~hnakamur1_source.changes
dput ppa:hnakamur/golang-1.10 ../build-area/golang-defaults_1.10~1ubuntu1~hnakamur1_source.changes
dput ppa:hnakamur/golang-1.10 ../build-area/golang-1.10-race-detector-runtime_0.0+git68e153~ubuntu16.04.1hnakamur1_source.changes

PPAでのビルド完了後、ローカルのレポジトリからインストールしたdebパッケージはアンインストールして、以下の手順でPPAからインストールして再度動作確認しました。

PPAからのインストール方法

add-apt-repository コマンドを使うために software-properties-common パッケージが必要です。インストールしていない場合は以下のコマンドでインストールします。

sudo apt update
sudo apt install software-properties-common

以下のコマンドで必要なパッケージ一式がインストールできます。 golang-1.10-doc パッケージは godoc コマンドを使うために必要ですので入れておきます。

sudo add-apt-repository ppa:hnakamur/golang-1.10
sudo apt update
sudo apt install golang-go golang-1.10-doc

インストールされたgoでバージョンや実行ファイルのパスを確認してみました。

root@xenial:~# go version
go version go1.10rc1 linux/amd64
root@xenial:~# which go
/usr/bin/go
root@xenial:~# ls -l /usr/bin/go
lrwxrwxrwx 1 root root 21 Jan 28 12:01 /usr/bin/go -> ../lib/go-1.10/bin/go

おわりに

まだ作ったばかりで軽い動作確認しかしてませんが、今後使っていこうと思います。