]> Ladyโ€™s Gitweb - Shushe/blobdiff - GNUmakefile
Allow โ›ฉ๏ธ๐Ÿ“ฐ ไนฆ็คพ to produce plain text
[Shushe] / GNUmakefile
index bcba827b8f63519de1c829f6c4c6def96ffdfd7c..98a08cb4d67c8cd5c9eb4d0df44bb1a784f687e1 100644 (file)
@@ -1,26 +1,32 @@
+# SPDX-FileCopyrightText: 2023, 2024 Lady <https://www.ladys.computer/about/#lady>
+# SPDX-License-Identifier: MPL-2.0
+
 SHELL = /bin/sh
 
 # โ” ยง BASIC INFORMATION โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
 override define makefileinfo
  โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
 SHELL = /bin/sh
 
 # โ” ยง BASIC INFORMATION โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
 override define makefileinfo
  โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
-โ•”โ•ก โŒ โ›ฉ๏ธ๐Ÿ“ฐ ไนฆ็คพ โˆท GNUmakefile โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
+โ•”โ•ก โŒ โ›ฉ๏ธ๐Ÿ“ฐ ไนฆ็คพ โˆท GNUmakefile โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
 โ•‘โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ                                โ•‘
 โ•Ÿโ”ฌ ยถ Prerequisites โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ•ข
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ Requires GยทNยทU Make, at least version 3.81, a version of   โ”‚โ•‘
 โ•‘โ”‚ uuencode with base64 support, and the various programs     โ”‚โ•‘
 โ•‘โ”‚ offered by libxml2 and libxslt. Beyond this, only programs โ”‚โ•‘
 โ•‘โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ                                โ•‘
 โ•Ÿโ”ฌ ยถ Prerequisites โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ•ข
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ Requires GยทNยทU Make, at least version 3.81, a version of   โ”‚โ•‘
 โ•‘โ”‚ uuencode with base64 support, and the various programs     โ”‚โ•‘
 โ•‘โ”‚ offered by libxml2 and libxslt. Beyond this, only programs โ”‚โ•‘
-โ•‘โ”‚ required by Posix are used, altho there is a chance of     โ”‚โ•‘
+โ•‘โ”‚ required by Posix are required, altho there is a chance of โ”‚โ•‘
 โ•‘โ”‚ version incompatibilities. The full list of program        โ”‚โ•‘
 โ•‘โ”‚ requirements is as follows :โ€”                             โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ โ€ข awk                                                      โ”‚โ•‘
 โ•‘โ”‚ โ€ข cat                                                      โ”‚โ•‘
 โ•‘โ”‚ version incompatibilities. The full list of program        โ”‚โ•‘
 โ•‘โ”‚ requirements is as follows :โ€”                             โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ โ€ข awk                                                      โ”‚โ•‘
 โ•‘โ”‚ โ€ข cat                                                      โ”‚โ•‘
+โ•‘โ”‚ โ€ข cksum                                                    โ”‚โ•‘
 โ•‘โ”‚ โ€ข cp                                                       โ”‚โ•‘
 โ•‘โ”‚ โ€ข date                                                     โ”‚โ•‘
 โ•‘โ”‚ โ€ข echo                                                     โ”‚โ•‘
 โ•‘โ”‚ โ€ข file                                                     โ”‚โ•‘
 โ•‘โ”‚ โ€ข find                                                     โ”‚โ•‘
 โ•‘โ”‚ โ€ข cp                                                       โ”‚โ•‘
 โ•‘โ”‚ โ€ข date                                                     โ”‚โ•‘
 โ•‘โ”‚ โ€ข echo                                                     โ”‚โ•‘
 โ•‘โ”‚ โ€ข file                                                     โ”‚โ•‘
 โ•‘โ”‚ โ€ข find                                                     โ”‚โ•‘
+โ•‘โ”‚ โ€ข git (optional)                                           โ”‚โ•‘
+โ•‘โ”‚ โ€ข ln                                                       โ”‚โ•‘
 โ•‘โ”‚ โ€ข mkdir (requires support for `-pยด)                        โ”‚โ•‘
 โ•‘โ”‚ โ€ข mv                                                       โ”‚โ•‘
 โ•‘โ”‚ โ€ข od (requires support for `-t x1ยด)                        โ”‚โ•‘
 โ•‘โ”‚ โ€ข mkdir (requires support for `-pยด)                        โ”‚โ•‘
 โ•‘โ”‚ โ€ข mv                                                       โ”‚โ•‘
 โ•‘โ”‚ โ€ข od (requires support for `-t x1ยด)                        โ”‚โ•‘
@@ -33,6 +39,7 @@ override define makefileinfo
 โ•‘โ”‚ โ€ข touch                                                    โ”‚โ•‘
 โ•‘โ”‚ โ€ข tr (requires support for `-dยด)                           โ”‚โ•‘
 โ•‘โ”‚ โ€ข uuencode (requires support for `-mยด and `-rยด)            โ”‚โ•‘
 โ•‘โ”‚ โ€ข touch                                                    โ”‚โ•‘
 โ•‘โ”‚ โ€ข tr (requires support for `-dยด)                           โ”‚โ•‘
 โ•‘โ”‚ โ€ข uuencode (requires support for `-mยด and `-rยด)            โ”‚โ•‘
+โ•‘โ”‚ โ€ข uudecode (requires support for `-mยด and `-rยด)            โ”‚โ•‘
 โ•‘โ”‚ โ€ข xargs (requires support for `-0ยด)                        โ”‚โ•‘
 โ•‘โ”‚ โ€ข xmlcatalog (provided by libxml2)                         โ”‚โ•‘
 โ•‘โ”‚ โ€ข xmllint (provided by libxml2)                            โ”‚โ•‘
 โ•‘โ”‚ โ€ข xargs (requires support for `-0ยด)                        โ”‚โ•‘
 โ•‘โ”‚ โ€ข xmlcatalog (provided by libxml2)                         โ”‚โ•‘
 โ•‘โ”‚ โ€ข xmllint (provided by libxml2)                            โ”‚โ•‘
@@ -44,13 +51,14 @@ override define makefileinfo
 โ•‘โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏโ•‘
 โ•Ÿโ”ฌ ยถ Usage โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ•ข
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏโ•‘
 โ•Ÿโ”ฌ ยถ Usage โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ•ข
 โ•‘โ”‚                                                            โ”‚โ•‘
-โ•‘โ”‚ โ€ข `make allยด: Compile, but do not install, all files.      โ”‚โ•‘
+โ•‘โ”‚ โ€ข `make allยด (default): Compile, but do not install, all   โ”‚โ•‘
+โ•‘โ”‚   files.                                                   โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ โ€ข `make cleanยด: Remove `BUILDDIRยด.                         โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ โ€ข `make cleanยด: Remove `BUILDDIRยด.                         โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
-โ•‘โ”‚ โ€ข `make goneยด: Remove installed files.                     โ”‚โ•‘
+โ•‘โ”‚ โ€ข `make goneยด: Remove `BUILDDIRยด and installed files.      โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
-โ•‘โ”‚ โ€ข `make helpยด (default): Print this message.               โ”‚โ•‘
+โ•‘โ”‚ โ€ข `make helpยด: Print this message.                         โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ โ€ข `make installยด: Compile all files and install in         โ”‚โ•‘
 โ•‘โ”‚   `DESTDIRยด.                                               โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ โ€ข `make installยด: Compile all files and install in         โ”‚โ•‘
 โ•‘โ”‚   `DESTDIRยด.                                               โ”‚โ•‘
@@ -58,6 +66,9 @@ override define makefileinfo
 โ•‘โ”‚ โ€ข `make listยด: List all recognized source files and their  โ”‚โ•‘
 โ•‘โ”‚   classification (including media type and dependencies).  โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ โ€ข `make listยด: List all recognized source files and their  โ”‚โ•‘
 โ•‘โ”‚   classification (including media type and dependencies).  โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
+โ•‘โ”‚ โ€ข `make uninstallยด: Remove installed files, but not        โ”‚โ•‘
+โ•‘โ”‚   `BUILDDIRยด.                                              โ”‚โ•‘
+โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ Set `VERBOSE=1ยด to see the text of commands as they are    โ”‚โ•‘
 โ•‘โ”‚ executed.                                                  โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
 โ•‘โ”‚ Set `VERBOSE=1ยด to see the text of commands as they are    โ”‚โ•‘
 โ•‘โ”‚ executed.                                                  โ”‚โ•‘
 โ•‘โ”‚                                                            โ”‚โ•‘
@@ -80,15 +91,17 @@ endef
 
 # Programs needed to run this makeยทfile.
 #
 
 # Programs needed to run this makeยทfile.
 #
-# If these are not installed on your computer, or you need to use a
-# different implementation, you can override the appropriate variable.
+# If these are not installed on your computer, or you need to use a different implementation, you can override the appropriate variable.
 AWK := awk
 CAT := cat
 AWK := awk
 CAT := cat
+CKSUM := cksum
 CP := cp
 DATE := date
 ECHO := echo
 FILE := file
 FIND := find
 CP := cp
 DATE := date
 ECHO := echo
 FILE := file
 FIND := find
+GIT := git
+LN := ln
 MKDIR := mkdir
 MV := mv
 OD := od
 MKDIR := mkdir
 MV := mv
 OD := od
@@ -100,6 +113,7 @@ STAT := stat
 TEST := test
 TOUCH := touch
 TR := tr
 TEST := test
 TOUCH := touch
 TR := tr
+UUDECODE := uudecode
 UUENCODE := uuencode
 XARGS := xargs
 XMLCATALOG := xmlcatalog
 UUENCODE := uuencode
 XARGS := xargs
 XMLCATALOG := xmlcatalog
@@ -108,15 +122,13 @@ XSLTPROC := xsltproc
 
 # The directory which contains the source files.
 #
 
 # The directory which contains the source files.
 #
-# Multiple directories can be given so long as files with the same name
-# do not exist in each.
+# Multiple directories can be given so long as files with the same name do not exist in each.
 SRCDIR := sources
 
 SRCDIR := sources
 
-# The directory which contains โ€œincludesโ€: Files which may be included
-# in other files but for which no final output will be generated.
+# The directory which contains โ€œincludesโ€:
+# Files which may be included in other files but for which no final output will be generated.
 #
 #
-# Multiple directories can be given so long as files with the same name
-# do not exist in each.
+# Multiple directories can be given so long as files with the same name do not exist in each.
 #
 # These can be inside of `SRCDIRยด directories if desired.
 INCLUDEDIR := sources/includes
 #
 # These can be inside of `SRCDIRยด directories if desired.
 INCLUDEDIR := sources/includes
@@ -127,65 +139,66 @@ BUILDDIR := build
 # The directory into which to output files on `make installยด.
 DESTDIR := public
 
 # The directory into which to output files on `make installยด.
 DESTDIR := public
 
-# The location of this Makefile (and related โ›ฉ๏ธ๐Ÿ“ฐ ไนฆ็คพ files),
-# relative to the current working directory.
+# The location of this Makefile (and related โ›ฉ๏ธ๐Ÿ“ฐ ไนฆ็คพ files), relative to the current working directory.
 #
 # By default, this is inferred from the variable `MAKEFILE_LISTยด.
 THISDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 
 #
 # By default, this is inferred from the variable `MAKEFILE_LISTยด.
 THISDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 
-# The location of the magic files to use when determining media types.
-#
-# One is provided as part of this repository, but you can override it
-# if you need different media type detection.
+# Configuration of `findยด.
 #
 #
-# Your computer probably has a more comprehensive one installed at
-# `/usr/share/file/magicยด, but it is not recommended that you use this
-# directly. Instead, link or copy just the files you expect to need for
-# your project.
-MAGICDIR := $(patsubst ./%,%,$(THISDIR)/magic)
+# By default, `findยด will ignore files which begin with a period and those which are likely to cause problems for `makeยด.
+EXTRAFINDRULES :=
+EXTRAFINDINCLUDERULES :=
+FINDRULES := ! '(' '(' -name '[.-]*' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a $(EXTRAFINDRULES),)
+FINDINCLUDERULES := $(FINDRULES)$(if $(EXTRAFINDINCLUDERULES), -a $(EXTRAFINDINCLUDERULES),)
 
 
-# Configuration of `findยด.
+# The list of magic files to use when determining media types.
+#
+# Some are provided as part of this repository, but you can add more if you need different media type detection.
 #
 #
-# By default, `findยด will not follow symlinks and will use extended
-# regular expressions, ignoring hidden files and those which begin with
-# a period.
-FINDRULES := -flags -nohidden -and ! '(' '(' -name '[.-]*' -or -name '*[:|$$%]*' ')' -and -prune ')'
-FINDINCLUDERULES := $(FINDRULES)
+# Your computer probably has several already installed at `/usr/share/file/magicยด.
+EXTRAMAGIC :=
+MAGIC := $(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/magic/*)) $(EXTRAMAGIC))
 
 # The list of parsers for plaintext file types.
 #
 
 # The list of parsers for plaintext file types.
 #
-# Which parsers are provided will influence which kinds of files are
-# recognized as plaintext.
-#
-# Each parser โœmustโœ have a template which matches โœonlyโœ XยทHยทTยทMยทL
-# `<script>ยด elements that have a `@typeยด of a plaintext type supported
-# by the parser. They may have multiple.
-PARSERS := $(patsubst ./%,%,$(wildcard $(THISDIR)/parsers/*.xslt))
+# Which parsers are provided will influence which kinds of files are recognized as plaintext.
+EXTRAPARSERS :=
+PARSERS := $(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/parsers/*.xslt)) $(EXTRAPARSERS))
 
 # The list of transforms.
 
 # The list of transforms.
-TRANSFORMS := $(patsubst ./%,%,$(wildcard $(THISDIR)/transforms/*.xslt))
+EXTRATRANSFORMS :=
+TRANSFORMS := $(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/transforms/*.xslt)) $(EXTRATRANSFORMS))
 
 # List of types which should be treated as XยทMยทL.
 XMLTYPES := application/xml text/xml
 
 
 # List of types which should be treated as XยทMยทL.
 XMLTYPES := application/xml text/xml
 
+ifdef GIT
+ifneq ($(wildcard $(THISDIR)/.git),)
+# A description of the current git revision of โ›ฉ๏ธ๐Ÿ“ฐ ไนฆ็คพ.
+THISREV := $(shell cd $(THISDIR); $(GIT) describe 2> /dev/null || $(GIT) rev-parse HEAD 2> /dev/null || true)
+endif
+
+ifneq ($(wildcard .git),)
+# A description of the current git revision of the working directory.
+SRCREV := $(shell $(GIT) describe 2> /dev/null || $(GIT) rev-parse HEAD 2> /dev/null || true)
+endif
+endif
+
 # Set to a nonยทempty value to print all commands as they run.
 VERBOSE :=
 
 # The default target for this makefile.
 # Set to a nonยทempty value to print all commands as they run.
 VERBOSE :=
 
 # The default target for this makefile.
-#
-# Print help and exit.
-.DEFAULT_GOAL := help
+.DEFAULT_GOAL := all
 
 # โ” ยง BEGIN MAKEยทFILE โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
 
 # โ”€ ยถ Nonโ€Recipe Variable Definitions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
 
 # โ” ยง BEGIN MAKEยทFILE โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
 
 # โ”€ ยถ Nonโ€Recipe Variable Definitions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
-# A variable with no value, usable when assigning values which contain
-# whitespace.
+# A variable with no value, usable when assigning values which contain whitespace.
 override empty :=
 
 override empty :=
 
-# A variable which contains a newline, to allow the generation of
-# multiline strings in function calls.
+# A variable which contains a newline, to allow the generation of multiline strings in function calls.
 override define newline
 
 
 override define newline
 
 
@@ -203,46 +216,59 @@ override quote = '$(subst ','"'"',$1)'
 # Outputs an `@ยด to silence rules, unless `VERBOSEยด is nonempty.
 override silent := $(if $(VERBOSE),,@)
 
 # Outputs an `@ยด to silence rules, unless `VERBOSEยด is nonempty.
 override silent := $(if $(VERBOSE),,@)
 
-# (callable) Escape special characters for use in sed regular
-# expressions.
+# (callable) Test to see if the prerequisites provided by the second argument matches the value in the file corresponding to the first argument in `$(BUILDDIR)/lastprereqsยด.
+# If not, save the new value and then add FORCE.
+# Return them regardless.
+#
+# Calling this variable is useful when a given target should be updated whenever its list of prerequisites changes in addition to whenever there is a change to one of its prerequisites.
+#
+# โ˜ก This variable creates at least one subshell every time it is computed.
+override diffprereqs = $(if $(subst $(shell $(CAT) $(call quote,$(BUILDDIR)/lastprereqs/$1) 2> /dev/null || true),,$2),$2 FORCE$(and $(shell $(call ensuredirectory,$(BUILDDIR)/lastprereqs) && $(PRINTF) '%s\n' $(call quote,$2) > $(BUILDDIR)/lastprereqs/$1),),$2)
+
+# (callable) Escape special characters for use in sed regular expressions.
 override sedesc = $(subst /,[/],$(subst $$,\$$,$(subst *,\*,$(subst .,\.,$(subst [,\[,$(subst ^,\^,$(subst \,\\,$1)))))))
 
 override sedesc = $(subst /,[/],$(subst $$,\$$,$(subst *,\*,$(subst .,\.,$(subst [,\[,$(subst ^,\^,$(subst \,\\,$1)))))))
 
+# The command to use for percentโ€decoding.
+override perdeccmd := $(SED) 's/|/%7C/g;s/[\]/%5C/g;s/%[0-9A-Fa-f]\{2\}/|&|/g' | $(TR) '|' '\n' | $(SED) '/^%[0-9A-Fa-f]\{2\}$$/!s/%/|%25|/' | $(TR) '|' '\n' | $(AWK) '$$0!~/%/{printf "%s",$$0}/%/{d="0123456789ABCDEF";v=substr(toupper($$0),2,2);printf "\\%04o",(index(d,substr(v,1,1))-1)*16+index(d,substr(v,2,1))-1}' | $(XARGS) -0 $(PRINTF) '%b'
+
 # (callable) Percentโ€decode the given strings.
 # (callable) Percentโ€decode the given strings.
-override perdec = $(foreach encoded,$1,$(shell $(PRINTF) '%s\n' $(call quote,$(encoded)) | $(SED) 's/`/`%60`/g;s/[\]/`%5C`/g;s/%[0-9A-Fa-f]\{2\}/`&`/g' | $(TR) '`' '\n' | $(SED) '/^%[0-9A-Fa-f]\{2\}$$/!s/%/`%25`/' | $(TR) '`' '\n' | $(AWK) '$$0!~/%/{printf("%s",$$0)}/%/{sub("%","0x");printf("\\%04o",$$0)}' | $(XARGS) -0 $(PRINTF) '%b'))
+#
+# โ˜ก This variable creates a subshell every time it is computed.
+override perdec = $(shell $(PRINTF) '%s\0450A' $(foreach encoded,$1,$(call quote,$(encoded))) | $(perdeccmd))
 
 # (callable) Percentโ€encode the given strings.
 #
 
 # (callable) Percentโ€encode the given strings.
 #
-# This singlyโ€encodes uยทrยทi characters and doublyโ€encodes other
-# characters, then calls `perdecยด to decode back to a single encoding.
-# The encoding assumes the input is a โ€œuยทrยทi componentโ€; eยทg that the
-# resulting string should only contain `pcharยด (but can contain any
-# `sub-delimยด).
-override perenc = $(foreach unencoded,$1,$(call perdec,$(shell $(PRINTF) '%s' $(call quote,$(unencoded)) | $(OD) -t x1 | $(SED) 's/^[0-9]*//;s/2[146-9A-Ea-e]/%&/g;s/3[0-9AaBbDd]/%&/g;s/40/%&/g;s/[46][1-9A-Fa-f]/%&/g;s/[57][0-9Aa]/%&/g;s/7[Ee]/%&/g;s/[ ][0-9A-Fa-f]\{2\}/%25&/g' | $(TR) -d ' \n' | $(TR) 'abcdef' 'ABCDEF')))
+# This singlyโ€encodes uยทrยทi characters and doublyโ€encodes other characters, then calls `perdecยด to decode back to a single encoding.
+# The encoding assumes the input is a โ€œuยทrยทi componentโ€; eยทg that the resulting string should only contain `pcharยด (but can contain any `sub-delimยด).
+#
+# It is assumed that the given strings do not contain newlines.
+#
+# โ˜ก This variable creates a subshell every time it is computed.
+override perenc = $(shell $(PRINTF) '%s\n' $(foreach unencoded,$1,$(call quote,$(unencoded))) | $(OD) -t x1 | $(SED) 's/^[0-9]*//;s/0[Aa]/%&/g;s/2[146-9A-Ea-e]/%&/g;s/3[0-9AaBbDd]/%&/g;s/40/%&/g;s/[46][1-9A-Fa-f]/%&/g;s/[57][0-9Aa]/%&/g;s/5[Ff]/%&/g;s/7[Ee]/%&/g;s/[ ][0-9A-Fa-f]\{2\}/%25&/g' | $(TR) -d ' \n' | $(TR) 'abcdef' 'ABCDEF' | $(perdeccmd))
 
 # (callable) Percentโ€encode each component in the given paths.
 
 # (callable) Percentโ€encode each component in the given paths.
-override pathenc = $(foreach path,$1,$(subst $(space),/,$(call perenc,$(subst /, ,$(path)))))
+#
+# โ˜ก This variable creates a subshell every time it is computed.
+override pathenc = $(subst %2F,/,$(call perenc,$1))
 
 
-# (overridable) Collect all of the applicable includes from the
-# includes directory.
-sourceincludes := $(shell $(FIND) $(FINDOPTS) $(INCLUDEDIR) -type f '(' $(FINDRULES) ')')
+# (overridable) Collect all of the applicable includes from the includes directory.
+sourceincludes := $(shell $(FIND) $(foreach dir,$(INCLUDEDIR),$(call quote,$(dir))) '(' $(FINDRULES) ')' -a -type f)
 
 
-# (overridable) Collect all of the applicable source files from the
-# source directory, removing any which are also includes.
-sourcefiles := $(filter-out $(sourceincludes),$(shell $(FIND) $(FINDOPTS) $(SRCDIR) -type f '(' $(FINDRULES) ')'))
+# (overridable) Collect all of the applicable source files from the source directory, removing any which are also includes.
+sourcefiles := $(filter-out $(sourceincludes),$(shell $(FIND) $(foreach dir,$(SRCDIR),$(call quote,$(dir))) '(' $(FINDRULES) ')' -a -type f))
 
 # Figure out the file type of each source file and source include.
 ifneq ($(wildcard $(BUILDDIR)/magic.mgc),)
 
 # Figure out the file type of each source file and source include.
 ifneq ($(wildcard $(BUILDDIR)/magic.mgc),)
-override types := $(shell $(SED) 's/^ *//;s/ *$$//;s/ {2,}/ /g' <<< $(call quote,$(sourcefiles) $(sourceincludes)) | $(TR) ' ' '\n' | $(FILE) -m $(call quote,$(BUILDDIR)/magic.mgc) --mime-type --separator ':' --files-from - | $(SED) 's/: */:/g')
+override types := $(shell $(SED) 's/^ *//;s/ *$$//;s/ {2,}/ /g' <<< $(call quote,$(sourcefiles) $(sourceincludes)) | $(TR) ' ' '\n' | $(FILE) -m $(call quote,$(BUILDDIR)/magic.mgc) --mime-type --separator '|' --files-from - | $(SED) 's/| */|/g')
 endif
 
 # Get the list of supported plaintext file types from the parser.
 ifneq ($(wildcard $(BUILDDIR)/parser.xslt),)
 endif
 
 # Get the list of supported plaintext file types from the parser.
 ifneq ($(wildcard $(BUILDDIR)/parser.xslt),)
-override plaintexttypes := $(filter-out $(XMLTYPES),$(shell $(XSLTPROC) $(call quote,$(THISDIR)/lib/parser2types.xslt) $(call quote,$(BUILDDIR)/parser.xslt)))
+override plaintexttypes := $(filter-out $(XMLTYPES),$(shell $(XMLLINT) --xpath '/*/*[@name="ไนฆ็คพ:parsers"]//*[namespace-uri()="http://www.w3.org/1999/xhtml" and local-name()="dd"]/text()' $(call quote,$(BUILDDIR)/parser.xslt)))
 endif
 
 endif
 
-# (callable) Get all of the files (source and includes) which have the
-# given types.
-override filesoftype = $(foreach type,$1,$(patsubst %:$(type),%,$(filter %:$(type),$(types))))
+# (callable) Get all of the files (source and includes) which have the given types.
+override filesoftype = $(foreach type,$1,$(patsubst %|$(type),%,$(filter %|$(type),$(types))))
 
 # Build up collections of various file types.
 override xmlfiles := $(call filesoftype,$(XMLTYPES))
 
 # Build up collections of various file types.
 override xmlfiles := $(call filesoftype,$(XMLTYPES))
@@ -250,10 +276,16 @@ override plaintextfiles := $(filter-out $(xmlfiles),$(call filesoftype,$(plainte
 override assetfiles := $(filter-out $(xmlfiles) $(plaintextfiles),$(sourcefiles) $(sourceincludes))
 
 # (callable) Get the types of the given files.
 override assetfiles := $(filter-out $(xmlfiles) $(plaintextfiles),$(sourcefiles) $(sourceincludes))
 
 # (callable) Get the types of the given files.
-override typeoffile = $(patsubst $(foreach file,$1,$(file):%),%,$(filter $(foreach file,$1,$(file):%),$(types)))
+override typeoffile = $(patsubst $(foreach file,$1,$(file)|%),%,$(filter $(foreach file,$1,$(file)|%),$(types)))
+
+# Pair each source magic file with its location in the build directory.
+override magicpair := $(foreach magicfile,$(MAGIC),$(magicfile)|$(BUILDDIR)/magic/$(notdir $(magicfile)))
 
 
-# (callable) Get the identifier for the given transform.
-override id = $(or $(shell $(XMLLINT) --xpath '/*/*[local-name()="id" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"]/text()[1]' $1),example:$(call pathenc,$(basename $(notdir $1))))
+# (callable) Get the source file for the given magic files.
+override magicsource = $(foreach magicpath,$1,$(patsubst %|$(magicpath),%,$(firstword $(filter %|$(magicpath),$(magicpair)))))
+
+# (callable) Get the build file for the given magic files.
+override magicfile = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(magicpair))))
 
 # (callable) Get the local path for the given source file.
 override sourcepath = $(firstword $(foreach directory,$(SRCDIR),$(if $(filter $(directory)/%,$1),$(patsubst $(directory)/%,%,$1),)))
 
 # (callable) Get the local path for the given source file.
 override sourcepath = $(firstword $(foreach directory,$(SRCDIR),$(if $(filter $(directory)/%,$1),$(patsubst $(directory)/%,%,$1),)))
@@ -262,51 +294,53 @@ override sourcepath = $(firstword $(foreach directory,$(SRCDIR),$(if $(filter $(
 override includepath = $(firstword $(foreach directory,$(INCLUDEDIR),$(if $(filter $(directory)/%,$1),$(patsubst $(directory)/%,%,$1),)))
 
 # (callable) Get base64 data uยทrยทiโ€™s for the given files.
 override includepath = $(firstword $(foreach directory,$(INCLUDEDIR),$(if $(filter $(directory)/%,$1),$(patsubst $(directory)/%,%,$1),)))
 
 # (callable) Get base64 data uยทrยทiโ€™s for the given files.
+#
+# โ˜ก This variable creates a subshell every time it is computed.
 override datauri = $(foreach file,$1,data:$(call typeoffile,$(file));base64,$(shell $(UUENCODE) -m -r $(call quote,$(file)) _ | tr -d ' \n'))
 
 # Pair each source file and include with its local uยทrยทi.
 override datauri = $(foreach file,$1,data:$(call typeoffile,$(file));base64,$(shell $(UUENCODE) -m -r $(call quote,$(file)) _ | tr -d ' \n'))
 
 # Pair each source file and include with its local uยทrยทi.
-override sourcelocalpair = $(foreach file,$(sourcefiles) $(sourceincludes),$(if $(filter $(file),$(sourceincludes)),$(file):about:shushe?include=$(call pathenc,$(call includepath,$(file))),$(file):about:shushe?source=$(call pathenc,$(call sourcepath,$(file)))))
+override sourcelocalpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|about:shushe?$(if $(filter $(file),$(sourceincludes)),include=$(call pathenc,$(call includepath,$(file))),source=$(call pathenc,$(call sourcepath,$(file)))))
 
 # (callable) Get local uris for the given files.
 
 # (callable) Get local uris for the given files.
-override localuri = $(foreach file,$1,$(patsubst $(file):%,%,$(filter $(file):%,$(sourcelocalpair))))
+override localuri = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcelocalpair))))
 
 # (callable) Get the source files for the given local uris.
 
 # (callable) Get the source files for the given local uris.
-override sourcefile = $(foreach local,$1,$(patsubst %:$(local),%,$(filter %:$(local),$(sourcelocalpair))))
+override sourcefile = $(foreach local,$1,$(patsubst %|$(local),%,$(filter %|$(local),$(sourcelocalpair))))
 
 
-# Adds a requirement on `$(BUILDDIR)/.update-typesยด if the file is
-# present.
+# Adds a requirement on `$(BUILDDIR)/.update-typesยด if the file is present.
 #
 #
-# This file is created after a reload due to type changes, and is
-# removed after. Requiring it ensures that file classifications are
-# upโ€toโ€date immediately after the reload.
+# This file is created after a reload due to type changes, and is removed after.
+# Requiring it ensures that file classifications are upยทtoยทdate immediately after the reload.
 override typeupdates := $(wildcard $(BUILDDIR)/.update-types)
 
 override typeupdates := $(wildcard $(BUILDDIR)/.update-types)
 
-# (callable) Get the location of the transformed XยทMยทL files for the
-# given source files.
-override parsed = $(foreach file,$1,$(if $(filter $(file),$(sourceincludes)),$(BUILDDIR)/includes/$(call includepath,$(file)),$(BUILDDIR)/sources/$(call sourcepath,$(file))))
-
 # Pair each source file and include with its parsed location.
 # Pair each source file and include with its parsed location.
-override sourceparsedpair = $(foreach file,$(sourcefiles) $(sourceincludes),$(file):$(call parsed,$(file)))
+override sourceparsedpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes/$(call includepath,$(file)),sources/$(call sourcepath,$(file))))
+
+# (callable) Get the location of the transformed XยทMยทL files for the given source files.
+override parsed = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourceparsedpair))))
 
 # (callable) Get the source files for the given parsed file.
 
 # (callable) Get the source files for the given parsed file.
-override unparsed = $(foreach file,$1,$(patsubst %:$(file),%,$(filter %:$(file),$(sourceparsedpair))))
+override unparsed = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(sourceparsedpair))))
+
+# Pair each parser, transform, or parsed file with its file uยทrยทi.
+override fileuripairs := $(join $(patsubst %,%|,$(PARSERS) $(TRANSFORMS) $(call parsed,$(sourcefiles) $(sourceincludes))),$(call pathenc,$(foreach uriable,$(PARSERS) $(TRANSFORMS) $(call parsed,$(sourcefiles) $(sourceincludes)),file://$(abspath $(uriable)))))
+
+# (callable) Get the file uยทrยทis for the given parsers, transforms, or parsed files.
+override fileuri = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(fileuripairs))))
 
 ifneq ($(wildcard $(BUILDDIR)/dependencies),)
 # Pair each file with a list of dependencies for it.
 
 ifneq ($(wildcard $(BUILDDIR)/dependencies),)
 # Pair each file with a list of dependencies for it.
-override dependenciesforfile := $(foreach file,$(sourcefiles),$(file):$(subst $(space),:,$(shell $(CAT) $(call quote,$(BUILDDIR)/dependencies) | $(SED) $(call quote,/^$(call sedesc,$(call localuri,$(file)))$$/$(comma)/^[^  ]/!d;/^ /!d;s/^ //))))
+override dependenciesforfile := $(foreach file,$(filter-out $(assetfiles),$(sourcefiles) $(sourceincludes)),$(file)|$(subst $(space),|,$(shell $(CAT) $(call quote,$(BUILDDIR)/dependencies) | $(SED) $(call quote,/^$(call sedesc,$(call localuri,$(file)))$$/$(comma)/^[^    ]/!d;/^ /!d;s/^ //))))
 
 
-# (callable) Get the list of dependency leiris for the given source
-# files.
+# (callable) Get the list of dependency leiris for the given source files.
 #
 # Recursive dependencies are marked with a leading `-ยด.
 #
 # Recursive dependencies are marked with a leading `-ยด.
-override dependencyuris = $(foreach file,$1,$(subst :, ,$(patsubst $(file):%,%,$(filter $(file):%,$(dependenciesforfile)))))
+override dependencyuris = $(foreach file,$1,$(subst |, ,$(patsubst $(file)|%,%,$(filter $(file)|%,$(dependenciesforfile)))))
 
 
-# (callable) Get the list of recursive dependencies for the given
-# source files.
+# (callable) Get the list of recursive dependencies for the given source files.
 override recursives = $(foreach uri,$(filter -%,$(call dependencyuris,$1)),$(call sourcefile,$(patsubst -%,%,$(uri))))
 
 override recursives = $(foreach uri,$(filter -%,$(call dependencyuris,$1)),$(call sourcefile,$(patsubst -%,%,$(uri))))
 
-# (callable) Get the list of (nonrecursive) dependencies for the given
-# source files.
+# (callable) Get the list of (nonrecursive) dependencies for the given source files.
 override dependencies = $(foreach uri,$(filter-out -%,$(call dependencyuris,$1)),$(call sourcefile,$(uri)))
 endif
 
 override dependencies = $(foreach uri,$(filter-out -%,$(call dependencyuris,$1)),$(call sourcefile,$(uri)))
 endif
 
@@ -318,96 +352,133 @@ override recursivefiles := $(foreach file,$(filter-out $(assetfiles),$(sourcefil
 # This is all of the nonยทasset, nonrecursive files.
 override compilablefiles := $(filter-out $(assetfiles) $(recursivefiles),$(sourcefiles))
 
 # This is all of the nonยทasset, nonrecursive files.
 override compilablefiles := $(filter-out $(assetfiles) $(recursivefiles),$(sourcefiles))
 
-# (callable) Get the compiled locations for the given source files.
-override compiled = $(foreach file,$1,$(BUILDDIR)/public/$(call sourcepath,$(file)))
+# Collect all files which can be installed.
+#
+# This is all of the comilable files and all asset sources.
+override installablefiles := $(compilablefiles) $(filter $(assetfiles),$(sourcefiles))
+
+ifneq ($(wildcard $(BUILDDIR)/destinations),)
+# Get the output of the destination transform.
+override destinations := $(shell $(CAT) $(BUILDDIR)/destinations)
+
+# Pair source files and their destinations.
+override sourcedestinationpair := $(foreach destination,$(destinations),$(call sourcefile,$(firstword $(subst |, ,$(destination))))|$(call perdec,$(subst $(space),|,$(wordlist 2,$(words $(subst |, ,$(destination))),$(subst |, ,$(destination))))))
 
 
-# Pair each source file and include with its compiled location.
-override sourcecompiledpair = $(foreach file,$(sourcefiles) $(sourceincludes),$(file):$(call compiled,$(file)))
+# (callable) Get the destination for the given source files.
+override destination = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcedestinationpair))))
+
+# Pair each source file with its compiled location.
+override sourcecompiledpair := $(foreach file,$(sourcefiles),$(file)|$(BUILDDIR)/results/$(call destination,$(file)))
+
+# (callable) Get the location of the transformed XยทMยทL files for the given source files.
+override compiled = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcecompiledpair))))
 
 # (callable) Get the source files for the given compiled file.
 
 # (callable) Get the source files for the given compiled file.
-override uncompiled = $(foreach file,$1,$(patsubst %:$(file),%,$(filter %:$(file),$(sourcecompiledpair))))
+override uncompiled = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(sourcecompiledpair))))
+
+# (callable) Get the location of the final built file for the given source files.
+override built = $(foreach file,$1,$(patsubst $(BUILDDIR)/results/%,$(BUILDDIR)/public/%,$(call compiled,$(file))))
 
 # (callable) Get the installed locations for the given source files.
 
 # (callable) Get the installed locations for the given source files.
-override installed = $(foreach file,$1,$(DESTDIR)/$(call sourcepath,$(file)))
+override installed = $(foreach file,$1,$(DESTDIR)/$(call destination,$(file)))
+endif
 
 # โ”€ ยถ Recipe Variable Definitions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
 
 # โ”€ ยถ Recipe Variable Definitions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
-# (callable) Check to see if the given directory exists and
-# create it if not.
+# (callable) Check to see if the given directory exists and create it if not.
 override ensuredirectory = if $(TEST) ! -d $(call quote,$1); then $(MKDIR) -p $(call quote,$1); fi
 
 override ensuredirectory = if $(TEST) ! -d $(call quote,$1); then $(MKDIR) -p $(call quote,$1); fi
 
-# (callable) Sanitize and wrap the provided plaintext file in
-#  XยทMยทL, printing to `stdoutยด.
-override wrapplaintext = $(PRINTF) '%s\n' "$$($(PRINTF) '%b' '<?xml version=\042\061.0\042?>\n<script xmlns=\042http://www.w3.org/1999/xhtml\042 type=\042$(call typeoffile,$1)\042><![CDATA['; $(CAT) $(call quote,$1) | $(TR) '\000\013\014' '\032\011\012' | $(SED) $$($(PRINTF) '%s%b' 's/]]>/]]]]><!\[CDATA\[>/g;s/\xEF\xBF\xBE/๏ฟฝ/g;s/\xEF\xBF\xBF/๏ฟฝ/g;$$!s/\r$$//g;s/\r/\n/g;$$!s/\xC2\x85$$//g;s/\xC2\x85/\n/g;s/\xE2\x80\xA8/\n/g;' 's/[\0001-\0010]/๏ฟฝ/g;s/[\0016-\0037]/๏ฟฝ/g'); $(PRINTF) '%s' ']]></script>')"
+# (callable) Get the identifier for the given parser or transform.
+override id = $(XMLLINT) --xpath '/*/*[local-name()="id" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"]/text()[1]' $(call quote,$1) 2> /dev/null || $(PRINTF) '%s\n' $(call quote,about:shushe?$(or $2,unknown)=$(call pathenc,$(basename $(notdir $1))))
 
 
-# โ”€ ยถ Phony Targets โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
+# (callable) Sanitize and wrap the provided plaintext file in XยทMยทL, printing to `stdoutยด.
+override wrapplaintext = $(TR) '\000\013\014' '\032\011\012' < $(call quote,$1) | $(SED) "$$($(PRINTF) '%b' 's/]]>/]]]]><!\\[CDATA\\[>/g\ns/\0357\0277\0276/๏ฟฝ/g\ns/\0357\0277\0277/๏ฟฝ/g\n$$!s/\\r$$//g\ns/\\r/\\n/g\n$$!s/\0302\0205$$//g\ns/\0302\0205/\\n/g;s/\0342\0200\0250/\\n/g;s/[\0001-\0010]/๏ฟฝ/g;s/[\0016-\0037]/๏ฟฝ/g')" | $(XARGS) -0 -J %% $(PRINTF) '%b%s%s\n' '<?xml version=\042\061.0\042?>\n<script xmlns=\042http://www.w3.org/1999/xhtml\042 type=\042$(call typeoffile,$1)\042><![CDATA[' %% ']]></script>'
 
 
-# Provide help.
-help:
-       $(silent)$(PRINTF) '%b' '$(subst $(newline),\n,$(makefileinfo))'
+# (callable) Check if the provided XยทMยทL file is XยทMยทL 1.1, and if so, coerce to XยทMยทL 1.0 as best as possible, printing the result (or the original file contents) to `stdoutยด.
+#
+# The XยทMยทL declaration will be dropped and character escapes for C0 control codes will be replaced with a literal `U+0091 PRIVATE USE ONEยด, which is invalid in XยทMยทL 1.1, but valid XยทMยทL 1.0 (making the replacement obvious).
+#
+# This isnโ€™t a perfect substitution (it makes some assumptions about the format of the underlying XยทMยทL), but it should be workable for most sensible, welformed files.
+override serializexml = $(SED) "$$($(PRINTF) '%b' '/<?xml[ \t]\\{1,\\}version=[\0042\0047]1.1/,$${ s/<?xml[^>]*?>/<!--<?xml version=\00421.1\0042?>-->/\n s/&\0043x0*[1-8BCEFbcef];/\0302\0221/g\n s/&\0043x0*1[0-9A-Fa-f];/\0302\0221/g\n s/&\00430*[1-8];/\0302\0221/g\n s/&\00430*1[124-9];/\0302\0221/g\n s/&\00430*2[0-9];/\0302\0221/g\n s/&\00430*3[01];/\0302\0221/g\n}')" < $(call quote,$1) | $(SED) "$$(PRINTF '%b' ':a\n/^\\n*$$/{ $$d\n N\n ba\n}')"
+
+# (callable) Test if the provided xpath expression matches the provided document.
+override xpath = $(XMLLINT) --xpath $(call quote,$1) $(call quote,$2) > /dev/null 2> /dev/null
+
+# (callable) Extract the value of the text nodes in the provided XยทMยทL document and print them to `stdoutยด.
+override extracttext = $(PRINTF) '%s' '<transform xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0"><output method="text" encoding="UTF-8"/></transform>' | $(XSLTPROC) - $(call quote,$1)
+
+# โ”€ ยถ Phony Targets โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
 # Compile all files, or error if any are recursive.
 
 # Compile all files, or error if any are recursive.
-all: $(call compiled,$(recursivefiles) $(compilablefiles) $(filter $(sourcefiles),$(assetfiles))) ;
+all : $(call built,$(recursivefiles) $(compilablefiles)) ;
 
 # Destroy buildfiles.
 
 # Destroy buildfiles.
-clean:
-       $(silent)$(RM) -rf $(BUILDDIR)/
+clean :
+       $(if $(BUILDDIR),$(silent)$(RM) -rf $(call quote,$(BUILDDIR)/),)
 
 
-# Destroy buildfiles and the install directory.
-gone:
-       $(silent)$(RM) -rf $(BUILDDIR)/ $(call compiled,$(recursivefiles) $(compilablefiles))
+# Destroy build directory and installed files.
+gone : clean uninstall ;
 
 
-# Install the compiled files into `DESTDIRยด.
-install: $(call installed,$(recursivefiles) $(compilablefiles) $(filter $(sourcefiles),$(assetfiles))) ;
+# Provide help.
+help :
+       @$(PRINTF) '%b' '$(subst $(newline),\n,$(makefileinfo))'
+
+# Install the compiled files into `DESTDIRยด, or error if any are recursive.
+install : $(call installed,$(recursivefiles) $(installablefiles)) ;
 
 # List all source files and includes and their computed types.
 
 # List all source files and includes and their computed types.
-list:
-       $(silent)$(PRINTF) '%b' $(call quote,$(foreach file,$(sort $(sourcefiles)) $(sort $(sourceincludes)),\0033[1m$(file)\0033[22m:$(call typeoffile,$(file)):[\0033[3m$(if $(filter $(file),$(xmlfiles)),xml,$(if $(filter $(file),$(plaintextfiles)),text,asset))$(if $(filter $(file),$(sourceincludes)),:include,)\0033[23m]$(if $(call dependencies,$(file))$(call recursives,$(file)), $(strip $(foreach recursive,$(call recursives,$(file)),\0033[93;41mโ€ข:Recursive:Dependency:\0033[39;49m:$(recursive)) $(foreach dependency,$(call dependencies,$(file)),\0033[2mโ€ข:Dependency:\0033[22m:$(dependency)))) )) | $(TR) ' :' '\n '
+list :
+       @$(PRINTF) '%b' $(call quote,$(foreach file,$(sort $(sourcefiles)) $(sort $(sourceincludes)),\0033[1m$(file)\0033[22m|$(call typeoffile,$(file))|[\0033[3m$(if $(filter $(file),$(xmlfiles)),xml,$(if $(filter $(file),$(plaintextfiles)),text,asset))$(if $(filter $(file),$(sourceincludes)),|include,)\0033[23m]$(if $(call dependencies,$(file))$(call recursives,$(file)), $(strip $(foreach recursive,$(call recursives,$(file)),\0033[93;41mโ€ข|Recursive|Dependency|\0033[39;49m|$(recursive)) $(foreach dependency,$(call dependencies,$(file)),\0033[2mโ€ข|Dependency|\0033[22m|$(dependency))))$(if $(filter $(file),$(sourcefiles)), โ†’|<\0033[4m/$(call destination,$(file))\0033[24m>,) )) | $(TR) ' |' '\n '
+
+# Destroy installed files.
+uninstall :
+       $(foreach file,$(installablefiles),$(if $(wildcard $(call installed,$(file))),$(silent)$(PRINTF) '%s\n' $(call quote,Removing </$(patsubst $(DESTDIR)/%,%,$(call installed,$(file)))>โ€ฆ)$(newline)$(silent)$(RM) -f $(call quote,$(call installed,$(file)))$(newline),))
 
 
-# Raise an error when attempting to build any files with recursive
-# dependencies.
-$(call compiled,$(recursivefiles)): $(BUILDDIR)/public/%:
-       @$(PRINTF) '%b\n' $(call quote,\0033[93;41mError:\0033[39;49m `$*ยด has recursive dependencies:\n$(subst :, ,$(subst $(space),$(newline),$(foreach recursive,$(call recursives,$(SRCDIR)/$*),โ€ข:$(patsubst $(SRCDIR)/%,%,$(recursive)))))) && false
+# Raise an error when attempting to build any files with recursive dependencies.
+$(call compiled,$(recursivefiles)) :
+       @$(PRINTF) '%b\n' $(call quote,\0033[93;41mError:\0033[39;49m `$(call uncompiled,$@)ยด has recursive dependencies:\n$(subst |, ,$(subst $(space),$(newline),$(foreach recursive,$(call recursives,$(call uncompiled,$@)),โ€ข|$(recursive))))) && false
+
+# Add as a prerequisite to treat the target as tho it were phony.
+FORCE : ;
 
 # โ”€ ยถ Special Targets โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
 
 # โ”€ ยถ Special Targets โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
-# Perform secondary expansion; this enables pattern rules to determine
-# their prerequisites based on the matched pattern.
-.SECONDEXPANSION: ;
+# Perform secondary expansion; this enables pattern rules to determine their prerequisites based on the matched pattern.
+.SECONDEXPANSION : ;
 
 # Donโ€™t use any implicit rules.
 
 # Donโ€™t use any implicit rules.
-.SUFFIXES: ;
+.SUFFIXES : ;
 
 
-# Phony rules; always consider these outโ€ofโ€date.
-.PHONY: all default clean gone info install list $(call compiled,$(recursivefiles));
+# Phony rules; always consider these outยทofยทdate.
+.PHONY : FORCE all default clean gone info install list uninstall $(call compiled,$(recursivefiles)) ;
 
 
-ifneq ($(wildcard $(BUILDDIR)/.update-types)$(wildcard $(BUILDDIR)/dependencies),)
-# Reload this makeยทfile if the dependency graph has changed.
+ifneq ($(typeupdates)$(wildcard $(BUILDDIR)/dependencies)$(wildcard $(BUILDDIR)/destinations),)
+# Reload this makeยทfile if the dependency graph or output destinations have changed.
+#
+# The dependency graph and output destinations are used to set the values of variables in this makeยทfile, so itโ€™s important to ensure that they are actually upยทtoยทdate prior to executing any later rules.
 #
 #
-# This graph is a dependency for some of the variables that this
-# makeยทfile uses, so itโ€™s important to ensure that they are actually
-# upโ€toโ€date prior to executing any later rules.
+# This recipe only exists after types have been updated or when the dependency graph or destinations file already exists.
 #
 #
-# This recipe only exists after types have been updated or when the
-# dependency graph already exists.
-$(THISDIR)/GNUmakefile:: $(BUILDDIR)/dependencies
+# โ€ป There is a chance that generating the dependencies will also update the parsers.
+$(THISDIR)/GNUmakefile :: $(BUILDDIR)/dependencies $(BUILDDIR)/destinations
        $(silent)$(TOUCH) $(THISDIR)/GNUmakefile
        $(silent)$(TOUCH) $(THISDIR)/GNUmakefile
-       $(silent)$(RM) -f $(BUILDDIR)/.update-types
-       @$(PRINTF) '%b\n' '\0033[1mDependency graph updated. Restartingโ€ฆ\0033[22m'
+ifeq ($(typeupdates),)
+       @if $(TEST) ! -f $(call quote,$(BUILDDIR)/.update-types); then $(PRINTF) '%b\n' '\0033[1mDependency graph and output destinations updated. Restartingโ€ฆ\0033[22m'; fi
+else
+       $(silent)$(RM) $(BUILDDIR)/.update-types
+       @$(PRINTF) '%b\n' '\0033[1mDependency graph and output destinations updated. Restartingโ€ฆ\0033[22m'
+endif
 endif
 
 endif
 
-ifeq ($(wildcard $(BUILDDIR)/.update-types),)
-# Reload this makeยทfile if any of the magic files or parsers have
-# changed.
+ifeq ($(typeupdates),)
+# Reload this makeยทfile if any of the magic files or parsers have changed.
 #
 #
-# These are used to classify source files, so if they have changed then
-# the makeยทfile must be reloaded.
+# These are used to classify source files, so if they have changed then the makeยทfile must be reloaded.
 #
 #
-# This recipe sleeps for one second to ensure that files built after
-# the restart have a more current timeยทstamp.
-$(THISDIR)/GNUmakefile:: $(BUILDDIR)/magic.mgc $(BUILDDIR)/parser.xslt $(THISDIR)/lib/parser2types.xslt
+# This recipe sleeps for one second to ensure that files built after the restart have a more current timeยทstamp.
+$(THISDIR)/GNUmakefile :: $(BUILDDIR)/magic.mgc $(BUILDDIR)/parser.xslt
        $(silent)$(TOUCH) $(THISDIR)/GNUmakefile
        $(silent)$(TOUCH) $(THISDIR)/GNUmakefile
-       $(silent)$(RM) -f $(call quote,$(BUILDDIR)/dependencies)
+       $(silent)$(RM) -f $(call quote,$(BUILDDIR)/dependencies) $(call quote,$(BUILDDIR)/destinations)
        @$(PRINTF) '%b\n' '\0033[1mMagic file or parsers have updated. Restartingโ€ฆ\0033[22m'
        $(silent)$(SLEEP) 1
        $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
        @$(PRINTF) '%b\n' '\0033[1mMagic file or parsers have updated. Restartingโ€ฆ\0033[22m'
        $(silent)$(SLEEP) 1
        $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
@@ -415,68 +486,92 @@ endif
 
 # โ”€ ยถ Build Targets โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
 
 # โ”€ ยถ Build Targets โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
+# Create symbolic links from the build directoryโ€™s store of magic files to their corresponding sources.
+$(call magicfile,$(MAGIC)) : $(BUILDDIR)/magic/% : $$(call magicsource,$$@)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(LN) -sf $(call quote,$(realpath $<)) $(call quote,$@)
+
 # Generate the compiled magic file from its sources.
 #
 # It must be updated if any of the files in the magic directory change.
 # Generate the compiled magic file from its sources.
 #
 # It must be updated if any of the files in the magic directory change.
-# It โœalsoโœ should be updated if any of the files in the magic
-# directory are deleted, but this isnโ€™t tracked presently.
-$(BUILDDIR)/magic.mgc: $(wildcard $(MAGICDIR)/*)
+$(BUILDDIR)/magic.mgc : $(call diffprereqs,magic,$(sort $(call magicfile,$(MAGIC))))
+       $(foreach outdated,$(filter-out $^,$(wildcard $(BUILDDIR)/magic/*)),$(silent)$(RM) $(call quote,$(outdated))$(newline))
        @$(ECHO) "Compiling new magicโ€ฆ"
        $(silent)$(call ensuredirectory,$(dir $@))
        @$(ECHO) "Compiling new magicโ€ฆ"
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)cd $(call quote,$(BUILDDIR)) && $(FILE) -C -m $(call quote,$(realpath $(MAGICDIR)))
+       $(silent)cd $(call quote,$(BUILDDIR)) && $(FILE) -C -m $(call quote,$(realpath $(BUILDDIR)/magic))
+       $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
 
 # Generate the main parser.
 
 # Generate the main parser.
-$(BUILDDIR)/parser.catalog: $(PARSERS)
+$(BUILDDIR)/parser.catalog : $(call diffprereqs,parsers,$(sort $(PARSERS)))
        @$(ECHO) "Generating catalog of parsersโ€ฆ"
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
        @$(ECHO) "Generating catalog of parsersโ€ฆ"
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
-       $(foreach parser,$(PARSERS),$(silent)$(XMLCATALOG) --add uri $(call quote,$(call id,$(parser))) $(call quote,$(call pathenc,../$(parser))) --noout $(call quote,$@)$(newline))
-$(BUILDDIR)/parser.xslt: $(BUILDDIR)/parser.catalog $(THISDIR)/lib/catalog2parser.xslt
+       $(foreach parser,$(PARSERS),$(silent)( $(call id,$(parser)) ) | $(XARGS) -I %% $(XMLCATALOG) --add uri %% $(call quote,$(call fileuri,$(parser))) --noout $(call quote,$@)$(newline))
+$(BUILDDIR)/parser.xslt : $(BUILDDIR)/parser.catalog $(THISDIR)/lib/catalog2parser.xslt
        @$(ECHO) "Generating main parserโ€ฆ"
        $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2parser.xslt) $(call quote,$<)
        @$(ECHO) "Generating main parserโ€ฆ"
        $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2parser.xslt) $(call quote,$<)
+       $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
 
 # Parse the files.
 #
 
 # Parse the files.
 #
-# Even plain XยทMยทL files are parsed, because they may contain XยทHยทTยทMยทL
-# `<script>ยด elements which contain other kinds of data. Asset files
-# are turned into HยทTยทMยทL embeds pointing to `data:ยด UยทRยทIโ€™s.
-$(call parsed,$(sourcefiles) $(sourceincludes)): %: $$(call unparsed,$$@) $(typeupdates)
+# Even plain XยทMยทL files are parsed, because they may contain XยทHยทTยทMยทL `<script>ยด elements which contain other kinds of data.
+# Asset files are turned into HยทTยทMยทL embeds pointing to `data:ยด UยทRยทIโ€™s.
+$(call parsed,$(sourcefiles) $(sourceincludes)) : % : $$(call unparsed,$$@) $(BUILDDIR)/parser.xslt $(typeupdates)
        @$(PRINTF) '%s\n' $(call quote,Processing `$<ยดโ€ฆ)
        $(silent)$(call ensuredirectory,$(dir $@))
        @$(PRINTF) '%s\n' $(call quote,Processing `$<ยดโ€ฆ)
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$<)" data="$(call datauri,$<)"/>) > $(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(CAT) $(call quote,$<)) | $(XSLTPROC) -o $(call quote,$@) $(call quote,$(BUILDDIR)/parser.xslt) -)
+       $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$<)" data="$(call datauri,$<)"/>) > $(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(call serializexml,$<)) | $(XSLTPROC) -o $(call quote,$@) --stringparam BUILDTIME $$(TZ= $(DATE) '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$<)) --stringparam SRCTIME $$(TZ= $(STAT) -f '%Sm' -t '%Y-%m-%dT%H:%M:%SZ' $(call quote,$<)) --stringparam CKSUM $$($(CKSUM) $(call quote,$<) | $(SED) 's/[ ].*//')$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/parser.xslt) -)
 
 
-# Generate a catalog of all parsed files, for use when processing
-# includes. This does not depend on actually transforming the files.
-$(BUILDDIR)/catalog: $(sourcefiles) $(sourceincludes) $(typeupdates)
+# Generate a catalog of all parsed files, for use when processing includes.
+#
+# This does not depend on actually transforming the files.
+$(BUILDDIR)/catalog : $(call diffprereqs,sources,$(sort $(sourcefiles) $(sourceincludes))) $(typeupdates)
        @$(ECHO) "Generating catalog of parsed filesโ€ฆ"
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
        @$(ECHO) "Generating catalog of parsed filesโ€ฆ"
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
-       $(foreach source,$(sourcefiles) $(sourceincludes),$(silent)$(XMLCATALOG) --add uri $(call quote,$(call localuri,$(source))) $(call quote,$(call pathenc,$(patsubst $(BUILDDIR)/%,%,$(call parsed,$(source))))#$(if $(filter $(source),$(assetfiles)),asset,xml)) --noout $(call quote,$@)$(newline))
+       $(foreach source,$(sourcefiles) $(sourceincludes),$(silent)$(XMLCATALOG) --add uri $(call quote,$(call localuri,$(source))) $(call quote,$(call fileuri,$(call parsed,$(source)))#$(if $(filter $(source),$(assetfiles)),asset,xml)) --noout $(call quote,$@)$(newline))
 
 # Build a list of dependencies for each parsed file.
 
 # Build a list of dependencies for each parsed file.
-$(BUILDDIR)/dependencies: $(BUILDDIR)/catalog $(call parsed,$(plaintextfiles) $(xmlfiles)) $(THISDIR)/lib/catalog2dependencies.xslt
+$(BUILDDIR)/dependencies : $(BUILDDIR)/catalog $(call parsed,$(plaintextfiles) $(xmlfiles)) $(THISDIR)/lib/catalog2dependencies.xslt
        @$(ECHO) "Identifying dependenciesโ€ฆ"
        $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2dependencies.xslt) $(call quote,$<)
 
        @$(ECHO) "Identifying dependenciesโ€ฆ"
        $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2dependencies.xslt) $(call quote,$<)
 
+# Generate a catalog of destinations for files.
+#
+# This depends on parsing nonยทasset source files, but not assets or includes.
+# It does not require knowing the dependencies.
+$(BUILDDIR)/destinations : $(BUILDDIR)/catalog $(call parsed,$(filter-out $(assetfiles),$(sourcefiles))) $(THISDIR)/lib/catalog2destinations.xslt
+       @$(ECHO) "Identifying output destinationsโ€ฆ"
+       $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2destinations.xslt) $(call quote,$<)
+
 # Generate the main transform.
 # Generate the main transform.
-$(BUILDDIR)/transform.catalog: $(TRANSFORMS)
+$(BUILDDIR)/transform.catalog : $(call diffprereqs,transforms,$(sort $(TRANSFORMS)))
        @$(ECHO) "Generating catalog of transformsโ€ฆ"
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
        @$(ECHO) "Generating catalog of transformsโ€ฆ"
        $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
-       $(foreach transform,$(TRANSFORMS),$(silent)$(XMLCATALOG) --add uri $(call quote,$(call id,$(transform))) $(call quote,$(call pathenc,../$(transform))) --noout $(call quote,$@)$(newline))
-$(BUILDDIR)/transform.xslt: $(BUILDDIR)/transform.catalog $(THISDIR)/lib/catalog2transform.xslt
+       $(foreach transform,$(TRANSFORMS),$(silent)( $(call id,$(transform)) ) | $(XARGS) -I %% $(XMLCATALOG) --add uri %% $(call quote,$(call fileuri,$(transform))) --noout $(call quote,$@)$(newline))
+$(BUILDDIR)/transform.xslt : $(BUILDDIR)/transform.catalog $(THISDIR)/lib/catalog2transform.xslt
        @$(ECHO) "Generating main transformโ€ฆ"
        $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2transform.xslt) $(call quote,$<)
 
        @$(ECHO) "Generating main transformโ€ฆ"
        $(silent)$(XSLTPROC) -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2transform.xslt) $(call quote,$<)
 
-# Generate the output files using the dependencies as necessary.
-$(call compiled,$(compilablefiles)): $(BUILDDIR)/public/%: $$(call parsed,$$(call uncompiled,$$@)) $(BUILDDIR)/transform.xslt $$(call parsed,$$(call dependencies,$$(call uncompiled,$$@)))
-       $(silent)$(call ensuredirectory,$(dir $@))
+# Compile the result files using the dependencies as necessary.
+$(call compiled,$(compilablefiles)) : $(BUILDDIR)/results/% : $$(call parsed,$$(call uncompiled,$$@)) $(BUILDDIR)/transform.xslt $$(call parsed,$$(call dependencies,$$(call uncompiled,$$@)))
        @$(PRINTF) '%s\n' $(call quote,Compiling </$*>โ€ฆ)
        @$(PRINTF) '%s\n' $(call quote,Compiling </$*>โ€ฆ)
-       $(silent)$(XSLTPROC) -o $(call quote,$@) --stringparam catalog 'catalog' --stringparam buildtime '$(shell TZ= $(DATE) '+%Y-%m-%dT%H:%M:%SZ')' --stringparam srctime '$(shell TZ= $(STAT) -f '%Sm' -t '%Y-%m-%dT%H:%M:%SZ' $(call quote,$(call uncompiled,$@)))' --stringparam path $(call quote,/$*) $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<)
-$(call compiled,$(filter $(assetfiles),$(sourcefiles))): $(BUILDDIR)/public/%: $$(call uncompiled,$$@)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(XSLTPROC) -o $(call quote,$@) --stringparam CATALOG 'catalog' --stringparam BUILDTIME $$(TZ= $(DATE) '+%Y-%m-%dT%H:%M:%SZ') --stringparam SRCTIME $$(TZ= $(STAT) -f '%Sm' -t '%Y-%m-%dT%H:%M:%SZ' $(call quote,$(call uncompiled,$@))) --stringparam IDENTIFIER $(call quote,$(call localuri,$(call uncompiled,$@))) --stringparam PATH $(call quote,/$*) --stringparam CKSUM $$($(CKSUM) $(call quote,$(call uncompiled,$@)) | $(SED) 's/[ ].*//')$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<)
+$(call compiled,$(filter $(assetfiles),$(sourcefiles))) : $(BUILDDIR)/results/% : $$(call uncompiled,$$@)
        @$(PRINTF) '%s\n' $(call quote,Compiling </$*>โ€ฆ)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)$(CP) $(call quote,$<) $(call quote,$@)
 
        @$(PRINTF) '%s\n' $(call quote,Compiling </$*>โ€ฆ)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)$(CP) $(call quote,$<) $(call quote,$@)
 
+# Create the final files from the compiled results (or error in the case of recursive ones).
+$(call built,$(compilablefiles)) : $(BUILDDIR)/public/% : $(BUILDDIR)/results/%
+       @$(PRINTF) '%s\n' $(call quote,Building </$*>โ€ฆ)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)if $(call xpath,/*[local-name()="raw-text" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$<); then $(RM) -f $(call quote,$@); $(call extracttext,$<) > $(call quote,$@); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$<); then $(RM) -f $(call quote,$@); $(call extracttext,$<) | $(TR) -d '\t\n\f\r ' | $(UUDECODE) -m -r > $(call quote,$@); else $(LN) -s -f $(call quote,$(subst $(space),,$(foreach component,$(subst /, ,$*),../))results/$*) $(call quote,$@); fi
+$(call built,$(filter $(assetfiles),$(sourcefiles)) $(recursivefiles)) : $(BUILDDIR)/public/% : $(BUILDDIR)/results/%
+       @$(PRINTF) '%s\n' $(call quote,Building </$*>โ€ฆ)
+       $(silent)$(call ensuredirectory,$(dir $@))
+       $(silent)$(LN) -s -f $(call quote,../results/$*) $(call quote,$@)
+
 # Install compiled files (or error in the case of recursive ones).
 # Install compiled files (or error in the case of recursive ones).
-$(call installed,$(filter $(assetfiles),$(sourcefiles)) $(recursivefiles) $(compilablefiles)): $(DESTDIR)/%: $(BUILDDIR)/public/%
+$(call installed,$(filter $(assetfiles),$(sourcefiles)) $(recursivefiles) $(compilablefiles)) : $(DESTDIR)/% : $(BUILDDIR)/public/%
        @$(PRINTF) '%s\n' $(call quote,Installing </$*>โ€ฆ)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)$(CP) $(call quote,$<) $(call quote,$@)
        @$(PRINTF) '%s\n' $(call quote,Installing </$*>โ€ฆ)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)$(CP) $(call quote,$<) $(call quote,$@)
This page took 0.0463 seconds and 4 git commands to generate.