golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.06k stars 17.68k forks source link

cmd/go: clarify package argument in 'go help run' summary #41830

Open brandondube opened 4 years ago

brandondube commented 4 years ago

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

$ go version
go version go1.14.4 darwin/amd64

Does this issue reproduce with the latest release?

I don't know

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/bdube/Library/Caches/go-build"
GOENV="/Users/bdube/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY="redacted"
GONOSUMDB="redacted"
GOOS="darwin"
GOPATH="/Users/bdube/go"
GOPRIVATE="redacted"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/Users/bdube/.asdf/installs/golang/1.14.4/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/bdube/.asdf/installs/golang/1.14.4/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/bdube/source/golab/go.mod"
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 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/1m/s4hjpz8s4wxfmj189l4chx30z_vgf2/T/go-build827010893=/tmp/go-build -gno-record-gcc-switches -fno-common

What did you do?

run go run main.go in a directory containing:

$tree
.
├── lib.go
├── main.go

What did you expect to see?

A successful compilation, on the basis that go help run begins with

$go help run
usage: go run [build flags] [-exec xprog] package [arguments...]

Run compiles and runs the named main Go package.

I wish to emphasize package and not file.

What did you see instead?

$ go run main.go
# command-line-arguments
./main.go:28:26: undefined: Config
./main.go:101:7: undefined: Config
./main.go:118:7: undefined: Config
./main.go:131:7: undefined: Config
./main.go:136:9: undefined: BuildMux

(build errors due to undefined symbols from lib.go)


The documentation for Go is very explicit in what a package is:

A package is a collection of source files in the same directory that are compiled together.

~ https://golang.org/doc/code.html#Organization

The output of $ go help packages perhaps disagrees:

$ go help packages 
Many commands apply to a set of packages:

    go action [packages]

Usually, [packages] is a list of import paths.

An import path that is a rooted path or that begins with
a . or .. element is interpreted as a file system path and
denotes the package in that directory.

Otherwise, the import path P denotes the package found in
the directory DIR/src/P for some DIR listed in the GOPATH
environment variable (For more details see: 'go help gopath').

If no import paths are given, the action applies to the
package in the current directory.
[...]

It may disagree on the basis of what an import path means. If import path ~= folder, then the file main.go is not a package, but the set of .go files in the directory is a package.

If we are to say that main.go is given as an identifier for its package, then go run main.go should pull in all source files for the package. I think that if main.go is given as a package in and of itself, this is different to an import path in the usual semantics of the language and the documentation (and wealth of tutorials, books, and so forth) about the language should also be updated.

bcmills commented 4 years ago

You mentioned go help packages, but didn't get to the paragraph that covers this case:

As a special case, if the package list is a list of .go files from a single directory, the command is applied to a single synthesized package made up of exactly those files, ignoring any build constraints in those files and ignoring any other files in the directory.

In that case, the “package” is still “a collection of source files in the same directory that are compiled together“ — it's just that the subset of the directory included in the package is determined by the command-line arguments rather than the usual build constraints.

brandondube commented 4 years ago

I guess the interpretation boils down to where the active word in the sentence "A package is a collection of source files in the same directory that are compiled together." is. If being in the same directory is acting, then it states that all go files in a directory must be in the same package. It is a compiler (linter? At least tooling...) error when you have files that declare different packages in the same directory. The majority of writing on Go nods in that direction.

If being in the same directory is passive (a requirement, but not defining), then I would say the behavior of go build main.go in this case is correct, otherwise I believe it is a bug.

There is a meta topic, too, of what determines what a package is at all -- can command line arguments restrict the scope of consideration for being a package? Why? Do the language rules allow sufficient ambiguity for there to be interpretation? Isn't the point of the language to be completely explicit, always, and remove ambiguity?