Golang って Solaris ではどうなのか調べてみたの続きになります。
ブートストラップに利用する Go 1.4.2 を Solaris 11.3 でビルドし、Go 1.5.3 を手に入れることがゴールになります。
(Solaris x86 環境が対象です)
作業ディレクトリ
$HOME/go ディレクトリを作業などもろもろ利用するディレクトリとします。
$ mkdir $HOME/go
$ cd $HOME/go
ビルドの準備
必要なパッケージをインストール。
# pkg install developer/versioning/git developer/gnu-binutils \
developer/build/gnu-make developer/gcc-48
ソースコードの入手
Go 1.4.3 と Go 1.5.2 を下記から入手し、$HOME/go ディレクトリに配置。
$ wget https://storage.googleapis.com/golang/go1.4.3.src.tar.gz
$ wget https://storage.googleapis.com/golang/go1.5.2.src.tar.gz
まずは Go 1.4.3 のビルド
アーカイブを展開し、go1.4.3 という名前に変更。
$ gtar xvzf go1.4.3.src.tar.gz
$ mv go go1.4.3
$ cd go1.4.3/src
$ PATH=/usr/gnu/bin:$PATH
$ export PATH
make.bash を実行
$ ./make.bash
# Building C bootstrap tool.
cmd/dist
# Building compilers and Go bootstrap tool for host, solaris/amd64.
lib9
libbio
liblink
:
testing/iotest
testing/quick
text/scanner
---
Installed Go for solaris/amd64 in /export/home/kazus/go/go1.4.3
Installed commands in /export/home/kazus/go/go1.4.3/bin
以上で、Go 1.4.3 のビルドは完了。
$ $HOME/go/go1.4.3/bin/go version
go version go1.4.3 solaris/amd64
このディレクトリをそのまま利用します。
Go 1.5.2 のビルド
Go 1.5 のビルドには、Go 1.4.3 が必要になるので、展開した Go 1.4.3 のディレクトリを $GOROOT_BOOTSTRAP に設定します。
$ GOROOT_BOOTSTRAP=$HOME/go/go1.4.3; export GOROOT_BOOTSTRAP
アーカイブを展開し、go1.5.2 という名前に変更。
$ gtar xvzf go1.5.2.src.tar.gz
$ mv go go1.5.2
go1.5.2/src に移動して make.bash を実行
$ cd go1.5.2/src
$ ./make.bash
##### Building Go bootstrap tool.
cmd/dist
##### Building Go toolchain using /export/home/kazus/go/go1.4.3.
bootstrap/internal/obj
bootstrap/asm/internal/flags
:
:
---
Installed Go for solaris/amd64 in /export/home/kazus/go/go1.5.2
Installed commands in /export/home/kazus/go/go1.5.2/bin
以上で、Go 1.5.2 のビルドは完了。
$ $HOME/go/go1.5.2/bin/go version
go version go1.5.2 solaris/amd64
GOPATH と GOROOT
ひとまず、出来上がった go1.5.2 の go コマンドに PATH を通しておきます。
これで、何も考えずに go コマンドを実行できるようになりました。
$ PATH=$HOME/go/go1.5.2/bin:$PATH; export PATH
続いて、ビルドした go コマンドが持っている環境変数を確認してみます。
$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="solaris"
GOOS="solaris"
GOPATH=""
GORACE=""
GOROOT="/export/home/kazus/go/go1.5.2"
GOTOOLDIR="/export/home/kazus/go/go1.5.2/pkg/tool/solaris_amd64"
GO15VENDOREXPERIMENT=""
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"
$GOROOT が埋め込まれているをことを確認できるので、$GOPATH のみを設定します。
$GOPATH に指定されたディレクトリはワーキングディレクトリとして利用され、$GOPATH/src にパッケージ、pkg にビルドされたライブラリ、bin に実行可能バイナリなどが格納されます。
このあたりは、特にココ!という場所は無いようなのでお好きなようにって感じでしょうか。
自身で作成したパッケージなどの構成にも関わるので、じっくり調べてみるのも良いかと思います。
$ GOPATH=$HOME/go; export GOPATH
もう一度、go env
を実行してみると、GOPATH に先ほど設定した $GOPATH の値が入っていることがわかります。
kazus@solaris:~/go$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="solaris"
GOOS="solaris"
GOPATH="/export/home/kazus/go"
GORACE=""
GOROOT="/export/home/kazus/go/go1.5.2"
GOTOOLDIR="/export/home/kazus/go/go1.5.2/pkg/tool/solaris_amd64"
GO15VENDOREXPERIMENT=""
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"
Hello, World!
How to Write Go Code などを参考に Hello,World! を実行してみます。
ソースはコピペで。
package main
import "fmt"
func main() {
fmt.Printf("Hello, world.\n")
}
go run で実行できます。
(一時的にワーキングディレクトリに実行可能ファイルを作成し、実行後は消去します。)
$ go run hello.go
hello, world
実行可能なバイナリを作成するには、go build を利用します。
$ go build hello.go
$ ls -al
total 2312
drwxr-xr-x 2 kazus staff 4 Jan 11 16:24 .
drwxr-xr-x 14 kazus staff 23 Jan 11 16:21 ..
-rwxr-xr-x 1 kazus staff 2349856 Jan 11 16:24 hello
-rw-r--r-- 1 kazus staff 77 Jan 11 16:22 hello.go
$ ./hello
hello, world
go build 時に -x オプションをつけることで、何が行われているか詳細を知ることができます。
$ go build -x hello.go
WORK=/tmp/go-build595923179
mkdir -p $WORK/command-line-arguments/_obj/
mkdir -p $WORK/command-line-arguments/_obj/exe/
cd /export/home/kazus/go/test
/export/home/kazus/go/go1.5.2/pkg/tool/solaris_amd64/compile -o $WORK/command-line-arguments.a -trimpath $WORK -p main -complete -buildid f68da26c4308377ead5ac41ebd2a70f05db675c6 -D _/export/home/kazus/go/test -I $WORK -pack ./hello.go
cd .
/export/home/kazus/go/go1.5.2/pkg/tool/solaris_amd64/link -o $WORK/command-line-arguments/_obj/exe/a.out -L $WORK -extld=gcc -buildmode=exe -buildid=f68da26c4308377ead5ac41ebd2a70f05db675c6 $WORK/command-line-arguments.a
cp $WORK/command-line-arguments/_obj/exe/a.out hello
まとめ
以上で Go 1.5 の環境を手に入れることができました。
あとは、もう好きにやっちゃってください。
下記は、お時間あればどうぞ。
ポータビリティ問題?
platform 依存の low-level interactions を利用した実装が多く見られるので、ポータビリティが損なわれているんじゃないか問題を Solaris 観点で。
確かに、Terminal 系のプログラムで ioctl 使っているものに遭遇して乗り越えられないもの多数
- Proposal: add Ioctl function to x/sys/unix for solaris and add TCGET*, TCSET*, TCSBRK, and TCXONC constants #12574
- x/crypto/ssh/terminal ReadPassword() not supported on Solaris #13085
-
On Go, Portability, and System Interfaces
ioctl などプラットフォーム固有の API を直接呼び出しすることによるポータビリティ問題について。
CGO を利用すれば幸せになる人は増えるが、オーバーヘッドなどの問題も絡んでくる -
Tcell - Terminal functionality for Pure Go apps
termbox-go でも Solaris/illumos をサポートしてもらおうとImprove portability for POSIX systems #99頑張ってみたが、中々うまくいかなかったよう。
結局、termbox-go を書き直した Tcell を公開
何かインストールしてみよう
この記事を参考に ccat, pt, peco にチャレンジしてみた
pt - The Platinum Searcher:
https://github.com/monochromegane/the_platinum_searcher
Go言語で作られたパターン検索ツール。
pt が依存している Terminal パッケージ が、Solaris に対応していないためインストールできず。
が、FreeBSD や Darwin (OS X) では CGO (Go から C の関数を呼び出すことができる)という仕組みを使ったものも提供されていたため、見よう見まねでごにょごにょしたら Solaris でも動くものが出来上がったので Pull Request してみた。
1.5 のリリースノートに書かれていた The Solaris port now has full support for cgo
を覚えていたので、そこからたどってみた。
というわけで、今日から Solaris でも pt 使えます。
$ go get github.com/monochromegane/the_platinum_searcher/...
$ $GOPATH/bin/pt --help
ccat - ccat is the colorizing cat:
https://github.com/jingweno/ccat
syntax highlighting をサポートした cat コマンド
やってみる。
$ go get -u github.com/jingweno/ccat
# github.com/jingweno/ccat
jingweno/ccat/ccat.go:22: undefined: isatty.IsTerminal
ccat パッケージに含まれ、かつ depend している go-isatty パッケージが Solaris をサポートしていないため、undefined: isatty.IsTerminal
でエラーとなる。
本家では Solaris をサポートしたパッケージを配布しているので、ccat.go を下記のように書き換える、もう一度、go get -u github.com/jingweno/ccat
すればインストールできる。
diff --git a/ccat.go b/ccat.go
index eae8a8e..b4a67b7 100644
--- a/ccat.go
+++ b/ccat.go
@@ -7,7 +7,7 @@ import (
"os"
"syscall"
- "github.com/jingweno/ccat/Godeps/_workspace/src/github.com/mattn/go-isatty"
+ "github.com/mattn/go-isatty"
)
type CCatPrinter interface {
もう一回
$ go get -fix -v -u github.com/jingweno/ccat
github.com/jingweno/ccat (download)
github.com/mattn/go-isatty (download)
Fetching https://golang.org/x/sys/unix?go-get=1
Parsing meta tags from https://golang.org/x/sys/unix?go-get=1 (status code 200)
get "golang.org/x/sys/unix": found meta tag main.metaImport{Prefix:"golang.org/x/sys", VCS:"git", RepoRoot:"https://go.googlesource.com/sys"} at https://golang.org/x/sys/unix?go-get=1
get "golang.org/x/sys/unix": verifying non-authoritative meta tag
Fetching https://golang.org/x/sys?go-get=1
Parsing meta tags from https://golang.org/x/sys?go-get=1 (status code 200)
golang.org/x/sys (download)
github.com/jingweno/ccat
ccat コマンドが $GOPATH/bin に作成されている。
$ ls $GOPATH/bin/ccat
/export/home/kazus/go/bin/ccat*
peco - Simplistic interactive filtering tool
これが、超絶便利そうだったのでインストールしてみたかったが Solaris をサポートしていない termbox への依存が激しくくじけました。
かわりに Python で実装された percol 置いときますね。
boom - HTTP(S) load generator, ApacheBench (ab) replacement, written in Go:
https://github.com/rakyll/boom
$ go get github.com/rakyll/boom
下記のエラーが出力されるので、pb/pb.go に patch を適用します。
# github.com/rakyll/pb
../src/github.com/rakyll/pb/pb.go:168: undefined: terminalWidth
パッチ:
$ git diff
diff --git a/pb_nix.go b/pb_nix.go
index 1f606aa..45bcfb0 100644
--- a/pb_nix.go
+++ b/pb_nix.go
@@ -1,4 +1,4 @@
-// +build linux darwin freebsd
+// +build linux darwin freebsd solaris
package pb
もう、一回。
今度は undefined: syscall.SYS_IOCTL
が出ました。
ちょっとこれを CGO 対応させるスキルがありません。
$ go get github.com/rakyll/boom
# github.com/rakyll/pb
./pb_nix.go:26: undefined: syscall.SYS_IOCTL
正しい手法ではないですが、go1.5.2 のソースを修正します。
書き換えたら go 1.5.2 のビルド手順と同じ make.bash を実行してください。
diff -cNr go/src/syscall/zsysnum_solaris_amd64.go go1.5.2/src/syscall/zsysnum_solaris_amd64.go
*** go/src/syscall/zsysnum_solaris_amd64.go Thu Dec 3 09:53:02 2015
--- go1.5.2/src/syscall/zsysnum_solaris_amd64.go Mon Jan 11 23:14:32 2016
***************
*** 8,13 ****
--- 8,14 ----
// TODO(aram): remove these before Go 1.3.
const (
+ SYS_IOCTL = 54
SYS_EXECVE = 59
SYS_FCNTL = 62
)
修正を加えたビルドが完了したら、また go get を実行します。
$ go get github.com/rakyll/boom
これで、$GOROOT/bin に boom バイナリが作成されているはず。
動作しました。
$ $GOPATH/bin/boom -n 10000 -c 100 -m POST http://192.168.100.15:8080
10000 / 10000 Booooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo! 100.00 %
Summary:
Total: 5.1659 secs.
Slowest: 1.2772 secs.
Fastest: 0.0025 secs.
Average: 0.0428 secs.
Requests/sec: 1935.7703
Total Data Received: 12670000 bytes.
Response Size per Request: 1267 bytes.
Status code distribution:
[404] 10000 responses
Response time histogram:
0.003 [1] |
0.130 [9902] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
0.257 [18] |
0.385 [2] |
0.512 [0] |
0.640 [0] |
0.767 [0] |
0.895 [0] |
1.022 [0] |
1.150 [26] |
1.277 [51] |
Latency distribution:
10% in 0.0170 secs.
25% in 0.0232 secs.
50% in 0.0310 secs.
75% in 0.0425 secs.
90% in 0.0543 secs.
95% in 0.0650 secs.
99% in 0.1263 secs.