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 dependencies provided by the second argument matches the value in the file corresponding to the first argument in `$(BUILDDIR)/lastprereqs´. # If not, return the third argument, plus an additional rule to save the new prerequisites. override makeandsavedeps = $(if $(subst $(shell $(CAT) $(call quote,$(BUILDDIR)/lastdeps/$1) 2> /dev/null || true),,$2),$3$(newline)$(silent)$(call ensuredirectory,$(BUILDDIR)/lastdeps)$(newline)$(silent)$(PRINTF) '%s\n' $(call quote,$2) > $(BUILDDIR)/lastdeps/$1,) # (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 : %/GNUmakefile : @$(PRINTF) '%s\n' $(call quote,Initializing git submodule at `$*´) $(silent)$(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))