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
何も表示されなかった。つまりenvtest
はENVTEST
環境変数をロードしにいっていることになる。
とはいえ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
で空文字列かどうかを判定して、空文字列だったら環境変数から取るとかにするのがいいのかな。