What version of Go are you using (go version
)?
$ go version cgo version go1.19.11
Does this issue reproduce with the latest release?
This issue does reproduce with the latest release.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/dbernadett/.cache/go-build" GOENV="/home/dbernadett/.config/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/dbernadett/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/dbernadett/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/home/dbernadett/.cache/bazel/_bazel_dbernadett/f2fcdd1f2e8b2102ba2af9a91a4f07d8/external/go_sdk" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/home/dbernadett/.cache/bazel/_bazel_dbernadett/f2fcdd1f2e8b2102ba2af9a91a4f07d8/external/go_sdk/pkg/tool/linux_amd64" GOVCS="" GOVERSION="go1.19.11" GCCGO="gccgo" GOAMD64="v1" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/home/dbernadett/Nuro/go.mod" GOWORK="" 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 -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2772875216=/tmp/go-build -gno-record-gcc-switches"
What did you do?
I ran cgo with a large number of arguments which exceeded my computers argument limit for fork/exec. This is a common problem and usually addressed by allowing arguments to be specified through a params file.
What did you expect to see?
I expect to see a flag, such as -param which allows arguments to be passed to the cgo executable. This would be very similar to how it is implemented here: https://github.com/bazelbuild/rules_go/blob/4211c6d32ee475a8fde1cfc91571e7c0bed67af4/go/tools/builders/compilepkg.go#L45
What did you see instead?
Instead, there is no params flag and calling the cgo executable with too many params on some platfoms causes fork/exec to fail.
Comment From: seankhliao
can you give an example invocation?
Comment From: dbernadett
echo "go run main.go -ldflags=\\" > command.sh
for i in {1..10000}; do echo "'-lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread'\\" >> command.sh ; done
echo "'-lpthread'" >> command.sh
bash command.sh
The above will work for a trivial hello_world go program if the number of -lpthread args is small. However if we overrun the limits on the mac getconf ARG_MAX
as found in this stack overflow post this is the output:
dbernadett@dbernadett-laptop seperate % go version
go version go1.21.3 darwin/arm64
dbernadett@dbernadett-laptop seperate % bash gen_command.sh
command.sh: line 1: /usr/local/go/bin/go: Argument list too long
Comment From: cherrymui
By "the cgo executable" you mean the cmd/cgo
command? But the example you gave in https://github.com/golang/go/issues/63882#issuecomment-1789818731 is passing very long ldflags to the go
command, not the cgo
command. Why do you need to pass very long flags to cgo
? Can you use environment variable GOFLAGS
, CGO_CFLAGS
, CGO_LDFLAGS
, or #cgo
directives in the source file instead?
Comment From: dbernadett
Here would be a real example with cgo which also fails:
echo "go tool cgo -- \\" > command.sh
for i in {1..10000}; do echo "-lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread \\" >> command.sh ; done
echo "main.go" >> command.sh
bash command.sh
Here is an example of it failing with env_vars on mac
echo "go tool cgo -- \\" > command.sh
echo "main.go" >> command.sh
CGO_LDFLAGS=""
for i in {1..10000}; do
CGO_LDFLAGS+="-lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread "
done
export CGO_LDFLAGS
bash command.sh
The cgo directive is neat, but seems impractical for use by the rules_go bazel ruleset.
Comment From: cherrymui
Thanks. It is unclear why you need a large number of flags, though.
Also, the flags are mostly to pass to the C toolchain, could you just write a response file and pass @response
and the cgo tool will pass it through?
Comment From: dbernadett
I am working for a company which is using bazel to build our go programs. It is more valuable to us (and probably other companies) that rules_go can just pass a mass of arguments to the cgo command instead of spending a bunch of time figuring out what flags are neccessary, and then how to ensure only the necessary flags are emitted by the go_library
bazel rule.
What is a response file? Could you provide either an example or some link to documentation.
Comment From: cherrymui
https://gcc.gnu.org/wiki/Response_Files
https://man7.org/linux/man-pages/man1/gcc.1.html search for @file
on the page
Comment From: dbernadett
echo "go tool cgo -debug-gcc -- \\" > command.sh
echo "main.go" >> command.sh
CGO_CFLAGS="@arg_file.txt "
for i in {1..2}; do
CGO_CFLAGS+="-lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread -lpthread "
done
export CGO_CFLAGS
bash command.sh
bash gen_command_env_vars.sh > debug.txt 2>&1
When I run the above commands, my debug.txt
doesn't seem to have any references to -lpthread. Would you know how to modify this example to get them to show up in the gcc calls?
Comment From: dbernadett
Just an update, working on verifying that @param file works for me.
Comment From: cherrymui
go tool cgo -debug-gcc
doesn't seem to show the flags, regardless of whether @param
is used or not. go tool cgo -debug-gcc
doesn't compile the C code anyway, so I'm not sure whether/why you want to pass those flags. Try go build -x
.
Still, could you show a real example that you need to pass a very long command line (not a synthetic one that pass -lpthread
many times)?
Comment From: dbernadett
Unfortunately I am working on proprietary code, but suffice it to say that we are using the go compiler through bazel. Is there a reason you need a concrete example?
Comment From: dbernadett
I could probably get a sample invocation, but it woulnd't be the easiest thing to do.
Comment From: dbernadett
Here is another description of the bug from the rules_go folks https://github.com/bazelbuild/rules_go/issues/2654
Comment From: dbernadett
Here is the line that generates a "way too long" CGO_LDFLAGS environment variable. https://github.com/bazelbuild/rules_go/blob/f2d409bc52d4945f283e89f8b501cbab65c83fbb/go/tools/builders/cgo2.go#L142 Maybe at this point we could create a params file and send it to cgo using the @paramfile syntax?
Comment From: gopherbot
Timed out in state WaitingForInfo. Closing.
(I am just a bot, though. Please speak up if this is a mistake or you have the requested information.)
Comment From: ianlancetaylor
Whatever problem remains here is probably fixed in the 1.23 release by https://go.dev/cl/584655.