From 5b79bc0b421928acc75f7fa4ce84df2dfe619e84 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Mon, 5 Oct 2020 00:23:19 -0700 Subject: [PATCH] fancy colours --- example/fancy.build | 3 ++- readme | 42 +++++++++++++++++++++++++++++++++++++++-- src/dependable.lisp | 2 +- src/fb-entry.lisp | 5 ++--- src/misc.lisp | 36 ++++++++++++++++++++++++++++------- src/parallel-build.lisp | 2 +- 6 files changed, 75 insertions(+), 15 deletions(-) diff --git a/example/fancy.build b/example/fancy.build index fc33e65..008834e 100644 --- a/example/fancy.build +++ b/example/fancy.build @@ -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) diff --git a/readme b/readme index 969f5dd..42d0005 100644 --- a/readme +++ b/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. diff --git a/src/dependable.lisp b/src/dependable.lisp index 6ad59f7..9766f5d 100644 --- a/src/dependable.lisp +++ b/src/dependable.lisp @@ -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)) diff --git a/src/fb-entry.lisp b/src/fb-entry.lisp index f543cc1..90247dc 100644 --- a/src/fb-entry.lisp +++ b/src/fb-entry.lisp @@ -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" diff --git a/src/misc.lisp b/src/misc.lisp index beca85c..32b808d 100644 --- a/src/misc.lisp +++ b/src/misc.lisp @@ -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*) diff --git a/src/parallel-build.lisp b/src/parallel-build.lisp index 91df104..17889f9 100644 --- a/src/parallel-build.lisp +++ b/src/parallel-build.lisp @@ -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)))