在Golang中,使用ldflags为二进制文件指定版本是无效的。

huangapple go评论114阅读模式
英文:

using ldflags for giving binary file a version not working in golang

问题

以下是翻译好的内容:

main.go的代码如下:

package main

func main() {
	println("hello world")
}

Makefile的代码如下:

flags=-X main.version=1.5.0

build:
	go build -ldflags "$(flags)" -o main main.go

然后我运行make,得到了main文件。

当我运行./main -v时,我只得到了:

hello world

为什么它没有显示1.5.0

go版本是go version go1.18 darwin/arm64,当我运行go version -m main时,我得到了:

main: go1.18
        path    command-line-arguments
        build   -compiler=gc
        build   -ldflags="-X main.version=1.5.0"
        build   CGO_ENABLED=1
        build   CGO_CFLAGS=
        build   CGO_CPPFLAGS=
        build   CGO_CXXFLAGS=
        build   CGO_LDFLAGS=
        build   GOARCH=arm64
        build   GOOS=darwin

我对ldflags有误解。它的工作原理如下:

package main

import (
	"fmt"
	"os"
)

var (
	version string
)

func main() {
	args := os.Args
	if len(args) == 2 && (args[1] == "--version" || args[1] == "-v") {
		fmt.Printf("project version: %s \n", version)
		return
	}
}
$ ./main -v 
project version: 1.5.0
英文:

The main.go as follows:

package main

func main() {
	println("hello world")
}

The Makefile as follows:

flags=-X main.version=1.5.0

build:
	go build -ldflags "$(flags)" -o main main.go

Then I run make, and got main file.

After I runing ./main -v, I just got:

hello world

Why it does not display 1.5.0?

go version is go version go1.18 darwin/arm64, when I run go version -m main, I got:

main: go1.18
        path    command-line-arguments
        build   -compiler=gc
        build   -ldflags="-X main.version=1.5.0"
        build   CGO_ENABLED=1
        build   CGO_CFLAGS=
        build   CGO_CPPFLAGS=
        build   CGO_CXXFLAGS=
        build   CGO_LDFLAGS=
        build   GOARCH=arm64
        build   GOOS=darwin

I had a misunderstanding of ldflags. It works as follows:

package main

import (
	"fmt"
	"os"
)

var (
	version string
)

func main() {
	args := os.Args
	if len(args) == 2 && (args[1] == "--version" || args[1] == "-v") {
		fmt.Printf("project version: %s \n", version)
		return
	}
}
$ ./main -v 
project version: 1.5.0

答案1

得分: 3

你正在设置的ldflags变量(version)必须在包级别的包中声明。处理-v选项的部分需要你自己实现。

package main

import "flag"

var version string

func main() {
    var vFlag bool
    flag.BoolVar(&vFlag, "v", false, "显示版本号")
    flag.Parse()
    
    if vFlag {
        println(version)
    } else {
        println("你好,世界")
    }
}
go build -ldflags "-X main.version=1.5.0" -o main main.go
./main -v
# 1.5.0
./main
# 你好,世界
英文:

The variable you're setting with ldflags (version) must be declared in the package at the package level. The handling of -v you yourself must implement.

package main

import "flag"

var version string

func main() {
    var vFlag bool
    flag.BoolVar(&vFlag, "v", false, "show version")
    flag.Parse()
    
    if vFlag {
        println(version)
    } else {
        println("hello world")
    }
}
go build -ldflags "-X main.version=1.5.0" -o main main.go
./main -v
# 1.5.0
./main
# hello world

答案2

得分: 2

如果要构建一个包(如 go build github.com/xxx/yyy/zzz),那么符号必须相应地加上前缀。例如:

go build \
    -ldflags "-X github.com/xxx/yyy/zzz/main.version=1.5.0" \
    -o my-awesome-app \
    github.com/xxx/yyy/zzz

顺便说一下,找出要使用的符号 ID 的另一种方法是运行 nm 命令,并使用 grep 查找你要查找的变量。

英文:

If one builds a package (as in go build github.com/xxx/yyy/zzz then the symbol must be prefixed accordingly. For example:

go build \
    -ldflags "-X github.com/xxx/yyy/zzz/main.version=1.5.0" \
    -o my-awesome-app \
    github.com/xxx/yyy/zzz

B.T.W. Another way to figure out which symbol ID to use is to run nm and grep for the variable you are looking for.

答案3

得分: 0

这条评论并不是对实际问题的回答,而是与标题相关的。因此,我认为在这里值得分享。

ldflags可能看起来不起作用的一个原因是它只对字符串类型的变量起作用。

例如:

package main

import "fmt"

var sss = "FOO"
var ccc = 2

func main() {
        fmt.Println("variables:", sss, ccc)
}
  • 使用go run main.go执行此代码会显示variables: FOO 2
  • 使用go run -ldflags="-X main.sss=BAR" main.go执行它会显示variables: BAR 2
  • 使用go run -ldflags="-X main.ccc=5" main.go执行它会显示main.ccc: cannot set with -X: not a var of type string (type.int)

另一个需要注意的地方是,如果缺少-X,你将不会收到错误消息。它只是不会按你的期望执行:

  • 使用go run -ldflags="main.sss=BAR" main.go执行它会显示variables: FOO 2
英文:

This comment is not an answer for the actual question but is related to the title. Therefore, I think it is worth sharing here.

One reason why ldflags may seem not to be working is that it works only for string type variables.

Example:

package main

import "fmt"

var sss = "FOO"
var ccc = 2

func main() {
        fmt.Println("variables:", sss, ccc)
}
  • Executing this code with go run main.go displays variables: FOO 2
  • Executing it with go run -ldflags="-X main.sss=BAR" main.go displays variables: BAR 2
  • Executing it with go run -ldflags="-X main.ccc=5" main.go displays main.ccc: cannot set with -X: not a var of type string (type.int)

Another gotcha is you get no error message if -X is missing. It just doesn't do what you expect:

  • Executing it with go run -ldflags="main.sss=BAR" main.go displays variables: FOO 2

huangapple
  • 本文由 发表于 2022年3月26日 17:16:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/71626755.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定