Carpe Diem

備忘録

ldflagsを使おうとしてハマったこと

概要

golangではbuild時にldflagsというオプションをつけると、変数に値を埋め込んだ状態でバイナリを生成することができます。
よく使われるのはビルド時のgitのcommitのハッシュを埋め込んで、そのバイナリがどのcommitで作成されたのかを明らかにして「想定したバージョンでビルドができているか」や「複数のサーバ間で同じバージョンを使用できているか」などをチェックしたりします。

今回はそのldflagsを使う上でハマったことを書きます。

環境

  • go 1.7.4

ハマったこと

go 1.5から書き方が変わった

以前はスペースで区切って

go build -ldflags "-X パッケージ名.変数 値"

でしたが、今は=を使って

go build -ldflags "-X パッケージ名.変数=値"

となります。

複数埋め込みたい場合は

go build -ldflags "-X パッケージ名.変数=値 -X パッケージ名.変数=値"

でOKです。

main packageじゃない変数に埋め込みたい

よくネットの情報で見るのはmain packageの変数に埋め込むやり方で

package main

import "fmt"

var version string

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

というファイルで

$ go build -ldflags "-X main.version=1.0.0"

で埋め込みます。これはこれで正しいのですが、では別パッケージになった場合

github.com/jun06t/sample/api/alive.go

package api

import "fmt"

var version string

func alive() {
    fmt.Println(version)
}

に対して

$ go build -ldflags "-X api.version=1.0.0"

はできるかというと、できません

正しくは$GOPATH/srcからのpathである必要があります。

$ go build -ldflags "-X github.com/jun06t/sample/api.version=1.0.0"

最後のapi.versionapiの部分はpackage名ではなくフォルダ名を指定する必要があるので注意してください。

usage: link [options] main.oが出る

$ COMMIT=$(git rev-parse --verify HEAD) \
>  BUILDDATE=$(date '+%Y/%m/%d %H:%M:%S %Z') \
>  go build -ldflags "-X github.com/jun06t/sample/api.commit=${COMMIT} -X github.com/jun06t/sample/api.builddate=${BUILDDATE}" 

として実行しようとしたところなぜか

# command-line-arguments
usage: link [options] main.o
  -B note
        add an ELF NT_GNU_BUILD_ID note when using ELF
  -C    check Go calls to C code
  -D address
        set data segment address (default -1)
  -E entry
        set entry symbol name
  -H type
        set header type
  -I linker
        use linker as ELF dynamic linker

というように使い方を表示されました。

原因はBUILDDATEの中身が2016/12/08 04:23:44 JSTのような形になっているのですが、これに半角スペースが含まれていることでGo1.5以前の記述とみなされて「使い方が間違ってるよ」と怒られてました。

正しくは

go build -ldflags "-X github.com/jun06t/sample/api.commit=${COMMIT} -X \"github.com/jun06t/sample/api.builddate=${BUILDDATE}\"" 

のように、空白を含む場合は-Xの引数全体を""で囲う必要があります。

git describe –tagsでエラー

これもよく載っていますが、埋め込む際に

$ git describe --tags

を使っているのを見ます。僕のリポジトリで実行したところ

$ git describe --tags
fatal: No names found, cannot describe anything.

というエラーになりました。理由はそのリポジトリにtagがなかったからです。

その場合コミットのハッシュ値にしたいと思うので

$ git rev-parse --verify HEAD

を使います。

[その他]バイナリに埋め込んだ方が良い情報

項目 コマンド
commit hash git rev-parse --verify HEAD
ビルド日時 date '+%Y/%m/%d %H:%M:%S %Z'
Goバージョン go version

などがあれば十分だと思います。

参考