2021-02-15 05:01:35 +01:00
|
|
|
# POTATO MAKE
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-02-11 11:55:40 +01:00
|
|
|
Potato Make is a scheme library that aims to simplify the task of
|
2021-02-04 13:32:11 +01:00
|
|
|
maintaining, updating, and regenerating programs. It is inspired by
|
2021-12-07 19:07:52 +01:00
|
|
|
the `make` utility in IEEE Std 1003.1-2017 (POSIX). With this library, you can write a
|
2021-02-04 13:32:11 +01:00
|
|
|
build script in Guile Scheme.
|
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
## Boilerplate
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
Add this at the top of your build script.
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
#!/usr/bin/env sh
|
|
|
|
exec guile -s "$0" "$@"
|
|
|
|
!#
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
(use-modules (potato make))
|
|
|
|
(initialize)
|
|
|
|
```
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
Add this at the bottom of your build script
|
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(execute)
|
|
|
|
```
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-02-15 04:56:12 +01:00
|
|
|
The rules go in between `initialize` and `build`.
|
|
|
|
|
|
|
|
## A Simple Example
|
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
#!/usr/bin/env sh
|
|
|
|
exec guile -s "$0" "$@"
|
|
|
|
!#
|
2021-02-15 04:56:12 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
(use-modules (potato make))
|
|
|
|
(initialize)
|
|
|
|
(:= CC "gcc")
|
|
|
|
(:= CFLAGS "-g -O2")
|
2021-02-15 04:56:12 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
(: "all" '("foo"))
|
|
|
|
(: "foo" '("foo.o" "bar.o")
|
|
|
|
(~ ($ CC) "-o" $@ $^))
|
|
|
|
(-> ".c" ".o"
|
|
|
|
(~ ($ CC) "-c" $<))
|
|
|
|
(execute)
|
|
|
|
```
|
2021-02-15 04:56:12 +01:00
|
|
|
|
|
|
|
## Command-Line Arguments
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-02-04 13:32:11 +01:00
|
|
|
This boilerplate loads the library functions and it parses the
|
|
|
|
command-line arguments. The command-line arguments are the following,
|
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
<your-script-name> [-hvqVeEbknB] [var=value...] [target_name...]
|
2021-02-10 15:28:32 +01:00
|
|
|
-h, --help
|
|
|
|
displays help
|
|
|
|
-v, --version
|
|
|
|
displays the version number of this script
|
2021-02-13 02:04:57 +01:00
|
|
|
-V [0,1,2,3], --verbosity=[0,1,2,3]
|
|
|
|
choose the verbosity of the output
|
2021-02-10 15:28:32 +01:00
|
|
|
-e, --environment
|
|
|
|
environment variables are converted to makevars
|
|
|
|
-E, --elevate-environment
|
|
|
|
environment variables are converted to makevars
|
|
|
|
and will override makevars set in the script
|
|
|
|
-b, --builtins
|
|
|
|
adds some default makevars and suffix rules
|
2021-02-15 04:54:37 +01:00
|
|
|
--ignore-errors [NOT IMPLEMENTED YET]
|
2021-02-10 15:28:32 +01:00
|
|
|
keep building even if a command fails
|
2021-02-15 04:54:37 +01:00
|
|
|
-k, --continue-on-error [NOT IMPLEMENTED YET]
|
2021-02-10 15:28:32 +01:00
|
|
|
keep building some targets even if a command fails
|
2021-02-15 04:54:37 +01:00
|
|
|
-n, --no-execute [NOT IMPLEMENTED YET]
|
2021-02-10 15:28:32 +01:00
|
|
|
print rules, but only execute rules marked as
|
|
|
|
'always execute'
|
2021-02-10 17:25:16 +01:00
|
|
|
-a, --ascii
|
2021-02-10 15:28:32 +01:00
|
|
|
use ASCII-only output and no colors
|
2021-02-15 04:54:37 +01:00
|
|
|
-W, --warn [NOT IMPLEMENTED YET]
|
2021-02-13 01:34:18 +01:00
|
|
|
enable warning messages
|
2021-02-04 13:32:11 +01:00
|
|
|
|
|
|
|
[var=value...]
|
|
|
|
set the value of makevars
|
|
|
|
[target_name...]
|
|
|
|
Set one or more targets to be executed. If no target
|
|
|
|
is specified, the first target found will be executed.
|
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
## MAKEVARS
|
|
|
|
|
|
|
|
A hash table called `%makevars` has string keys. These procedures
|
|
|
|
are syntax that add quotation marks around `key`, so you call them without the quotes on
|
|
|
|
`key`. The returned value of `$` is a string, or an empty string on failure.
|
2021-02-15 05:01:35 +01:00
|
|
|
You define makevars in the script, in the environment, or on the command line.
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
($ KEY) -> "VAL"
|
2021-02-13 01:34:18 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
($ key [transformer])
|
|
|
|
Look up `key` in the `%makevars` hash table and return the
|
|
|
|
result as a string. If `key` is not found, return an empty
|
|
|
|
string. If a string-to-string transformer procedure is
|
|
|
|
provided, apply it to each space-separated token in the
|
|
|
|
result.
|
2021-02-13 01:34:18 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
(?= key val)
|
|
|
|
Assign `val` to `key` in the `%makevars` hash table. If `val`
|
|
|
|
is a procedure, assign its output to `key` the first time that
|
|
|
|
`key` is referenced.
|
2021-02-13 01:34:18 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
(:= key val)
|
|
|
|
Assign `val` to `key` in the `%makevars` hash table. If `val`
|
|
|
|
is a procedure, evaluate it and assign its output to `key`
|
|
|
|
immediately.
|
2021-02-13 01:34:18 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
## Rules
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
The *target rule* is for when the target, and the prerequisites, if any,
|
|
|
|
have filenames or phony names.
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(: target-name '(prereq-name-1 prereq-name-2 ...)
|
|
|
|
recipe-1
|
|
|
|
recipe-2
|
|
|
|
...)
|
|
|
|
```
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
`target-name` is a string which is either a filename to be
|
|
|
|
created or an phony name like "all" or "clean".
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
Recipe as a string to be evaluated by the system
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(: "foo.o" '("foo.c")
|
|
|
|
"cc -c foo.o")
|
|
|
|
```
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
Recipe as a procedure
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(: "clean-foo" '()
|
|
|
|
(lambda ()
|
|
|
|
(delete-file "foo.o")))
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
Recipe as a procedure that returns #f to indicate failure
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(: "recent" '()
|
|
|
|
(lambda ()
|
|
|
|
(if condition
|
|
|
|
#t
|
|
|
|
#f))))
|
|
|
|
```
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
Recipe as a procedure returning a string to be evaluated by the
|
|
|
|
system
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(: "foo.o" '("foo.c")
|
|
|
|
(lambda ()
|
|
|
|
(format #f "cc ~A -c foo.c" some-flags))
|
|
|
|
```
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
Recipe using recipe helper procedures, which create a string to
|
|
|
|
be evaluated by the system
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(: "foo.c" '("foo.c")
|
|
|
|
(~ ($ CC) ($ CFLAGS) "-c" $<))
|
|
|
|
```
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
Recipe as a boolean to indicate pass or failure without doing any
|
|
|
|
processing. For example, the rule below tells Potato Make that
|
|
|
|
the file "foo.c" exists without actually testing for it.
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(: "foo.c" '() #t)
|
|
|
|
```
|
|
|
|
|
|
|
|
If there is no recipe at all, it is shorthand for the recipe #t,
|
|
|
|
indicating a recipe that always passes. This is used
|
|
|
|
in prerequisite-only target rules, such as below, which passes
|
|
|
|
so long as the prerequisites pass. These two rules are the same.
|
|
|
|
|
|
|
|
```scheme
|
|
|
|
(: "all" '("foo.exe"))
|
|
|
|
(: "all" '("foo.exe") #t)
|
|
|
|
```
|
2021-02-15 04:54:37 +01:00
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
Lastly, if the recipe is #f, this target will always fail.
|
|
|
|
|
|
|
|
```scheme
|
|
|
|
(: "fail" '() #f)
|
|
|
|
```
|
2021-02-15 04:54:37 +01:00
|
|
|
|
|
|
|
The *suffix rule* is a generic rule to convert one source file to a
|
|
|
|
target file, based on the filename extensions.
|
|
|
|
|
2021-12-07 19:16:51 +01:00
|
|
|
```scheme
|
|
|
|
(-> ".c" ".o"
|
|
|
|
(~ ($ CC) ($ CFLAGS) "-c" $< "-o" $@))
|
|
|
|
```
|
2021-02-15 04:54:37 +01:00
|
|
|
|
|
|
|
## Recipe Helpers
|
|
|
|
|
|
|
|
Concatenate elements with `~`. `~` inserts spaces between the
|
|
|
|
elements.
|
|
|
|
|
|
|
|
Elements can be
|
|
|
|
- strings
|
|
|
|
- procedures that return strings
|
|
|
|
- `%makevar` hash-table references
|
|
|
|
- automatic variables
|
|
|
|
- anything whose string representation as created by
|
|
|
|
(format #f "~A" ...) make sense
|
|
|
|
|
|
|
|
Any procedures are applied lazily, when the rule is executed.
|
|
|
|
|
|
|
|
(~ "string" (lambda () "string") ($ KEY) $@ 100 )
|
|
|
|
|
|
|
|
Three versions of `~` with special effects
|
|
|
|
(~- ...) ignores any errors
|
|
|
|
(~@ ...) doesn't print recipe to console
|
|
|
|
(~+ ...) runs even when `--no-execute` was chosen
|
|
|
|
|
|
|
|
## Automatic Variables
|
|
|
|
|
|
|
|
Recipes can contain the following automatic variables
|
2021-02-04 13:32:11 +01:00
|
|
|
|
2021-02-15 04:54:37 +01:00
|
|
|
$@ the target
|
|
|
|
$* the target w/o a filename suffix
|
|
|
|
$< the first prerequisite
|
|
|
|
$^ the prerequisites, as a single space-separated string
|
|
|
|
$$^ the prerequisites, as a scheme list of strings
|
|
|
|
$? the prerequisites that are files newer than the target file
|
|
|
|
as a single space-separated string
|
|
|
|
$$? the prerequisites that are files newer than the target file
|
|
|
|
as a scheme list of strings
|
2021-11-18 17:18:38 +01:00
|
|
|
|
|
|
|
## POSIX Makefile Parser
|
|
|
|
|
|
|
|
Recipes can contain the following parser function
|
|
|
|
|
|
|
|
(parse ...) reads a standard Makefile and creates
|
|
|
|
rules based on its contents.
|