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