--- title: Go Modules and Packages tags: Go --- ## Summary - key reading in this [useful article] - `go generate` is ran by finding directive `//go:generate command arg` (not a comment) - `go mod tidy` does not look at what is required in `go generate` so need to manually download with `go get` - `go get` downloads packages to different location depending if `GO111MODULE` is set to auto / on / off - all required external packages in module-aware mode must be defined in their `go.mod`, even if it was define in a parent module ## Backgound I was going through the Flow [Fungible Token repo] and wanted to understand how to generate contracts bytes in [`lib/go/contracts`]. **Note:** `go generate` scans the file for directives, which are lines of the form: ```go //go:generate command argument... ``` which really confused me because I did not know it was not a comment. Anyway, in this case, the generation directives are in `lib/go/contracts` and packages in `lib/go/templates`. ```go //go:generate go run github.com/kevinburke/go-bindata/go-bindata -prefix ../../../contracts -o internal/assets/assets.go -pkg assets -nometadata -nomemcopy ../../../contracts/... ``` This means we need to have `github.com/kevinburke/go-bindata/go-bindata` available. This is where I ran into my first encounter of Go modules and packages. Simply put by this [useful article]: > If you work with Go, you deal with packages and modules all the time. In Go, a package is a directory of .go files, and packages form the basic building blocks of a Go program. Using packages, you organize your code into reusable units. A module, on the other hand, is a collection of Go packages, with dependencies and versioning built-in. However, throughout different versions of Go, modules were managed differently. I will only talk about from 1.16 onwards here. ### Go Env First, if we look at the env var for my local Go ```sh > go env GO111MODULE="" GOPATH="/Users/belsy/go" GOROOT="/usr/local/Cellar/go/1.16.4/libexec" GOVERSION="go1.16.4" ``` The interesting env var are listed above. In particular, we can see that this `GO111MODULE` is set to on. By default this is set to "" / on from Go version 1.16. This means go will assume it to be module-aware mode. ### Module-aware mode In short this means: - Go projects do not need to reside in GOPATH - Package management is greatly improved Practically, one can use a `go.mod` file to specify all the required packages which can be automated by using `go mod tidy`. In a sense, similar to `Cargo.toml` in Rust and `go.sum` is similar to `Cargo.lock` for locked versioning. Regardless if you have `go.mod`, the packages are all installed in the centralised `GOPATH/pkg/mod` ## What was the problem? All of the above is good and well, so what was the problem? First in `lib/go`, I ran: ```sh make generate ``` The error message I get is ```sh /Applications/Xcode.app/Contents/Developer/usr/bin/make generate -C contracts go generate no required module provides package github.com/kevinburke/go-bindata/go-bindata; to add it: go get github.com/kevinburke/go-bindata/go-bindata contracts.go:3: running "go": exit status 1 make[1]: *** [generate] Error 1 make: *** [generate] Error 2 ``` After running `go get github.com/kevinburke/go-bindata/go-bindata` in `lib/go` it is the same error. ### Solution 1: `go get` in module-aware mode without updating go.mod After running `go get github.com/kevinburke/go-bindata/go-bindata` in `lib/go`, the package was installed in the designated `~/go/pkg/mod/...` path. However, since the Makefile only called the command, where actually needed install this required package was in the modules within the directory, `lib/go/contracts`, `lib/go/templates` where `//go:generate ...` directives were found. So we have to manually go into each directory to get the packages, which results in updates to their mod files as Klaus has [provided]. ### Solution 2: `go get` not in module-aware mode In the absent of my knowledge about Go modules / packages, I had thought that `go get ...` was not a module-aware mode command - as it was before Go Modules. This was of course not true as discussed above. However, it took me down a road to learn that you can set `go env -w GO111MODULE=off` and use `go get` to download the third party packages to `GOPATH/src`. Since it is **not** module-aware, the `go.mod` files are ignored by Go. Go simply source the third package from `GOPATH/src` and run smoothly. [Fungible Token repo]: https://github.com/onflow/flow-ft [`lib/go/contracts`]: https://github.com/onflow/flow-ft/tree/master/lib/go/contracts [useful article]: https://levelup.gitconnected.com/using-modules-and-packages-in-go-36a418960556 [provided]: https://github.com/nanuuki/flow-ft/commit/c7369674bed3434cf9cfc70bda09c79495fae384