go buildを試しつつGoのパッケージの規則を覚えた
go buildでバイナリを作る
go buildコマンドを実行すると、カレントディレクトリからmainパッケージを探してバイナリを作ってくれる。
Githubでの管理を念頭に推奨されるプロジェクト構成
- go getでgithub.comから依存ライブラリを取ってくる
- importで自己ないし外部プロジェクトのモジュールを参照する
上記2点を考慮すると、以下の記事で紹介されている構成にしておくのが無難らしい。
Golangで自分自身で定義したパッケージをインポートする方法あれこれ - Qiita
$GOPATH/src/github.com/[username]/[appname]
この中で最初から作業をしてしまう.
実際に試してみた
$GOPATH/src/github.com/oyakata/tokyo ├── hello │ ├── api.go # helloパッケージ │ └── main.go # helloパッケージ └── main.go # mainパッケージ
まず、tokyo/main.goの内容は以下。
package main import ( ikzo "github.com/oyakata/ikzo/hello" "github.com/oyakata/tokyo/good" tyo "github.com/oyakata/tokyo/hello" ) func main() { ikzo.World() // ikzoのhello.World()を実行 tyo.World() // tokyoのhello.World()を実行 tyo.GotoTokyo() // tokyoのhello/api.goに定義した関数 best.DoBest(1000) // tokyoのgood/main.goに定義した関数 }
わたしは /home/echizen/_go をGOPATHに指定したので、以下の手順でプロジェクトを配備した。
$ mkdir -p /home/echizen/_go/src $ cd /home/echizen/_go/src $ git clone git@github.com:oyakata/ikzo.git $ git clone git@github.com:oyakata/tokyo.git $ cd tokyo $ export GOPATH=/home/echizen/_go $ go build -o tyo # => tyoという名前のバイナリができる # あるいは $ GOPATH=/home/echizen/_go go build -o tyo $ ./tyo # tokyo/main.goのmainに書いた処理が実行される
イレギュラーなことも試してみた
ルール通りにやれば何ということもなくビルド&実行できたのだが、いくつかルールを破ってみた場合にどうなるのか試してみた。
対象ディレクトリ配下に複数のmainパッケージのモジュールを置く
例えば、tokyo/の直下にmain_tyo.goとmain_ikzo.goという、mainパッケージのモジュールを2つ置いてgo buildしてみる。
これはコンパイルエラーが出てビルドが失敗する。
echizen@Seigaku:~/_go/src/github.com/oyakata/tokyo$ go build # github.com/oyakata/tokyo ./main_tyo.go:5: main redeclared in this block previous declaration at ./main_ikzo.go:7
異なる名前のパッケージ宣言を持つモジュールを同じディレクトリの中に置く
例えば、tokyo/helloの中で、main.goはhelloパッケージ、api.goはapiパッケージを宣言してみる。
これもコンパイルエラーになる。
echizen@Seigaku:~/_go/src/github.com/oyakata/tokyo$ go build main.go:6:2: found packages api (api.go) and hello (main.go) in /home/echizen/_go/src/github.com/oyakata/tokyo/hello
ディレクトリと異なる名前でパッケージ宣言してはいけないのか?
例えば、tokyo/goodディレクトリの中で、bestパッケージを宣言してみる。
これはコンパイルが通る。が、インポートすると best という名前で認識される。
package main import "github.com/oyakata/tokyo/good" func main() { // good.DoBest(1000) // パッケージ宣言は best なので、goodという名前では参照できない // # command-line-arguments // ./main_tyo.go:6: imported and not used: "github.com/oyakata/tokyo/good" as best // ./main_tyo.go:13: undefined: good in good.DoBest best.DoBest(1000) // これは大丈夫 }
或いは
package main import good "github.com/oyakata/tokyo/good" func main() { good.DoBest(1000) }
このように、(ディレクトリの名前はgoodにもかかわらず)名前付きインポートでわざわざgoodという名前を指定するといった煩雑なことをしなければならない。
それだったら最初からディレクトリの名前とパッケージ宣言は合わせておけよ、というわけで、やっぱり面倒なことをしないに限る。