Getting Started
Install GoMake and run your first target in five minutes.
Installation
Install with a single command (requires Go 1.26+):
curl -fsSL https://raw.githubusercontent.com/ctx42/gomake/master/install.sh | sh
Or directly with go run:
go run github.com/ctx42/gomake/cmd/install@latest
After installation, verify it works:
gomake --version
# gomake v0.26.1
With custom built-in targets
Pass a targets.yaml to compile external target packages permanently into the
binary at install time:
go run github.com/ctx42/gomake/cmd/install@latest --targets=./targets.yaml
Or forward --targets through the install script with sh -s --:
curl -fsSL https://raw.githubusercontent.com/ctx42/gomake/master/install.sh | sh -s -- --targets=./targets.yaml
Repeat --targets to combine several files, for example a public and a
private set of targets.
See Builtin targets for details.
Installing from a local clone
To build from a checked-out copy of the source instead of a published
release — for instance to install unreleased changes on master — run the
installer from the clone. It builds whatever is in your working tree; no tag,
release, or module proxy is involved:
go run ./cmd/install
--targets works the same way:
go run ./cmd/install --targets=./targets.yaml
Use the package path ./cmd/install, not a file path like
cmd/install/install.go — building from an explicit file leaves the build
metadata empty, and the installer then mistakes the run for a published
install and fails.
Versioning
gomake --version reports the version the Go toolchain recorded for the
binary, so the string says where the build came from:
| Build | Version |
|---|---|
Published release (…@latest) | v0.26.1 |
| From a clone | v0.26.2-0.20260921121020-5bde820e3c1c+dirty |
| From a source copy, no repository | (devel) |
The middle form is a Go pseudo-version: the last tag with its patch raised, a
pre-release stamp holding the commit time and hash, and +dirty when the
work tree carried uncommitted changes. It sorts after v0.26.1 and before
v0.26.2, so a build from a clone never claims to be the release it was
built on top of.
A published install is the one build the toolchain cannot version by itself:
it compiles from the module cache, which carries no repository to read. The
installer stamps the version there with -ldflags -X.
An install from a clone with --targets is stamped too. Compiling external
targets in regenerates files in the source tree, which would mark every such
build +dirty, so the installer builds from a temporary copy of the files
the build reads and stamps the version the toolchain gives the untouched
clone.
Your first makefile
Create makefile.go in your project root. Your targets live in
makefile.go; the only other files GoMake loads are OS/arch variants such as
makefile_linux.go (see Writing targets):
//go:build gomake
package main
import (
"context"
"fmt"
"github.com/ctx42/ring/pkg/ring"
)
// Hello prints a greeting.
func Hello(ctx context.Context, rng *ring.Ring) error {
fmt.Fprintln(rng.Stdout(), "Hello from GoMake!")
return nil
}
Run it:
gomake hello
# Hello from GoMake!
List targets:
gomake --list
# hello prints a greeting
Get help:
gomake --help hello
What happens on first run
- GoMake finds
makefile.goin the current directory. - It creates a temporary build directory and copies your makefile sources.
- It generates a thin
mainpackage that wires your targets to the runner. - It compiles the package with
go build. - It caches the binary under
~/.cache/gomake/bin/. - It runs the binary with the target name and any extra arguments.
On subsequent runs with unchanged sources, steps 1–5 are skipped. The cached binary is used directly.
Next steps
- Writing targets — full target syntax
- Namespaces — group targets into hierarchies
- Importing targets — share targets across projects
- CLI reference — all flags and options