summaryrefslogtreecommitdiff
path: root/build-aux/Makefile.once.head
diff options
context:
space:
mode:
Diffstat (limited to 'build-aux/Makefile.once.head')
-rw-r--r--build-aux/Makefile.once.head/00-dist.mk44
-rw-r--r--build-aux/Makefile.once.head/00-quote.mk49
-rw-r--r--build-aux/Makefile.once.head/00-var.mk36
-rw-r--r--build-aux/Makefile.once.head/00-write-ifchanged.mk1
-rw-r--r--build-aux/Makefile.once.head/10-dist.mk85
-rw-r--r--build-aux/Makefile.once.head/10-files.mk100
-rw-r--r--build-aux/Makefile.once.head/10-gitfiles.mk75
-rw-r--r--build-aux/Makefile.once.head/10-gnuconf.mk205
-rw-r--r--build-aux/Makefile.once.head/10-nested.mk46
-rw-r--r--build-aux/Makefile.once.head/10-std.mk39
-rw-r--r--build-aux/Makefile.once.head/10-texinfo.mk47
-rw-r--r--build-aux/Makefile.once.head/10-write-atomic.mk23
-rw-r--r--build-aux/Makefile.once.head/10-write-ifchanged.mk23
-rw-r--r--build-aux/Makefile.once.head/zz-mod.mk59
14 files changed, 748 insertions, 84 deletions
diff --git a/build-aux/Makefile.once.head/00-dist.mk b/build-aux/Makefile.once.head/00-dist.mk
deleted file mode 100644
index d5bfcd3..0000000
--- a/build-aux/Makefile.once.head/00-dist.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2015-2016 Luke Shumaker
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# Developer configuration
-
-dist.exts ?= .tar.gz
-dist.pkgname ?= $(PACKAGE)
-dist.version ?= $(VERSION)
-
-ifeq ($(dist.pkgname),)
-$(error dist.pkgname must be set)
-endif
-ifeq ($(dist.version),)
-$(error dist.version must be set)
-endif
-
-# User configuration
-
-CP ?= cp
-GZIP ?= gzip
-MKDIR ?= mkdir
-MKDIR_P ?= mkdir -p
-MV ?= mv
-RM ?= rm -f
-TAR ?= tar
-
-GZIPFLAGS ?= $(GZIP_ENV)
-GZIP_ENV ?= --best
-
-# Implementation
-
-at.phony += dist
diff --git a/build-aux/Makefile.once.head/00-quote.mk b/build-aux/Makefile.once.head/00-quote.mk
new file mode 100644
index 0000000..94bc943
--- /dev/null
+++ b/build-aux/Makefile.once.head/00-quote.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2016 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.quote.description = Macros to quote tricky strings
+define mod.quote.doc
+# Inputs:
+# (none)
+# Outputs:
+# - Global variable: `quote.var` : GNU Make variables
+# - Global variable: `quote.pattern` : GNU Make patterns
+# - Global variable: `quote.ere` : POSIX Extended Regular Expressions
+# - Global variable: `quote.bre` : POSIX Basic Regular Expressions
+# - Global variable: `quote.shell` : POSIX sh(1) strings
+# - Global variable: `quote.shell-each`: POSIX sh(1) strings
+#
+# Escaping/quoting things is hard! This module provides a number of
+# functions to escape/quote strings for various contexts.
+#
+# `quote.shell-each` quotes each list-item separately (munging
+# whitespace), while `quote.shell` keeps them as one string (preserving
+# whitespace).
+endef
+mod.quote.doc := $(value mod.quote.doc)
+
+_quote.backslash = $(if $1,$(call _quote.backslash,$(wordlist 2,$(words $1),$1),$(subst $(firstword $1),\$(firstword $1),$2)),$2)
+
+quote.var = $(subst $(at.nl),\$(at.nl),$(subst $$,$$$$,$1))
+quote.pattern = $(call _quote.backslash, \ % ,$1)
+quote.ere = $(call _quote.backslash, \ ^ . [ $$ ( ) | * + ? { ,$1)
+quote.bre = $(call _quote.backslash, \ ^ . [ $$ * ,$1)
+
+quote.shell-each = $(foreach _quote.tmp,$1,$(call quote.shell,$(_quote.tmp)))
+
+# I put this as the last line in the file because it confuses Emacs
+# syntax highlighting and makes the remainder of the file difficult to
+# edit.
+quote.shell = $(subst $(at.nl),'$$'\n'','$(subst ','\'',$1)')
diff --git a/build-aux/Makefile.once.head/00-var.mk b/build-aux/Makefile.once.head/00-var.mk
new file mode 100644
index 0000000..7c9e6ff
--- /dev/null
+++ b/build-aux/Makefile.once.head/00-var.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2016-2017 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.var.description = Depend on the values of variables
+define mod.var.doc
+# Inputs:
+# (user-defined)
+# Outputs:
+# Target : `$(outdir)/.var.%`
+# Directory variable: `at.targets`
+# Directory variable: `var.`
+#
+# It's a well-known secret that many files generated by a Makefile vary with
+# the values of particular variables, but that GNU Make can't track these
+# dependencies. Well, with some cleverness, it actually can!
+#
+# With this module, to depend on the value of a variable, depend on
+# `$(outdir)/.var.VARNAME`, or `$(var.)VARNAME` for short.
+endef
+mod.var.doc := $(value mod.var.doc)
+
+var. = $(patsubst ./%,%,$(outdir)/.var.)
+
+.PHONY: _var.FORCE
diff --git a/build-aux/Makefile.once.head/00-write-ifchanged.mk b/build-aux/Makefile.once.head/00-write-ifchanged.mk
deleted file mode 100644
index 79ef1c4..0000000
--- a/build-aux/Makefile.once.head/00-write-ifchanged.mk
+++ /dev/null
@@ -1 +0,0 @@
-WRITE_IFCHANGED = $(topsrcdir)/build-aux/write-ifchanged
diff --git a/build-aux/Makefile.once.head/10-dist.mk b/build-aux/Makefile.once.head/10-dist.mk
new file mode 100644
index 0000000..3621195
--- /dev/null
+++ b/build-aux/Makefile.once.head/10-dist.mk
@@ -0,0 +1,85 @@
+# Copyright (C) 2015-2017 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.dist.description = `dist` target to create distribution tarballs
+define mod.dist.doc
+# User variables:
+# - `CP ?= cp`
+# - `GZIP ?= gzip`
+# - `MKDIR ?= mkdir`
+# - `MKDIR_P ?= mkdir -p`
+# - `MV ?= mv`
+# - `RM ?= rm -f`
+# - `TAR ?= tar`
+# - `GZIPFLAGS ?= $(GZIP_ENV)`
+# - `GZIP_ENV ?= --best` (only used via `GZIPFLAGS`, not directly)
+# Inputs:
+# - Global variable : `dist.exts` (Default: `.tar.gz`)
+# - Global variable : `dist.pkgname` (Default: first of PACKAGE_TARNAME PACKAGE PACKAGE_NAME)
+# - Global variable : `dist.version` (Default: first of PACKAGE_VERSION VERSION)
+# - Directory variable : `files.src`
+# Outputs:
+# - Directory variable : `files.out.int` (only in top dir)
+# - .PHONY Target : `$(outdir)/dist`
+# - Target : `$(topoutdir)/$(dist.pkgname)-$(dist.version)`
+# - Target : `$(topoutdir)/$(dist.pkgname)-$(dist.version).tar`
+# - Target : `$(topoutdir)/$(dist.pkgname)-$(dist.version).tar.gz`
+#
+# Provide the standard `dist` .PHONY target, based on the `files` module
+# information.
+#
+# You may change the default compression target easily via the
+# `dist.exts` variable, but you must define the rule for it manually.
+#
+# Bugs:
+#
+# The tarball isn't reproducible. It uses file-system ordering of
+# files, and includes timestamps.
+endef
+mod.dist.doc := $(value mod.dist.doc)
+
+PACKAGE_TARNAME ?=
+PACKAGE ?=
+PACKAGE_NAME ?=
+PACKAGE_VERSION ?=
+VERSION ?=
+
+# Developer configuration
+
+dist.exts ?= .tar.gz
+dist.pkgname ?= $(firstword $(PACKAGE_TARNAME) $(PACKAGE) $(PACKAGE_NAME))
+dist.version ?= $(firstword $(PACKAGE_VERSION) $(VERSION))
+
+ifeq ($(dist.pkgname),)
+$(error Autothing module: dist: dist.pkgname must be set)
+endif
+ifeq ($(dist.version),)
+$(error Autothing module: dist: dist.version must be set)
+endif
+
+_dist.files =
+
+# User configuration
+
+CP ?= cp
+GZIP ?= gzip
+MKDIR ?= mkdir
+MKDIR_P ?= mkdir -p
+MV ?= mv
+RM ?= rm -f
+TAR ?= tar
+
+GZIPFLAGS ?= $(GZIP_ENV)
+GZIP_ENV ?= --best
diff --git a/build-aux/Makefile.once.head/10-files.mk b/build-aux/Makefile.once.head/10-files.mk
new file mode 100644
index 0000000..564f9d6
--- /dev/null
+++ b/build-aux/Makefile.once.head/10-files.mk
@@ -0,0 +1,100 @@
+# Copyright (C) 2015-2017 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.files.description = Keeping track of groups of files
+mod.files.depends += nested
+define mod.files.doc
+# User variables:
+# - `DESTDIR ?=`
+# - `RM ?= rm -f`
+# - `RMDIR_P ?= rmdir -p --ignore-fail-on-non-empty`
+# - `TRUE ?= true`
+# Inputs:
+# - Global variable : `files.groups ?= all`
+# - Global variable : `files.default ?= all`
+# - Global variable : `files.vcsclean ?= files.vcsclean`
+# - Global variable : `files.generate ?= files.generate`
+# - Directory variable : `files.src.src` # Sources
+# - Directory variable : `files.src.int` # Intermediates; deletable
+# - Directory variable : `files.src.cfg` # Outputs needed to run ./configure
+# - Directory variable : `files.src.gen` # Other outputs
+# - Directory variable : `files.out.slow` # Things to exclude from `make mostlyclean`
+# - Directory variable : `files.out.int` # Intermediates
+# - Directory variable : `files.out.cfg` # Outputs created by ./configure
+# - Directory variable : `files.out.$(group)` for `group` in `$(files.groups)`
+# - Directory variable : `files.sys.$(group)` for `group` in `$(files.groups)`
+# Outputs:
+# - Global variable : `nested.targets`
+# - Global variable : `at.targets`
+# - Global variable : `.DEFAULT_GOAL = $(files.default)`
+# - Directory variable : `files.src`
+# - Directory variable : `files.out`
+# - Directory variable : `files.sys`
+# - Creative .PHONY targets:
+# - `$(outdir)/$(files.generate)`
+# - `$(outdir)/$(group)` for `group` in `$(files.groups)`
+# - `$(outdir)/install`
+# - `$(outdir)/install-$(group)` for `group` in `$(filter-out $(files.default),$(files.groups))`
+# - `$(outdir)/installdirs`
+# - Destructive .PHONY targets:
+# - `$(outdir)/uninstall`
+# - `$(outdir)/mostlyclean`
+# - `$(outdir)/clean`
+# - `$(outdir)/distclean`
+# - `$(outdir)/maintainer-clean`
+# - `$(outdir)/$(files.vcsclean)`
+#
+# Basic `*` wildcards are supported. Use `*`, not `%`; it will automatically
+# substitute `*`->`%` where appropriate.
+#
+# Each of the destructive targets depends on `$(target)-hook`, which
+# is defined to be a "double-colon rule" allowing you to add your own
+# code.
+#
+# TODO: prose documentation
+endef
+mod.files.doc := $(value mod.files.doc)
+
+files.groups ?= all
+files.default ?= all
+files.vcsclean ?= files.vcsclean
+files.generate ?= files.generate
+
+.DEFAULT_GOAL = $(files.default)
+
+# Standard creative PHONY targets
+nested.targets += $(files.generate)
+nested.targets += install installdirs
+nested.targets += $(foreach g,$(files.groups),$g)
+nested.targets += $(foreach g,$(filter-out $(files.default),$(files.groups)),install-$g install-$gdirs)
+# Standard destructive PHONY targets
+nested.targets += uninstall mostlyclean clean distclean maintainer-clean $(files.vcsclean)
+
+# User configuration
+
+DESTDIR ?=
+
+RM ?= rm -f
+RMDIR_P ?= rmdir -p --ignore-fail-on-non-empty
+TRUE ?= true
+
+# Utility functions
+
+_files.XARGS = $(if $(strip $2),$1 $(strip $2))
+
+_files.maintainer-clean-warning:
+ @echo 'This command is intended for maintainers to use; it'
+ @echo 'deletes files that may need special tools to rebuild.'
+.PHONY: _files.maintainer-clean-warning
diff --git a/build-aux/Makefile.once.head/10-gitfiles.mk b/build-aux/Makefile.once.head/10-gitfiles.mk
new file mode 100644
index 0000000..8566a7f
--- /dev/null
+++ b/build-aux/Makefile.once.head/10-gitfiles.mk
@@ -0,0 +1,75 @@
+# Copyright (C) 2016-2017 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.gitfiles.description = Automatically populate files.src.src from git
+mod.gitfiles.depends += files nested write-ifchanged quote
+mod.gitfiles.files += $(topsrcdir)/$(gitfiles.file)
+define mod.gitfiles.doc
+# Inputs:
+# - Global variable : `gitfiles.file` (Default: gitfiles.mk)
+# - Directory variable : `nested.subdirs`
+# - External : git
+# Outputs:
+# - File : `$(topsrcdir)/$(gitfiles.file)`
+# - Directory variable : `files.src.src`
+# - Directory variable : `files.src.gen` (only in top dir)
+#
+# The `files` module has a variable (`files.src.src`) that you (the
+# developer) set to list "pure" source files; the type of files that you
+# would check into a version control system. Since you are a
+# responsible developer, you use a version control system. Since the
+# computer is already maintaining a list of these files *in the VCS*,
+# why should you--a filthy human--need to also maintain the list? Enter
+# gitfiles, which will talk to git to maintain `files.src.src`, but
+# won't require that the git repository be distributed to
+# installing-users.
+#
+# If `$(topsrcdir)/.git` exists, then it will generate
+# `$(topsrcdir)/$(gitfiles.file)`. Otherwise, it will assume that
+# `$(topsrcdir)/$(gitfiles.file)` already exists.
+#
+# It will use the information in `$(topsrcdir)/$(gitfiles.file)` to
+# append to `files.src.src` in each directory
+#
+# Finally, since the generated `$(topsrcdir)/$(gitfiles.file)` must be
+# distributed to users, it is added to $(topsrcdirs)'s `files.src.gen`.
+#
+# When setting `files.src.src`, it needs to know which files "belong" to
+# the current directory directly, and which "belong" to a further
+# subdirectory. To do this, it uses an expression involving
+# `$(nested.subdirs)`.
+#
+# While gitfiles sets `files.src.src` very early in `each.head`, because
+# `nested.subdirs` might not be set yet, it may or may not be safe to
+# use the value of `$(files.src.src)` in your Makefile, depending on how
+# you set `nested.subdirs`.
+endef
+mod.gitfiles.doc := $(value mod.gitfiles.doc)
+
+gitfiles.file ?= gitfiles.mk
+
+_gitfiles.all =
+-include $(topsrcdir)/$(gitfiles.file)
+
+ifneq ($(wildcard $(topsrcdir)/.git),)
+$(topsrcdir)/$(gitfiles.file): _gitfiles.FORCE
+ @(cd $(@D) && git ls-files --recurse-submodules -z) | sed -z -e 's/\$$/\$$$$/g' -e 's/\n/$$(at.nl)/g' | xargs -r0 printf '_gitfiles.all+=%s\n' | $(WRITE_IFCHANGED) $@
+.PHONY: _gitfiles.FORCE
+endif
+
+_gitfiles.dir = $(call at.relto,$(topsrcdir),$(srcdir))
+_gitfiles.pat = $(patsubst ./%,%,$(_gitfiles.dir)/%)
+_gitfiles.dir.all = $(patsubst $(_gitfiles.pat),%,$(filter $(_gitfiles.pat),$(_gitfiles.all)))
+_gitfiles.dir.src = $(filter-out $(addsuffix /%,$(nested.subdirs)),$(_gitfiles.dir.all))
diff --git a/build-aux/Makefile.once.head/10-gnuconf.mk b/build-aux/Makefile.once.head/10-gnuconf.mk
new file mode 100644
index 0000000..87baa14
--- /dev/null
+++ b/build-aux/Makefile.once.head/10-gnuconf.mk
@@ -0,0 +1,205 @@
+# Copyright (C) 2016-2017 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.gnuconf.description = GNU standard configuration variables
+define mod.gnuconf.doc
+# Inputs:
+# - Global variable: `gnuconf.pkgname`
+# (Default: `$(firstword $(PACKAGE_TARNAME) $(PACKAGE) $(PACKAGE_NAME))`)
+# Outputs:
+# (see below)
+#
+# This module defines default values (using `?=`) a huge list of
+# variables specified in the GNU Coding Standards that installing-users
+# expect to be able to set.
+#
+# This is based on §7.2 "Makefile Conventions" of the July 25, 2016
+# release of the GNU Coding Standards.
+endef
+mod.gnuconf.doc := $(value mod.gnuconf.doc)
+
+PACKAGE_TARNAME ?=
+PACKAGE ?=
+PACKAGE_NAME ?=
+gnuconf.pkgname ?= $(firstword $(PACKAGE_TARNAME) $(PACKAGE) $(PACKAGE_NAME))
+ifeq ($(gnuconf.pkgname),)
+$(error Autothing module: gnuconf: gnuconf.pkgname must be set)
+endif
+
+# 7.2.2: Utilities in Makefiles
+# -----------------------------
+
+# It's ok to hard-code these commands in rules, but who wants to
+# memorize the list of what's ok?
+AWK ?= awk
+CAT ?= cat
+CMP ?= cmp
+CP ?= cp
+DIFF ?= diff
+ECHO ?= echo
+EGREP ?= egrep
+EXPR ?= expr
+FALSE ?= false
+GREP ?= grep
+INSTALL_INFO ?= install-info
+LN ?= ln
+LS ?= ls
+MKDIR ?= mkdir
+MV ?= mv
+PRINTF ?= printf
+PWD ?= pwd
+RM ?= rm
+RMDIR ?= rmdir
+SED ?= sed
+SLEEP ?= sleep
+SORT ?= sort
+TAR ?= tar
+TEST ?= test
+TOUCH ?= touch
+TR ?= tr
+TRUE ?= true
+
+# 7.2.2: Utilities in Makefiles/7.2.3: Variables for Specifying Commands
+# ----------------------------------------------------------------------
+
+# Standard user-configurable programs.
+#
+# The list of programs here is specified in §7.2.2, but the associated FLAGS
+# variables are specified in §7.2.3. I found it cleaner to list them together.
+AR ?= ar
+ARFLAGS ?=
+BISON ?= bison
+BISONFLAGS ?=
+CC ?= cc
+CFLAGS ?= # CFLAGS instead of CCFLAGS
+FLEX ?= flex
+FLEXFLAGS ?=
+INSTALL ?= install
+# There is no INSTALLFLAGS[0]
+LD ?= ld
+LDFLAGS ?=
+LDCONFIG ?= ldconfig # TODO[1]
+LDCONFIGFLAGS ?=
+LEX ?= lex
+LFLAGS ?= # LFLAGS instead of LEXFLAGS
+#MAKE
+MAKEINFO ?= makeinfo
+MAKEINFOFLAGS ?=
+RANLIB ?= ranlib # TODO[1]
+RANLIBFLAGS ?=
+TEXI2DVI ?= texi2dvi
+TEXI2DVIFLAGS ?=
+YACC ?= yacc
+YFLAGS ?= # YFLAGS instead of YACCFLAGS
+
+CPPFLAGS ?=
+
+LN_S ?= ln -s # TODO[2]
+
+CHGRP ?= chgrp
+CHGRPFLAGS ?=
+CHMOD ?= chmod
+CHMODFLAGS ?=
+CHOWN ?= chown
+CHOWNFLAGS ?=
+MKNOD ?= mknod
+MKNODFLAGS ?=
+
+# [0]: There is no INSTALLFLAGS because it would be inconsistent with how the
+# standards otherwise recommend using $(INSTALL); with INSTALL_PROGRAM and
+# INSTALL_DATA; which are specified in a way precluding the use of
+# INSTALLFLAGS. To have the variable, but to ignore it in the common case
+# would be confusing.
+#
+# [1]: The RANLIB and LDCONFIG variables need some extra smarts; §7.2.2 says:
+#
+# > When you use ranlib or ldconfig, you should make sure nothing bad
+# > happens if the system does not have the program in question. Arrange
+# > to ignore an error from that command, and print a message before the
+# > command to tell the user that failure of this command does not mean a
+# > problem. (The Autoconf ‘AC_PROG_RANLIB’ macro can help with this.)
+#
+# [2]: The LN_S variable isn't standard, but we have it here as an (incomplete)
+# stub to help support this bit of §7.2.2:
+#
+# > If you use symbolic links, you should implement a fallback for
+# > systems that don’t have symbolic links.
+
+# 7.2.3: Variables for Specifying Commands
+# ----------------------------------------
+
+INSTALL_PROGRAM ?= $(INSTALL)
+INSTALL_DATA ?= ${INSTALL} -m 644
+
+# 7.2.5: Variables for Installation Directories
+# ---------------------------------------------
+
+# Root for the installation
+prefix ?= /usr/local
+exec_prefix ?= $(prefix)
+# Executable programs
+bindir ?= $(exec_prefix)/bin
+sbindir ?= $(exec_prefix)/sbin
+libexecdir ?= $(exec_prefix)/libexec
+# Data files
+datarootdir ?= $(prefix)/share
+datadir ?= $(datarootdir)
+sysconfdir ?= $(prefix)/etc
+sharedstatedir ?= $(prefix)/com
+localstatedir ?= $(prefix)/var
+runstatedir ?= $(localstatedir)/run
+# Specific types of files
+includedir ?= $(prefix)/include
+oldincludedir ?= /usr/include
+docdir ?= $(datarootdir)/doc/$(gnuconf.pkgname)
+infodir ?= $(datarootdir)/info
+htmldir ?= $(docdir)
+dvidir ?= $(docdir)
+pdfdir ?= $(docdir)
+psdir ?= $(docdir)
+libdir ?= $(exec_prefix)/lib
+lispdir ?= $(datarootdir)/emacs/site-lisp
+localedir ?= $(datarootdir)/locale
+
+mandir ?= $(datarootdir)/man
+man1dir ?= $(mandir)/man1
+man2dir ?= $(mandir)/man2
+man3dir ?= $(mandir)/man3
+man4dir ?= $(mandir)/man4
+man5dir ?= $(mandir)/man5
+man6dir ?= $(mandir)/man6
+man7dir ?= $(mandir)/man7
+man8dir ?= $(mandir)/man8
+
+manext ?= .1
+man1ext ?= .1
+man2ext ?= .2
+man3ext ?= .3
+man4ext ?= .4
+man5ext ?= .5
+man6ext ?= .6
+man7ext ?= .7
+man8ext ?= .8
+
+# 7.2.7: Install Command Categories
+# ---------------------------------
+
+PRE_INSTALL ?=
+POST_INSTALL ?=
+NORMAL_INSTALL ?=
+
+PRE_UNINSTALL ?=
+POST_UNINSTALL ?=
+NORMAL_UNINSTALL ?=
diff --git a/build-aux/Makefile.once.head/10-nested.mk b/build-aux/Makefile.once.head/10-nested.mk
new file mode 100644
index 0000000..d903d53
--- /dev/null
+++ b/build-aux/Makefile.once.head/10-nested.mk
@@ -0,0 +1,46 @@
+# Copyright (C) 2016-2017 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.nested.description = Easy nested .PHONY targets
+define mod.nested.doc
+# Inputs:
+# - Global variable : `nested.targets`
+# - Directory variable : `nested.subdirs`
+# Outputs:
+# - .PHONY Targets : `$(addprefix $(outdir)/,$(nested.targets))`
+# - Variable : `at.subdirs`
+# - Variable : `at.targets`
+#
+# The Autothing `at.subdirs` slates a subdirectory's Makefile for inclusion,
+# but doesn't help with recursive targets like `all`, `install`, or `clean`,
+# which one would expect to descend into subdirectories. Enter `nested`:
+# Define a global list of targets that are recursive/nested, and then in each
+# directory define a list of subdirectries that one would expect them to
+# recurse into.
+#
+# Directories added to `nested.subdirs` are automatically added to `at.subdirs`
+# during the each.tail phase.
+#
+# It may help to think of at.subdirs and nested.subdirs in terms of their
+# Automake conterparts:
+#
+# | Autothing | GNU Automake |
+# +----------------+--------------+
+# | at.subdirs | DIST_SUBDIRS |
+# | nested.subdirs | SUBDIRS |
+endef
+mod.nested.doc := $(value mod.nested.doc)
+
+nested.targets ?=
diff --git a/build-aux/Makefile.once.head/10-std.mk b/build-aux/Makefile.once.head/10-std.mk
deleted file mode 100644
index 3e058ec..0000000
--- a/build-aux/Makefile.once.head/10-std.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2015-2016 Luke Shumaker
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# Declare the default target
-all: build
-.PHONY: all noop
-
-# Standard creative PHONY targets
-at.phony += build install installdirs
-# Standard destructive PHONY targets
-at.phony += uninstall mostlyclean clean distclean maintainer-clean
-
-at.dirlocal += std.src_files
-at.dirlocal += std.gen_files
-at.dirlocal += std.cfg_files
-at.dirlocal += std.out_files
-at.dirlocal += std.sys_files
-at.dirlocal += std.clean_files
-at.dirlocal += std.slow_files
-
-# User configuration
-
-DESTDIR ?=
-
-RM ?= rm -f
-RMDIR_P ?= rmdir -p
-TRUE ?= true
diff --git a/build-aux/Makefile.once.head/10-texinfo.mk b/build-aux/Makefile.once.head/10-texinfo.mk
new file mode 100644
index 0000000..d24852d
--- /dev/null
+++ b/build-aux/Makefile.once.head/10-texinfo.mk
@@ -0,0 +1,47 @@
+# Copyright (C) 2016-2017 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.texinfo.description = The GNU documentation system
+mod.texinfo.depends += files nested gnuconf
+define mod.texinfo.doc
+# User variables (in addition to gnuconf):
+# - `TEXI2HTML ?= makeinfo --html`
+# - `TEXI2PDF ?= texi2pdf`
+# - `TEXI2PS ?= texi2dvi --ps`
+# Inputs:
+# - Directory variable : `texinfo.docs ?=`
+# Outputs:
+# - Global variable : `files.groups += html dvi pdf ps`
+# - Global variable : `nested.targets += info`
+# - Directory variable : `files.src.gen`
+# - Directory variable : `files.out.{dvi,html,pdf,ps}`
+# - Directory variable : `files.sys.{dvi,html,pdf,ps,all}`
+# - .PHONY target : `$(outdir)/info`
+# - Target : `$(outdir)/%.info`
+# - Target : `$(outdir)/%.dvi`
+# - target : `$(outdir)/%.html`
+# - target : `$(outdir)/%.pdf`
+# - Target : `$(outdir)/%.ps`
+#
+# TODO: prose documentation
+endef
+mod.texinfo.doc := $(value mod.texinfo.doc)
+
+TEXI2HTML ?= makeinfo --html
+TEXI2PDF ?= texi2pdf
+TEXI2PS ?= texi2dvi --ps
+
+files.groups += html dvi pdf ps
+nested.targets += info
diff --git a/build-aux/Makefile.once.head/10-write-atomic.mk b/build-aux/Makefile.once.head/10-write-atomic.mk
new file mode 100644
index 0000000..c4aa808
--- /dev/null
+++ b/build-aux/Makefile.once.head/10-write-atomic.mk
@@ -0,0 +1,23 @@
+mod.write-atomic.description = `write-atomic` auxiliary build script
+mod.write-atomic.files += $(topsrcdir)/build-aux/write-atomic
+define mod.write-atomic.doc
+# User variables:
+# - `WRITE_ATOMIC ?= $(topsrcdir)/build-aux/write-atomic`
+# Inputs:
+# (none)
+# Outputs:
+# (none)
+#
+# The $(WRITE_ATOMIC) program reads a file from stdin, and writes it to
+# the file named in argv[1], but does so atomically.
+#
+# That is, the following lines are almost equivalient:
+#
+# ... > $@
+# ... | $(WRITE_ATOMIC) $@
+#
+# The are only different in that one is atomic, while the other is not.
+endef
+mod.write-atomic.doc := $(value mod.write-atomic.doc)
+
+WRITE_ATOMIC ?= $(topsrcdir)/build-aux/write-atomic
diff --git a/build-aux/Makefile.once.head/10-write-ifchanged.mk b/build-aux/Makefile.once.head/10-write-ifchanged.mk
new file mode 100644
index 0000000..649aab9
--- /dev/null
+++ b/build-aux/Makefile.once.head/10-write-ifchanged.mk
@@ -0,0 +1,23 @@
+mod.write-ifchanged.description = `write-ifchanged` auxiliary build script
+mod.write-ifchanged.files += $(topsrcdir)/build-aux/write-ifchanged
+define mod.write-ifchanged.doc
+# User variables:
+# - `WRITE_IFCHANGED ?= $(topsrcdir)/build-aux/write-ifchanged`
+# Inputs:
+# (none)
+# Outputs:
+# (none)
+#
+# The $(WRITE_IFCHANGED) program reads a file from stdin, and writes it to the
+# file named in argv[1], but does so atomically, but more importantly, does so
+# in a way that does not bump the file's ctime if the new content is the same
+# as the old content.
+#
+# That is, the following lines are almost equivalient:
+#
+# ... > $@
+# ... | $(WRITE_ATOMIC) $@
+endef
+mod.write-ifchanged.doc := $(value mod.write-ifchanged.doc)
+
+WRITE_IFCHANGED ?= $(topsrcdir)/build-aux/write-ifchanged
diff --git a/build-aux/Makefile.once.head/zz-mod.mk b/build-aux/Makefile.once.head/zz-mod.mk
new file mode 100644
index 0000000..95d251d
--- /dev/null
+++ b/build-aux/Makefile.once.head/zz-mod.mk
@@ -0,0 +1,59 @@
+# Copyright (C) 2016 Luke Shumaker
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+mod.mod.description = Display information about Autothing modules
+mod.mod.depends += quote
+define mod.mod.doc
+# Inputs:
+# - Files : `$(topsrcdir)/build-aux/Makefile.*/??-*.mk`
+# - Global variable : `mod.*.description`
+# - Global variable : `mod.*.depends`
+# - Global variable : `mod.*.files`
+# - Global variable : `mod.*.doc`
+# Outputs:
+# - Directory variable : `at.targets`
+# - .PHONY Target : `$(outdir)/at-variables-local`
+# - .PHONY Target : `$(outdir)/at-variables-global`
+# - .PHONY Target : `$(outdir)/at-variables`
+# - .PHONY Target : `$(outdir)/at-variables/%`
+# - .PHONY Target : `$(outdir)/at-values`
+# - .PHONY Target : `$(outdir)/at-values/%`
+# - .PHONY Target : `$(outdir)/at-modules`
+# - .PHONY Target : `$(outdir)/at-modules/%`
+# - .PHONY Target : `$(outdir)/at-noop`
+#
+# TODO: prose documentation
+endef
+mod.mod.doc := $(value mod.mod.doc)
+
+# The trickery that is _mod.empty/_mod.space is from §6.2 of the GNU Make
+# manual, "The Two Flavors of Variables".
+_mod.empty :=
+_mod.space := $(_mod.empty) #
+undefine _mod.empty
+# _mod.rest is equivalent to GMSL rest.
+_mod.rest = $(wordlist 2,$(words $1),$1)
+
+_mod.file2mod = $(foreach _mod.tmp,$(patsubst %.mk,%,$(notdir $1)),$(subst $(_mod.space),-,$(call _mod.rest,$(subst -, ,$(_mod.tmp)))))
+
+_mod.modules := $(sort $(call _mod.file2mod,$(wildcard $(topsrcdir)/build-aux/Makefile.*/??-*.mk)))
+undefine _mod.rest
+undefine _mod.file2mod
+
+$(eval $(foreach _mod.tmp,$(_mod.modules),\
+ mod.$(_mod.tmp).description ?=$(at.nl)\
+ mod.$(_mod.tmp).depends ?=$(at.nl)\
+ mod.$(_mod.tmp).files ?=$(at.nl)\
+ mod.$(_mod.tmp).doc ?=$(at.nl)))