Removed rash integration again and backported raco call.
This commit is contained in:
@@ -1,176 +1,135 @@
|
||||
# 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, Racket tool execution and a few cleanup helpers.
|
||||
`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.
|
||||
|
||||
A makefile only defines its targets. Loading or running the file does not build
|
||||
anything by itself. Builds are started explicitly with `make`.
|
||||
## Functional makefiles
|
||||
|
||||
```racket
|
||||
#lang racket-makefile
|
||||
#lang racket
|
||||
|
||||
(define CC 'cc)
|
||||
(define CFLAGS '(-Wall -O2))
|
||||
(require racket-makefile)
|
||||
|
||||
(default-target all)
|
||||
(phony all clean)
|
||||
(makefile wiki
|
||||
(default-target all)
|
||||
(phony all clean status)
|
||||
|
||||
(target all
|
||||
(deps "hello"))
|
||||
(target status
|
||||
(displayln "status"))
|
||||
|
||||
(target "hello"
|
||||
(deps "hello.c")
|
||||
(run `(,CC ,@CFLAGS -o $target $<)))
|
||||
(target clean
|
||||
(rm-rf "compiled"))
|
||||
|
||||
(target clean
|
||||
(rm-f "hello")
|
||||
(rm-rf "compiled")
|
||||
(cleanup "scrbl" '("**.html" "**.js" "**.css")))
|
||||
(target all
|
||||
(deps status)
|
||||
(displayln "all")))
|
||||
```
|
||||
|
||||
## 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.8.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:
|
||||
A `makefile` form defines real target procedures. The example above defines, among others:
|
||||
|
||||
```racket
|
||||
> (make)
|
||||
> (make clean)
|
||||
> (make all)
|
||||
> (make clean all)
|
||||
makefile-target-wiki-status
|
||||
makefile-target-wiki-clean
|
||||
makefile-target-wiki-all
|
||||
```
|
||||
|
||||
Bare identifiers in `make` are target names, so no quote is needed. For
|
||||
example, `(make clean)` selects the target named `clean`.
|
||||
|
||||
After editing the makefile, use `refresh-makefile` in the same Interactions
|
||||
window to reload the makefile without restarting the Racket process:
|
||||
They are ordinary procedures:
|
||||
|
||||
```racket
|
||||
> (refresh-makefile)
|
||||
> (make all)
|
||||
(procedure? makefile-target-wiki-status)
|
||||
(makefile-target-wiki-status)
|
||||
```
|
||||
|
||||
This works both with `#lang racket-makefile` and with an ordinary `#lang racket`
|
||||
makefile that requires `main.rkt`. It is useful when the makefile requires modules
|
||||
that are expensive to load. Unchanged required modules can remain instantiated
|
||||
while the target definitions from the makefile are registered again.
|
||||
|
||||
## Running Racket tools with `raco`
|
||||
|
||||
Use `raco` to invoke a Racket tool from a target without depending on `%PATH%`
|
||||
or `$PATH`:
|
||||
`make` is also an ordinary procedure. Target names are explicit Racket values:
|
||||
|
||||
```racket
|
||||
(phony setup test)
|
||||
|
||||
(target setup
|
||||
(raco '(setup racket-makefile)))
|
||||
|
||||
(target test
|
||||
(raco '(test -p racket-makefile)))
|
||||
(make)
|
||||
(make 'status)
|
||||
(make 'clean 'all)
|
||||
```
|
||||
|
||||
`racket-makefile` first looks for `raco` in the console binary directory of
|
||||
the Racket installation that is currently running the makefile. It then tries
|
||||
the directory containing the current `racket` executable and uses `PATH` only
|
||||
as a final fallback. On Windows this normally finds `raco.exe` next to
|
||||
`racket.exe` even when the Racket directory is not in `%PATH%`.
|
||||
`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.
|
||||
|
||||
The argument rules are the same as for `run`: symbols, strings, paths and
|
||||
numbers are converted to command-line arguments, nested lists are flattened,
|
||||
and `$target`, `$deps` and `$<` are available inside a recipe.
|
||||
## Makefile prefixes
|
||||
|
||||
## 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`:
|
||||
Every makefile has a prefix:
|
||||
|
||||
```racket
|
||||
#lang racket-makefile
|
||||
(makefile wiki
|
||||
(target status ...))
|
||||
|
||||
(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."))
|
||||
(makefile audio
|
||||
(target status ...))
|
||||
```
|
||||
|
||||
`list-dir/files` returns matching files and directories. The regexp is matched
|
||||
against the file or directory name itself, not against the complete path.
|
||||
`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. Results are returned as usable 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:
|
||||
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:
|
||||
|
||||
```racket
|
||||
(define sources '("foo.c" "bar.c" "baz.c"))
|
||||
(current-makefile-prefix)
|
||||
;; 'audio
|
||||
|
||||
(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))
|
||||
(make 'status)
|
||||
;; invokes makefile-target-audio-status through the make engine
|
||||
```
|
||||
|
||||
Dependency expressions may produce lists; they are recursively flattened.
|
||||
`current-makefile-prefix` is a parameter, so another registered makefile can be selected explicitly:
|
||||
|
||||
The language adds `target`, `deps`, `phony`, `default-target`, `make`, `run`,
|
||||
`raco`, `rm-f`, `rm-rf`, `cleanup`, `list-dir/files`, `list-files`, `list-dirs`,
|
||||
`$target`, `$deps` and `$<`. Everything else is ordinary Racket.
|
||||
```racket
|
||||
(current-makefile-prefix 'wiki)
|
||||
(make 'status)
|
||||
```
|
||||
|
||||
See the installed `racket-makefile` Scribble documentation for the full API.
|
||||
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`:
|
||||
|
||||
```racket
|
||||
(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:
|
||||
|
||||
```racket
|
||||
(makefile example
|
||||
(default-target all)
|
||||
(phony all clean)
|
||||
...)
|
||||
```
|
||||
|
||||
The automatic recipe values remain available inside target procedures:
|
||||
|
||||
```racket
|
||||
$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:
|
||||
|
||||
```racket
|
||||
(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`.
|
||||
|
||||
Reference in New Issue
Block a user