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