Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/go: 1.8beta2 cross compilation fails without CGO_ENABLED=0 #18360

Closed
tsuna opened this issue Dec 17, 2016 · 7 comments
Closed

cmd/go: 1.8beta2 cross compilation fails without CGO_ENABLED=0 #18360

tsuna opened this issue Dec 17, 2016 · 7 comments

Comments

@tsuna
Copy link
Contributor

tsuna commented Dec 17, 2016

What version of Go are you using (go version)?

go version go1.8beta2 darwin/amd64

What operating system and processor architecture are you using (go env)?

mid-2012 MBP running macOS 10.9.5

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/tsuna/go"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.8beta2/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.8beta2/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

Try to cross-compile the following program

package main

import "net"

func main() {
	net.Listen("tcp", "127.0.0.1:0")
}

What did you expect to see?

$ brew switch go 1.7.4
3 links created for /usr/local/Cellar/go/1.7.4
$ GOOS=linux GOARCH=386 go build ./main.go
$ file main
main: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped

What did you see instead?

$ brew switch go 1.8beta2
3 links created for /usr/local/Cellar/go/1.8beta2
$ GOOS=linux GOARCH=386 go build ./main.go
# runtime/cgo
ld: unknown option: --build-id=none
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Additional information

Output with -x with Go 1.7.4:

$ GOOS=linux GOARCH=386 go build -x ./main.go
WORK=/var/folders/8j/3m62t7m92958kqxt9s3chtrr0000gn/T/go-build342276376
mkdir -p $WORK/command-line-arguments/_obj/
mkdir -p $WORK/command-line-arguments/_obj/exe/
cd /Users/tsuna/go/src/arista
/usr/local/Cellar/go/1.7.4/libexec/pkg/tool/darwin_amd64/compile -o $WORK/command-line-arguments.a -trimpath $WORK -p main -complete -buildid fe4cb02508eb842193f386e2b4cc9600cbc8577a -D _/Users/tsuna/go/src/arista -I $WORK -pack ./main.go
cd .
/usr/local/Cellar/go/1.7.4/libexec/pkg/tool/darwin_amd64/link -o $WORK/command-line-arguments/_obj/exe/a.out -L $WORK -extld=clang -buildmode=exe -buildid=fe4cb02508eb842193f386e2b4cc9600cbc8577a $WORK/command-line-arguments.a
mv $WORK/command-line-arguments/_obj/exe/a.out main

Output with -x with Go 1.8beta2:

$ GOOS=linux GOARCH=386 go build -x ./main.go
WORK=/var/folders/8j/3m62t7m92958kqxt9s3chtrr0000gn/T/go-build080300991
mkdir -p $WORK/runtime/cgo/_obj/
mkdir -p $WORK/runtime/
cd /usr/local/Cellar/go/1.8beta2/libexec/src/runtime/cgo
CGO_LDFLAGS="-g" "-O2" "-lpthread" /usr/local/Cellar/go/1.8beta2/libexec/pkg/tool/darwin_amd64/cgo -objdir $WORK/runtime/cgo/_obj/ -importpath runtime/cgo -import_runtime_cgo=false -import_syscall=false -- -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror cgo.go
cd $WORK
clang -fdebug-prefix-map=a=b -c trivial.c
clang -gno-record-gcc-switches -c trivial.c
cd /usr/local/Cellar/go/1.8beta2/libexec/src/runtime/cgo
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/_cgo_export.o -c $WORK/runtime/cgo/_obj/_cgo_export.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/cgo.cgo2.o -c $WORK/runtime/cgo/_obj/cgo.cgo2.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/gcc_context.o -c ./gcc_context.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/gcc_fatalf.o -c ./gcc_fatalf.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/gcc_libinit.o -c ./gcc_libinit.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/gcc_linux_386.o -c ./gcc_linux_386.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/gcc_setenv.o -c ./gcc_setenv.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/gcc_traceback.o -c ./gcc_traceback.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/gcc_util.o -c ./gcc_util.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/gcc_386.o -c ./gcc_386.S
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -I $WORK/runtime/cgo/_obj/ -g -O2 -Wall -Werror -o $WORK/runtime/cgo/_obj/_cgo_main.o -c $WORK/runtime/cgo/_obj/_cgo_main.c
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -o $WORK/runtime/cgo/_obj/_cgo_.o $WORK/runtime/cgo/_obj/_cgo_main.o $WORK/runtime/cgo/_obj/_cgo_export.o $WORK/runtime/cgo/_obj/cgo.cgo2.o $WORK/runtime/cgo/_obj/gcc_context.o $WORK/runtime/cgo/_obj/gcc_fatalf.o $WORK/runtime/cgo/_obj/gcc_libinit.o $WORK/runtime/cgo/_obj/gcc_linux_386.o $WORK/runtime/cgo/_obj/gcc_setenv.o $WORK/runtime/cgo/_obj/gcc_traceback.o $WORK/runtime/cgo/_obj/gcc_util.o $WORK/runtime/cgo/_obj/gcc_386.o -g -O2 -lpthread
/usr/local/Cellar/go/1.8beta2/libexec/pkg/tool/darwin_amd64/cgo -dynpackage cgo -dynimport $WORK/runtime/cgo/_obj/_cgo_.o -dynout $WORK/runtime/cgo/_obj/_cgo_import.go -dynlinker
cd $WORK
clang -no-pie -c trivial.c
cd /usr/local/Cellar/go/1.8beta2/libexec/src/runtime/cgo
clang -I . -fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -o $WORK/runtime/cgo/_obj/_all.o $WORK/runtime/cgo/_obj/_cgo_export.o $WORK/runtime/cgo/_obj/cgo.cgo2.o $WORK/runtime/cgo/_obj/gcc_context.o $WORK/runtime/cgo/_obj/gcc_fatalf.o $WORK/runtime/cgo/_obj/gcc_libinit.o $WORK/runtime/cgo/_obj/gcc_linux_386.o $WORK/runtime/cgo/_obj/gcc_setenv.o $WORK/runtime/cgo/_obj/gcc_traceback.o $WORK/runtime/cgo/_obj/gcc_util.o $WORK/runtime/cgo/_obj/gcc_386.o -g -O2 -Wl,-r -nostdlib -Wl,--build-id=none
# runtime/cgo
ld: unknown option: --build-id=none
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Output with -x with Go 1.8beta2 with CGO_ENABLED=0:

$ CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -x ./main.go
WORK=/var/folders/8j/3m62t7m92958kqxt9s3chtrr0000gn/T/go-build902542865
mkdir -p $WORK/net/_obj/
mkdir -p $WORK/
cd /usr/local/Cellar/go/1.8beta2/libexec/src/net
/usr/local/Cellar/go/1.8beta2/libexec/pkg/tool/darwin_amd64/compile -o $WORK/net.a -trimpath $WORK -p net -buildid faa57ce85e83a4bd8e6d6a838952d59be1a0d72c -D _/usr/local/Cellar/go/1.8beta2/libexec/src/net -I $WORK -pack ./addrselect.go ./cgo_stub.go ./conf.go ./dial.go ./dnsclient.go ./dnsclient_unix.go ./dnsconfig_unix.go ./dnsmsg.go ./fd_mutex.go ./fd_poll_runtime.go ./fd_posix.go ./fd_unix.go ./file.go ./file_unix.go ./hook.go ./hook_cloexec.go ./hook_unix.go ./hosts.go ./interface.go ./interface_linux.go ./ip.go ./iprawsock.go ./iprawsock_posix.go ./ipsock.go ./ipsock_posix.go ./lookup.go ./lookup_unix.go ./mac.go ./net.go ./nss.go ./parse.go ./pipe.go ./port.go ./port_unix.go ./sendfile_linux.go ./sock_cloexec.go ./sock_linux.go ./sock_posix.go ./sockopt_linux.go ./sockopt_posix.go ./sockoptip_linux.go ./sockoptip_posix.go ./tcpsock.go ./tcpsock_posix.go ./tcpsockopt_posix.go ./tcpsockopt_unix.go ./udpsock.go ./udpsock_posix.go ./unixsock.go ./unixsock_posix.go ./writev_unix.go
mkdir -p $WORK/command-line-arguments/_obj/
mkdir -p $WORK/command-line-arguments/_obj/exe/
cd /Users/tsuna/go/src/arista
/usr/local/Cellar/go/1.8beta2/libexec/pkg/tool/darwin_amd64/compile -o $WORK/command-line-arguments.a -trimpath $WORK -p main -complete -buildid 75b54d4cf228f82475f968e679ea5b98632c9f49 -D _/Users/tsuna/go/src/arista -I $WORK -pack ./main.go
cd .
/usr/local/Cellar/go/1.8beta2/libexec/pkg/tool/darwin_amd64/link -o $WORK/command-line-arguments/_obj/exe/a.out -L $WORK -extld=clang -buildmode=exe -buildid=75b54d4cf228f82475f968e679ea5b98632c9f49 $WORK/command-line-arguments.a
mv $WORK/command-line-arguments/_obj/exe/a.out main
@davecheney
Copy link
Contributor

davecheney commented Dec 17, 2016 via email

@tsuna
Copy link
Contributor Author

tsuna commented Dec 17, 2016

This is my go env with 1.7.4:

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/tsuna/go"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.7.4/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.7.4/libexec/pkg/tool/darwin_amd64"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"

Looking at this a bit closer, I see that the differences between 1.7.4 and 1.8beta2, I'm wondering whether this is not a packaging bug with homebrew, as it appears that now the default value of CGO_ENABLED is recorded when go itself is built (by cmd/dist/buildgo.go), and on my system I found

$ rg defaultCGO_ENABLED /usr/local/Cellar/go/1.8beta2
[...]
/usr/local/Cellar/go/1.8beta2/libexec/src/go/build/zcgo.go
5:const defaultCGO_ENABLED = "1"

This was changed in commit 0ba3c60 as part of #12808, which I just read. I'm not sure what to think, with either of these versions of Go go env shows CGO_ENABLED="1" but with Go 1.7.4 it gets turned off automatically when cross compiling, which seems to be what we want based on #5104.

@tsuna
Copy link
Contributor Author

tsuna commented Dec 17, 2016

Ha, just seeing your reply @davecheney, looks like we're coming to the same conclusion. So was this working by chance with homebrew with earlier versions of Go, because CGO_ENABLED wasn't sticky before?

Are we really saying "if you want to cross-compile, you should build Go itself with CGO_ENABLED=0 or, at the time you cross-compile, build with CGO_ENABLED=0"?

@davecheney
Copy link
Contributor

davecheney commented Dec 17, 2016 via email

@tsuna
Copy link
Contributor Author

tsuna commented Dec 17, 2016

I'm not sure I follow now... But homebrew didn't change how it builds Go between 1.7.4 and 1.8beta2. See https://github.com/Homebrew/homebrew-core/commits/master/Formula/go.rb – the formula has been building Go with CGO_ENABLED=1 in the environment by default for a long time.

@minux
Copy link
Member

minux commented Dec 17, 2016 via email

@tsuna
Copy link
Contributor Author

tsuna commented Dec 17, 2016

OK so their formula was working by chance before. What you're saying is that unless the user wants to explicitly disable cgo by building the formula with --without-cgo, the formula should not set CGO_ENABLED to any value during the build.

I tested this change to their formula and indeed things now works as intended:

--- a/Formula/go.rb
+++ b/Formula/go.rb
@@ -63,7 +63,9 @@ class Go < Formula
     cd "src" do
       ENV["GOROOT_FINAL"] = libexec
       ENV["GOOS"]         = "darwin"
-      ENV["CGO_ENABLED"]  = build.with?("cgo") ? "1" : "0"
+      if build.without? "cgo"
+        ENV["CGO_ENABLED"] = "0"
+      end
       system "./make.bash", "--no-clean"
     end
 

I'll send them a pull request. Thanks for the quick response!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants