]> Lady’s Gitweb - Caudex/blob - GNUmakefile
Always run recipe if deps are empty
[Caudex] / GNUmakefile
1 SHELL = /bin/sh
2
3 # ━ § BASIC INFORMATION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4 override define makefileinfo
5 ╭──────────────────────────────╮
6 ╔╡ ⁌ 🪾📰 Caudex ∷ GNUmakefile ╞═══════════════════════════════╗
7 ║╰──────────────────────────────╯ ║
8 ╟┬ ¶ Prerequisites ───────────────────────────────────────────┬╢
9 ║│ │║
10 ║│ Requires G·N·U Make, at least version 3.81, and all of the │║
11 ║│ requirements of ⛩️📰 书社, which is included as a git │║
12 ║│ submodule. Run `make help-shushe´ for more information. │║
13 ║╰────────────────────────────────────────────────────────────╯║
14 ╟┬ ¶ Usage ───────────────────────────────────────────────────┬╢
15 ║│ │║
16 ║│ • `make all´ (default): Compile, but do not install, all │║
17 ║│ files. │║
18 ║│ │║
19 ║│ • `make clean´: Remove `BUILDDIR´. │║
20 ║│ │║
21 ║│ • `make clean´: Remove `BUILDDIR´. │║
22 ║│ │║
23 ║│ • `make gone´: Remove `BUILDDIR´ and installed files. │║
24 ║│ │║
25 ║│ • `make help´: Print this message. │║
26 ║│ │║
27 ║│ • `make install´: Compile all files and install in │║
28 ║│ `DESTDIR´. │║
29 ║│ │║
30 ║│ • `make list´: List all recognized source files and their │║
31 ║│ classification (including media type and dependencies). │║
32 ║│ │║
33 ║│ • `make uninstall´: Remove installed files, but not │║
34 ║│ `BUILDDIR´. │║
35 ║│ │║
36 ║│ • `make +⟨CATEGORY⟩´: Create a new entry in ⟨CATEGORY⟩ and │║
37 ║│ output its path. │║
38 ║│ │║
39 ║│ Set `VERBOSE=1´ to see the text of commands as they are │║
40 ║│ executed. │║
41 ║│ │║
42 ║│ See `README.markdown´ for a more involved description of │║
43 ║│ the capabilities and configuration of this program. │║
44 ║╰────────────────────────────────────────────────────────────╯║
45 ╟┬ ¶ Copyright & License ─────────────────────────────────────┬╢
46 ║│ │║
47 ║│ Copyright © 2024 Lady [@ Lady’s Computer]. │║
48 ║│ │║
49 ║│ This Source Code Form is subject to the terms of the │║
50 ║│ Mozilla Public License, v 2.0. If a copy of the M·P·L was │║
51 ║│ not distributed with this file, You can obtain one at │║
52 ║│ <http://mozilla.org/MPL/2.0/>. │║
53 ║╰────────────────────────────────────────────────────────────╯║
54 ╚══════════════════════════════════════════════════════════════╝
55 endef
56
57 # ━ § MAKE·FILE SETUP ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
58
59 # Programs needed to run this make·file.
60 #
61 # If these are not installed on your computer, or you need to use a different implementation, you can override the appropriate variable.
62 #
63 # See also the documentation for ⛩️📰 书社, which specifies additional programs.
64 AWK := awk
65 CAT := cat
66 ECHO := echo
67 GIT := git
68 MKDIR := mkdir
69 OD := od
70 PRINTF := printf
71 RM := rm
72 SED := sed
73 TEST := test
74 TR := tr
75 XARGS := xargs
76 XMLCATALOG := xmlcatalog
77
78 # The directory which contains the codex entries and related metadata.
79 SRCDIR := entries
80
81 # The directory which contains additional assets for the codex generator.
82 ASSETDIR := assets
83
84 # The directory which contains includes for additional assets for the codex generator.
85 ASSETINCLUDEDIR := $(ASSETDIR)/includes
86
87 # The directory in which to generate temporary buildfiles.
88 BUILDDIR := build
89
90 # The directory into which to output files on `make´.
91 DESTDIR := public
92
93 # The location of this Makefile (and related ⛩️📰 书社 files), relative to the current working directory.
94 #
95 # By default, this is inferred from the variable `MAKEFILE_LIST´.
96 THISDIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
97
98 # Extra magic files to forward to ⛩️📰 书社.
99 #
100 # Your computer probably has several already installed at `/usr/share/file/magic´.
101 EXTRAMAGIC :=
102
103 # Extra parsers to forward to ⛩️📰 书社.
104 #
105 # Which parsers are provided will influence which kinds of files are recognized as plaintext.
106 EXTRAPARSERS :=
107
108 # Extra transforms to forward to ⛩️📰 书社.
109 EXTRATRANSFORMS :=
110
111 # Variables to communicate to further calls to Make.
112 #
113 # By default, `MAKEOVERRIDES´ contains all variable overrides specified on the commandline.
114 # However, some values are specific to 🪾📰 Caudex and may have different meaning in other make·files; filter these out.
115 MAKEOVERRIDES := $(filter-out SRCDIR=% ASSETDIR=% BUILDDIR=% DESTDIR=% THISDIR=% EXTRAMAGIC=% EXTRAPARSERS=% EXTRATRANSFORMS=%,$(MAKEOVERRIDES))
116
117 # The location of ⛩️📰 书社.
118 SHUSHE := $(THISDIR)/.⛩️📰
119
120 # The name of the generator program.
121 GENERATOR := 🪾📰 Caudex
122
123 # A description of the current git revision of 🪾📰 Caudex.
124 VERSION := $(shell cd $(THISDIR); $(GIT) describe 2> /dev/null || $(GIT) rev-parse HEAD 2> /dev/null || true)
125
126 # Set to a non·empty value to print all commands as they run.
127 VERBOSE :=
128
129 # The default target for this makefile.
130 .DEFAULT_GOAL := all
131
132 # ━ § BEGIN MAKE·FILE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
133
134 # ─ ¶ Non‐Recipe Variable Definitions ─────────────────────────────────
135
136 # A variable which contains a newline, to allow the generation of multiline strings in function calls.
137 override define newline
138
139
140 endef
141
142 # (callable) Quote the given string for use within shell calls.
143 override quote = '$(subst ','"'"',$1)'
144
145 # Outputs an `@´ to silence rules, unless `VERBOSE´ is nonempty.
146 override silent := $(if $(VERBOSE),,@)
147
148 # The list of categories, determined by the set of directories in `SRCDIR´ with corresponding metadata files.
149 override categories := $(sort $(patsubst $(SRCDIR)/%/@,%,$(wildcard $(SRCDIR)/*/@)))
150
151 # (callable) The set of file locations for the entries of the provided categories.
152 override entriesforcategory = $(sort $(foreach category,$1,$(wildcard $(SRCDIR)/$(category)/???-????) $(wildcard $(SRCDIR)/$(category)/???-????,*)))
153
154 # A random W·R·M·G(·like) base⹀32 identifier.
155 #
156 # This variable returns a different value each time it is referenced.
157 # Use `foreach´ to save the value for repeated usage.
158 #
159 # This variable recursively calls itself to ensure there is no existing entry with the resulting identifier.
160 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)))
161
162 # (callable) Returns the identifiers of the provided entries.
163 override identifier = $(shell $(TR) ' ' '\n' <<< $(call quote,$1) | $(SED) 's/^\(.*[/]\)\{0,1\}\(.\{3\}-.\{4\}\)\(,[^/]*\)\{0,1\}$$/\2/')
164
165 # Output locations for compiled catalog files for categories.
166 override categorycatalogs := $(patsubst %,$(BUILDDIR)/catalogs/categories/%/index,$(categories))
167
168 # Output locations for compiled catalog files for entries.
169 override entrycatalogs := $(foreach entry,$(call entriesforcategory,$(categories)),$(patsubst $(SRCDIR)/%,$(BUILDDIR)/catalogs/entries/%,$(entry)))
170
171 # Output locations for all compiled catalog files.
172 override allcatalogs := $(BUILDDIR)/catalogs/indices/index $(BUILDDIR)/catalogs/indices/fullindex $(categorycatalogs) $(entrycatalogs)
173
174 # (overridable) Options to pass to ⛩️📰 书社.
175 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))
176
177 # ─ ¶ Recipe Variable Definitions ─────────────────────────────────────
178
179 # (callable) Check to see if the given directory exists and create it if not.
180 override ensuredirectory = if $(TEST) ! -d $(call quote,$1); then $(MKDIR) -p $(call quote,$1); fi
181
182 # (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´.
183 # If not, return the third argument, plus an additional rule to save the new prerequisites.
184 override makeandsavedeps = $(if $(or $(if $2,,1),$(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,)
185
186 # (callable) Make the catalog for the provided category.
187 override define makecategorycatalog
188 @$(PRINTF) '%s\n' $(call quote,Generating catalog for category `$1´…)
189 $(silent)$(call ensuredirectory,$(BUILDDIR)/catalogs/categories/$1)
190 $(silent)$(XMLCATALOG) --create --noout $(call quote,$(BUILDDIR)/catalogs/categories/$1/index)
191 $(silent)$(XMLCATALOG) --add uri '?' 'about:category' --noout $(call quote,$(BUILDDIR)/catalogs/categories/$1/index)
192 $(silent)$(XMLCATALOG) --add uri '@' $(call quote,$1/@) --noout $(call quote,$(BUILDDIR)/catalogs/categories/$1/index)
193 $(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))
194 endef
195
196 # (callable) Make the catalog for the dynamic or static index.
197 override define makeindexcatalog
198 @$(PRINTF) '%s\n' 'Generating $(if $1,static,dynamic) catalog index…'
199 $(silent)$(call ensuredirectory,$(BUILDDIR)/catalogs/indices)
200 $(silent)$(XMLCATALOG) --create --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index)
201 $(silent)$(XMLCATALOG) --add uri '.' '$(if $1,standalone,index).xhtml' --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index)
202 $(silent)$(XMLCATALOG) --add uri '?' 'about:$(if $1,full,)index' --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index)
203 $(silent)$(XMLCATALOG) --add uri '@' '@' --noout $(call quote,$(BUILDDIR)/catalogs/indices/$(if $1,full,)index)
204 $(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))
205 endef
206
207 # ─ ¶ ⛩️📰 书社 Targets ──────────────────────────────────────────────
208
209 # Targets to forward to ⛩️📰 书社.
210 all install list uninstall : $(SHUSHE)/GNUmakefile catalogs
211 $(silent)$(MAKE) -f $(call quote,$<) $(call quote,$@) $(shusheopts)
212 %-shushe : $(SHUSHE)/GNUmakefile FORCE
213 $(silent)$(MAKE) -f $(call quote,$<) $(call quote,$*) $(shusheopts)
214 build/⛩️📰/% : $(SHUSHE)/GNUmakefile catalogs FORCE
215 $(SILENT)$(MAKE) -f $(call quote,$<) $(call quote,$@) $(shusheopts)
216 public/% : $(SHUSHE)/GNUmakefile catalogs FORCE
217 $(SILENT)$(MAKE) -f $(call quote,$<) $(call quote,$@) $(shusheopts)
218
219 # ─ ¶ Phony Targets ───────────────────────────────────────────────────
220
221 # Generate all catalogs, then remove any which no longer have corresponding source files.
222 catalogs : $(allcatalogs)
223 @$(PRINTF) '%s\n' 'Removing any outdated catalogs…'
224 $(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))
225 $(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))
226
227 # Destroy buildfiles.
228 clean:
229 $(if $(BUILDDIR),$(silent)$(RM) -rf $(call quote,$(BUILDDIR)/),)
230
231 # Provide help.
232 help :
233 @$(PRINTF) '%b' '$(subst $(newline),\n,$(makefileinfo))'
234
235 # Destroy build directory and installed files.
236 gone : clean uninstall ;
237
238 # List the i·d’s of all recognized entries.
239 listids :
240 @$(TR) '| ' ' \n' <<< '$(strip $(foreach category,$(categories),\0033[1m$(category)\0033[22m: $(patsubst %,•|%,$(call identifier,$(call entriesforcategory,$(category)))) ))' | $(XARGS) -0 $(PRINTF) '%b'
241
242 # Output a random unused identifier.
243 wrmg :
244 @$(ECHO) $(wrmg)
245
246 # Create a new entry in the provided category and output its path.
247 +% : FORCE
248 $(silent)$(call ensuredirectory,$(SRCDIR)/$*)
249 $(if $(wildcard $(SRCDIR)/$*/@),,$(silent)$(PRINTF) '%b' '%%\nCATEGORY : $*\n%%\n' > '$(SRCDIR)/$*/@')
250 $(foreach identifier,$(wrmg),@$(PRINTF) '%b' '%%\nENTRY : $(identifier)\n%%\n\n' > '$(SRCDIR)/$*/$(identifier)'$(newline)@$(ECHO) '$(SRCDIR)/$*/$(identifier)')
251
252 # ─ ¶ Special Targets ─────────────────────────────────────────────────
253
254 # Perform secondary expansion; this enables pattern rules to determine their prerequisites based on the matched pattern.
255 .SECONDEXPANSION : ;
256
257 # Don’t use any implicit rules.
258 .SUFFIXES : ;
259
260 # Treat targets with this as a prerequisite as though they were phony.
261 #
262 # Mainly useful in pattern rules.
263 FORCE : ;
264
265 # Phony rules; always consider these out·of·date.
266 .PHONY : FORCE all build catalogs clean gone help install list listids uninstall wrmg ;
267
268 # ─ ¶ Build Targets ───────────────────────────────────────────────────
269
270 # Initialize the ⛩️📰 书社 repository if it is empty.
271 $(SHUSHE)/GNUmakefile : $(THISDIR)/%/GNUmakefile :
272 @$(PRINTF) '%s\n' $(call quote,Initializing git submodule at `$*´)
273 $(silent)cd $(THISDIR) && $(GIT) submodule update --init $(call quote,$*)
274
275 # Touch parsers and transforms if the files in `lib/´ have changed.
276 $(PARSERS) $(TRANSFORMS) : $(wildcard lib/*.xslt)
277 $(silent)$(TOUCH) $(call quote,$@)
278
279 # Create an empty codex metadata file if none exists.
280 $(SRCDIR)/@ :
281 $(silent)$(PRINTF) '%b' '%%\nCODEX :\n%%\n' > $(call quote,$@)
282
283 # Create category catalogs.
284 $(categorycatalogs) : $(BUILDDIR)/catalogs/categories/%/index : FORCE
285 $(call makeandsavedeps,$*,$(call entriesforcategory,$*),$(call makecategorycatalog,$*))
286
287 # Create entry catalogs.
288 $(entrycatalogs) : $(BUILDDIR)/catalogs/entries/% :
289 @$(PRINTF) '%s\n' $(call quote,Generating catalog for document `$(call identifier,$*)´…)
290 $(silent)$(call ensuredirectory,$(dir $@))
291 $(silent)$(XMLCATALOG) --create --noout $(call quote,$@)
292 $(silent)$(XMLCATALOG) --add uri '.' '$(call identifier,$*).xhtml' --noout $(call quote,$@)
293 $(silent)$(XMLCATALOG) --add uri '?' 'about:entry' --noout $(call quote,$@)
294 $(silent)$(XMLCATALOG) --add uri '@' $(call quote,$*) --noout $(call quote,$@)
295
296 $(BUILDDIR)/catalogs/indices/index : FORCE | $(SRCDIR)/@
297 $(call makeandsavedeps,index,$(categories),$(call makeindexcatalog,))
298
299 $(BUILDDIR)/catalogs/indices/fullindex : FORCE | $(SRCDIR)/@
300 $(call makeandsavedeps,fullindex,$(categories),$(call makeindexcatalog,1))
This page took 0.058744 seconds and 5 git commands to generate.