Coverage report: /home/ellis/comp/core/app/skel/comp/makefile.lisp
Kind | Covered | All | % |
expression | 66 | 101 | 65.3 |
branch | 0 | 0 | nil |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; makefile.lisp --- GNU Makefile Components
3
;; GNU Makefile skel components.
7
;; Makefiles are a reasonably portable build medium. We can parse them using
8
;; the same general strategy as GNU make and compile them from skelfiles
9
;; (rule, source, target, command).
11
;; HACK 2023-09-15: MVP
13
;; SO, the absolute priority ATM is to transpile our `sk-rule' objects
14
;; into a working Makefile. We're ignoring most of the niceties like
15
;; line-splitting and any JIT or compile-time execution.
17
;; https://github.com/takagi/lake
19
;; https://www.gnu.org/software/make/manual/html_node/Parsing-Makefiles.html
22
(in-package :skel/comp/makefile)
24
(defparameter *default-makefile* "makefile")
25
(defparameter *makefile-extension* "mk")
27
;; TODO 2023-09-27: what is $(@D) ?? (target-dir)
28
(defvar *mk-magic-vars* #(#\@ #\< #\^ #\* #\+ #\? #\|))
30
(defvar *mk-command-prefixes* #(#\@ #\- #\+))
32
(deftype mk-val-designator () '(member nil :simple :immediate :conditional :recursive :once :append :shell))
34
(defstruct mk-val (kind nil :type mk-val-designator) (val nil :type ast:form))
38
(val (make-mk-val) :type mk-val))
40
;; https://www.gnu.org/software/make/manual/html_node/Makefile-Contents.html
41
(defclass makefile (skel sk-meta)
42
((directives :initform (make-array 0 :adjustable t :fill-pointer 0)
43
:type (vector list) :accessor mk-directives)
44
(variables :initform (make-hash-table)
45
:type (hash-table) :accessor mk-vars)
46
(explicit :initform (make-array 0 :element-type 'sk-rule :adjustable t :fill-pointer 0)
47
:type (vector sk-rule) :accessor mk-erules)
48
(implicit :initform (make-array 0 :element-type 'sk-rule :adjustable t :fill-pointer 0)
49
:type (vector sk-rule) :accessor mk-irules))
50
(:documentation "A virtual GNU Makefile."))
52
(defmethod push-mk-rule ((self sk-rule) (place makefile) &optional implicit)
54
(vector-push-extend self (mk-irules place))
55
(vector-push-extend self (mk-erules place))))
57
(defmethod push-mk-directive ((self list) (place makefile))
58
(vector-push-extend self (mk-directives place)))
60
(defmethod push-mk-var ((self cons) (place makefile))
61
(destructuring-bind (k v) self
62
(setf (gethash k (mk-vars place)) v)))
64
(defmethod sk-compile ((self makefile) &key stream &allow-other-keys)
65
"Compile the makefile SELF to output STREAM."
66
(with-open-stream (s stream)
67
(with-slots (directives variables explicit implicit) self
69
(loop for d across directives
70
do (write d :stream s)
73
(maphash (lambda (x y) (format s "~A=~A~%" x y)) variables)
75
(loop for exp across explicit
76
do (format s "~A:~A;~A~%"
79
(when-let ((recipe (sk-rule-recipe exp)))
80
(sk-write-string recipe))))
81
;; TODO implicit rules
82
(loop for imp across implicit
83
do (format s "~A:~A;~A~%"
86
(sk-write-string (sk-rule-recipe imp)))))))
88
(defmethod sk-write-file ((self makefile) &key (path *default-makefile*) (comment t) (if-exists :overwrite))
89
(with-open-file (out path
92
:if-does-not-exist :create)
94
(make-source-header-comment
98
:description (sk-description self)
99
:opts '("mode: makefile-gmake;"))
101
(sk-compile self :stream out)))
103
(defmethod sk-read-file ((self makefile) path)
104
(with-open-file (f path :direction :input)))
108
;; simplified version of GNU Make Automatic Variables
110
;; don't need these: $% $? $+ $*
112
;; (defmacro def-mk-auto (sym ll &body body))
114
;; (def-mk-auto $@ (rule) (sk-rule-target rule))
115
;; (def-mk-auto $< (rule) (car (sk-rule-source rule)))
116
;; (def-mk-auto $^ (rule) (sk-rule-source rule))