---
# System prepended metadata

title: Go Modules and Packages
tags: [Go]

---

---
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
