]> Lady’s Gitweb - Shushe/blobdiff - GNUmakefile
Allow overriding of finalization program
[Shushe] / GNUmakefile
index 2c77723f6fd24507cd0c9b8331a3648212fb0524..0a76e49901bb3ec1157b31cdac8ed5df93a47a44 100644 (file)
@@ -19,15 +19,16 @@ override define makefileinfo
 ║│                                                            │║
 ║│ • awk                                                      │║
 ║│ • cat                                                      │║
 ║│                                                            │║
 ║│ • awk                                                      │║
 ║│ • cat                                                      │║
+║│ • cd                                                       │║
 ║│ • cksum                                                    │║
 ║│ • cp                                                       │║
 ║│ • date                                                     │║
 ║│ • cksum                                                    │║
 ║│ • cp                                                       │║
 ║│ • date                                                     │║
+║│ • diff                                                     │║
 ║│ • file                                                     │║
 ║│ • find                                                     │║
 ║│ • grep                                                     │║
 ║│ • git (optional)                                           │║
 ║│ • ln                                                       │║
 ║│ • file                                                     │║
 ║│ • find                                                     │║
 ║│ • grep                                                     │║
 ║│ • git (optional)                                           │║
 ║│ • ln                                                       │║
-║│ • ls                                                       │║
 ║│ • mkdir                                                    │║
 ║│ • mv                                                       │║
 ║│ • od                                                       │║
 ║│ • mkdir                                                    │║
 ║│ • mv                                                       │║
 ║│ • od                                                       │║
@@ -99,15 +100,16 @@ endef
 # 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
 # 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
+CD := cd
 CKSUM := cksum
 CP := cp
 DATE := date
 CKSUM := cksum
 CP := cp
 DATE := date
+DIFF := diff
 FILE := file
 FIND := find
 GIT := git
 GREP := grep
 LN := ln
 FILE := file
 FIND := find
 GIT := git
 GREP := grep
 LN := ln
-LS := ls
 MKDIR := mkdir
 MV := mv
 OD := od
 MKDIR := mkdir
 MV := mv
 OD := od
@@ -147,7 +149,7 @@ SRCDIR := sources
 # 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.
 # 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
+INCLUDEDIR := $(SRCDIR)/includes
 
 # The directory in which to generate temporary buildfiles.
 #
 
 # The directory in which to generate temporary buildfiles.
 #
@@ -171,8 +173,8 @@ THISDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 # By default, `find´ will ignore files which begin with a period and those which are likely to cause problems for `make´.
 EXTRAFINDRULES :=
 EXTRAFINDINCLUDERULES :=
 # 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),)
+FINDRULES := ! '(' '(' -name '[.-]*' -a ! -name '.' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a '(' $(EXTRAFINDRULES) ')',)
+FINDINCLUDERULES := $(FINDRULES)$(if $(EXTRAFINDINCLUDERULES), -a '(' $(EXTRAFINDINCLUDERULES) ')',)
 
 # The list of magic files to use when determining media types.
 #
 
 # The list of magic files to use when determining media types.
 #
@@ -198,15 +200,18 @@ TRANSFORMS := $(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/transforms/*.xslt))
 # ends accordingly.
 XMLTYPES := application/xml text/xml +xml
 
 # ends accordingly.
 XMLTYPES := application/xml text/xml +xml
 
+# A program to run on basic X·M·L files after they are transformed.
+FINALIZE := $(XMLLINT) --nonet --nsclean
+
 ifdef GIT
 ifneq ($(wildcard $(THISDIR)/.git),)
 # A description of the current git revision of ⛩️📰 书社.
 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)
+THISREV := $(shell $(CD) $(THISDIR); $(GIT) describe 2>>/dev/null || $(GIT) rev-parse HEAD 2>>/dev/null || :)
 endif
 
 ifneq ($(wildcard .git),)
 # A description of the current git revision of the working directory.
 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)
+SRCREV := $(shell $(GIT) describe 2>>/dev/null || $(GIT) rev-parse HEAD 2>>/dev/null || :)
 endif
 endif
 
 endif
 endif
 
@@ -231,6 +236,12 @@ VERBOSE :=
 # The default target for this makefile.
 .DEFAULT_GOAL := all
 
 # The default target for this makefile.
 .DEFAULT_GOAL := all
 
+# Flags for use when calling the shell.
+#
+# `-e` enables early exit from invocations of multiple commands after
+# the first failure.
+.SHELLFLAGS := -c -e
+
 # ━ § BEGIN SHARED MAKE·FILE CONSTRUCTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
 # ─ ¶ Non‐Recipe Variable Definitions ─────────────────────────────────
 # ━ § BEGIN SHARED MAKE·FILE CONSTRUCTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
 # ─ ¶ Non‐Recipe Variable Definitions ─────────────────────────────────
@@ -255,17 +266,13 @@ override quote = '$(subst ','"'"',$1)'
 
 # (callable) Get the modified time of the provided file.
 #
 
 # (callable) Get the modified time of the provided file.
 #
-# Only the date·time information available via `ls -l´ is supported; that is, only minute precision for files newer than six months, and only day precision for files which are older.
-# This is, unfortunately, the best that can be done in pure Posix as of now.
-#
-# There is an easier implementation which provides the full date·time by archiving an empty file and then reading it back out of the archive :—
-#
-#     $(shell LC_TIME=POSIX TZ=UTC0 $(TOUCH) -m -r $(callquote,$1) $(BUILDDIR)/.mtime && $(PAX) -w -x ustar $(BUILDDIR)/.mtime | $(PAX) -v -o 'listopt=%(mtime=%Y-%m-%dT%H:%M:%SZ)T')
+# This touches a file containing only a newline and then diffs it with `/dev/null´ and extracts the timestamp from the diff.
+# Interestingly, on Macintosh, the format of `diff -u´ is only Posixy (including a fractional component and timezone) when `COMMAND_MODE=legacy´; however, the timezone will always be zero and the fractional component is ignorable, so it’s not necessary to worry about that here.
 #
 #
-# However, it depends on the `listopt´ option in `pax´, which (despite being specified in Posix) no implementations actually support.
+# The diff will always have an exit status of 1, but this is ignored by piping into Sed.
 #
 # ☡ This variable creates a subshell every time it is computed.
 #
 # ☡ This variable creates a subshell every time it is computed.
-override modtime = $(shell { $(DATE) -u '+%Y-%m'; LC_TIME=POSIX TZ=UTC0 ls -q -A -l $(call quote,$1) | $(SED) 's/\([^ ]* \{1,\}\)\{5\}\(\([^ ]* \{1,\}\)\{3\}\).*/\2/;s/ \([0123456789]\) / 0\1 /;s/Jan/01/;s/Feb/02/;s/Mar/03/;s/Apr/04/;s/May/05/;s/Jun/06/;s/Jul/07/;s/Aug/08/;s/Sep/09/;s/Oct/10/;s/Nov/11/;s/Dec/12/;s/\([0123456789]\{2\}\) *\([0123456789]\{2\}\) *\([0123456789]\{4\}\)/\3-\1-\2T00:00:00Z/;s/\([0123456789]\{2\}\) *\([0123456789]\{2\}\) *\([0123456789:]\{5\}\)/XXXX-\1-\2T\3:00Z/'; } | $(TR) -d ' ' | $(AWK) -F '-' 'NR==1{year=$$1;month=$$2}$$1=="XXXX"&&$$2<=month{print year"-"$$2"-"$$3}$$1=="XXXX"&&$$2>month{print year-1"-"$$2"-"$$3}NR>1&&$$1!="XXXX"')
+override modtime = $(shell if $(TEST) ! -f $(call quote,$(BUILDDIR)/.mtime); then $(PRINTF) '%b' '\n' > $(call quote,$(BUILDDIR)/.mtime); fi; $(TOUCH) -r $(call quote,$1) $(call quote,$(BUILDDIR)/.mtime); TZ=UTC0 $(DIFF) -u $(call quote,$(BUILDDIR)/.mtime) /dev/null | $(SED) '1!d;s/.*  \([^ ]*\) \([^ ]*\).*$$/\1T\2Z/')
 
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
 
 
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
 
@@ -287,13 +294,13 @@ override xargsquote = $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/;$$!s/$$/\\/
 override xargsmultiquote = $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/)
 
 # (callable) Test if the provided xpath expression matches the provided document.
 override xargsmultiquote = $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/)
 
 # (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
+override xpath = $(XMLLINT) --noent --nonet --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) --nonet --novalid - $(call quote,$1)
 
 # (callable) Process the provided transformation result and output the result to the provided location, given the provided relative path.
 
 # (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) --nonet --novalid - $(call quote,$1)
 
 # (callable) Process the provided transformation result and output the result to the provided location, given the provided relative path.
-override processresultto = if $(call xpath,/*[local-name()="raw-text" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(call extracttext,$1) > $(call quote,$2); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then { $(PRINTF) '%s\n' 'begin-base64 644 -'; $(call extracttext,$1) | $(TR) -d '\t\n\f\r '; $(PRINTF) '\n%s\n' '===='; } | $(UUDECODE) -o /dev/stdout > $(call quote,$2); elif $(call xpath,/*[local-name()="archive" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(MAKE) -f $(call quote,$(abspath $(THISDIR)/GNUmakefile)) $(call quote,$2) NAME=$(call quote,$3) SRC=$(call quote,$1) BUILDDIR=$(call quote,$(BUILDDIR)/archive/$3) DESTDIR=$(call quote,$(patsubst %/,%,$(dir $2))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive'; else $(XMLLINT) --nsclean $(call quote,$1) > $(call quote,$2); fi
+override processresultto = if $(call xpath,/*[local-name()="raw-text" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(call extracttext,$1) >|$(call quote,$2); elif $(call xpath,/*[local-name()="base64-binary" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then { $(PRINTF) '%s\n' 'begin-base64 644 -'; $(call extracttext,$1) | $(TR) -d '\t\n\f\r '; $(PRINTF) '\n%s\n' '===='; } | $(UUDECODE) -o /dev/stdout >|$(call quote,$2); elif $(call xpath,/*[local-name()="archive" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$1); then $(MAKE) -f $(call quote,$(abspath $(THISDIR)/GNUmakefile)) NAME=$(call quote,$3) SRC=$(call quote,$1) BUILDDIR=$(call quote,$(BUILDDIR)/archive/$3) DESTDIR=$(call quote,$(patsubst %/,%,$(dir $2))) MODE='urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive' $(call quote,$2); else $(FINALIZE) $(call quote,$1) >|$(call quote,$2); fi
 
 # ━ § BEGIN DEFAULT MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
 
 # ━ § BEGIN DEFAULT MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
@@ -308,7 +315,7 @@ ifeq ($(MODE),urn:fdc:ladys.computer:20231231:Shu1She4:mode:default)
 # 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.
 # 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)
+override diffprereqs = $(if $(subst $(shell $(CAT) $(call quote,$(BUILDDIR)/lastprereqs/$1) 2>>/dev/null || :),,$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)))))))
 
 # (callable) Escape special characters for use in sed regular expressions.
 override sedesc = $(subst /,[/],$(subst $$,\$$,$(subst *,\*,$(subst .,\.,$(subst [,\[,$(subst ^,\^,$(subst \,\\,$1)))))))
@@ -337,10 +344,10 @@ override perenc = $(shell $(PRINTF) '%s\n' $(foreach unencoded,$1,$(call quote,$
 override pathenc = $(subst %2F,/,$(call perenc,$1))
 
 # (overridable) Collect all of the applicable includes from the includes directory.
 override pathenc = $(subst %2F,/,$(call perenc,$1))
 
 # (overridable) Collect all of the applicable includes from the includes directory.
-sourceincludes := $(shell $(FIND) $(foreach dir,$(INCLUDEDIR),$(call quote,$(dir))) '(' $(FINDRULES) ')' -a -type f)
+sourceincludes := $(if $(and $(INCLUDEDIR),$(wildcard $(INCLUDEDIR))),$(patsubst ./%,%,$(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.
 
 # (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))
+sourcefiles := $(if $(and $(SRCDIR),$(wildcard $(SRCDIR))),$(filter-out $(sourceincludes),$(patsubst ./%,%,$(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),)
@@ -349,7 +356,7 @@ endif
 
 # Get the list of supported plaintext file types from the parser.
 ifneq ($(wildcard $(BUILDDIR)/parser.xslt),)
 
 # Get the list of supported plaintext file types from the parser.
 ifneq ($(wildcard $(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)))
+override plaintexttypes := $(filter-out $(XMLTYPES),$(shell $(XMLLINT) --noent --nonet --xpath '/*/*[@name="书社:parsers"]//*[namespace-uri()="http://www.w3.org/1999/xhtml" and local-name()="dd"]/text()' $(call quote,$(BUILDDIR)/parser.xslt)))
 endif
 
 # (callable) Get all of the files (source and includes) which have the provided types.
 endif
 
 # (callable) Get all of the files (source and includes) which have the provided types.
@@ -363,7 +370,7 @@ 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 = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(types))),$(error Unable to get type of file `$(file)´)))
 
 # Pair each source magic file with its location in the build directory.
 override magicpair := $(foreach magicfile,$(MAGIC),$(magicfile)|$(BUILDDIR)/magic/$(notdir $(magicfile)))
 
 # Pair each source magic file with its location in the build directory.
 override magicpair := $(foreach magicfile,$(MAGIC),$(magicfile)|$(BUILDDIR)/magic/$(notdir $(magicfile)))
@@ -375,10 +382,10 @@ override magicsource = $(foreach magicpath,$1,$(patsubst %|$(magicpath),%,$(firs
 override magicfile = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(magicpair))))
 
 # (callable) Get the local path for the given source file.
 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),)))
+override sourcepath = $(or $(firstword $(foreach directory,$(SRCDIR),$(if $(filter .,$(directory)),$(wildcard $1),$(if $(filter $(directory)/%,$1),$(patsubst $(directory)/%,%,$1),)))),$(error Unable to get local path for source file `$1´))
 
 # (callable) Get the local path for the given include.
 
 # (callable) Get the local path for the given include.
-override includepath = $(firstword $(foreach directory,$(INCLUDEDIR),$(if $(filter $(directory)/%,$1),$(patsubst $(directory)/%,%,$1),)))
+override includepath = $(or $(firstword $(foreach directory,$(INCLUDEDIR),$(if $(filter .,$(directory)),$(wildcard $1),$(if $(filter $(directory)/%,$1),$(patsubst $(directory)/%,%,$1),)))),$(error Unable to get local path for include file `$1´))
 
 # (callable) Get base64 data u·r·i’s for the given files.
 #
 
 # (callable) Get base64 data u·r·i’s for the given files.
 #
@@ -394,11 +401,11 @@ override localuri = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,
 # (callable) Get the source files for the given local uris.
 override sourcefile = $(foreach local,$1,$(patsubst %|$(local),%,$(filter %|$(local),$(sourcelocalpair))))
 
 # (callable) Get the source files for the given local uris.
 override sourcefile = $(foreach local,$1,$(patsubst %|$(local),%,$(filter %|$(local),$(sourcelocalpair))))
 
-# Adds a requirement on `$(BUILDDIR)/.update-types´ if the file is present.
+# Resolves to the `FORCE´ target if `$(BUILDDIR)/.update-types´ 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.
-override typeupdates := $(wildcard $(BUILDDIR)/.update-types)
+# This file is created before a reload due to type changes, and is removed after.
+# This ensures that file classifications are up·to·date immediately after the reload.
+override typeupdates := $(if $(wildcard $(BUILDDIR)/.update-types),FORCE,)
 
 # Pair each source file and include with its parsed location.
 override sourceparsedpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes/$(call includepath,$(file)),sources/$(call sourcepath,$(file))))
 
 # Pair each source file and include with its parsed location.
 override sourceparsedpair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes/$(call includepath,$(file)),sources/$(call sourcepath,$(file))))
@@ -413,7 +420,7 @@ override unparsed = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),
 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 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))))
+override fileuri = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(fileuripairs))),$(error Unable to get file u·r·i for `$(file)´)))
 
 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.
@@ -425,9 +432,13 @@ override dependenciesforfile := $(foreach file,$(filter-out $(assetfiles),$(sour
 override dependencyuris = $(foreach file,$1,$(subst |, ,$(patsubst $(file)|%,%,$(filter $(file)|%,$(dependenciesforfile)))))
 
 # (callable) Get the list of recursive dependencies for the given source files.
 override dependencyuris = $(foreach file,$1,$(subst |, ,$(patsubst $(file)|%,%,$(filter $(file)|%,$(dependenciesforfile)))))
 
 # (callable) Get the list of recursive dependencies for the given source files.
+#
+# If the file cannot have dependencies (e·g is an asset file), the resulting value will be the empty string.
 override recursives = $(foreach uri,$(filter -%,$(call dependencyuris,$1)),$(call sourcefile,$(patsubst -%,%,$(uri))))
 
 # (callable) Get the list of (nonrecursive) dependencies for the given source files.
 override recursives = $(foreach uri,$(filter -%,$(call dependencyuris,$1)),$(call sourcefile,$(patsubst -%,%,$(uri))))
 
 # (callable) Get the list of (nonrecursive) dependencies for the given source files.
+#
+# If the file cannot have dependencies (e·g is an asset file), the resulting value will be the empty string.
 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
 
@@ -451,8 +462,10 @@ 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 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))))))
 
-# (callable) Get the destination for the given source files.
-override destination = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcedestinationpair))))
+# (callable) Get the destination for the given source files, or return `NOTDEF´.
+#
+# The fallback here is because destinations are used to generate targets and thus must always be non·empty, even when they haven’t been generated yet.
+override destination = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcedestinationpair))),NOTDEF))
 
 # Pair each source file with its compiled location.
 override sourcecompiledpair := $(foreach file,$(sourcefiles),$(file)|$(BUILDDIR)/results/$(call destination,$(file)))
 
 # Pair each source file with its compiled location.
 override sourcecompiledpair := $(foreach file,$(sourcefiles),$(file)|$(BUILDDIR)/results/$(call destination,$(file)))
@@ -476,17 +489,17 @@ endif
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
 
 # (callable) Get the identifier for the given parser or transform.
 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
 
 # (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))))
+override id = $(XMLLINT) --noent --nonet --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))))
 
 # (callable) Sanitize and wrap the provided plaintext file in X·M·L, printing to `stdout´.
 
 # (callable) Sanitize and wrap the provided plaintext file in X·M·L, printing to `stdout´.
-override wrapplaintext = { $(PRINTF) '%s\n%s' '<?xml version="1.0"?>' '<script xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$1)"><![CDATA['; $(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\ns/\0342\0200\0250/\\n/g\ns/[\0001\0002\0003\0004\0005\0006\0007\0010]/�/g\ns/[\0016\0017\0020\0021\0022\0023\0024\0025\0026\0027\0031\0032\0033\0034\0035\0036\0037]/�/g')"; $(PRINTF) '%s\n' ']]></script>'; }
+override wrapplaintext = { $(PRINTF) '%s\n%s' '<?xml version="1.0"?>' '<script xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$1)"><![CDATA['; $(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\ns/\0342\0200\0250/\\n/g\ns/[\0001\0002\0003\0004\0005\0006\0007\0010]/�/g\ns/[\0016\0017\0020\0021\0022\0023\0024\0025\0026\0027\0031\0032\0033\0034\0035\0036\0037]/�/g')"; $(PRINTF) '%s\n' ']]></script>'; }
 
 # (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.
 
 # (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*[12345678BCEFbcef];/\0302\0221/g\n s/&\0043x0*1[0123456789ABCDEFabcdef];/\0302\0221/g\n s/&\00430*[12345678];/\0302\0221/g\n s/&\00430*1[12456789];/\0302\0221/g\n s/&\00430*2[0123456789];/\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}')"
+override serializexml = $(SED) "$$($(PRINTF) '%b' '/<?xml[ \t]\\{1,\\}version=[\0042\0047]1.1/,$${ s/<?xml[^>]*?>/<!--<?xml version=\00421.1\0042?>-->/\n s/&\0043x0*[12345678BCEFbcef];/\0302\0221/g\n s/&\0043x0*1[0123456789ABCDEFabcdef];/\0302\0221/g\n s/&\00430*[12345678];/\0302\0221/g\n s/&\00430*1[12456789];/\0302\0221/g\n s/&\00430*2[0123456789];/\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}')"
 
 # ─ ¶ Phony Targets ───────────────────────────────────────────────────
 
 
 # ─ ¶ Phony Targets ───────────────────────────────────────────────────
 
@@ -521,7 +534,7 @@ uninstall :
 
 # Raise an error when attempting to build any files with recursive dependencies.
 $(call built,$(recursivefiles)) :
 
 # Raise an error when attempting to build any files with recursive dependencies.
 $(call built,$(recursivefiles)) :
-       @$(PRINTF) '%b\n' $(call quote,\0033[93;41mError:\0033[39;49m `$(call unbuilt,$@)´ has recursive dependencies:\n$(subst |, ,$(subst $(space),$(newline),$(foreach recursive,$(call recursives,$(call unbuilt,$@)),•|$(recursive))))) >&2 && false
+       @$(PRINTF) '%b\n' $(call quote,\0033[93;41mError:\0033[39;49m `$(call unbuilt,$@)´ has recursive dependencies:\n$(subst |, ,$(subst $(space),$(newline),$(foreach recursive,$(call recursives,$(call unbuilt,$@)),•|$(recursive))))) >&2 && exit 1
 
 # Add as a prerequisite to treat the target as tho it were phony.
 FORCE : ;
 
 # Add as a prerequisite to treat the target as tho it were phony.
 FORCE : ;
@@ -534,6 +547,9 @@ FORCE : ;
 # Don’t use any implicit rules.
 .SUFFIXES : ;
 
 # Don’t use any implicit rules.
 .SUFFIXES : ;
 
+# Don’t delete these files even if Make is stopped in the process of rebuilding them.
+.PRECIOUS : GNUmakefile ;
+
 # Phony rules; always consider these out·of·date.
 .PHONY : FORCE all default clean gone info install list listout uninstall $(call built,$(recursivefiles)) ;
 
 # Phony rules; always consider these out·of·date.
 .PHONY : FORCE all default clean gone info install list listout uninstall $(call built,$(recursivefiles)) ;
 
@@ -583,7 +599,7 @@ $(BUILDDIR)/magic.mgc : $(call diffprereqs,magic,$(sort $(call magicfile,$(MAGIC
        $(foreach outdated,$(filter-out $^,$(wildcard $(BUILDDIR)/magic/*)),$(silent)$(RM) $(call quote,$(outdated))$(newline))
        $(call inform,$(PRINTF) '%s\n' 'Compiling new magic…' >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(foreach outdated,$(filter-out $^,$(wildcard $(BUILDDIR)/magic/*)),$(silent)$(RM) $(call quote,$(outdated))$(newline))
        $(call inform,$(PRINTF) '%s\n' 'Compiling new magic…' >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
-       $(silent)cd $(call quote,$(BUILDDIR)) && $(FILE) -C -m $(call quote,$(realpath $(BUILDDIR)/magic))
+       $(silent)$(CD) $(call quote,$(BUILDDIR)) && $(FILE) -C -m $(call quote,$(realpath $(BUILDDIR)/magic))
        $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
 
 # Generate the main parser.
        $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
 
 # Generate the main parser.
@@ -603,7 +619,7 @@ $(BUILDDIR)/parser.xslt : $(BUILDDIR)/parser.catalog $(THISDIR)/lib/catalog2pars
 $(call parsed,$(sourcefiles) $(sourceincludes)) : % : $$(call unparsed,$$@) $(BUILDDIR)/parser.xslt $(typeupdates)
        $(call inform,$(PRINTF) '%s\n' $(call quote,Processing `$<´…) >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
 $(call parsed,$(sourcefiles) $(sourceincludes)) : % : $$(call unparsed,$$@) $(BUILDDIR)/parser.xslt $(typeupdates)
        $(call inform,$(PRINTF) '%s\n' $(call quote,Processing `$<´…) >&2)
        $(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,$<),$(call serializexml,$<)) | $(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$<)) --stringparam SRCTIME '$(call modtime,$<)' --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) -)
+       $(silent)$(if $(filter $<,$(assetfiles)),$(PRINTF) '%s\n' $(call quote,<?xml version="1.0"?><object xmlns="http://www.w3.org/1999/xhtml" type="$(call typeoffile,$<)" data="$(call datauri,$<)"/>) >|$(call quote,$@),$(if $(filter $<,$(plaintextfiles)),$(call wrapplaintext,$<),$(call serializexml,$<)) | $(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$<)) --stringparam SRCTIME '$(call modtime,$<)' --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.
 #
 
 # Generate a catalog of all parsed files, for use when processing includes.
 #
@@ -716,7 +732,7 @@ $(DESTDIR)/% : $(SRC) $(foreach file,$(archivefiles),$(BUILDDIR)/files/$(file))
        $(call inform,$(PRINTF) '%s\n' $(call quote,Archiving </$(NAME)>…) >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)$(RM) -f -R $(call quote,$@)
        $(call inform,$(PRINTF) '%s\n' $(call quote,Archiving </$(NAME)>…) >&2)
        $(silent)$(call ensuredirectory,$(dir $@))
        $(silent)$(RM) -f -R $(call quote,$@)
-       $(silent)cd $(call quote,$(BUILDDIR)/files); if $(call xpath,/*/@*[local-name()="expanded" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$(abspath $<)); then $(MKDIR) -p $(call quote,$(abspath $@)); $(PRINTF) '%s\n' $(foreach file,$(archivefiles),$(call quote,$(file))) | $(PAX) -r -w $(call quote,$(abspath $@)); else $(PRINTF) '%s\n' $(foreach file,$(archivefiles),$(call quote,$(file))) | $(PAX) -w -x ustar > $(call quote,$(abspath $@)); fi
+       $(silent)$(CD) $(call quote,$(BUILDDIR)/files); if $(call xpath,/*/@*[local-name()="expanded" and namespace-uri()="urn:fdc:ladys.computer:20231231:Shu1She4"],$(abspath $<)); then $(MKDIR) -p $(call quote,$(abspath $@)); $(PRINTF) '%s\n' $(foreach file,$(archivefiles),$(call quote,$(file))) | $(PAX) -r -w $(call quote,$(abspath $@)); else $(PRINTF) '%s\n' $(foreach file,$(archivefiles),$(call quote,$(file))) | $(PAX) -w -x ustar >|$(call quote,$(abspath $@)); fi
 
 # ━ § END DEFINED MAKE·FILE MODES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
 
 # ━ § END DEFINED MAKE·FILE MODES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
This page took 0.087493 seconds and 4 git commands to generate.