golangのldflagsに引っかかった

golangにはビルド時のリンク関連の制御のldflagsオプションがある。

ldflagsを利用するとビルド時に変数の埋め込みなどが出来るのだが、これで引っかかった。

やろうとしていたことは次の様なコード。

環境変数の代わりにldflagsで変数埋め込みを行い、実行する場合は環境変数の設定を無くしたかった。

package main

import (
    "fmt"
    "os"
)

var envtest string = os.Getenv("ENVTEST")

func main() {
    fmt.Println(envtest)
}

実際にこれを go build -ldflags "-X main.envtest=goodnight" ./main.goの様にldflagsを使って変数埋め込み行いビルドした。

環境変数を設定していない状態で、生成したバイナリを実行するとこの様な結果になる。

$ ./main

何も表示されなかった。つまりenvtestENVTEST環境変数をロードしにいっていることになる。 とはいえstringsコマンドをかけてやると普通に出てくる。どういうことなの。

$ strings ./main | grep goodnight
goodnight

え〜と思い代入文を外して実験した。

package main

import (
    "fmt"
)

var envtest string

func main() {
    fmt.Println(envtest)
}

これで全く同じ方法でビルドした。

$ ./main 
goodnight

埋め込まれてる!!!!!!!!!!

ネタバラシ

ドキュメントを見たところちゃんと書いてあった

-X importpath.name=value

Set the value of the string variable in importpath named name to value. This is only effective if the variable is declared in the source code either uninitialized or initialized to a constant string expression. -X will not work if the initializer makes a function call or refers to other variables. Note that before Go 1.5 this option took two separate arguments.

「This is only effective if the variable is declared in the source code either uninitialized or initialized to a constant string expression.」とのことだったので、ちゃんとドキュメントは読もうな.....

ちなみに開発環境では環境変数使って実行環境では使いたくないときはどうするべきなんだろう。。。 initで空文字列かどうかを判定して、空文字列だったら環境変数から取るとかにするのがいいのかな。