go: cmd/go: give a better error message when building Go package with CGO_ENABLED=0

When trying to cross compile the go compiler silently ignores any files that use import "C" statement. In this example I’ve tried to compile for windows on a linux host machine, but this issue seems to be present on other host platforms as well. It seems to do this because it disables CGO_ENABLED being disabled by default when the host and target platform mismatch despite the required toolchains being present (mingw-w64 in my case).

I managed to resolve this issue by enabling CGO_ENABLED and setting CC and CXX, but this issue is more about the unclear error message.

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

go version go1.10 linux/amd64

Does this issue reproduce with the latest release?

Yes.

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

Without GOOS:

GOARCH="amd64"
GOBIN=""
GOCACHE="/home/ikkerens/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/usr/lib/go:/var/git/Go"
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
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-build897508503=/tmp/go-build -gno-record-gcc-switches"

With GOOS=windows

GOARCH="amd64"
GOBIN=""
GOCACHE="/home/ikkerens/.cache/go-build"
GOEXE=".exe"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="windows"
GOPATH="/usr/lib/go:/var/git/Go"
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="0"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-m64 -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build822882573=/tmp/go-build -gno-record-gcc-switches"

What did you do?

2 Go files:

// cgo.go
package main

import "C"

func test() {
}
// main.go
package main

func main() {
        test()
}

What did you expect to see?

Some kind of warning that cgo.go is being skipped in compilation due to CGO_ENABLED being 0.

What did you see instead?

# test
./main.go:4:2: undefined: test

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 17
  • Comments: 22 (15 by maintainers)

Commits related to this issue

Most upvoted comments

imho the result is even worse if you consider the example of @ikkerens with any external package imported, e.g.

// cgo.go
package main

import "C"
import "github.com/pkg/errors" // just an arbitrary package

func test() {
        _ = errors.New("my error")
}

Instead of ./main.go:4:2: undefined: test the error message will be cannot find module for path github.com/pkg/errors. This just took me literally hours, because I was expecting an imported package to be dependent on CGO, while the actual issue was just me forgetting about an import "C" in the code.

This is really misleading and hard to track down…

One way we could do better would be for the go tool, if there is a compilation error, to report that some files were excluded due to build constraints (we already do that for the case where build constraints exclude all files). We could perhaps even pay closer attention to the cgo build constraint, and explicitly point the user to docs about the CGO_ENABLED environment variable.

Something else that comes to mind is a static analysis check (in vet?) that would say something along the lines of this package will fail to cross-compile and build with CGO_ENABLED=0. That is, checking if a package typechecks properly both with and without the cgo build tag.

cgo is disabled when cross compiling.

On 23 February 2018 at 23:51, mingrammer notifications@github.com wrote:

Hmm … same problem to me. It seems like go can not find source file which import “C”.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/golang/go/issues/24068#issuecomment-368000943, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAcA6QypqjQExMh4eOyNRD3rHH6LVhxks5tXrRTgaJpZM4SQ0Ut .

That is, we don’t have the type check the package assuming a different set of build constraints. We just note that the compilation failed and print “by the way, the following files were not passed to the compiler due to build constraints: x.go …”.

I just recently experienced something similar when trying to cross-compile, I think that the error message should also print the build constraints being applied, i.e.:

# $ go env
#    GOOS=windows
#    GOARCH=386
#    CGO_ENABLED=1
go build -tags "abc" ./subpkg

if the constraints happen to exclude all files, then it’d be great if it printed something like the following:

go build example.com/mainpkg/subpkg: build constraints ("cgo windows 386 abc")  exclude all Go files in /path/to/sources/example.com/mainpkg/subpkg

In my case I was cross-compiling from Windows Subsystem for Linux to a windows target that had CGO files, I initially had not set CGO_ENABLED=1 and it took me a while to realize it b.c. the only build constraints I had in mind where windows, 386 and abc and the error message did not bring it up.

Getting the applied build constraints would allow one to do the following:

$ go list -tags 'cgo windows 386 abc' -f '{{.IgnoredGoFiles}}' ./subpkg
[important.go]

It’d be great if the go list command supported printing also the non-go files that are ignored, something like:

$ go list -tags 'cgo windows 386 abc' -f '{{.IgnoredFiles}}' ./subpkg
[important.go bindings.c]