Files
racket-makefile/README.md
T

3.6 KiB

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.