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.
go version)?go version go1.10 linux/amd64
Yes.
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"
2 Go files:
// cgo.go
package main
import "C"
func test() {
}
// main.go
package main
func main() {
test()
}
md5-4be1b38e4d4bfaecc24d7d8c93f3527e
# test
./main.go:4:2: undefined: test
Did you run go build ?
Yes, the two commands I used for comparison are:
GOOS=linux go build
GOOS=windows go build
The second one produces the "undefined" error message.
Hmm .. same problem to me. It seems like go can not find source file which import "C" when GOOS=windows
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
.
@davecheney I am aware, the issue in question is more about the lack of a proper error message instead of silently ignoring the affected files and thus causing "undefined" errors.
Should all packages using cgo fail to build with CGO_ENABLED=0? That seems wrong to me - some standard library packages build both with and without cgo, such as os/user.
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.
Even go vet would indeed be very helpful, as I spent quite some time trying to find out why my build wouldn't work.
Regarding letting builds fail, I definitely don't think it should, but even building with -x -v doesn't give any information about skipping the file because there isn't any.
All I'm asking for is more information for when this occurs. And you could potentially suppress any warnings/errors when the //+build cgo is used.
The Go compiler doesn't have a notion of warnings, so -x -v should not affect its output.
I guess another option, which is similar to what you're asking, is to make the compiler give a helpful message in this case. But, for it to know to do that, it would have to know that the package type-checks properly with CGO. That's a non-trivial amount of extra work involved.
I'll leave that one to you/the team, as I have no knowledge of the compiler itself. I opened this issue as someone I had spoken to not too long ago was getting this same error without knowing why, and it wasn't until encountering it myself that I understood the cause of it. Any kind of message either in the compiler or even the documentation would be very helpful.
The documentation ( https://golang.org/cmd/cgo/#hdr-Using_cgo_with_the_go_command ) currently specifies that CGO_ENABLED will be disabled if the target platform is different from the host, but fails to mention that any files still using import "C" will be ignored as if //+build cgo is implied.
So even if the amount of work required to add a helpful compiler message is non-trivial, I'd imagine a slight addition to the documentation wouldn't be.
Agreed that improving the documentation is an easy win - if you'd like to help, you're most welcome to. Should be easy now that we accept pull requests.
Change https://golang.org/cl/96655 mentions this issue: cmd/cgo: clarify implicit "cgo" build constraint
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.
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 ...".
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).
Compare #26967.
While I can't speak for the complexity/reward ratio as rsc mentions, personally it would've saved me a few hours of debugging. That said, my personal problem was more along the lines of the cgo build tag being implied moreso than a build tag being enforced.
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]
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...
I had this problem and solved it by deleting the line "package main" in the first line of the go-file
and type "package whatever", did "go build ."
Then I changed back to "package main" and did "go build ." and the problem was resolved.
(I figured the problem came from pasting in code from a webpage, perhaps not unix-style but windows style?)
Hope it helps!
I can reproduce it without CGO_ENABLED involved. This compiler error is not precise.
Most helpful comment
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_ENABLEDenvironment variable.