Modernizing Make

Whether you’re actually utilizing Make’s build capabilities, or simply using it to run ad-hoc “tasks”, Make is a ubiquitous tool used across the industry, but can we improve upon it without starting from scratch?

MMake or “Modern Make” is a small Go program wrapping standard Make to augment its functionality, providing nice help output, remote inclusion, and possibly more in the future.

Help output

The first small feature is first-class target help output. Suppose you have the following makefile with a few targets defined, you’d like to have a way to view the help from the command-line right?

# Start the dev server.
#
# Note that the API must also be running.
start:
@gopherjs -m -v serve --http :3000 github.com/tj/docs/client
.PHONY: start
# Start the API server.
api:
@go run server/cmd/api/api.go
.PHONY: api
# Display dependency graph.
deps:
@godepgraph github.com/tj/docs/client | dot -Tsvg | browser
.PHONY: deps
# Display size of dependencies.
size:
@gopherjs build client/*.go -m -o /tmp/out.js
@du -h /tmp/out.js
@gopher-count /tmp/out.js | sort -nr
.PHONY: size

With make aliased to mmake you can simply run make help:

start      Start the dev server.
api Start the API server.
deps Display dependency graph.
size Display size of dependencies.

Alternatively you may view the full description for a single target via make help start :

Start the dev server.
Note that the API must be also running.

Remote includes

The second feature currently supported is recursive remote includes, which are stored in /usr/local/include providing backwards-compatible support for users without mmake installed.

For example to extract some common functionality for your team, you might want a repo with common includes like ./deploy.mk, ./lint.mk and so on. The include directive supports directories as well, so you can structure these repos however you like.

include github.com/apex/make/deploy
include github.com/apex/make/lint
include github.com/apex/make/test
include github.com/apex/make/ci

Alternatively you might want one include per environment such as Node or Golang, making it easy to keep the team up-to-date.

include github.com/apex/make/node
include github.com/apex/make/golang

If you’re worried about arbitrary code execution, then simply fork a project and retain full control.


I’ve been wanting this for years but never actually got around to it! If you use Make check out the project at https://github.com/tj/mmake, and if you don’t, maybe now you’ll consider it :).