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: documentation of go build -o flag is misleading #36784

Closed
perillo opened this issue Jan 26, 2020 · 18 comments
Closed

cmd/go: documentation of go build -o flag is misleading #36784

perillo opened this issue Jan 26, 2020 · 18 comments
Labels
Documentation FrozenDueToAge GoCommand cmd/go WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Milestone

Comments

@perillo
Copy link
Contributor

perillo commented Jan 26, 2020

The documentation of go build says:

The -o flag forces build to write the resulting executable or object
to the named output file or directory, instead of the default behavior described
in the last two paragraphs. If the named output is a directory that exists,
then any resulting executables will be written to that directory.

However an object is generated only if the -o flag specifies a file.

To make things more confusing, when I have a non main package in the project root and a main package in a sub-directory, go build -o file ./... reports:

go build: cannot write multiple packages to non-directory file
@ianlancetaylor ianlancetaylor changed the title go/cmd: documentation of go build -o flag is misleading cmd/go: documentation of go build -o flag is misleading Jan 26, 2020
@bcmills
Copy link
Contributor

bcmills commented Jan 27, 2020

Emphasis mine:

If the named output is a directory that exists, then any resulting executables will be written to that directory.

go build -o dir ./... does not generate non non-executable objects because they are not executables.

go build -o file ./... does not write an executable to the file because it would be ambiguous, and if you know that there is only one executable you may as well request only that executable.

(CC @jayconrod @matloob)

@bcmills
Copy link
Contributor

bcmills commented Jan 27, 2020

The -o dir functionality was added for #14295, and intended to address the use-cases there.

Could you describe the use-cases that led you to expect different behavior for these conditions? That might help us better tailor the documentation and/or behavior for those use-cases.

@bcmills bcmills added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Jan 27, 2020
@bcmills bcmills added this to the Unplanned milestone Jan 27, 2020
@perillo
Copy link
Contributor Author

perillo commented Feb 1, 2020

It is just that the documentation and error message seems a bit inconsistent to me.
As an example cannot write multiple packages to non-directory file may means that multiple packages (objects) can be written to a directory.

However today I found a behavior that surprised me. In my Go projects I have a Makefile with the rule:

build:
	go build -o build ./...

I have to change the rule to go build ./... when there are no main packages, but today I notice that when I have both main a non main packages, the non main packages are not compiled (and discarded).

This is consistent with how go build behave, however I think it would be much more intuitive is go build -o build ./... will compile everything and write the resulting executables and/or object files to the build directory.

@bcmills
Copy link
Contributor

bcmills commented Feb 3, 2020

I have to change the rule to go build ./... when there are no main packages

That probably should not be necessary. However, that is significantly different from the issue that you reported initially, which was that “an object is generated only if the -o flag specifies a file.”

@perillo
Copy link
Contributor Author

perillo commented Feb 5, 2020

Sorry, probably it was a _test.go file that contained an error and was ignored (as documented) by go build.

About the documentation, what do you think about changing

The -o flag forces build to write the resulting executable or object
to the named output file or directory, instead of the default behavior described
in the last two paragraphs. If the named output is a directory that exists,
then any resulting executables will be written to that directory.

to

The -o flag forces build to write the resulting executable or object
to the named output file, instead of the default behavior described
in the last two paragraphs. If the named output is a directory that exists,
then any resulting executables will be written to that directory.

From some tests, go build never writes an object file to a directory; you have to specify a file.

$ go build/ -o build ./pkg
go build: no main packages to build

Thanks.

@bcmills
Copy link
Contributor

bcmills commented Feb 5, 2020

I would like the first clause of the sentence to be complete and accurate, since that is often the only part that folks read (especially when they're just skimming flag descriptions).

So I think we need to keep “directory” in that first clause, rather than deferring it to the next sentence.

@perillo
Copy link
Contributor Author

perillo commented Feb 5, 2020

I can't think of a good solution .
The problem is that go build treats main packages and non main packages differently.

If the -o flag is a file, go build will write both the executable or the archive to that file.

But if the -o flag is a directory, go build will not write the resulting archive to an output file (in the directory specified by the -o flag) named after the first source file or the source code directory, like with a main package.

@bcmills
Copy link
Contributor

bcmills commented Feb 7, 2020

The problem is that go build treats main packages and non main packages differently.

That property is intentional: the use-case in #14295 is to be able to build all of the binaries in a given project, without the restrictions of GOBIN (which, at least according to our documentation, must be an absolute path).

So, can we step up a level? What is the concrete problem that you're trying to address where the behavior of the -o flag is causing trouble? (Maybe we can find a clearer way to address that use-case directly.)

@perillo
Copy link
Contributor Author

perillo commented Feb 7, 2020

The problem is the one I wrote in the issue title: documentation of go build -o flag is misleading, at least for me.

Thanks.

@pjweinb
Copy link

pjweinb commented Aug 11, 2020

it's more than a documentation problem. if -o is a directory and one is building a non-main package, go build reports an error

go build -o /tmp /Users/pjw/tools/internal/lsp
go build: no main packages to build

go build -o /tmp/foo /Users/pjw/tools/internal/lsp
no error

gopherbot pushed a commit to golang/tools that referenced this issue Aug 11, 2020
https://go-review.googlesource.com/c/tools/+/246419/2 fixed a problem
but introduced a new one, as go build treats -o directories differently
depending on whether or not a main package is being built.
(see  golang/go#36784)

This change explicitly constructs a temporary file for go build
to use.

Change-Id: I096748e9af5014428dab8a5aad703f062fe88d50
Reviewed-on: https://go-review.googlesource.com/c/tools/+/247899
Run-TryBot: Peter Weinberger <pjw@google.com>
Reviewed-by: Pontus Leitzler <leitzler@gmail.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
@cherrymui
Copy link
Member

I run into this as well.

$ go build -o /tmp runtime
go build: no main packages to build
$ go build -o /tmp/runtime.a runtime # works

I usually spell out the file name. I was just feeling lazy today.

Also, related, or not,

$ go test -c -o /tmp runtime
go test runtime.test: build output "/tmp" already exists and is a directory

This time it is an executable, but it doesn't work. go test's -o flag is documented separately, so it may not be the same issue.

Reading this issue, I'm not sure what is the intended behavior. Maybe it is fine if this is intended. I just shouldn't be lazy...

@perillo
Copy link
Contributor Author

perillo commented Apr 14, 2021

The current documentation is

The -o flag forces build to write the resulting executable or object
to the named output file or directory, instead of the default behavior described
in the last two paragraphs. If the named output is an existing directory or
ends with a slash or backslash, then any resulting executables
will be written to that directory.

It still incorrectly says that an object can be written to a directory. Unfortunately I can't think of a better way to express this without making the documentation harder to read.

@perillo

This comment was marked as resolved.

@seankhliao

This comment was marked as resolved.

@gopherbot
Copy link

Change https://golang.org/cl/312391 mentions this issue: cmd/go/internal/work: make go build more consistent

@bcmills

This comment was marked as resolved.

@perillo

This comment was marked as resolved.

normegil added a commit to normegil/evevulcan that referenced this issue May 11, 2021
normegil added a commit to normegil/evevulcan that referenced this issue May 12, 2021
@seankhliao seankhliao added WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. GoCommand cmd/go and removed WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. labels Dec 26, 2022
@gopherbot
Copy link

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.)

@golang golang locked and limited conversation to collaborators Jan 26, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Documentation FrozenDueToAge GoCommand cmd/go WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

6 participants