Coverage report: /home/ellis/comp/core/app/skel/comp/makefile.lisp

KindCoveredAll%
expression66101 65.3
branch00nil
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;; makefile.lisp --- GNU Makefile Components
2
 
3
 ;; GNU Makefile skel components.
4
 
5
 ;;; Commentary:
6
 
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).
10
 
11
 ;;  HACK 2023-09-15: MVP
12
 
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.
16
 
17
 ;; https://github.com/takagi/lake
18
 
19
 ;; https://www.gnu.org/software/make/manual/html_node/Parsing-Makefiles.html
20
 
21
 ;;; Code:
22
 (in-package :skel/comp/makefile)
23
 
24
 (defparameter *default-makefile* "makefile")
25
 (defparameter *makefile-extension* "mk")
26
 
27
 ;;  TODO 2023-09-27: what is $(@D) ?? (target-dir)
28
 (defvar *mk-magic-vars* #(#\@ #\< #\^ #\* #\+ #\? #\|))
29
 
30
 (defvar *mk-command-prefixes* #(#\@ #\- #\+))
31
 
32
 (deftype mk-val-designator () '(member nil :simple :immediate :conditional :recursive :once :append :shell))
33
 
34
 (defstruct mk-val (kind nil :type mk-val-designator)  (val nil :type ast:form))
35
 
36
 (defstruct mk-var
37
   (key "" :type string)
38
   (val (make-mk-val) :type mk-val))
39
 
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."))
51
 
52
 (defmethod push-mk-rule ((self sk-rule) (place makefile) &optional implicit)
53
   (if implicit
54
       (vector-push-extend self (mk-irules place))
55
       (vector-push-extend self (mk-erules place))))
56
 
57
 (defmethod push-mk-directive ((self list) (place makefile))
58
   (vector-push-extend self (mk-directives place)))
59
 
60
 (defmethod push-mk-var ((self cons) (place makefile))
61
   (destructuring-bind (k v) self
62
     (setf (gethash k (mk-vars place)) v)))
63
 
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
68
       ;; directives
69
       (loop for d across directives
70
             do (write d :stream s)
71
             do (terpri s))
72
       ;; variables
73
       (maphash (lambda (x y) (format s "~A=~A~%" x y)) variables)
74
       ;; explicit rules
75
       (loop for exp across explicit
76
             do (format s "~A:~A;~A~%" 
77
                        (sk-rule-target exp)
78
                        (sk-rule-source exp)
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~%" 
84
                        (sk-rule-target imp)
85
                        (sk-rule-source imp)
86
                        (sk-write-string (sk-rule-recipe imp)))))))
87
 
88
 (defmethod sk-write-file ((self makefile) &key (path *default-makefile*) (comment t) (if-exists :overwrite))
89
   (with-open-file (out path
90
                        :direction :output
91
                        :if-exists if-exists
92
                        :if-does-not-exist :create)
93
     (when comment (princ
94
                    (make-source-header-comment
95
                     (name self)
96
                     :cchar #\#
97
                     :timestamp t
98
                     :description (sk-description self)
99
                     :opts '("mode: makefile-gmake;"))
100
                    out))
101
     (sk-compile self :stream out)))
102
 
103
 (defmethod sk-read-file ((self makefile) path)
104
   (with-open-file (f path :direction :input)))
105
 
106
 ;;; Auto Vars
107
 
108
 ;; simplified version of GNU Make Automatic Variables
109
 
110
 ;; don't need these: $% $? $+ $*
111
 
112
 ;; (defmacro def-mk-auto (sym ll &body body))
113
 
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))
117