Sometimes you need a specific version of Terraform a build for your combination of Operating System / Architecture doesn't exist. This can be because that combination came out later than the version of Terraform you are after, or some other reason.
But, no fear, Golang compiler is great, and the Terraform codebase is pretty easy.
This describes a build process that produces a working binary, BUT(!) this is not a combination of Golang and Terraform code version that is supported in any official capacity by anyone at HashiCorp.
Plese read the process described above, as well as the resulting binary, as your personal effort that you can perform thanks to the beauty of open source. Any bug/issue reported against a non-HashiCorp released binary, it's very likely going to be rejected.
Additionally, the resulting binary is NOT signed by HashiCorp, so share it at your own risk.
Have a version of Golang installed, that supports your Go/Arch combination (duh!).
Step 0. As my target combination is darwin / arm64
, I'll use my current local Golang version 1.17.8
.
For a list of all the available Golang versions, see the official download page.
Step 1. Work out the latet version of TF 0.12 available:
at the time of writing is v0.12.31
(tag tree).
Step 2. Procure the specific code tree:
$ git clone git@github.com:hashicorp/terraform.git
$ cd terraform
$ git checkout v0.12.31
Step 3. This is the only "tricky" bit, and it's not even that much. Open in your editor ./scripts/build.sh
.
In there, apply a patch like this one:
diff --git i/scripts/build.sh w/scripts/build.sh
index 72af007ee0..07af5d8f0f 100755
--- i/scripts/build.sh
+++ w/scripts/build.sh
@@ -15,9 +15,9 @@ GIT_COMMIT=$(git rev-parse HEAD)
GIT_DIRTY=$(test -n "`git status --porcelain`" && echo "+CHANGES" || true)
# Determine the arch/os combos we're building for
-XC_ARCH=${XC_ARCH:-"386 amd64 arm"}
-XC_OS=${XC_OS:-linux darwin windows freebsd openbsd solaris}
-XC_EXCLUDE_OSARCH="!darwin/arm !darwin/386"
+XC_ARCH=${XC_ARCH:-"386 amd64 arm64"}
+XC_OS=${XC_OS:-darwin}
+XC_EXCLUDE_OSARCH="!darwin/386"
# Delete the old dir
echo "==> Removing old directory..."
Step 4. Run make fmt
, otherwise the build will fail because it does a check of golang formatting beforehand:
...
make: *** [fmtcheck] Error 1
./signal_unix.go
You can use the command: `make fmt` to reformat code.
$ make fmt
gofmt -w $(find . -not -path "./vendor/*" -type f -name '*.go')
Step 5. Build it:
$ make bin
==> Checking that code complies with gofmt requirements...
GOFLAGS=-mod=vendor go generate ./...
# go fmt doesn't support -mod=vendor but it still wants to populate the
# module cache with everything in go.mod even though formatting requires
# no dependencies, and so we're disabling modules mode for this right
# now until the "go fmt" behavior is rationalized to either support the
# -mod= argument or _not_ try to install things.
GO111MODULE=off go fmt command/internal_plugin_list.go > /dev/null
==> Removing old directory...
==> Building...
Number of parallel builds: 9
--> darwin/arm64: github.com/hashicorp/terraform
--> darwin/amd64: github.com/hashicorp/terraform
==> Packaging...
--> darwin_amd64
adding: terraform (deflated 70%)
--> darwin_arm64
adding: terraform (deflated 71%)
==> Results:
total 90976
Step 6. ... Profit!
$ ls pkg/*
pkg/darwin_amd64.zip pkg/darwin_arm64.zip
pkg/darwin_amd64:
terraform*
pkg/darwin_arm64:
terraform*
The above notes are of course "generic", but you might have spotted the special interest for the build target Darwin/ARM64
. This is because the issue I was solving related to own MacBook Pro.
In case you are also running on MacBook Pro, on Apple Silicon, another way it to rely on Rosetta, the transparent translation layer that macOS provides, to run Darwin/AMD64
binaries on Darwin/ARM64
.
After testing, older builds of Terraform targeting AMD64
seem to work just fine, even when interacting with Terraform Providers compiled for ARM64
(because of how awesome the software architecture of Terraform is :) ).