racket-makefile
1 A functional makefile
2 Makefile definitions
makefile
target
deps
phony
default-target
3 Executing targets
make
current-makefile-prefix
makefile-targets
4 Rash integration
5 Recipe context
$target
$deps
$<
6 Dependency processing
7 Refreshing definitions
refresh-makefile
8 Running commands
run
raco
9 Cleanup helpers
rm-f
rm-rf
cleanup
list-dir/  files
list-files
list-dirs
9.3.0.2

racket-makefile🔗ℹ

Hans Dijkema / hans@dijkewijk.nl

 (require racket-makefile) package: racket-makefile

racket-makefile provides make-style dependency builds as ordinary Racket functionality. The package has no Rash dependency. Rash integration is provided by the separate rash-makefile package.

1 A functional makefile🔗ℹ

A makefile is declared with one prefix and a set of target clauses:

(require racket-makefile)
 
(makefile wiki
  (default-target all)
  (phony status clean all)
 
  (target status
    (displayln "status"))
 
  (target clean
    (rm-rf "compiled"))
 
  (target all
    (deps status)
    (displayln "all")))

The makefile form defines real Racket procedures. The example defines makefile-target-wiki-status, makefile-target-wiki-clean, and makefile-target-wiki-all. They can be inspected or called like any other procedure.

(procedure? makefile-target-wiki-status)
(makefile-target-wiki-status)

Calling a generated target procedure directly executes the recipe directly. Calling the target through make adds dependency traversal and timestamp based rebuilding.

2 Makefile definitions🔗ℹ

syntax

(makefile prefix clause ...)

Defines one prefixed makefile. The prefix is a literal identifier, string, path, or quoted symbol. Each clause is a target, phony, or default-target clause.

Before registering the new clauses, registrations for the same prefix are removed. After all clauses are registered, current-makefile-prefix is set to the prefix. Consequently the last evaluated makefile form becomes the active makefile.

A target named status in a makefile with prefix wiki defines the procedure makefile-target-wiki-status.

syntax

(target name (deps dependency ...) body ...)

Defines a named target procedure inside makefile. The name is a literal identifier, string, path, or quoted symbol. The target procedure executes body ....

Dependency expressions are evaluated when the makefile is registered. A dependency expression may produce nested lists; the build engine flattens them.

A target without a deps clause has no dependencies.

syntax

(deps dependency ...)

Specifies target dependencies. The form is valid only as the dependency clause of target.

syntax

(phony name ...)

Marks the named targets as phony for the surrounding makefile prefix. A phony target is always executed when requested or reached as a dependency.

syntax

(default-target name)

Selects the target used by (make) for the surrounding makefile prefix. If no default is specified, the first declared target is used.

The declaration forms target, deps, phony, and default-target are not standalone declarations in version 0.3.0. They are clauses of makefile.

3 Executing targets🔗ℹ

procedure

(make name ...)  void?

  name : (or/c symbol? path-string?)
Builds the supplied targets in the makefile selected by current-makefile-prefix. make is an ordinary procedure, so symbolic target names are quoted explicitly.

With no arguments, the configured default target is used. If no explicit default exists, the first target of the active makefile is used. Multiple supplied targets are processed in order, and shared dependencies are built once during one make call.

For a target that needs rebuilding, the engine looks up the target procedure in makefile-targets and calls it.

A parameter containing the active makefile prefix, or #f before any makefile has been evaluated. Evaluating makefile sets the parameter persistently to that makefile’s prefix.

Another registered makefile can be selected explicitly:

(current-makefile-prefix 'wiki)
(make 'status)

The global prefix-aware target registry. Registry values are the generated target procedures themselves. This binding is exposed mainly for inspection and tooling; normal target execution should use make.

4 Rash integration🔗ℹ

Rash integration is intentionally provided by the separate rash-makefile package so that racket-makefile remains a pure Racket dependency.

5 Recipe context🔗ℹ

syntax

$target

The current target name while a generated target procedure is running.

syntax

$deps

The flattened list of dependencies of the current target.

syntax

$<

The first dependency of the current target. An error is raised when the target has no dependencies.

The generated procedure establishes this context even when called directly.

6 Dependency processing🔗ℹ

A non-phony target is rebuilt when its output does not exist or when a dependency is newer than the target. Registered target dependencies are built first. A dependency that is neither a registered target in the same prefix nor an existing file is an error. Dependency cycles are reported as errors.

Multiple makefile prefixes can remain registered simultaneously. Dependency lookup stays within the prefix of the target being built.

7 Refreshing definitions🔗ℹ

procedure

(refresh-makefile)  void?

Reloads the source module containing the most recently evaluated makefile form. Existing makefile registrations are cleared before the source is evaluated again. Modules already instantiated in the current namespace are reused.

In DrRacket, pressing Run is usually the simpler way to reevaluate a Racket or Rash makefile.

8 Running commands🔗ℹ

procedure

(run command)  void?

  command : list?
Runs an external command directly without an intermediate shell. Symbols, strings, paths, numbers, and nested lists are converted to command-line arguments. A non-zero result raises an error.

The symbols '$target, '$deps, and '$< are expanded from the current target context when they occur in the command list.

procedure

(raco command)  void?

  command : list?
Runs raco from the active Racket installation. The command is supplied as a list, for example (raco '(setup racket-makefile)). The helper first looks in the console executable directory of the current Racket installation, then next to the running Racket executable, and only then on PATH. A non-zero result raises an error.

9 Cleanup helpers🔗ℹ

procedure

(rm-f path ...)  void?

  path : path-string?
Removes files when they exist. Missing files are ignored. Directories are rejected.

procedure

(rm-rf path ...)  void?

  path : path-string?
Removes files or directory trees recursively. Missing paths are ignored.

procedure

(cleanup directory patterns)  void?

  directory : path-string?
  patterns : list?
Removes files below directory that match the supplied Racket glob patterns.

procedure

(list-dir/files directory    
  regexp    
  [#:recursive recursive])  list?
  directory : path-string?
  regexp : regexp?
  recursive : any/c = #f
Returns matching files and directories. The regular expression is applied to each file or directory name, not to the complete path.

procedure

(list-files directory    
  regexp    
  [#:recursive recursive])  list?
  directory : path-string?
  regexp : regexp?
  recursive : any/c = #f
Like list-dir/files, but keeps only files.

procedure

(list-dirs directory    
  regexp    
  [#:recursive recursive])  list?
  directory : path-string?
  regexp : regexp?
  recursive : any/c = #f
Like list-dir/files, but keeps only directories.