【问题标题】:static linking a no-op binary with `net` and cgo turned off fails将无操作二进制文件与“net”静态链接并关闭 cgo 失败
【发布时间】:2021-10-29 17:37:45
【问题描述】:

我试图提交错误报告 (https://github.com/golang/go/issues/48081) 但被发送到这里。

我正在尝试静态链接二进制文件,即使没有操作二进制文件也遇到了陷阱问题。

$ go version
go version go1.17 linux/amd64

请注意,我使用的是 docker golang:1.17-buster 图像,但这也适用于 1.16。

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build838287027=/tmp/go-build -gno-record-gcc-switches"

我尝试静态编译一个简单的主文件:

$ cat go.mod
module naphatkrit/go-bug-repro

go 1.17
$ cat main.go
package main

func main() {
}

然后我使用静态链接我的二进制文件所需的标志运行 go build,这导致无法找到 cgo 的警告。

$ go build -a -v -o /tmp/my-binary -ldflags "-linkmode external -extldflags -static" -trimpath .
runtime/internal/sys
internal/goexperiment
internal/cpu
internal/abi
runtime/internal/atomic
runtime/internal/math
internal/bytealg
runtime
naphatkrit/go-bug-repro
# naphatkrit/go-bug-repro
loadinternal: cannot find runtime/cgo

执行二进制会导致陷阱错误

$ /tmp/my-binary
Trace/breakpoint trap

此外,以下是 strace 显示的内容:

root@3f441e3ed41c:/code# strace /tmp/my-binary
execve("/tmp/my-binary", ["/tmp/my-binary"], 0x7fff5db80d00 /* 10 vars */) = 0
brk(NULL)                               = 0xf03000
brk(0xf041c0)                           = 0xf041c0
arch_prctl(ARCH_SET_FS, 0xf03880)       = 0
uname({sysname="Linux", nodename="3f441e3ed41c", ...}) = 0
readlink("/proc/self/exe", "/tmp/my-binary", 4096) = 14
brk(0xf251c0)                           = 0xf251c0
brk(0xf26000)                           = 0xf26000
arch_prctl(ARCH_SET_FS, 0x55fd90)       = 0
--- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---
+++ killed by SIGTRAP +++
Trace/breakpoint trap

如果我强行包含 runtime/cgo,构建警告消失,编译后的二进制文件运行良好。

$ cat main.go
package main

import _ "runtime/cgo"

func main() {
}
$ go build -a -v -o /tmp/my-binary -ldflags "-linkmode external -extldflags -static" -trimpath .
internal/race
runtime/internal/sys
internal/abi
internal/cpu
internal/goexperiment
runtime/internal/atomic
sync/atomic
runtime/internal/math
internal/bytealg
runtime
sync
runtime/cgo
naphatkrit/go-bug-repro
$ /tmp/my-binary
$

我做的静态链接错了吗?

为方便起见,我已在https://github.com/naphatkrit/go-bug-repro 发布了我的repro


编辑:我意识到我过于简化了我的重现,这有损于我所面临的问题。我正在尝试做的是静态链接使用net 的二进制文件并关闭其 cgo 使用。

特别是,请考虑一下,看看它与上述问题有何相同:

package main

import _ "net"

func main() {
}
$ go build -a -v -o /tmp/gobuild -ldflags "-linkmode external -extldflags -static" -trimpath -tags 'netgo' .
...
loadinternal: cannot find runtime/cgo
$ /tmp/gobuild
Trace/breakpoint trap

【问题讨论】:

    标签: go


    【解决方案1】:

    Go 默认构建静态二进制文件(除非您实际使用 cgo 导入 C 代码)。 std 库有两个例外。 net 和 os/user 包默认使用本机代码。

    编辑:

    要在没有本机代码的情况下使用net 包,您可以这样做

    CGO_ENABLED=0 go build ...

    或

    go build -tags netgo ...

    但是你所拥有的也应该可以工作,尽管我会省略 -a 标志。

    【讨论】:

    • 我意识到在试图简化我的复制时,我删除了一些重要的上下文并混淆了这个问题。我要解决的问题是弄清楚如何正确静态链接使用 net 的二进制文件,同时仍然关闭其 cgo 使用。让我更新一下原来的问题。
    • 这很有趣...对于net,您可以使用CGO_ENABLED=0 go build ...,也可以使用“netgo”标签-go build -tags netgo ...。我将使用_ net 导入再次尝试您的代码,但我能够使用上述两种方法使用net/http 静态构建一些东西。
    猜你喜欢
    • 1970-01-01
    • 2013-06-02
    • 2013-10-06
    • 2015-03-19
    • 2014-10-25
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多