WIP: GNU Guile-based solution for project management https://pman.rxt.eco
Go to file
Jacob Hrbek 70e83193cb
Quality Assurance, Audit and Tags (#14)
Fixes: #10

Authored-by: Jacob Hrbek <kreyren@rixotstudio.cz>
Reviewed-on: #14
Co-authored-by: Jacob Hrbek <kreyren@noreply.git.dotya.ml>
Co-committed-by: Jacob Hrbek <kreyren@noreply.git.dotya.ml>
2022-09-03 10:35:09 +02:00
docs Rename documents->docs 2022-08-28 07:05:52 +02:00
examples Quality Assurance, Audit and Tags (#14) 2022-09-03 10:35:09 +02:00
src Quality Assurance, Audit and Tags (#14) 2022-09-03 10:35:09 +02:00
tests Quality Assurance, Audit and Tags (#14) 2022-09-03 10:35:09 +02:00
.gitignore Quality Assurance, Audit and Tags (#14) 2022-09-03 10:35:09 +02:00
Expat-LICENSE.txt Quality Assurance, Audit and Tags (#14) 2022-09-03 10:35:09 +02:00
GPLv3-LICENSE.md Quality Assurance, Audit and Tags (#14) 2022-09-03 10:35:09 +02:00
NOTES.md Clean up output 2021-02-14 19:54:37 -08:00
README.md Merge pull request #3 from Kreyren/patch-3 2021-12-07 15:55:27 -08:00
TAGS.org Quality Assurance, Audit and Tags (#14) 2022-09-03 10:35:09 +02:00
pman Quality Assurance, Audit and Tags (#14) 2022-09-03 10:35:09 +02:00

POTATO MAKE

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.

Boilerplate

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.

A Simple Example

#!/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)

Command-Line Arguments

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.

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. 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.

Rules

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" $@))

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

 $@    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

POSIX Makefile Parser

 Recipes can contain the following parser function

 (parse ...) reads a standard Makefile and creates
 rules based on its contents.