SHELL = /bin/sh # ━ § BASIC INFORMATION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ override define makefileinfo ╭──────────────────────────────╮ ╔╡ ⁌ 🪾📰 Caudex ∷ GNUmakefile ╞═══════════════════════════════╗ ║╰──────────────────────────────╯ ║ ╟┬ ¶ Prerequisites ───────────────────────────────────────────┬╢ ║│ │║ ║│ Requires G·N·U Make, at least version 3.81, and all of the │║ ║│ requirements of ⛩️📰 书社, which is included as a git │║ ║│ submodule. Run `make help-shushe´ for more information. │║ ║╰────────────────────────────────────────────────────────────╯║ ╟┬ ¶ Usage ───────────────────────────────────────────────────┬╢ ║│ │║ ║│ • `make all´ (default): Compile, but do not install, all │║ ║│ files. │║ ║│ │║ ║│ • `make clean´: Remove `BUILDDIR´. │║ ║│ │║ ║│ • `make clean´: Remove `BUILDDIR´. │║ ║│ │║ ║│ • `make gone´: Remove `BUILDDIR´ and installed files. │║ ║│ │║ ║│ • `make help´: Print this message. │║ ║│ │║ ║│ • `make install´: Compile all files and install in │║ ║│ `DESTDIR´. │║ ║│ │║ ║│ • `make list´: List all recognized source files and their │║ ║│ classification (including media type and dependencies). │║ ║│ │║ ║│ • `make uninstall´: Remove installed files, but not │║ ║│ `BUILDDIR´. │║ ║│ │║ ║│ • `make +⟨CATEGORY⟩´: Create a new entry in ⟨CATEGORY⟩ and │║ ║│ output its path. │║ ║│ │║ ║│ Set `VERBOSE=1´ to see the text of commands as they are │║ ║│ executed. │║ ║│ │║ ║│ See `README.markdown´ for a more involved description of │║ ║│ the capabilities and configuration of this program. │║ ║╰────────────────────────────────────────────────────────────╯║ ╟┬ ¶ Copyright & License ─────────────────────────────────────┬╢ ║│ │║ ║│ Copyright © 2024 Lady [@ Lady’s 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 │║ ║│ not distributed with this file, You can obtain one at │║ ║│ . │║ ║╰────────────────────────────────────────────────────────────╯║ ╚══════════════════════════════════════════════════════════════╝ endef # ━ § MAKE·FILE SETUP ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # 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. # # See also the documentation for ⛩️📰 书社, which specifies additional programs. AWK := awk CAT := cat ECHO := echo GIT := git MKDIR := mkdir OD := od PRINTF := printf RM := rm SED := sed TEST := test TR := tr XARGS := xargs XMLCATALOG := xmlcatalog # The directory which contains the codex entries and related metadata. SRCDIR := entries # The directory which contains additional assets for the codex generator. ASSETDIR := assets # The directory which contains includes for additional assets for the codex generator. ASSETINCLUDEDIR := $(ASSETDIR)/includes # The directory in which to generate temporary buildfiles. BUILDDIR := build # The directory into which to output files on `make´. DESTDIR := public # 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)))) # Extra magic files to forward to ⛩️📰 书社. # # Your computer probably has several already installed at `/usr/share/file/magic´. EXTRAMAGIC := # Extra parsers to forward to ⛩️📰 书社. # # Which parsers are provided will influence which kinds of files are recognized as plaintext. EXTRAPARSERS := # Extra transforms to forward to ⛩️📰 书社. EXTRATRANSFORMS := # Variables to communicate to further calls to Make. # # By default, `MAKEOVERRIDES´ contains all variable overrides specified on the commandline. # However, some values are specific to 🪾📰 Caudex and may have different meaning in other make·files; filter these out. MAKEOVERRIDES := $(filter-out SRCDIR=% ASSETDIR=% BUILDDIR=% DESTDIR=% THISDIR=% EXTRAMAGIC=% EXTRAPARSERS=% EXTRATRANSFORMS=%,$(MAKEOVERRIDES)) # The location of ⛩️📰 书社. SHUSHE := $(THISDIR)/.⛩️📰 # The name of the generator program. GENERATOR := 🪾📰 Caudex # A description of the current git revision of 🪾📰 Caudex. VERSION := $(shell cd $(THISDIR); $(GIT) describe 2> /dev/null || $(GIT) rev-parse HEAD 2> /dev/null || true) # Set to a non·empty value to print all commands as they run. VERBOSE := # The default target for this makefile. .DEFAULT_GOAL := all # ━ § BEGIN MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ─ ¶ Non‐Recipe Variable Definitions ───────────────────────────────── # A variable which contains a newline, to allow the generation of multiline strings in function calls. override define newline endef # (callable) Quote the given string for use within shell calls. override quote = '$(subst ','"'"',$1)' # Outputs an `@´ to silence rules, unless `VERBOSE´ is nonempty. override silent := $(if $(VERBOSE),,@) # The list of categories, determined by the set of directories in `SRCDIR´ with corresponding metadata files. override categories := $(sort $(patsubst $(SRCDIR)/%/@,%,$(wildcard $(SRCDIR)/*/@))) # (callable) The set of file locations for the entries of the provided categories. override entriesforcategory = $(sort $(foreach category,$1,$(wildcard $(SRCDIR)/$(category)/???-????) $(wildcard $(SRCDIR)/$(category)/???-????,*))) # A random W·R·M·G(·like) base⹀32 identifier. # # This variable returns a different value each time it is referenced. # Use `foreach´ to save the value for repeated usage. # # This variable recursively calls itself to ensure there is no existing entry with the resulting identifier. override wrmg = $(foreach attempt,$(shell $(OD) -t u4 -N 4 /dev/random | $(SED) 's/^[0-9]* *//' | $(TR) -d ' \n' | $(AWK) 'BEGIN{chars="0123456789ABCDEFGHJKMNPQRSTVWXYZ&~@=U"}{d=32^5;r=$$0%(32^6);printf("%s",substr(chars,r%37,1));while(d>0){printf("%s", substr(chars,int(r/d),1));if(d==32^4)printf("%s", "-");r%=d;d=int(d/32)}}'),$(if $(wildcard $(SRCDIR)/*/($(attempt))*),$(call wrmg),$(attempt))) # (callable) Returns the identifiers of the provided entries. override identifier = $(shell $(TR) ' ' '\n' <<< $(call quote,$1) | $(SED) 's/^\(.*[/]\)\{0,1\}\(.\{3\}-.\{4\}\)\(,[^/]*\)\{0,1\}$$/\2/') # Output locations for compiled catalog files for categories. override categorycatalogs := $(patsubst %,$(BUILDDIR)/catalogs/categories/%/index,$(categories)) # Output locations for compiled catalog files for entries. override entrycatalogs := $(foreach entry,$(call entriesforcategory,$(categories)),$(patsubst $(SRCDIR)/%,$(BUILDDIR)/catalogs/entries/%,$(entry))) # Output locations for all compiled catalog files. override allcatalogs := $(BUILDDIR)/catalogs/indices/index $(BUILDDIR)/catalogs/indices/fullindex $(categorycatalogs) $(entrycatalogs) # (overridable) Options to pass to ⛩️📰 书社. override shusheopts := SRCDIR=$(call quote,$(if $(wildcard $(ASSETDIR)),$(ASSETDIR),) $(if $(entrycatalogs),$(BUILDDIR)/catalogs/entries,) $(BUILDDIR)/catalogs/indices) BUILDDIR=$(call quote,$(BUILDDIR)/⛩️📰) INCLUDEDIR=$(call quote,$(SRCDIR) $(if $(wildcard $(ASSETINCLUDEDIR)),$(ASSETINCLUDEDIR),) $(if $(categorycatalogs),$(BUILDDIR)/catalogs/categories,)) DESTDIR=$(call quote,$(DESTDIR)) EXTRAMAGIC=$(call quote,$(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/magic/*)) $(EXTRAMAGIC))) EXTRAPARSERS=$(call quote,$(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/parsers/*.xslt)) $(EXTRAPARSERS))) EXTRATRANSFORMS=$(call quote,$(sort $(patsubst ./%,%,$(wildcard $(THISDIR)/transforms/*.xslt)) $(EXTRATRANSFORMS))) GENERATOR=$(call quote,$(GENERATOR)) VERSION=$(call quote,$(VERSION)) # ─ ¶ Recipe Variable Definitions ───────────────────────────────────── # (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 # (callable) Test to see if the file provided by the first argument exists and the dependencies provided by the third argument matches the value in the file corresponding to the second argument in `$(BUILDDIR)/lastprereqs´. # If not, return the fourth argument, plus an additional rule to save the new prerequisites. # # ※ If the third argument is empty, the fourth argument is always returned. override makeandsavedeps = $(if $(or $(if $3,,1),$(if $(wildcard $1),,1),$(subst $(shell $(CAT) $(call quote,$(BUILDDIR)/lastdeps/$2) 2> /dev/null || true),,$3)),$4$(newline)$(silent)$(call ensuredirectory,$(BUILDDIR)/lastdeps)$(newline)$(silent)$(PRINTF) '%s\n' $(call quote,$3) > $(call quote,$(BUILDDIR)/lastdeps/$2),) # (callable) Make the catalog for the provided category. override define makecategorycatalog @$(PRINTF) '%s\n' $(call quote,Generating catalog for category `$1´…) $(silent)$(call ensuredirectory,$(BUILDDIR)/catalogs/categories/$1) $(silent)$(XMLCATALOG) --create --noout $(call quote,$(BUILDDIR)/catalogs/categories/$1/index) $(silent)$(XMLCATALOG) --add uri '?' 'about:category' --noout $(call quote,$(BUILDDIR)/catalogs/categories/$1/index) $(silent)$(XMLCATALOG) --add uri '@' $(call quote,$1/@) --noout $(call quote,$(BUILDDIR)/catalogs/categories/$1/index) $(foreach entry,$(call entriesforcategory,$1),$(silent)$(XMLCATALOG) --add uri $(call quote,$(call identifier,$(entry))) $(call quote,$(patsubst $(SRCDIR)/%,%,$(entry))) --noout $(call quote,$(BUILDDIR)/catalogs/categories/$1/index)$(newline)) endef # (callable) Make the catalog for the dynamic or static index. override define makeindexcatalog @$(PRINTF) '%s\n' 'Generating $(if $1,static,dynamic) catalog index…' $(silent)$(call ensuredirectory,$(BUILDDIR)/catalogs/indices) $(silent)$(XMLCATALOG) --create --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index) $(silent)$(XMLCATALOG) --add uri '.' '$(if $1,standalone,index).xhtml' --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index) $(silent)$(XMLCATALOG) --add uri '?' 'about:$(if $1,full,)index' --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index) $(silent)$(XMLCATALOG) --add uri '@' '@' --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index) $(foreach category,$(categories),$(silent)$(XMLCATALOG) --add uri $(call quote,$(category)) $(call quote,$(category)/index) --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index)$(newline)) endef # ─ ¶ ⛩️📰 书社 Targets ────────────────────────────────────────────── # Targets to forward to ⛩️📰 书社. all install list uninstall : $(SHUSHE)/GNUmakefile catalogs $(silent)$(MAKE) -f $(call quote,$<) $(call quote,$@) $(shusheopts) %-shushe : $(SHUSHE)/GNUmakefile FORCE $(silent)$(MAKE) -f $(call quote,$<) $(call quote,$*) $(shusheopts) build/⛩️📰/% : $(SHUSHE)/GNUmakefile catalogs FORCE $(SILENT)$(MAKE) -f $(call quote,$<) $(call quote,$@) $(shusheopts) public/% : $(SHUSHE)/GNUmakefile catalogs FORCE $(SILENT)$(MAKE) -f $(call quote,$<) $(call quote,$@) $(shusheopts) # ─ ¶ Phony Targets ─────────────────────────────────────────────────── # Generate all catalogs, then remove any which no longer have corresponding source files. catalogs : $(allcatalogs) @$(PRINTF) '%s\n' 'Removing any outdated catalogs…' $(foreach deletedcategory,$(filter-out $(categorycatalogs),$(wildcard $(BUILDDIR)/catalogs/categories/*/index)),@$(PRINTF) '%s\n' $(call quote,Removing `$(patsubst $(BUILDDIR)/catalogs/categories/%/index,%,$(deletedcategory))´…)$(newline)$(silent)$(RM) -rf $(call quote,./$(dir $(deletedcategory)))$(newline)$(silent)$(RM) -rf $(call quote,./$(patsubst $(BUILDDIR)/catalogs/categories/%,$(BUILDDIR)/catalogs/entries/%,$(dir $(deletedcategory))))$(newline)) $(foreach deletedentry,$(filter-out $(entrycatalogs),$(wildcard $(BUILDDIR)/catalogs/entries/*/*)),@$(PRINTF) '%s\n' $(call quote,Removing `$(patsubst $(BUILDDIR)/catalogs/entries/%,%,$(deletedentry))´…)$(newline)$(silent)$(RM) $(call quote,./$(deletedentry))$(newline)) # Destroy buildfiles. clean: $(if $(BUILDDIR),$(silent)$(RM) -rf $(call quote,$(BUILDDIR)/),) # Provide help. help : @$(PRINTF) '%b' '$(subst $(newline),\n,$(makefileinfo))' # Destroy build directory and installed files. gone : clean uninstall ; # List the i·d’s of all recognized entries. listids : @$(TR) '| ' ' \n' <<< '$(strip $(foreach category,$(categories),\0033[1m$(category)\0033[22m: $(patsubst %,•|%,$(call identifier,$(call entriesforcategory,$(category)))) ))' | $(XARGS) -0 $(PRINTF) '%b' # Output a random unused identifier. wrmg : @$(ECHO) $(wrmg) # Create a new entry in the provided category and output its path. +% : FORCE $(silent)$(call ensuredirectory,$(SRCDIR)/$*) $(if $(wildcard $(SRCDIR)/$*/@),,$(silent)$(PRINTF) '%b' '%%\nCATEGORY : $*\n%%\n' > '$(SRCDIR)/$*/@') $(foreach identifier,$(wrmg),@$(PRINTF) '%b' '%%\nENTRY : $(identifier)\n%%\n\n' > '$(SRCDIR)/$*/$(identifier)'$(newline)@$(ECHO) '$(SRCDIR)/$*/$(identifier)') # ─ ¶ Special Targets ───────────────────────────────────────────────── # Perform secondary expansion; this enables pattern rules to determine their prerequisites based on the matched pattern. .SECONDEXPANSION : ; # Don’t use any implicit rules. .SUFFIXES : ; # Treat targets with this as a prerequisite as though they were phony. # # Mainly useful in pattern rules. FORCE : ; # Phony rules; always consider these out·of·date. .PHONY : FORCE all build catalogs clean gone help install list listids uninstall wrmg ; # ─ ¶ Build Targets ─────────────────────────────────────────────────── # Initialize the ⛩️📰 书社 repository if it is empty. $(SHUSHE)/GNUmakefile : $(THISDIR)/%/GNUmakefile : @$(PRINTF) '%s\n' $(call quote,Initializing git submodule at `$*´) $(silent)cd $(THISDIR) && $(GIT) submodule update --init $(call quote,$*) # Touch parsers and transforms if the files in `lib/´ have changed. $(PARSERS) $(TRANSFORMS) : $(wildcard lib/*.xslt) $(silent)$(TOUCH) $(call quote,$@) # Create an empty codex metadata file if none exists. $(SRCDIR)/@ : $(silent)$(PRINTF) '%b' '%%\nCODEX :\n%%\n' > $(call quote,$@) # Create category catalogs. $(categorycatalogs) : $(BUILDDIR)/catalogs/categories/%/index : FORCE $(call makeandsavedeps,$@,$*,$(call entriesforcategory,$*),$(call makecategorycatalog,$*)) # Create entry catalogs. $(entrycatalogs) : $(BUILDDIR)/catalogs/entries/% : @$(PRINTF) '%s\n' $(call quote,Generating catalog for document `$(call identifier,$*)´…) $(silent)$(call ensuredirectory,$(dir $@)) $(silent)$(XMLCATALOG) --create --noout $(call quote,$@) $(silent)$(XMLCATALOG) --add uri '.' '$(call identifier,$*).xhtml' --noout $(call quote,$@) $(silent)$(XMLCATALOG) --add uri '?' 'about:entry' --noout $(call quote,$@) $(silent)$(XMLCATALOG) --add uri '@' $(call quote,$*) --noout $(call quote,$@) $(BUILDDIR)/catalogs/indices/index : FORCE | $(SRCDIR)/@ $(call makeandsavedeps,$@,index,$(categories),$(call makeindexcatalog,)) $(BUILDDIR)/catalogs/indices/fullindex : FORCE | $(SRCDIR)/@ $(call makeandsavedeps,$@,fullindex,$(categories),$(call makeindexcatalog,1))