chiark / gitweb /
src/: Write dependency-tracking Makefile fragments.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 8 Aug 2019 11:58:07 +0000 (12:58 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 8 Aug 2019 12:03:14 +0000 (13:03 +0100)
And deploy them in the Makefile!

doc/SYMBOLS
doc/module.tex
doc/output.tex
src/frontend.lisp
src/module-output.lisp
src/module-parse.lisp
src/module-proto.lisp
test/Makefile.am
vars.am

index e533a3815f996eb9f54942b64833d01ba4105c21..cd3dbed49db1e6f88d000027e661ec74b4dc40cb 100644 (file)
@@ -586,6 +586,7 @@ module-output.lisp
   one-off-output                                function
   output-module                                 function
   output-type-pathname                          function
   one-off-output                                function
   output-module                                 function
   output-type-pathname                          function
+  write-dependency-file                         generic
 
 module-parse.lisp
   class-item
 
 module-parse.lisp
   class-item
@@ -606,6 +607,7 @@ module-proto.lisp
   module                                        class
   module-dependencies                           generic setf-generic
   module-errors                                 generic
   module                                        class
   module-dependencies                           generic setf-generic
   module-errors                                 generic
+  module-files                                  generic setf-generic
   module-import                                 generic
   module-items                                  generic setf-generic
   module-name                                   generic
   module-import                                 generic
   module-items                                  generic setf-generic
   module-name                                   generic
@@ -1353,6 +1355,10 @@ module-dependencies
   t module
 module-errors
   module
   t module
 module-errors
   module
+module-files
+  module
+(setf module-files)
+  t module
 module-import
   t
   module
 module-import
   t
   module
@@ -1656,6 +1662,8 @@ vtmsgs-entries
   vtmsgs
 vtmsgs-subclass
   vtmsgs
   vtmsgs
 vtmsgs-subclass
   vtmsgs
+write-dependency-file
+  module t t
 
 -----------------------------------------------------------------------------
 Package `sod-frontend'
 
 -----------------------------------------------------------------------------
 Package `sod-frontend'
index 5d245dd19820cc274b8e4ed34a9c9c3910290784..ca9e13e6bd88942f7b81483ea5b8c85bfc66b616 100644 (file)
@@ -50,7 +50,8 @@
 \end{describe}
 
 \begin{describe}{cls}
 \end{describe}
 
 \begin{describe}{cls}
-    {module () \&key :name :pset :items :dependencies :variables :state}
+    {module ()
+      \&key :name :pset :items :files :dependencies :variables :state}
 \end{describe}
 
 \begin{describe*}
 \end{describe}
 
 \begin{describe*}
@@ -59,6 +60,8 @@
      \dhead{gf}{module-errors @<module> @> @<integer>}
      \dhead{gf}{module-items @<module> @> @<list>}
      \dhead{gf}{setf (module-items @<module>) @<list>}
      \dhead{gf}{module-errors @<module> @> @<integer>}
      \dhead{gf}{module-items @<module> @> @<list>}
      \dhead{gf}{setf (module-items @<module>) @<list>}
+     \dhead{gf}{module-files @<module> @> @<list>}
+     \dhead{gf}{setf (module-files @<module>) @<list>}
      \dhead{gf}{module-dependencies @<module> @> @<list>}
      \dhead{gf}{setf (module-dependencies @<module>) @<list>}
      \dhead{gf}{module-state @<module> @> @<symbol>}
      \dhead{gf}{module-dependencies @<module> @> @<list>}
      \dhead{gf}{setf (module-dependencies @<module>) @<list>}
      \dhead{gf}{module-state @<module> @> @<symbol>}
index 042317870e81d0f1cf858755f8bdb540245f8248..5b464ba50e1b28d961e636143dfdb96f93e52308 100644 (file)
@@ -193,6 +193,9 @@ until the third.  So the final processing order is
   \end{describe*}
 \end{describe}
 
   \end{describe*}
 \end{describe}
 
+\begin{describe}{gf}{write-dependency-file @<module> @<reason> @<output-dir>}
+\end{describe}
+
 \begin{describe}{fun}{output-module @<module> @<reason> @<stream>}
 \end{describe}
 
 \begin{describe}{fun}{output-module @<module> @<reason> @<stream>}
 \end{describe}
 
index 1d0938250cc9f4726f3aa155ef11b7c44302be05..41f38cd5af909bdba2d2af6b73e4cc2471f49377 100644 (file)
@@ -98,6 +98,7 @@ (defun main ()
        (backtracep nil)
        (builtinsp nil)
        (stdoutp nil)
        (backtracep nil)
        (builtinsp nil)
        (stdoutp nil)
+       (track-deps-p nil)
        (args nil))
 
     ;; Option definitions.
        (args nil))
 
     ;; Option definitions.
@@ -145,6 +146,9 @@     (define-program
                                                  :print nil))))
                           (error (error)
                             (option-parse-error "~A" error))))))
                                                  :print nil))))
                           (error (error)
                             (option-parse-error "~A" error))))))
+               (#\M "track-dependencies"
+                    "Write make(1) fragments recording dependencies."
+                    (set track-deps-p))
                (#\p "stdout"
                     ("Write output files to standard output.")
                     (set stdoutp))
                (#\p "stdout"
                     ("Write output files to standard output.")
                     (set stdoutp))
@@ -190,7 +194,11 @@     (define-program
                             :direction :output
                             :if-exists :supersede
                             :if-does-not-exist :create)
                             :direction :output
                             :if-exists :supersede
                             :if-does-not-exist :create)
-                         (output-module module reason stream))))
+                         (output-module module reason stream))
+
+                       (when track-deps-p
+                         (write-dependency-file module reason
+                                                output-path))))
 
                   ;; Error recovery.
                   (continue ()
 
                   ;; Error recovery.
                   (continue ()
index fe04f2b7460a15fc2696672de8cf983503a2576f..f9eb3a47b952ac9e3ee01d3ed644f262ee6ed2a4 100644 (file)
@@ -212,6 +212,7 @@ (defun declare-output-type (reason pathname)
 
    The output file name will be constructed by merging the module's pathname
    with PATHNAME."
 
    The output file name will be constructed by merging the module's pathname
    with PATHNAME."
+  (pushnew reason *output-types*)
   (setf (get reason 'output-type) pathname))
 
 (export 'output-type-pathname)
   (setf (get reason 'output-type) pathname))
 
 (export 'output-type-pathname)
@@ -246,6 +247,51 @@ (defmethod module-output-file
                (make-pathname :directory nil
                               :defaults (module-name module)))))
 
                (make-pathname :directory nil
                               :defaults (module-name module)))))
 
+(export 'write-dependency-file)
+(defgeneric write-dependency-file (module reason output-dir)
+  (:documentation
+   "Write a dependency-tracking make(1) fragment.
+
+   Specifically, we've processed a MODULE for a particular REASON (a
+   symbol), and the user has requested that output be written to OUTPUT-DIR
+   (a pathname): determine a suitable output pathname and write a make(1)
+   fragment explaining that the output file we've made depends on all of the
+   files we had to read to load the module."))
+
+(defmethod write-dependency-file ((module module) reason output-dir)
+  (let* ((common-case
+         ;; Bletch.  We want to derive the filetype from the one we're
+         ;; given, but we need to determine the environment's preferred
+         ;; filetype case to do that.  Make a pathname and inspect it to
+         ;; find out how to do this.
+
+         (if (upper-case-p
+                          (char (pathname-type (make-pathname
+                                                :type "TEST"
+                                                :case :common))
+                                0))
+                         #'string-upcase
+                         #'string-downcase))
+
+        (outpath (output-type-pathname reason))
+        (deppath (make-pathname :type (concatenate 'string
+                                                   (pathname-type outpath)
+                                                   (funcall common-case
+                                                            "-DEP"))
+                                :defaults outpath))
+        (outfile (module-output-file module reason output-dir))
+        (depfile (module-output-file module deppath output-dir)))
+
+    (with-open-file (dep depfile
+                    :direction :output
+                    :if-exists :supersede
+                    :if-does-not-exist :create)
+      (format dep "### -*-makefile-*-~%~
+                  ~A:~{ \\~%   ~A~}~%"
+             outfile
+             (cons (module-name module)
+                   (module-files module))))))
+
 (define-clear-the-decks reset-output-types
   "Clear out the registered output types."
   (dolist (reason *output-types*) (remprop reason 'output-type))
 (define-clear-the-decks reset-output-types
   "Clear out the registered output types."
   (dolist (reason *output-types*) (remprop reason 'output-type))
index df058bee46bc179b69181dd2dab942d65cdc1d28..311206d00a242b597985eae8a3ee5e5f348eef75 100644 (file)
@@ -156,6 +156,7 @@ (define-pluggable-parser module file (scanner pset)
                                                            :truename true)))
                                   (when module
                                     (module-import module)
                                                            :truename true)))
                                   (when module
                                     (module-import module)
+                                    (pushnew path (module-files *module*))
                                     (pushnew module
                                              (module-dependencies
                                               *module*))))
                                     (pushnew module
                                              (module-dependencies
                                               *module*))))
@@ -170,7 +171,9 @@ (define-pluggable-parser module file (scanner pset)
                   (common name "LISP" "Lisp file"
                           (lambda (path true)
                             (handler-case
                   (common name "LISP" "Lisp file"
                           (lambda (path true)
                             (handler-case
-                                (load true :verbose nil :print nil)
+                                (progn
+                                  (pushnew path (module-files *module*))
+                                  (load true :verbose nil :print nil))
                               (error (error)
                                 (cerror* "Error loading Lisp file ~S: ~A"
                                          path error)))))))))))
                               (error (error)
                                 (cerror* "Error loading Lisp file ~S: ~A"
                                          path error)))))))))))
index 1fbba7c0ff410a0c823e3934dd93ecaa56f8d894..ca0d511dd2d77face5ebc28589d736306abfe980 100644 (file)
@@ -149,13 +149,14 @@ (defgeneric finalize-module (module)
 ;;; Module objects.
 
 (export '(module module-name module-pset module-errors
 ;;; Module objects.
 
 (export '(module module-name module-pset module-errors
-         module-items module-dependencies module-state))
+         module-items module-files module-dependencies module-state))
 (defclass module ()
   ((name :initarg :name :type pathname :reader module-name)
    (%pset :initarg :pset :initform (make-pset)
          :type pset :reader module-pset)
    (errors :initarg :errors :initform 0 :type fixnum :reader module-errors)
    (items :initarg :items :initform nil :type list :accessor module-items)
 (defclass module ()
   ((name :initarg :name :type pathname :reader module-name)
    (%pset :initarg :pset :initform (make-pset)
          :type pset :reader module-pset)
    (errors :initarg :errors :initform 0 :type fixnum :reader module-errors)
    (items :initarg :items :initform nil :type list :accessor module-items)
+   (files :initarg :files :initform nil :type list :accessor module-files)
    (dependencies :initarg :dependencies :initform nil
                 :type list :accessor module-dependencies)
    (variables :initarg :variables :type list :accessor module-variables
    (dependencies :initarg :dependencies :initform nil
                 :type list :accessor module-dependencies)
    (variables :initarg :variables :type list :accessor module-variables
@@ -181,6 +182,8 @@ (defclass module ()
 
      * A list of other modules that this one depends on.
 
 
      * A list of other modules that this one depends on.
 
+     * A list of other files this module has read.
+
      * A list of module-variable values, in the order in which they're named
        in `*module-bindings-alist*'.
 
      * A list of module-variable values, in the order in which they're named
        in `*module-bindings-alist*'.
 
index de5b63444b860b1f0dcdaaaa266f0fc407505c49..3ffec2bba5f5adb2bb344e0e1ac38b073e0ce771 100644 (file)
@@ -29,6 +29,7 @@ include       $(top_srcdir)/vars.am
 ### The silly Chimaera example.
 
 check_PROGRAMS         += chimaera
 ### The silly Chimaera example.
 
 check_PROGRAMS         += chimaera
+-include chimaera.c-dep chimaera.h-dep
 
 EXTRA_DIST             += chimaera.sod
 nodist_chimaera_SOURCES         = chimaera.c chimaera.h
 
 EXTRA_DIST             += chimaera.sod
 nodist_chimaera_SOURCES         = chimaera.c chimaera.h
@@ -45,6 +46,7 @@ check-local:: chimaera chimaera.ref
 
 TESTS                  += test
 check_PROGRAMS         += test
 
 TESTS                  += test
 check_PROGRAMS         += test
+-include test.c-dep test.h-dep
 
 EXTRA_DIST             += test.sod
 nodist_test_SOURCES     = test.c test.h
 
 EXTRA_DIST             += test.sod
 nodist_test_SOURCES     = test.c test.h
@@ -59,6 +61,7 @@ check-local:: kwtest kwtest.ref
        diff -u $(srcdir)/kwtest.ref kwtest.out
 
 check_PROGRAMS         += rat
        diff -u $(srcdir)/kwtest.ref kwtest.out
 
 check_PROGRAMS         += rat
+-include rat.c-dep rat.h-dep
 
 EXTRA_DIST             += rat.sod rat.ref
 nodist_rat_SOURCES      = rat.c rat.h
 
 EXTRA_DIST             += rat.sod rat.ref
 nodist_rat_SOURCES      = rat.c rat.h
diff --git a/vars.am b/vars.am
index b3f81b7fbac1bd64658601a4453cab96eaae2b92..21f03ce83d872f8900f592f779ae1428eaec9445 100644 (file)
--- a/vars.am
+++ b/vars.am
@@ -94,8 +94,10 @@ V_SOD_h_0             = @echo "  SOD[h]   $@";
 SUFFIXES               += .c .h .sod
 .sod.c:; $(V_SOD_c)$(SOD) -tc $<
 .sod.h:; $(V_SOD_h)$(SOD) -th $<
 SUFFIXES               += .c .h .sod
 .sod.c:; $(V_SOD_c)$(SOD) -tc $<
 .sod.h:; $(V_SOD_h)$(SOD) -th $<
-%.c: %.sod $(SOD); $(V_SOD_c)$(SOD) -tc $<
-%.h: %.sod $(SOD); $(V_SOD_h)$(SOD) -th $<
+%.c: %.sod $(SOD); $(V_SOD_c)$(SOD) -M -tc $<
+%.h: %.sod $(SOD); $(V_SOD_h)$(SOD) -M -th $<
+
+DISTCLEANFILES         += *.c-dep *.h-dep
 
 ###--------------------------------------------------------------------------
 ### Silent rules for Lisp.
 
 ###--------------------------------------------------------------------------
 ### Silent rules for Lisp.