racket-makefile
racket-makefile provides make-style dependency builds as ordinary Racket functionality.
racket-makefile is a Racket library and has no dependency on Rash. Rash integration is provided separately by the rash-makefile package.
Functional makefiles
#lang racket
(require racket-makefile)
(makefile wiki
(default-target all)
(phony all clean status)
(target status
(displayln "status"))
(target clean
(rm-rf "compiled"))
(target all
(deps status)
(displayln "all")))
A makefile form defines real target procedures. The example above defines, among others:
makefile-target-wiki-status
makefile-target-wiki-clean
makefile-target-wiki-all
They are ordinary procedures:
(procedure? makefile-target-wiki-status)
(makefile-target-wiki-status)
make is also an ordinary procedure. Target names are explicit Racket values:
(make)
(make 'status)
(make 'clean 'all)
make resolves target names for the active makefile in the global makefile-targets registry. It handles dependencies and timestamp checks and invokes the registered target procedure when the target needs to run.
Makefile prefixes
Every makefile has a prefix:
(makefile wiki
(target status ...))
(makefile audio
(target status ...))
Targets with the same name can therefore coexist. Evaluating a makefile form makes that prefix current. Consequently the last makefile definition evaluated is the one used by an unqualified make call:
(current-makefile-prefix)
;; 'audio
(make 'status)
;; invokes makefile-target-audio-status through the make engine
current-makefile-prefix is a parameter, so another registered makefile can be selected explicitly:
(current-makefile-prefix 'wiki)
(make 'status)
Re-evaluating a makefile with the same prefix replaces the registrations for that prefix.
Rash integration
Rash integration is intentionally kept out of this package. Install and require the separate rash-makefile package when make target line syntax is desired.
Targets and dependencies
A target is declared only inside makefile:
(makefile example
(target "program"
(deps "program.c")
(run '(cc -o program program.c))))
Target and makefile names are literal identifiers, strings, paths, or quoted symbols. Dependencies may be expressions and may return nested lists; the build engine flattens them.
phony and default-target are also makefile clauses:
(makefile example
(default-target all)
(phony all clean)
...)
The automatic recipe values remain available inside target procedures:
$target
$deps
$<
Because a target is a real procedure, calling the generated procedure directly runs its recipe directly. Calling it through make adds dependency traversal and timestamp-based rebuilding.
Refreshing
A makefile form remembers the source module in which it occurs. refresh-makefile reloads that source without restarting the Racket process:
(refresh-makefile)
(make 'all)
In DrRacket, pressing Run is normally the simpler way to reevaluate a Rash or Racket makefile.
Helpers
The functional helpers provided by racket-makefile are run, raco, rm-f, rm-rf, cleanup, list-dir/files, list-files, and list-dirs. raco locates the executable belonging to the active Racket installation before falling back to PATH.
racket-makefile also continues to re-export the package APIs it uses for build scripts, including git-cli, package-zipper, net/sendurl, and racket/string.