# 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`. ```racket #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: ```text raco pkg install ``` For a versioned archive, give the package name explicitly: ```text 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`: ```text 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: ```text 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: ```racket > (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`: ```racket #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: ```racket (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.