X-Git-Url: https://git.ladys.computer/Shushe/blobdiff_plain/d71cc3861468e5ce418a3cf3ace5730689e41dce..af35f96d77cd8ae1b6fb5332509ba115f07fefb5:/GNUmakefile?ds=inline diff --git a/GNUmakefile b/GNUmakefile index 4ea43a5..3161ecd 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -10,11 +10,10 @@ override define makefileinfo ║╰────────────────────────────╯ ║ ╟┬ ¶ 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 required, altho there is a chance of │║ -║│ version incompatibilities. The full list of program │║ +║│ Requires G·N·U Make, at least version 3.81, the Fine Free │║ +║│ File Command, and the various programs packaged with │║ +║│ libxml2 and libxslt. Beyond this, only programs specified │║ +║│ by Posix are required. The full list of program │║ ║│ requirements is as follows :— │║ ║│ │║ ║│ • awk │║ @@ -23,16 +22,17 @@ override define makefileinfo ║│ • cksum │║ ║│ • cp │║ ║│ • date │║ -║│ • diff │║ -║│ • file │║ +║│ • diff (with -u) │║ +║│ • file (specifically the Fine Free File Command) │║ ║│ • find │║ ║│ • grep │║ ║│ • git (optional) │║ ║│ • ln │║ +║│ • make (specifically G·N·U Make, version 3.81 or later) │║ ║│ • mkdir │║ ║│ • mv │║ ║│ • od │║ -║│ • pax (only when generating archives) │║ +║│ • pax (ustar format, when generating archives) │║ ║│ • printf │║ ║│ • rm │║ ║│ • sed │║ @@ -83,7 +83,7 @@ override define makefileinfo ║╰────────────────────────────────────────────────────────────╯║ ╟┬ ¶ 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 │║ @@ -149,11 +149,21 @@ 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. +# +# This variable is also used by the two‐stage `MODE´, where it gives the include directory for the second stage. INCLUDEDIR := $(foreach dir,$(SRCDIR),$(dir)/includes) +# The directory which contains the data files. +# +# Only used in the two‐stage `MODE´, and defaults to that `MODE´ if this directory exists. +# This directory is used as the include directory in the first stage. +# +# Multiple directories can be given so long as files with the same name do not exist in each. +DATADIR := + # The directory in which to generate temporary buildfiles. # -# This variable is also used by the archiving `MODE´. +# This variable is also used by the archiving and two‐stage `MODE´s. BUILDDIR := build # The directory into which to output files on `make install´. @@ -165,17 +175,28 @@ DESTDIR := public # # By default, this is inferred from the variable `MAKEFILE_LIST´. # -# This variable is also used by the archiving `MODE´. +# This variable is also used by the archiving and two‐stage `MODE´s. THISDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) # Configuration of `find´. # # By default, `find´ will ignore files which begin with a period and those which are likely to cause problems for `make´. +# +# These variables are also used by the two‐stage `MODE´. EXTRAFINDRULES := EXTRAFINDINCLUDERULES := -FINDRULES := ! '(' '(' -name '[.-]*' -a ! -name '.' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a '(' $(EXTRAFINDRULES) ')',) +FINDRULES := '!' '(' '(' -name '[.-]*' -a '!' -name '.' -o -name '*[][*?:|$$%\#\\; ]*' -o -name '*[)]' ')' -a -prune ')'$(if $(EXTRAFINDRULES), -a '(' $(EXTRAFINDRULES) ')',) FINDINCLUDERULES := $(FINDRULES)$(if $(EXTRAFINDINCLUDERULES), -a '(' $(EXTRAFINDINCLUDERULES) ')',) +# File extensions which indicate files in `SRCDIR´ which should be built as part of the first, rather than second, stage of the two‐stage `MODE´. +DATAEXT := rdf + +# Rules for identifying files in `SRCDIR´ which should be built as part of the first, rather than second, stage of the two‐stage `MODE´. +# +# By default, this just constructs rules from `DATAEXT´. +EXTRAFINDDATARULES := +FINDDATARULES := -name '.' $(foreach ext,$(DATAEXT), -o -name '$(subst ','"'"',[!.]*.$(ext))')$(if $(EXTRAFINDDATARULES), -a '(' $(EXTRAFINDDATARULES) ')',) + # 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. @@ -184,12 +205,24 @@ FINDINCLUDERULES := $(FINDRULES)$(if $(EXTRAFINDINCLUDERULES), -a '(' $(EXTRAFIN EXTRAMAGIC := MAGIC := $(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/magic/*)) $(EXTRAMAGIC)) +# The list of depedencies for parsers. +# +# When these files change, the assumption is that the result of the parsers will change as well, even if the parsers themselves have not. +EXTRAPARSERLIBS := +PARSERLIBS := $(sort $(THISDIR)/lib/split.xslt $(EXTRAPARSERLIBS)) + # The list of parsers for plaintext file types. # # 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 depedencies for transforms. +# +# When these files change, the assumption is that the result of the transforms will change as well, even if the transforms themselves have not. +EXTRATRANSFORMLIBS := +TRANSFORMLIBS := $(sort $(THISDIR)/lib/serialize.xslt $(EXTRATRANSFORMLIBS)) + # The list of transforms. EXTRATRANSFORMS := TRANSFORMS := $(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/transforms/*.xslt)) $(EXTRATRANSFORMS)) @@ -221,11 +254,14 @@ endif # The following modes are available :— # # • ‹ urn:fdc:ladys.computer:20231231:Shu1She4:mode:default ›: -# The default mode; typical Shushe behaviours. +# The default mode; typical ⛩📰 书社 behaviours. # # • ‹ urn:fdc:ladys.computer:20231231:Shu1She4:mode:archive ›: # Generates archive files from parse results. -MODE := urn:fdc:ladys.computer:20231231:Shu1She4:mode:default +# +# • ‹ urn:fdc:ladys.computer:20231231:Shu1She4:mode:initial ›: +# The initial mode that this make·file starts in; this builds the magic file and parsers and then recursively calls into the default mode to build the files. +MODE := urn:fdc:ladys.computer:20231231:Shu1She4:mode:initial # Set to a non·empty value to silence informative messages. QUIET := @@ -269,9 +305,57 @@ override space := $(empty) $(empty) # A variable which contains a single comma. override comma := , +# (callable) Make empty strings non·empty, and non·empty strings empty. +override not = $(if $1,,1) + # (callable) Quote the given string for use within shell calls. override quote = '$(subst ','"'"',$1)' +# The command to use for percent‐decoding. +override perdeccmd := $(SED) 's/|/%7C/g;s/[\]/%5C/g;s/%[0123456789ABCDEFabcdef]\{2\}/|&|/g' | $(TR) '|' '\n' | $(SED) '/^%[0123456789ABCDEFabcdef]\{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}' | $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/;$$!s/$$/\\/) | $(XARGS) -E '' $(PRINTF) '%b' + +# (callable) Percent‐decode the given strings. +# +# ☡ 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. +# +# 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/^[0123456789]*//;s/0[Aa]/%&/g;s/2[146789ABCDEabcde]/%&/g;s/3[0123456789AaBbDd]/%&/g;s/40/%&/g;s/[46][123456789ABCDEFabcdef]/%&/g;s/[57][0123456789Aa]/%&/g;s/5[Ff]/%&/g;s/7[Ee]/%&/g;s/[ ][0123456789ABCDEFabcdef]\{2\}/%25&/g' | $(TR) -d ' \n' | $(TR) 'abcdef' 'ABCDEF' | $(perdeccmd)) + +# (callable) Percent‐encode each component in the given paths. +# +# ☡ This variable creates a subshell every time it is computed. +override pathenc = $(subst %2F,/,$(call perenc,$1)) + +# (callable) Create a unique name for the given file, based on its absolute path. +# +# ☡ This variable creates a subshell every time it is computed. +namehash = $(shell $(PRINTF) '%s' $(call quote,$(abspath $1)) | $(CKSUM) | $(SED) 's/ .*//' | $(XARGS) -E '' $(PRINTF) '%X')-$(notdir $1) + +# The location of this make·file. +override makefile := $(abspath $(THISDIR)/GNUmakefile) + +# Non·empty if `help´ or `clean´, and no targets other than `help´ or `clean´, were specified as goals on the commandline. +override notbuilding := $(and $(filter help clean,$(MAKECMDGOALS)),$(call not,$(filter-out help clean,$(MAKECMDGOALS)))) + +# (callable) Tests 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, saves the new value. +# Returns the values plus the file in `$(BUILDDIR)/lastprereqs´, which will always be newer than the target if there was a change. +# +# 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. +# +# If `$(notbuilding)´ is non·empty, this variable produces no result to avoid unnecessary work. +# +# ☡ This variable creates at least one subshell every time it is computed. +override diffprereqs = $(if $(notbuilding),,$(and $(subst $(shell $(CAT) $(call quote,$(BUILDDIR)/lastprereqs/$1) 2>>/dev/null || :),,$2),$(shell $(call ensuredirectory,$(BUILDDIR)/lastprereqs) && $(PRINTF) '%s\n' $(call quote,$2) >|$(BUILDDIR)/lastprereqs/$1),)$2 $(BUILDDIR)/lastprereqs/$1) + # ─ ¶ Recipe Variable Definitions ───────────────────────────────────── # Outputs an `@´ to silence rules, unless `VERBOSE´ is non·empty. @@ -286,19 +370,22 @@ override ensuredirectory = if $(TEST) ! -d $(call quote,$1); then $(MKDIR) -p $( # Quote standard input in such a way that piping it to xargs will result in it being processed as a single argument. # # If standard input ends in a newline, it is stripped; all other newlines are preserved. -override xargsquote = $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/;$$!s/$$/\\/) +override xargsquote := $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/;$$!s/$$/\\/) # Quote standard input in such a way that piping it to xargs will result in each line being processed as a single argument. -override xargsmultiquote = $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/) +override xargsmultiquote := $(SED) $(call quote,s/'/'"'"'/g;s/^/'/;s/$$/'/) # (callable) Test if the provided xpath expression matches the provided document. override xpath = $(XMLLINT) --noent --nonet --xpath $(call quote,$1) $(call quote,$2) >>/dev/null 2>>/dev/null +# (callable) Get the identifier for the given parser or transform. +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) Extract the value of the text nodes in the provided X·M·L document and print them to `stdout´. -override extracttext = $(PRINTF) '%s' '' | $(XSLTPROC) --nonet --novalid - $(call quote,$1) +override extracttext = $(PRINTF) '%s' '' | $(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 +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 $(makefile) 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 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -306,15 +393,6 @@ ifeq ($(MODE),urn:fdc:ladys.computer:20231231:Shu1She4:mode:default) # ─ ¶ Non‐Recipe Variable Definitions ───────────────────────────────── -# (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 || :),,$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 X·M·L. override xmlesc = $(subst >,>,$(subst <,<,$(subst &,&,$1))) @@ -324,34 +402,6 @@ override attresc = $(subst ",",$(call xmlesc,$1)) # (callable) Escape special characters for use in sed regular expressions. 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/%[0123456789ABCDEFabcdef]\{2\}/|&|/g' | $(TR) '|' '\n' | $(SED) '/^%[0123456789ABCDEFabcdef]\{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}' | $(xargsquote) | $(XARGS) -E '' $(PRINTF) '%b' - -# (callable) Percent‐decode the given strings. -# -# ☡ 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. -# -# 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/^[0123456789]*//;s/0[Aa]/%&/g;s/2[146789ABCDEabcde]/%&/g;s/3[0123456789AaBbDd]/%&/g;s/40/%&/g;s/[46][123456789ABCDEFabcdef]/%&/g;s/[57][0123456789Aa]/%&/g;s/5[Ff]/%&/g;s/7[Ee]/%&/g;s/[ ][0123456789ABCDEFabcdef]\{2\}/%25&/g' | $(TR) -d ' \n' | $(TR) 'abcdef' 'ABCDEF' | $(perdeccmd)) - -# (callable) Percent‐encode each component in the given paths. -# -# ☡ This variable creates a subshell every time it is computed. -override pathenc = $(subst %2F,/,$(call perenc,$1)) - -# (callable) Create a unique name for the given file, based on its absolute path. -# -# ☡ This variable creates a subshell every time it is computed. -namehash = $(shell $(PRINTF) '%s' $(call quote,$(abspath $1)) | $(CKSUM) | $(SED) 's/ .*//' | $(XARGS) -E '' $(PRINTF) '%X')-$(notdir $1) - # (overridable) Collect all of the applicable includes from the includes directory. sourceincludes := $(if $(and $(INCLUDEDIR),$(wildcard $(INCLUDEDIR))),$(patsubst ./%,%,$(shell $(FIND) $(foreach dir,$(INCLUDEDIR),$(call quote,$(dir))) '(' $(FINDINCLUDERULES) ')' -a -type f -a -print)),) @@ -379,16 +429,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 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/$(call namehash,$(magicfile))) - -# (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)))) +override typeoffile = $(foreach file,$1,$(or $(patsubst $(file)|%,%,$(filter $(file)|%,$(types))),application/octet-stream)) # (callable) Get the local path for the given source file. 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´)) @@ -414,7 +455,7 @@ override sourcefile = $(foreach local,$1,$(patsubst %|$(local),%,$(filter %|$(lo # # 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,) +override typeupdates := $(and $(wildcard $(BUILDDIR)/.update-types),FORCE) # Pair each source file and include with its metadata location. override sourcemetadatapair := $(foreach file,$(sourcefiles) $(sourceincludes),$(file)|$(BUILDDIR)/$(if $(filter $(file),$(sourceincludes)),includes.metadata/$(call includepath,$(file)),sources.metadata/$(call sourcepath,$(file)))) @@ -434,10 +475,10 @@ override parsed = $(foreach file,$1,$(patsubst $(file)|%,%,$(filter $(file)|%,$( # (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, transform, source file, or parsed file with its file u·r·i. +override fileuripairs := $(join $(patsubst %,%|,$(BUILDDIR) $(TRANSFORMS) $(sourcefiles) $(sourceincludes) $(call parsed,$(sourcefiles) $(sourceincludes))),$(call pathenc,$(foreach uriable,$(BUILDDIR) $(TRANSFORMS) $(sourcefiles) $(sourceincludes) $(call parsed,$(sourcefiles) $(sourceincludes)),file://$(abspath $(uriable))))) -# (callable) Get the file u·r·is for the given parsers, transforms, parsed files, or metadata compilations. +# (callable) Get the file u·r·is for the given transforms, source file or parsed files. 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),) @@ -478,12 +519,13 @@ ifneq ($(wildcard $(BUILDDIR)/destinations),) 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))) @@ -502,13 +544,9 @@ override unbuilt = $(foreach file,$1,$(call uncompiled,$(patsubst $(BUILDDIR)/pu # (callable) Get the installed locations for the given source files. override installed = $(foreach file,$1,$(DESTDIR)/$(call destination,$(file))) -endif # ─ ¶ Recipe Variable Definitions ───────────────────────────────────── -# (callable) Get the identifier for the given parser or transform. -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´. override wrapplaintext = { $(PRINTF) '%s\n%s' '' ''; } @@ -524,17 +562,6 @@ override serializexml = $(SED) "$$($(PRINTF) '%b' '/&2; fi) -else - $(silent)$(RM) $(call quote,$(BUILDDIR)/.update-types) - $(call inform,$(PRINTF) '%b\n' '\0033[1mDependency graph and output destinations updated. Restarting…\0033[22m' >&2) -endif -endif - -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. -# -# 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)$(RM) -f $(call quote,$(BUILDDIR)/dependencies) $(call quote,$(BUILDDIR)/destinations) - $(call inform,$(PRINTF) '%b\n' '\0033[1mMagic file or parsers have updated. Restarting…\0033[22m' >&2) - $(silent)$(SLEEP) 1 - $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types) -endif + $(if $(typeupdates),$(silent)$(RM) $(call quote,$(BUILDDIR)/.update-types),) + $(call inform,$(PRINTF) '%b\n' '\0033[1mDependency graph$(comma) output destinations$(comma) and transforms were updated. Restarting…\0033[22m' >&2) # ─ ¶ 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. -$(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 $@)) - $(silent)$(CD) $(call quote,$(BUILDDIR)) && $(FILE) -C -m $(call quote,$(realpath $(BUILDDIR)/magic)) - $(silent)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types) - -# Generate the main parser. -$(BUILDDIR)/parser.catalog : $(call diffprereqs,parsers,$(sort $(PARSERS))) - $(call inform,$(PRINTF) '%s\n' 'Generating catalog of parsers…' >&2) - $(silent)$(XMLCATALOG) --create --noout $(call quote,$@) - $(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)$(TOUCH) $(call quote,$(BUILDDIR)/.update-types) - # Generate R·D·F metadata for files. -$(call metadata,$(sourcefiles) $(sourceincludes)) : % : $$(call datadata,$$@) $(typeupdates) +$(call metadata,$(sourcefiles) $(sourceincludes)) : % : $$(call datadata,$$@) $(THISDIR)/.metadata-format-changed-since $(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) '$(if $(filter $<,$(assetfiles)),,)%s' $(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) '<书社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" nfo:fileUrl="%s">$(if $(filter $<,$(assetfiles)),,)<书社vocab:hasParsedFile nfo:fileUrl="%s"/>%s' $(call quote,$(call attresc,$(call localuri,$<))) $(call quote,$(call attresc,$(if $(filter $<,$(sourceincludes)),$(call includepath,$<),$(call sourcepath,$<)))) $(call quote,$(call attresc,$(call fileuri,$<))) $(call quote,$(call attresc,$(call typeoffile,$<))) $(call quote,$(call attresc,$(call fileuri,$(call parsed,$<)))) >|$(call quote,$@) # Parse the files. # # Even plain X·M·L files are parsed, because they may contain X·H·T·M·L `