2026-08-08 23:36:35 +02:00
2026-08-08 23:36:35 +02:00
2026-08-08 14:32:18 +02:00
2026-08-08 23:36:35 +02:00
2026-08-08 23:36:35 +02:00
2026-08-08 23:36:35 +02:00
2026-08-08 23:36:35 +02:00
2026-08-08 23:36:35 +02:00
2026-08-08 13:43:39 +02:00
2026-08-08 23:36:35 +02:00
2026-08-08 23:36:35 +02:00

racket-makefile

racket-makefile is a small #lang for make-style builds. It keeps ordinary Racket available and only adds targets, dependencies, timestamp based rebuilds, phony targets, external command execution and a few cleanup helpers.

A makefile only defines its targets. Loading or running the file does not build anything by itself. Builds are started explicitly with make.

#lang racket-makefile

(define CC 'cc)
(define CFLAGS '(-Wall -O2))

(default-target all)
(phony all clean)

(target all
  (deps "hello"))

(target "hello"
  (deps "hello.c")
  (run `(,CC ,@CFLAGS -o $target $<)))

(target clean
  (rm-f "hello")
  (rm-rf "compiled")
  (cleanup "scrbl" '("**.html" "**.js" "**.css")))

Installation

Install a local checkout with:

raco pkg install

For a versioned archive, give the package name explicitly:

raco pkg install --name racket-makefile racket-makefile-0.1.4.zip

Running targets

Load the makefile with -t and evaluate a make expression with -e:

racket -t Makefile.rkt -e "(make)"
racket -t Makefile.rkt -e "(make all)"
racket -t Makefile.rkt -e "(make clean)"
racket -t Makefile.rkt -e "(make clean all)"

(make) uses the target selected with default-target. If no default target is specified, the first declared target is used.

Loading the file alone only registers the targets:

racket -t Makefile.rkt

No recipe is executed in that case.

In DrRacket, open the makefile and press Run. This also only loads and registers the targets. Then use the Interactions window:

> (make)
> (make clean)
> (make all)
> (make clean all)

Bare identifiers in make are target names, so no quote is needed. For example, (make clean) selects the target named clean.

Regexp-based cleanup

For cleanup rules that need more control than globs, racket-makefile also provides small directory/regexp helpers. The results are ordinary path lists, so they can be passed directly to rm-f and rm-rf with apply:

#lang racket-makefile

(default-target all)
(phony all clean)

(target all
  (displayln "use (make clean)"))

(target clean
  (display "cleaning up...")
  (apply rm-rf
         (list-dirs "." #px"compiled$" #:recursive #t))
  (apply rm-f
         (list-files "." #px"(?i:(?:[.]bak|~)$)" #:recursive #t))
  (displayln "done."))

list-dir/files returns matching files and directories. list-files and list-dirs restrict the result to files or directories. All three scan one directory level by default; use #:recursive #t to walk the complete tree. Non-recursive results are returned as complete paths, so the lists can be fed directly to rm-f or rm-rf with apply.

Generated targets

Because the rest of the language is ordinary Racket, targets can be generated with normal definitions and loops:

(define sources '("foo.c" "bar.c" "baz.c"))

(define objects
  (for/list ([src sources])
    (define obj (path-replace-extension src #".o"))
    (target obj
      (deps src)
      (run `(cc -c $< -o $target)))
    obj))

(target all
  (deps objects))

Dependency expressions may produce lists; they are recursively flattened.

The language adds target, deps, phony, default-target, make, run, rm-f, rm-rf, cleanup, list-dir/files, list-files, list-dirs, $target, $deps and $<. Everything else is ordinary Racket.

See the installed racket-makefile Scribble documentation for the full API.

S
Description
No description provided
Readme MIT 113 KiB
Languages
Racket 96.2%
Makefile 3.8%