# ━ § BASIC INFORMATION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
override define makefileinfo
╭────────────────────────────╮
-╔╡ ⁌ ⛩️📰 书社 ∷ GNUmakefile ╞═════════════════════════════════╗
+╔╡ ⁌ ⛩📰 书社 ∷ GNUmakefile ╞═════════════════════════════════╗
║╰────────────────────────────╯ ║
╟┬ ¶ Prerequisites ───────────────────────────────────────────┬╢
║│ │║
║╰────────────────────────────────────────────────────────────╯║
╟┬ ¶ Copyright & License ─────────────────────────────────────┬╢
║│ │║
-║│ Copyright © 2023–2024 Lady [@ Lady’s Computer]. │║
+║│ Copyright © 2023–2024 Lady [@ Ladys Computer]. │║
║│ │║
║│ This Source Code Form is subject to the terms of the │║
║│ Mozilla Public License, v 2.0. If a copy of the M·P·L was │║
# This variable is also used by the archiving `MODE´.
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´.
#
ifdef GIT
ifneq ($(wildcard $(THISDIR)/.git),)
-# A description of the current git revision of ⛩️📰 书社.
+# A description of the current git revision of ⛩📰 书社.
THISREV := $(shell $(CD) $(THISDIR); $(GIT) describe 2>>/dev/null || $(GIT) rev-parse HEAD 2>>/dev/null || :)
endif
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)
+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 --nomkdir --nowrite - $(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)) 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
# (callable) Get the source files for the given parsed file.
override unparsed = $(foreach file,$1,$(patsubst %|$(file),%,$(filter %|$(file),$(sourceparsedpair))))
-# Pair each parser, transform, source file, parsed file, or metadata compilation with its file u·r·i.
-override fileuripairs := $(join $(patsubst %,%|,$(PARSERS) $(TRANSFORMS) $(sourcefiles) $(sourceincludes) $(call parsed,$(sourcefiles) $(sourceincludes)) $(BUILDDIR)/metadata),$(call pathenc,$(foreach uriable,$(PARSERS) $(TRANSFORMS) $(sourcefiles) $(sourceincludes) $(call parsed,$(sourcefiles) $(sourceincludes)) $(BUILDDIR)/metadata,file://$(abspath $(uriable)))))
+# Pair each build directory, parser, transform, or source file with its file u·r·i.
+override fileuripairs := $(join $(patsubst %,%|,$(BUILDDIR) $(PARSERS) $(TRANSFORMS) $(sourcefiles) $(sourceincludes)),$(call pathenc,$(foreach uriable,$(BUILDDIR) $(PARSERS) $(TRANSFORMS) $(sourcefiles) $(sourceincludes),file://$(abspath $(uriable)))))
# (callable) Get the file u·r·is for the given parsers, transforms, parsed files, or metadata compilations.
override fileuri = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(fileuripairs))),$(error Unable to get file u·r·i for `$(file)´)))
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))))))
+override sourcedestinationpair := $(foreach destination,$(destinations),$(call sourcefile,$(firstword $(subst |, ,$(destination))))|$(subst $(space),|,$(wordlist 2,$(words $(subst |, ,$(destination))),$(subst |, ,$(destination)))))
+endif
-# (callable) Get the destination for the given source files, or return `NOTDEF´.
+# (callable) Get the destination for the given source files, or return `.NOTDEF/$1´.
#
-# 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))
+# The fallback here is because destinations are used to generate targets and thus must always be non·empty and should be unique, even when they haven’t been generated yet.
+override destination = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(sourcedestinationpair))),.NOTDEF/$1))
# Pair each source file with its compiled location.
override sourcecompiledpair := $(foreach file,$(sourcefiles),$(file)|$(BUILDDIR)/results/$(call destination,$(file)))
# (callable) Get the installed locations for the given source files.
override installed = $(foreach file,$1,$(DESTDIR)/$(call destination,$(file)))
-endif
# ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
$(foreach parser,$(PARSERS),$(silent){ $(call id,$(parser)); $(PRINTF) '%s\n' $(call quote,$(call fileuri,$(parser))) '--noout' $(call quote,$@); } | $(xargsmultiquote) | $(XARGS) -E '' $(XMLCATALOG) --add uri$(newline))
$(BUILDDIR)/parser.xslt : $(BUILDDIR)/parser.catalog $(THISDIR)/lib/catalog2parser.xslt
$(call inform,$(PRINTF) '%s\n' 'Generating main parser…' >&2)
- $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) $(call quote,$(THISDIR)/lib/catalog2parser.xslt) $(call quote,$<)
+ $(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite $(call quote,$(THISDIR)/lib/catalog2parser.xslt) $(call quote,$<) >|$(call quote,$@)
$(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types)
# Generate R·D·F metadata for files.
-$(call metadata,$(sourcefiles) $(sourceincludes)) : % : $$(call datadata,$$@) $(typeupdates)
+#
+# This “depends” on `$(THISDIR)/lib/expandmetadata.xslt´ not because it is an actual dependency, but because a change to that file strongly suggests a change to these rules has occurred as well.
+$(call metadata,$(sourcefiles) $(sourceincludes)) : % : $$(call datadata,$$@) $(THISDIR)/lib/expandmetadata.xslt $(typeupdates)
$(call inform,$(PRINTF) '%s\n' $(call quote,Generating metadata for `$<´…) >&2)
$(silent)$(call ensuredirectory,$(dir $@))
- $(silent){ if $(TEST) ! -f $(call quote,$(BUILDDIR)/.mtime); then $(PRINTF) '%b' '\n' >|$(call quote,$(BUILDDIR)/.mtime); fi; $(TOUCH) -r $(call quote,$<) $(call quote,$(BUILDDIR)/.mtime); $(DIFF) -u $(call quote,$(BUILDDIR)/.mtime) /dev/null | $(SED) '1!d;s/.* \([^ ]*\) \([^ ]*\).*$$/\1T\2Z/'; $(CKSUM) $(call quote,$<) | $(SED) 's/[ ].*//'; } | $(xargsmultiquote) | $(XARGS) -E '' $(PRINTF) '<?xml version="1.0"?><nfo:LocalFileDataObject xmlns:dct="http://purl.org/dc/terms/" xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#" xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:about="%s" nfo:fileUrl="%s"><nie:interpretedAs>$(if $(filter $<,$(assetfiles)),<nfo:InformationElement nie:mimeType="%s"/>,<nfo:PlainTextDocument nie:mimeType="%s"/>)</nie:interpretedAs><dct:hasFormat><nfo:LocalFileDataObject nfo:fileUrl="%s"><nie:interpretedAs><nfo:PlainTextDocument nie:mimeType="application/xml"/></nie:interpretedAs></nfo:LocalFileDataObject></dct:hasFormat><nfo:fileLastModified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">%s</nfo:fileLastModified><nfo:hasHash nfo:hashAlgorithm="CRC32" nfo:hashValue="%s"/></nfo:LocalFileDataObject>' $(call quote,$(call attresc,$(call localuri,$<))) $(call quote,$(call attresc,$(call fileuri,$<))) $(call quote,$(call attresc,$(call typeoffile,$<))) $(call quote,$(call attresc,$(call fileuri,$(call parsed,$<)))) >|$(call quote,$@)
+ $(silent){ if $(TEST) ! -f $(call quote,$(BUILDDIR)/.mtime); then $(PRINTF) '%b' '\n' >|$(call quote,$(BUILDDIR)/.mtime); fi; $(TOUCH) -r $(call quote,$<) $(call quote,$(BUILDDIR)/.mtime); $(DIFF) -u $(call quote,$(BUILDDIR)/.mtime) /dev/null | $(SED) '1!d;s/.* \([^ ]*\) \([^ ]*\).*$$/\1T\2Z/'; $(CKSUM) $(call quote,$<) | $(SED) 's/[ ].*//'; } | $(xargsmultiquote) | $(XARGS) -E '' $(PRINTF) '<?xml version="1.0"?><书社vocab:$(if $(filter $<,$(sourceincludes)),IncludeFile,SourceFile) xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#" xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:" rdf:about="%s" 书社vocab:path="%s"><nie:interpretedAs>$(if $(filter $<,$(assetfiles)),<nfo:InformationElement nie:mimeType="%s"/>,<nfo:PlainTextDocument nie:mimeType="%s"/>)</nie:interpretedAs><nfo:fileLastModified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">%s</nfo:fileLastModified><nfo:hasHash nfo:hashAlgorithm="CRC32" nfo:hashValue="%s"/></书社vocab:$(if $(filter $<,$(sourceincludes)),IncludeFile,SourceFile)>' $(call quote,$(call attresc,$(call localuri,$<))) $(call quote,$(call attresc,$(if $(filter $<,$(sourceincludes)),$(call includepath,$<),$(call sourcepath,$<)))) $(call quote,$(call attresc,$(call typeoffile,$<))) >|$(call quote,$@)
# Parse the files.
#
$(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,<?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,$<))$(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 --nomkdir --nowrite --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$<))$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/parser.xslt) - >|$(call quote,$@))
# Collect the metadata into a single file.
-$(BUILDDIR)/metadata : $(call diffprereqs,metadatas,$(call metadata,$(sort $(sourcefiles) $(sourceincludes))))
+$(BUILDDIR)/metadata : $(call diffprereqs,metadatas,$(call metadata,$(sort $(sourcefiles) $(sourceincludes)))) $(call parsed,$(filter-out $(assetfiles),$(sourcefiles) $(sourceincludes))) $(THISDIR)/lib/expandmetadata.xslt
$(call inform,$(PRINTF) '%s\n' 'Compiling metadata…' >&2)
- $(silent){ $(PRINTF) '%s' '<?xml version="1.0"?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">'; $(foreach meta,$(call metadata,$(sort $(sourcefiles) $(sourceincludes))),$(CAT) $(call quote,$(meta)) | $(SED) 's/<?xml version="1.0"?>//';) $(PRINTF) '%s\n' '</rdf:RDF>'; } >|$(call quote,$@)
+ $(silent){ $(PRINTF) '<?xml version="1.0"?><rdf:RDF xmlns:nie="http://www.semanticdesktop.org/ontologies/2007/01/19/nie#" xmlns:nfo="http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:书社vocab="urn:fdc:ladys.computer:20231231:Shu1She4:vocab:"><书社vocab:BuildDirectory nfo:fileUrl="%s"/>' $(call quote,$(call attresc,$(call fileuri,$(BUILDDIR)))); { $(foreach meta,$(call metadata,$(sort $(sourcefiles) $(sourceincludes))),$(CAT) $(call quote,$(meta));) } | $(SED) 's/<?xml version="1.0"?>//g'; $(PRINTF) '%s\n' '</rdf:RDF>'; } | $(XSLTPROC) --nonet --novalid --nomkdir --nowrite $(call quote,$(THISDIR)/lib/expandmetadata.xslt) - | $(XMLLINT) --nonet --nsclean - >|$(call quote,$@)
# Build a list of dependencies for each parsed file.
-$(BUILDDIR)/dependencies : $(BUILDDIR)/metadata $(call parsed,$(filter-out $(assetfiles),$(sourcefiles) $(sourceincludes))) $(THISDIR)/lib/metadata2dependencies.xslt
+$(BUILDDIR)/dependencies : $(BUILDDIR)/metadata $(THISDIR)/lib/metadata2dependencies.xslt
$(call inform,$(PRINTF) '%s\n' 'Identifying dependencies…' >&2)
$(silent)$(TOUCH) $(call quote,$@)
- $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) $(call quote,$(THISDIR)/lib/metadata2dependencies.xslt) $(call quote,$<)
+ $(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite $(call quote,$(THISDIR)/lib/metadata2dependencies.xslt) $(call quote,$<) >|$(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)/metadata $(call parsed,$(filter-out $(assetfiles),$(sourcefiles))) $(THISDIR)/lib/metadata2destinations.xslt
+$(BUILDDIR)/destinations : $(BUILDDIR)/metadata $(THISDIR)/lib/metadata2destinations.xslt
$(call inform,$(PRINTF) '%s\n' 'Identifying output destinations…' >&2)
$(silent)$(TOUCH) $(call quote,$@)
- $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) $(call quote,$(THISDIR)/lib/metadata2destinations.xslt) $(call quote,$<)
+ $(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite $(call quote,$(THISDIR)/lib/metadata2destinations.xslt) $(call quote,$<) >|$(call quote,$@)
# Generate the main transform.
$(BUILDDIR)/transform.catalog : $(call diffprereqs,transforms,$(sort $(TRANSFORMS)))
$(foreach transform,$(TRANSFORMS),$(silent){ $(call id,$(transform)); $(PRINTF) '%s\n' $(call quote,$(call fileuri,$(transform))) '--noout' $(call quote,$@); } | $(xargsmultiquote) | $(XARGS) -E '' $(XMLCATALOG) --add uri$(newline))
$(BUILDDIR)/transform.xslt : $(BUILDDIR)/transform.catalog $(BUILDDIR)/metadata $(THISDIR)/lib/catalog2transform.xslt
$(call inform,$(PRINTF) '%s\n' 'Generating main transform…' >&2)
- $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam METADATA $(call quote,$(call fileuri,$(BUILDDIR)/metadata)) $(call quote,$(THISDIR)/lib/catalog2transform.xslt) $(call quote,$<)
+ $(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite --stringparam METADATA $(call quote,$(call fileuri,$(BUILDDIR))/metadata) $(call quote,$(THISDIR)/lib/catalog2transform.xslt) $(call quote,$<) >|$(call quote,$@)
# Compile the result files using the dependencies as necessary.
$(call compiled,$(compilablefiles)) : $(BUILDDIR)/results/% : $$(call parsed,$$(call uncompiled,$$@)) $$(call parsed,$$(call dependencies,$$(call uncompiled,$$@))) $(BUILDDIR)/transform.xslt $(BUILDDIR)/metadata
$(call inform,$(PRINTF) '%s\n' $(call quote,Compiling </$*>…) >&2)
$(silent)$(call ensuredirectory,$(dir $@))
- $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) --stringparam METADATA 'metadata' --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$(call uncompiled,$@))) --stringparam PATH $(call quote,/$*)$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/transform.xslt) $(call quote,$<)
+ $(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite --stringparam METADATA 'metadata' --stringparam BUILDTIME $$($(DATE) -u '+%Y-%m-%dT%H:%M:%SZ') --stringparam IDENTIFIER $(call quote,$(call localuri,$(call uncompiled,$@)))$(if $(THISREV), --stringparam THISREV $(call quote,$(THISREV)),)$(if $(SRCREV), --stringparam SRCREV $(call quote,$(SRCREV)),) $(call quote,$(BUILDDIR)/transform.xslt) $(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/%
# Build the extractor transform for extracting the contents of the archive source file.
$(BUILDDIR)/extractor.xslt : $(SRC) $(THISDIR)/lib/archive2extractor.xslt
$(silent)$(call ensuredirectory,$(dir $@))
- $(silent)$(XSLTPROC) --nonet --novalid -o $(call quote,$@) $(call quote,$(THISDIR)/lib/archive2extractor.xslt) $(call quote,$<)
+ $(silent)$(XSLTPROC) --nonet --novalid --nomkdir --nowrite $(call quote,$(THISDIR)/lib/archive2extractor.xslt) $(call quote,$<) >|$(call quote,$@)
# Use the extractor transform to extract the archive source file out into its components.
#