前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang -ldflags 的一个技巧

Golang -ldflags 的一个技巧

作者头像
poslua
发布2019-08-19 14:55:01
3.9K0
发布2019-08-19 14:55:01
举报
文章被收录于专栏:posluaposlua

我在开发 go 的项目时,习惯上会在编译后的二进制文件中注入 git 等版本信息后再发布。一直以来都是这么做的:

代码语言:javascript
复制
package main

import (
    "fmt"
    "os"
    "runtime"
)

var buildstamp = ""
var githash = ""

func main() {
    args := os.Args
    if len(args) == 2 && (args[1] == "--version" || args[1] == "-v") {
        fmt.Printf("Git Commit Hash: %s\n", githash)
        fmt.Printf("UTC Build Time : %s\n", buildstamp)
        return
    }
}

然后编译的时候,通过链接选项 -X 来动态传入版本信息:

代码语言:javascript
复制
flags="-X main.buildstamp=`date -u '+%Y-%m-%d_%I:%M:%S%p'` -X main.githash=`git describe --long --dirty --abbrev=14`"
go build -ldflags "$flags" -x -o build-version main.go

这样编译后的程序就可以通过 -v 参数查看版本信息了

代码语言:javascript
复制
[root@KONG:bin (master)]# ./build-version -v
Git Commit Hash: 1.3-5-ge9edea3e8f986d
UTC Build Time : 2018-09-30_03:40:36AM
[root@KONG:bin (master)]#

然而在多人协作的项目时,大家的 go 版本可能会不同,所以我又尝试将 go version 信息植入到程序中。

代码语言:javascript
复制
package main

import (
    "fmt"
    "os"
    "runtime"
)

var buildstamp = ""
var githash = ""
var goversion = ""

func main() {
    args := os.Args
    if len(args) == 2 && (args[1] == "--version" || args[1] == "-v") {
        fmt.Printf("Git Commit Hash: %s\n", githash)
        fmt.Printf("UTC Build Time : %s\n", buildstamp)
        fmt.Printf("Golang Version : %s\n", goversion)
        return
    }
}

通过添加编译参数: -X main.goversion=$(go version),然而却失败了。通过错误输出可以判断是因为 go version 的输出有空格,导致编译被打断。之后我又改了下编译参数,添加了单引号: -X main.goversion='$(go version)',遗憾的是,编译依然无法通过。

记得之前,我看到过 codis 的源码是通过一个 shell 脚本生成一个额外的 go package 来处理的:

代码语言:javascript
复制
version=`git log --date=iso --pretty=format:"%cd @%H" -1`
if [ $? -ne 0 ]; then
    version="unknown version"
fi

compile=`date +"%F %T %z"`" by "`go version`
if [ $? -ne 0 ]; then
    compile="unknown datetime"
fi

describe=`git describe --tags 2>/dev/null`
if [ $? -eq 0 ]; then
    version="${version} @${describe}"
fi

cat << EOF | gofmt > pkg/utils/version.go
package utils
const (
    Version = "$version"
    Compile = "$compile"
)
EOF

cat << EOF > bin/version
version = $version
compile = $compile
EOF

但是这样,每开启一个新项目都需要额外的 shell 脚本,也够麻烦的。所以,很长时间我都是这么来偷懒的:

代码语言:javascript
复制
package main

import (
    "fmt"
    "os"
    "runtime"
)

var buildstamp = ""
var githash = ""
var goversion = fmt.Sprintf("%s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH)

func main() {
    args := os.Args
    if len(args) == 2 && (args[1] == "--version" || args[1] == "-v") {
        fmt.Printf("Git Commit Hash: %s\n", githash)
        fmt.Printf("UTC Build Time : %s\n", buildstamp)
        fmt.Printf("Golang Version : %s\n", goversion)
        return
    }
}

但是这样的话,也有一个问题:就是在交叉编译的时候无法正确反应出 go 的版本。比如,你是在 OSX 下编译 linux 的可执行程序,这时候你通过 -v 参数查看显示的也是 linux 平台,而不是期待的 darwin 平台。

不过,近日我在闲逛 go nuts 时,看到一个贴子:v1.5 -ldflags -X change breaks when string has a space,谈到了这个技巧:如果要赋值的变量包含空格,需要用引号将 -X 后面的变量和值都扩起来。原来如此,再次 build 一下,还真好用:

代码语言:javascript
复制
flags="-X 'main.goversion=$(go version)'"
go build -ldflags "$flags" -x -o build-version main.go

子曰:三人行,必有我师焉。看来,社区还得逛起来呀~~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 poslua 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档