"go build" records the GOROOT info of the machine the result binary is produced on?

119 views
Skip to first unread message

tapi...@gmail.com

unread,
Mar 9, 2021, 12:38:19 AM3/9/21
to golang-nuts
I have two machines, their GOROOTs are different.
I build a binary on one machine then transfer the binary to the other.
It runs well on the machine the binary is produced on, but fails on the other.

The code reporting the error is

      unsafePkgerr := build.Import("unsafe""", build.FindOnly)
       if err != nil {
              log.Fatal(fmt.Errorf("build.Import: %w", err))
       }

The error is

      build.Import: go/build: go list unsafe: exit status 2
      go: cannot find GOROOT directory: /home/myname/path/of/GOROOT


Axel Wagner

unread,
Mar 9, 2021, 2:53:19 AM3/9/21
to tapi...@gmail.com, golang-nuts
https://golang.org/pkg/runtime/#GOROOT

GOROOT returns the root of the Go tree. It uses the GOROOT environment variable, if set at process start, or else the root used during the Go build.

I don't understand how you expect a binary to find GOROOT otherwise, if you don't set the environment variable.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/c02407eb-2fec-4195-8ef3-46a33e233c66n%40googlegroups.com.

Axel Wagner

unread,
Mar 9, 2021, 2:57:18 AM3/9/21
to tapi...@gmail.com, golang-nuts
(more immediately relevant is probably https://golang.org/pkg/go/build/#Default, but it documents the same behavior)

tapi...@gmail.com

unread,
Mar 9, 2021, 4:09:12 AM3/9/21
to golang-nuts
I see two problems here.

1. By the document, it looks it should check the result of `go env GOROOT` firstly, but it doesn't.

2. It exposes some personal privacy to make the last attempt work. By the document, it looks some personal privacy will be always record in the binary file, even if the last attempt is not adopted in the end.

Axel Wagner

unread,
Mar 9, 2021, 5:02:34 AM3/9/21
to tapi...@gmail.com, golang-nuts
On Tue, Mar 9, 2021 at 10:09 AM tapi...@gmail.com <tapi...@gmail.com> wrote:
1. By the document, it looks it should check the result of `go env GOROOT` firstly, but it doesn't.

I don't think that's true. The documentation says, it looks in $GOROOT and if that's not set, in the GOROOT of the go binary it was built on. `go env GOROOT`, on the other hand, first reports $GOROOT, if set, and otherwise reports the GOROOT *that particular go command resides in*. That is, `go env GOROOT` does not report $GOROOT, it also has its own, distinct fallback built in, which may differ from the one `foo` uses (if it was built with another go installation).

That, again, seems like the correct choice - after all, we can't assume there actually *is* a go command, when we run `foo`. It is common to run a go binary on a system without a go installation.

2. It exposes some personal privacy to make the last attempt work. By the document, it looks some personal privacy will be always record in the binary file, even if the last attempt is not adopted in the end.

That is true. I think the practicalities of being able to run go tools without configuration or environment variables outweigh this, though. For example, if a user installs go and (say) goimports from their distribution repository, we want the goimports binary to be able to find stdlib packages, even if the user does not have GOROOT set.
Having the actual filesystem paths built in also simplifies debugging - it means a debugger can find the files and show you source information. While `go env GOROOT` might be able to replace the fallback for the former use-case, it wouldn't be available to the debugger.

Note that you can always remove any host-specific information by building a go release in a generic path and use that to build go packages. That is also what happens if you use a go release provided by your distribution. So the downsides don't seem enormous, given that you can always circumvent them with relatively little hassle.


On Tuesday, March 9, 2021 at 2:53:19 AM UTC-5 axel.wa...@googlemail.com wrote:
https://golang.org/pkg/runtime/#GOROOT

GOROOT returns the root of the Go tree. It uses the GOROOT environment variable, if set at process start, or else the root used during the Go build.

I don't understand how you expect a binary to find GOROOT otherwise, if you don't set the environment variable.

On Tue, Mar 9, 2021 at 6:38 AM tapi...@gmail.com <tapi...@gmail.com> wrote:
I have two machines, their GOROOTs are different.
I build a binary on one machine then transfer the binary to the other.
It runs well on the machine the binary is produced on, but fails on the other.

The code reporting the error is

      unsafePkgerr := build.Import("unsafe""", build.FindOnly)
       if err != nil {
              log.Fatal(fmt.Errorf("build.Import: %w", err))
       }

The error is

      build.Import: go/build: go list unsafe: exit status 2
      go: cannot find GOROOT directory: /home/myname/path/of/GOROOT


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/c02407eb-2fec-4195-8ef3-46a33e233c66n%40googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

tapi...@gmail.com

unread,
Mar 9, 2021, 6:38:38 AM3/9/21
to golang-nuts
On Tuesday, March 9, 2021 at 5:02:34 AM UTC-5 axel.wa...@googlemail.com wrote:
On Tue, Mar 9, 2021 at 10:09 AM tapi...@gmail.com <tapi...@gmail.com> wrote:
1. By the document, it looks it should check the result of `go env GOROOT` firstly, but it doesn't.

I don't think that's true. The documentation says, it looks in $GOROOT and if that's not set, in the GOROOT of the go binary it was built on. `go env GOROOT`, on the other hand, first reports $GOROOT, if set, and otherwise reports the GOROOT *that particular go command resides in*. That is, `go env GOROOT` does not report $GOROOT, it also has its own, distinct fallback built in, which may differ from the one `foo` uses (if it was built with another go installation).

That, again, seems like the correct choice - after all, we can't assume there actually *is* a go command, when we run `foo`. It is common to run a go binary on a system without a go installation.

But isn't assuming GOROOT exists almost equivalent to assuming "go" command exists?

Axel Wagner

unread,
Mar 9, 2021, 7:04:17 AM3/9/21
to tapi...@gmail.com, golang-nuts
On Tue, Mar 9, 2021 at 12:39 PM tapi...@gmail.com <tapi...@gmail.com> wrote:
But isn't assuming GOROOT exists almost equivalent to assuming "go" command exists?

Maybe. As I said, it might have been possible to try `go env GOROOT` instead or in addition to looking at $GOROOT. It might even be possible to change that default now. There would likely still need to be *some* fallback (as exec'ing `go` might fail). I honestly don't know. I do know that the documentation currently does not say `go/build` is looking at `go env`, though, but that it directly inspects the environment.

In any case, note that you can get whatever behavior you like by explicitly setting Context.GOROOT. Given that it's easy to overwrite the default behavior and given that `go/build` should, in practice, be considered to be superseded by `golang.org/x/tools/go/packages`, I don't personally feel much need to discuss the particulars. Maybe someone else has more of a stake in this.

tapi...@gmail.com

unread,
Mar 9, 2021, 8:23:05 AM3/9/21
to golang-nuts
On Tuesday, March 9, 2021 at 7:04:17 AM UTC-5 axel.wa...@googlemail.com wrote:
On Tue, Mar 9, 2021 at 12:39 PM tapi...@gmail.com <tapi...@gmail.com> wrote:
But isn't assuming GOROOT exists almost equivalent to assuming "go" command exists?

Maybe. As I said, it might have been possible to try `go env GOROOT` instead or in addition to looking at $GOROOT. It might even be possible to change that default now. There would likely still need to be *some* fallback (as exec'ing `go` might fail). I honestly don't know. I do know that the documentation currently does not say `go/build` is looking at `go env`, though, but that it directly inspects the environment.

In any case, note that you can get whatever behavior you like by explicitly setting Context.GOROOT. Given that it's easy to overwrite the default behavior and given that `go/build` should, in practice, be considered to be superseded by `golang.org/x/tools/go/packages`, I don't personally feel much need to discuss the particulars. Maybe someone else has more of a stake in this.

`golang.org/x/tools/go/packages` parse "unsafe" in an unexpected way, which is why I turned to "build.Import" instead.

This workaround by setting Context.GOROOT. should work, I think. Thanks for the suggestion.
Reply all
Reply to author
Forward
0 new messages