Skip to content

Instantly share code, notes, and snippets.

@kmoe
Created March 2, 2020 15:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kmoe/21368bcf91cae532041921756f0a1511 to your computer and use it in GitHub Desktop.
Save kmoe/21368bcf91cae532041921756f0a1511 to your computer and use it in GitHub Desktop.

Makefiles and Go vendoring

TL;DR

Vendoring in Go 1.13+ probably doesn't work the way you expect, and neither do environment variables in Makefiles. If you maintain a Terraform provider, it's likely your vendor/ directory is being completely ignored during builds and releases.

Add this to the top of your Makefile/GNUMakefile:

.EXPORT_ALL_VARIABLES:
GOFLAGS=-mod=vendor

Go vendoring

As of Go 1.13, the go command runs in module mode by default. When in module mode, it completely ignores vendor/ directories (https://tip.golang.org/cmd/go/#hdr-Modules_and_vendoring).

To override this, use the -mod=vendor flag on commands like go build, or set GOFLAGS=-mod=vendor in the environment.

Environment variables in Makefiles

Variables set in the standard way (FOO=bar) at the top of Makefiles are not automatically exported to child processes, although they can be interpolated into commands run in that Makefile's targets.

Variables can be exported to child processes by setting the .EXPORT_ALL_VARIABLES pseudo-target, as described in the manual: https://www.gnu.org/software/make/manual/make.html#index-_002eEXPORT_005fALL_005fVARIABLES

Example

Consider the following Makefile:

.EXPORT_ALL_VARIABLES:
GOFLAGS=-mod=vendor

target:
	go env | grep GOFLAGS

When make is run, the following output will appear:

$  make
go env | grep GOFLAGS
GOFLAGS="-mod=vendor"

Now remove the .EXPORT_ALL_VARIABLES: line. Run make again:

$  make
go env | grep GOFLAGS
GOFLAGS=""

Shouldn't the lines after .EXPORT_ALL_VARIABLES be tab-indented? Why lay it out like that if it's not a real target?

The lines following the .EXPORT_ALL_VARIABLES: pseudo-target are not a recipe, and should not be indented. In fact, if they are then the variables will not be exported.

While .EXPORT_ALL_VARIABLES can in fact appear anywhere in the Makefile and will apply the export behaviour to all variables, we recommend the convention of including those variables for which we specifically need the export behaviour directly underneath the pseudo-target.

This convention, although I have not found it discussed anywhere, seems to be in use in the Makefiles of popular Go projects, e.g.: https://github.com/kubernetes/kubernetes/blob/598c279ecc078df87e745afdb5ef1279adfa4014/build/root/Makefile#L40

Can't I just use export GOFLAGS=-mod=vendor instead?

Yes, this works, except it causes a syntax error in old versions of make, so the manual recommends use of .EXPORT_ALL_VARIABLES instead. Realistically, both are probably fine for your situation.

Honourable mention

A special mention goes out to terraform-provider-powerdns for being the only provider in the terraform-providers org to have set up the Makefile correctly prior to this memo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment