fancy colours

This commit is contained in:
Moonchild 2020-10-05 00:23:19 -07:00
parent 474353345f
commit 5b79bc0b42
6 changed files with 75 additions and 15 deletions

@ -1,5 +1,6 @@
(defun runp (cmd)
(assert (zerop (uiop:wait-process (uiop:launch-program cmd :output *standard-output* :error-output *error-output*)))))
(unless (zerop (uiop:wait-process (uiop:launch-program cmd :output *standard-output* :error-output *error-output*)))
(die "command '~a' failed" cmd)))
(defclass c-compiler (buildable)
((cached-snapshot :accessor c-compiler-executable :initform nil)

42
readme

@ -4,7 +4,45 @@ Models constraints of and is able to interoperate with any other build system.
(Ideally. In practice, something like scons will be impractical; but make,
cargo, cpan, dub, etc. are fine.)
Closest in design to shake (https://shakebuild.com/). Primary differences:
- Build starts instantly. No need to build your build file.
Pros:
- Fast
* Don't do any more work than you have to
+ SCons, redo, and bazel (and bazel's derivatives--buck, please, etc.)
get this right. Most others (make, ninja, etc.) don't.
× ninja has an open ticket to resolve this, but maintainers seem
uninterested in resolving it. (https://github.com/ninja-build/ninja/issues/1459)
+ Example: purely syntactic (not semantic) change shouldn't require a re-link.
* Parallel
- Correct
* Always rebuild if you have to
+ SCons, redo, and bazel&co (again) get this right.
+ Example: update system c compiler or headers.
× For some, even just updating locally-referenced headers is enough.
- Easy to use for tiny projects, but programmable enough to scale indefinitely
* SCons hits these points, but it's slow; not pathologically so, just incidentally.
* Redo uses shell, which has difficulty with abstraction.
* Ditto make.
* Bazel (and derivatives) are interesting:
+ Reasonably powerful programming language
+ Build description for a toy project looks reasonable: 5
lines indicating source and target files.
But:
+ Heavyweight. Slow startup time is solved by running a persistent build
server; not unreasonable for google-scale projects but that seems like
overkill when you look at the 20-line build description it executes.
+ Builtin build rules insufficiently introspectible or modifiable.
For example, changing the toolchain used, or the build flags, is much
more complex than it need be--than it is, in most build systems.
× Partly, this is just because those build rules don't expose hooks to
modify those attributes. But mostly it's because the build language
doesn't lend itself well to such dynamism, so it's not encouraged.
× (https://github.com/bazelbuild/bazel/issues/2954,
https://github.com/bazelbuild/bazel/issues/4644)
It's not a problem that such bugs exist, but it is a problem that
they can't be easily fixed or worked around 'in userspace'.
The closest build systems to solving all these are SCons and Shake
(https://shakebuild.com/). SCons is slow. Compared with shake, we have:
- No conflation of build targets with on-disc files. Represent deployment,
dependencies from (network) package registry, ...
- Build starts instantly. No need to build your build file.

@ -11,7 +11,7 @@
(defclass buildable ()
((dependencies :initarg :dependencies :initform nil :accessor dependencies)
(cached-snapshot :initform nil)
(pretty-name :initarg :pretty-name :initform "" :accessor pretty-name)
(pretty-name :initarg :pretty-name :initform nil :accessor pretty-name)
(unique-key :initform nil :accessor unique-key)))
(defgeneric snapshot (buildable))

@ -4,7 +4,7 @@
(defun main ()
(unless (probe-file "fancy.build")
(die "Could not find build description file 'fancy.build'."))
(die "could not find build description file 'fancy.build'"))
(when (probe-file "fancy.buildcache")
(with-open-file (fp "fancy.buildcache"
@ -21,12 +21,11 @@
(load "fancy.build"))
(let ((targets-list (mapcar #'(lambda (name)
(or (gethash name *targets*) (die "No target named '~a'." name)))
(or (gethash name *targets*) (die "no target named '~a'" name)))
(or (uiop:command-line-arguments) '("default")))))
(parallel-build (if (cdr targets-list)
(make-instance 'buildable :dependencies targets-list)
(car targets-list))))
;(naively-build target)
(with-open-file (fp "fancy.buildcache"

@ -1,6 +1,6 @@
(in-package :fancybuild)
(export 'target)
(export '(target die dwarn notice))
(defparameter *targets* (make-hash-table :test #'equal))
(defparameter *global-cache* (make-hash-table :test #'equal))
@ -15,11 +15,35 @@
`(let ((- ,test))
(unless - ,@body)))
(defun stdout-tty-p () (interactive-stream-p *standard-output*))
(defun clr-maybe (seq)
(if (stdout-tty-p)
(apply #'format `(,nil ,seq #\esc))
""))
(defun clr-red () (clr-maybe "~a[31m"))
(defun clr-green () (clr-maybe "~a[32m"))
(defun clr-brown () (clr-maybe "~a[33m"))
(defun clr-blue () (clr-maybe "~a[34m"))
(defun clr-magenta () (clr-maybe "~a[35m"))
(defun clr-cyan () (clr-maybe "~a[36m"))
(defun clr-gray () (clr-maybe "~a[37m")) ; note: may be black on some terminals; avoid
(defun clr-reset () (clr-maybe "~a[0m"))
(defun clr-bold () (clr-maybe "~a[1m"))
(defun clr-dim () (clr-maybe "~a[2m"))
(defun clr-invert () (clr-maybe "~a[3m"))
(defun clr-underline () (clr-maybe "~a[4m"))
(defun die (&rest msg)
(apply #'format (cons t msg))
(format t "~%")
(format t "~a~aERROR~a: ~a~%" (clr-bold) (clr-red) (clr-reset) (apply #'format (cons nil msg)))
(uiop:quit 1))
(defun dwarn (&rest msg)
(format t "~a~aWARNING~a: ~a~%" (clr-bold) (clr-brown) (clr-reset) (apply #'format (cons nil msg))))
(defun notice (&rest msg)
(format t "~a~%" (apply #'format (cons nil msg))))
(defun target (name target)
(setf (gethash name *targets*) target))
@ -32,10 +56,8 @@
(unless (and (slot-value b 'cached-snapshot)
(not (is-dirty b (slot-value b 'cached-snapshot))))
(format t "Building ~a...~%" (pretty-name b))
(handler-case (do-build b)
(error ()
(die "Error building ~a!" (pretty-name b)))))
(notice "building ~a..." (pretty-name b))
(do-build b))
(setf (slot-value b 'cached-snapshot) (snapshot b))
(when (unique-key b)
(setf (gethash (unique-key b) *global-cache*)

@ -38,7 +38,7 @@
:do (let ((b (pop currently-buildable)))
(when (check-dirty (parallel-buildable-base b))
(awhen (pretty-name (parallel-buildable-base b))
(format t "Building ~a...~%" -))
(notice "building ~a..." -))
(do-build (parallel-buildable-base b))
(setf (slot-value (parallel-buildable-base b) 'cached-snapshot) (snapshot (parallel-buildable-base b)))
(setf (gethash (unique-key (parallel-buildable-base b)) *global-cache*) (slot-value (parallel-buildable-base b) 'cached-snapshot)))