Potato Make is a scheme library that aims to simplify the task of
maintaining, updating, and regenerating programs. It is inspired by
the make
utility in IEEE Std 1003.1-2017 (POSIX). With this library, you can write a
build script in Guile Scheme.
Add this at the top of your build script.
#!/usr/bin/env sh
exec guile -s "$0" "$@"
!#
(use-modules (potato make))
(initialize)
Add this at the bottom of your build script
(execute)
The rules go in between initialize
and build
.
#!/usr/bin/env sh
exec guile -s "$0" "$@"
!#
(use-modules (potato make))
(initialize)
(:= CC "gcc")
(:= CFLAGS "-g -O2")
(: "all" '("foo"))
(: "foo" '("foo.o" "bar.o")
(~ ($ CC) "-o" $@ $^))
(-> ".c" ".o"
(~ ($ CC) "-c" $<))
(execute)
This boilerplate loads the library functions and it parses the command-line arguments. The command-line arguments are the following,
<your-script-name> [-hvqVeEbknB] [var=value...] [target_name...]
-h, --help
displays help
-v, --version
displays the version number of this script
-V [0,1,2,3], --verbosity=[0,1,2,3]
choose the verbosity of the output
-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
--ignore-errors [NOT IMPLEMENTED YET]
keep building even if a command fails
-k, --continue-on-error [NOT IMPLEMENTED YET]
keep building some targets even if a command fails
-n, --no-execute [NOT IMPLEMENTED YET]
print rules, but only execute rules marked as
'always execute'
-a, --ascii
use ASCII-only output and no colors
-W, --warn [NOT IMPLEMENTED YET]
enable warning messages
[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.
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.
You define makevars in the script, in the environment, or on the command line.
($ KEY) -> "VAL"
($ 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.
(?= 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.
(:= 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.
The target rule is for when the target, and the prerequisites, if any, have filenames or phony names.
(: target-name '(prereq-name-1 prereq-name-2 ...)
recipe-1
recipe-2
...)
target-name
is a string which is either a filename to be
created or an phony name like "all" or "clean".
Recipe as a string to be evaluated by the system
(: "foo.o" '("foo.c")
"cc -c foo.o")
Recipe as a procedure
(: "clean-foo" '()
(lambda ()
(delete-file "foo.o")))
Recipe as a procedure that returns #f to indicate failure
(: "recent" '()
(lambda ()
(if condition
#t
#f))))
Recipe as a procedure returning a string to be evaluated by the system
(: "foo.o" '("foo.c")
(lambda ()
(format #f "cc ~A -c foo.c" some-flags))
Recipe using recipe helper procedures, which create a string to be evaluated by the system
(: "foo.c" '("foo.c")
(~ ($ CC) ($ CFLAGS) "-c" $<))
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.
(: "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.
(: "all" '("foo.exe"))
(: "all" '("foo.exe") #t)
Lastly, if the recipe is #f, this target will always fail.
(: "fail" '() #f)
The suffix rule is a generic rule to convert one source file to a target file, based on the filename extensions.
(-> ".c" ".o"
(~ ($ CC) ($ CFLAGS) "-c" $< "-o" $@))
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
Recipes can contain the following automatic variables
$@ 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
Recipes can contain the following parser function
(parse ...) reads a standard Makefile and creates
rules based on its contents.