This is my understanding of go packaging from playing around trying to do what I wanted, not what other tutorials wanted me to do. More info: module reference
To get a simple go sandbox, let's demo in a container
> docker run -it golang
First, what is our GOPATH? If it isn't set, go defaults to ~/go.
> echo $GOPATH
/go
This is the location that packages and executables are installed to - usually
containing bin/, pkg/ and src/.
Go searches each directory listed in GOPATH to find source code, but new packages are always downloaded into the first directory in the list.
Lets make a new go module. We can write it to any in the list of $GOPATH/src
directories.
> mkdir /go/src/foo
> cd /go/src/foo
> go mod init jenne.uk/foo # creates go.mod
The go module is named with a domain to distinguish modules that may have the
same name, for a repo on github it might be called github.com/<user>/<repo>.
Let's look at what a dummy package might look like. Say we've just written the following three go files.
> tree
/go/src/foo
├── go.mod
├── a.go
├── b.go
└── bar
└── c.go
> cat a.go
package main
import (
"fmt"
"jenne.uk/foo/bar"
)
func main() {
fmt.Println("a")
printName()
bar.PrintName()
}
> cat b.go
package main
import "fmt"
func printName() {
fmt.Println("b")
}
> cat bar/c.go
package bar
import "fmt"
func PrintName() {
fmt.Println("c")
}
First we see that every go file needs to begin with a package statement. All
root level go files are part of the main package (if creating an executable
rather than a library), one of which defines the main() function where
execution starts.
A package is a directory containing go files. All files in that directory have
the same package <name> statement, the directory name doesn't matter.
Second we see that any function defined in a package (directory) is available
implicitly across the package. Function printName() defined in b.go can be
called in a.go.
Third we see that to import another package (even if defined in the same
module), we use the module prefix jenne.uk/foo in front of the name defined
in our package statement: package bar. Note, across pacakges, that we can
only import/export names that are capitalised - like PrintName() in bar.
So let's run this executable by passing all the files in the main package:
> go run a.go b.go
b
c
we could equally build and run the executable:
> go build
> ./foo
a
b
c
or install the executable to $GOPATH/bin:
> go install
> ls /go/bin
foo