Golang Cafe #25 まとめ デバッグとリリースビルドの切り替え方法を考える

2014/04/13に開催された「Golang Cafe #25」についてのまとめです。
今回はご新規様が参加されましたので、この度めでたく「https://plus.google.com/u/0/communities/107075098212007233819」の管理メンバーにご昇格された+RyujiIwata氏がご新規様にGolang Cafe #1(私のまとめ)の内容をご教授されておりました。
(私なんぞはまだまだ精進が足らぬようです)
その間、私はいつもながら+TakashiYokoyama氏に質問をぶつけたり、試してみたことを話していました。

build時のターゲットを切り替えるには

C#ですとビルド時にDebugかReleaseを切り替えたり、Seasar系ですとenv.txtを変更したりだとかありますが、いわゆる#if DEBUGのようなことをGo言語でするにはどうしたらいいのかという疑問が出てきました。
というのも、先日のエントリー(Go言語でプロファイリング(CPU profiling検証編)Go言語でプロファイリング(MEMORY recyclingというよりメモリ使用状況の調査編))でGo言語でのプロファイリングを試してみたのですが、いずれもソースコードにプロファイリング用のコードを追加しなくてはなりません。実際にリリースするときにはプロファイリング用のコードとかデバッグ用のコードとかは削除(少なくとも無効に)しておきたいです。


+TakashiYokoyama氏にもすぐには思い出せなかったらしく、私も色々調べてみたところ何件かヒットしました。
http://golang.org/pkg/go/build/
Development vs Production Environments (replacements for #ifdef DEBUG)
How to properly use build tags?


上記内容を参考にしながら考えたところ「ビルドタグ」を使用してファイルを差し替えれば解決できそうなので試してみました。
以下の3つのファイル用意します。

conditional_build/
                  env/
                      env.go
                      env_release.go
                  sample1.go

env.go

// +build !release

package env

const DEBUG = true

env_release.go

// +build release

package env

const DEBUG = false

sample1.go

package main

import (
    "fmt"

    "conditional_build/env/"
)

func main() {
    if env.DEBUG {
        fmt.Println("debug")
    }

    fmt.Println("hello go")
}

このように

// +build タグ

しておくとビルド時のtagsでファイルを切り替えることができるようです。詳しい書式はこちらで確認して下さい。
そのままビルドすると

$ go build -o sample1.exe
$ sample1.exe
debug
hello go

デバッグ用のロジックが有効になります。
リリース用のビルドを行うには-tagsオプションを使用します。

$ go build -o sample1.exe -tags=release
$ sample1.exe
hello go

今度はデバッグ用のロジックが無効になりました。
実際に出力したexeがどこまで最適化されているか分かりませんが、Goのコンパイラは優秀だと思うので、DEBUGの値をconstで宣言しているのでif DEBUGのブロックごと削除してくれているのではないかと思います。(というかそうであって欲しいです)


また、http://kwmt27.net/index.php/2013/04/09/golang-debug%E3%83%AD%E3%82%B0%E3%82%92%E5%9F%8B%E3%82%81%E8%BE%BC%E3%82%80%E3%81%AB%E3%81%AF%EF%BC%9F/にも書かれてありましたが、Goのmail.Messageソースコードにもデバッグ用のコードがあるようです。

var debug = debugT(false)

type debugT bool

func (d debugT) Printf(format string, args ...interface{}) {
    if d {
        log.Printf(format, args...)
    }
}

C#の拡張メソッドでも似たようなことができますが、なれないとこのような書き方は思いつきません。
ただdebug=falseを直書きしているので、

package util

import (
    "log"

    "conditional_build/env"
)

var Debug = debugT(env.DEBUG)

type debugT bool

func (d debugT) Printf(format string, args ...interface{}) {
    if d {
        log.Printf(format, args...)
    }
}

このように私が書いたようにしておけば実際のコードを変更することなく、デバッグ用コードを無効にできるのではないかと思います。


今回のコードもリポジトリにあげておこうと思うのですが、私の間違った操作でリポジトリを壊してしまったので復旧次第あげておきます。

Nitrous.IO

以前から名前を聞いたことはあったのですが、実際に試したことはまだありませんでした。
https://www.nitrous.io/がなんぞや、という方はこの辺りの記事をご参照ください。
http://www.publickey1.jp/blog/13/web_idepaasnirousiorubypythonnodejsgo.html


先日たまたまGoogle+上でNitrous.IO上でのGoに関連するエントリーをお見かけして、招待コード付きでご紹介されていたので試しに登録してみました。

Chrome上でGo言語(ほかRubyPHP)の開発環境を利用できます。
左側にディレクトリツリー、真ん中にエディタ、右がチャット、下がコンソール(補完もできます)です。ちょっとしたものなら開発してそのまま公開できそうです。
ただ現時点ではGoのバージョンが1.1なので1.2系に更新しておきます。
(go関係のファイルは$HOME/.goと$HOME/.google_appengineにあります)

$ mkdir temp
$ cd temp
$ wget https://go.googlecode.com/files/go1.2.1.linux-amd64.tar.gz
$ tar zxf go1.2.1.linux-amd64.tar.gz
$ mv $HOME/.go $HOME/.go1.1
$ mv go $HOME/.go
$ go version
go version go1.2.1 linux/amd64
$ cd $HOME
$ rm -Rf .go1.1
$ rm -Rf temp

ご興味のある方はぜひこちらのリンクからご登録を!(お互いポイントアップらしいのですが)
https://www.nitrous.io/join/Z0jrNDdIFIw?utm_source=nitrous.io&utm_medium=copypaste&utm_campaign=referral

次回は

次回からはDockerソースコードを読んでいくそうです。