diff options
author | Luke Shumaker <lukeshu@sbcglobal.net> | 2017-02-04 22:44:15 -0500 |
---|---|---|
committer | Luke Shumaker <lukeshu@sbcglobal.net> | 2017-02-04 22:44:15 -0500 |
commit | c40b7b42592fd801cae5a845ff778e054d0f85de (patch) | |
tree | 8ec957c26ed2298707f76d4dbe0cda8df8f0c19e | |
parent | 837a1236abe4b58850202420ec3ee3e8509340cd (diff) | |
parent | eaf336a9265399520e3cf71d4979446b98bdf48d (diff) |
Merge remote-tracking branch 'autothing/v3/master'
40 files changed, 1977 insertions, 360 deletions
@@ -1,8 +1,12 @@ depends.txt -.srcfiles.mk parabolaweb* !parabolaweb*.in !parabolaweb*.c !parabolaweb.conf !parabolaweb.ini + +.tmp.* +.var.* + +gitfiles.mk diff --git a/README.md b/README.md new file mode 120000 index 0000000..5e5ea4a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +build-aux/Makefile.README.txt
\ No newline at end of file diff --git a/automake.head.mk b/automake.head.mk deleted file mode 100644 index 37d3b07..0000000 --- a/automake.head.mk +++ /dev/null @@ -1,56 +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/>. - -_am = am_ - -_am_noslash = $(patsubst %/.,%,$(patsubst %/,%,$1)) -# These are all $(call _am_func,parent,child) -#_am_relto = $(if $2,$(shell realpath -sm --relative-to='$1' $2)) -_am_is_subdir = $(filter $(abspath $1)/%,$(abspath $2)/.) -_am_relto_helper = $(if $(call _am_is_subdir,$1,$2),$(patsubst $1/%,%,$(addsuffix /.,$2)),$(addprefix ../,$(call _am_relto_helper,$(patsubst %/,%,$(dir $1)),$2))) -_am_relto = $(call _am_noslash,$(call _am_relto_helper,$(call _am_noslash,$(abspath $1)),$(call _am_noslash,$(abspath $2)))) -# Note that _am_is_subdir says that a directory is a subdirectory of -# itself. -_am_path = $(call _am_relto,.,$1) -am_path = $(foreach p,$1,$(call _am_relto,$p)) - -## Declare the default target -all: build -.PHONY: all - -## Set outdir and srcdir (assumes that topoutdir and topsrcdir are -## already set) -outdir := $(call _am_path,$(dir $(lastword $(filter-out %.mk,$(MAKEFILE_LIST))))) -srcdir := $(call _am_path,$(topsrcdir)/$(call _am_relto,$(topoutdir),$(outdir))) - -_am_included_makefiles := $(_am_included_makefiles) $(call _am_path,$(outdir)/Makefile) - -## Empty variables for use by each Makefile -$(_am)subdirs = -$(_am)depdirs = - -$(_am)src_files = -$(_am)gen_files = -$(_am)cfg_files = -$(_am)out_files = -$(_am)sys_files = - -$(_am)clean_files = -$(_am)slow_files = - -ifeq ($(_am_NO_ONCE),) -include $(topsrcdir)/common.once.head.mk -endif -include $(topsrcdir)/common.each.head.mk diff --git a/automake.tail.mk b/automake.tail.mk deleted file mode 100644 index a24820b..0000000 --- a/automake.tail.mk +++ /dev/null @@ -1,139 +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/>. - -include $(topsrcdir)/common.each.tail.mk - - -# Aggregate variables - -# Add some more defaults to the *_files variables -$(_am)clean_files += $($(_am)gen_files) $($(_am)cfg_files) $($(_am)out_files) - -# Now namespace the *_files variables -define _am_save_variables -_am_src_files/$(outdir) = $(addprefix $(srcdir)/,$($(_am)src_files)) -_am_gen_files/$(outdir) = $(addprefix $(srcdir)/,$($(_am)gen_files)) -_am_cfg_files/$(outdir) = $(addprefix $(outdir)/,$($(_am)cfg_files)) -_am_out_files/$(outdir) = $(addprefix $(outdir)/,$($(_am)out_files)) -_am_sys_files/$(outdir) = $(addprefix $(DESTDIR),$($(_am)sys_files)) -_am_clean_files/$(outdir) = $(addprefix $(outdir)/,$($(_am)clean_files)) -_am_slow_files/$(outdir) = $(addprefix $(outdir)/,$($(_am)slow_files)) -_am_subdirs/$(outdir) = $($(_am)subdirs) -endef -$(eval $(_am_save_variables)) - -# And add them to the $(parent)_*_files variables (if applicable) -define _am_add_subdir -_am_src_files/%(outdir) += $(_am_src_files/%(subdir)) -_am_gen_files/%(outdir) += $(_am_gen_files/%(subdir)) -_am_cfg_files/%(outdir) += $(_am_cfg_files/%(subdir)) -_am_out_files/%(outdir) += $(_am_out_files/%(subdir)) -_am_sys_files/%(outdir) += $(_am_sys_files/%(subdir)) -_am_clean_files/%(outdir) += $(_am_clean_files/%(subdir)) -_am_slow_files/%(outdir) += $(_am_slow_files/%(subdir)) -endef -$(foreach subdir,$(call _am_path,$(addprefix $(outdir)/,$($(_am)subdirs))),$(eval $(subst %(outdir),$(outdir),$(subst %(subdir),$(subdir),$(value _am_add_subdir))))) - -_am_outdirs := $(_am_outdirs) $(outdir) - - -# Do some per-directory magic - -_am_phony = build install uninstall mostlyclean clean distclean maintainer-clean check - -.PHONY: $(addprefix $(outdir)/,$(_am_phony)) - -$(addprefix $(outdir)/,uninstall mostlyclean clean distclean maintainer-clean):: - $(RM) -- $(sort $(_am_$(@F)/$(@D))) - $(RMDIRS) $(sort $(dir $(_am_$(@F)/$(@D)))) 2>/dev/null || $(TRUE) - -# 'build' and 'install' must be defined later, because the -# am_*_files/* variables might not be complete yet. - - -# Include Makefiles from other directories - -define _am_nl - - -endef - -$(foreach _am_NO_ONCE,y,\ - $(foreach makefile,$(foreach dir,$($(_am)subdirs) $($(_am)depdirs),$(call _am_path,$(outdir)/$(dir)/Makefile)),\ - $(eval include $(filter-out $(_am_included_makefiles),$(makefile))))) - - -# This only gets evaluated once, after all of the other Makefiles are read -ifeq ($(_am_NO_ONCE),) -# Empty directory-level variables -outdir = /bogus -srcdir = /bogus - -$(_am)subdirs = -$(_am)depdirs = - -$(_am)src_files = -$(_am)gen_files = -$(_am)cfg_files = -$(_am)out_files = -$(_am)sys_files = -$(_am)clean_files = -$(_am)slow_files = - -_am_clean_files/$(topoutdir) += $(topoutdir)/$(PACKAGE)-$(VERSION).tar.gz -$(addprefix $(topoutdir)/,mostlyclean clean distclean maintainer-clean) :: - $(RM) -r -- $(topoutdir)/$(PACKAGE)-$(VERSION) - -define _am_directory_rules -# Constructive phony targets -$(outdir)/build : $(_am_out_files/%(outdir)) -$(outdir)/install: $(_am_sys_files/%(outdir)) -# Destructive phony targets -_am_uninstall/%(outdir) = $(_am_sys_files/%(outdir)) -_am_mostlyclean/%(outdir) = $(filter-out $(_am_slow_files/%(outdir)) $(_am_cfg_files/%(outdir)) $(_am_gen_files/%(outdir)) $(_am_src_files/%(outdir)),$(_am_clean_files/%(outdir))) -_am_clean/%(outdir) = $(filter-out $(_am_cfg_files/%(outdir)) $(_am_gen_files/%(outdir)) $(_am_src_files/%(outdir)),$(_am_clean_files/%(outdir))) -_am_distclean/%(outdir) = $(filter-out $(_am_gen_files/%(outdir)) $(_am_src_files/%(outdir)),$(_am_clean_files/%(outdir))) -_am_maintainer-clean/%(outdir) = $(filter-out $(_am_src_files/%(outdir)),$(_am_clean_files/%(outdir))) -endef -$(foreach outdir,$(_am_outdirs),$(eval $(subst %(outdir),$(outdir),$(value _am_directory_rules)))) - -# Add the `dist` target -.PHONY: dist -dist: $(topoutdir)/$(PACKAGE)-$(VERSION).tar.gz -$(topoutdir)/$(PACKAGE)-$(VERSION).tar.gz: $(topoutdir)/$(PACKAGE)-$(VERSION) - $(TAR) czf $@ -C $(<D) $(<F) -_am_copyfile = $(MKDIRS) $(dir $2) && $(CP) -T $1 $2 -_am_addfile = $(call _am_copyfile,$3,$2/$(call _am_relto,$1,$3)) -$(topoutdir)/$(PACKAGE)-$(VERSION): $(_am_src_files/$(topoutdir)) $(_am_gen_files/$(topoutdir)) - $(RM) -r $@ - @PS4='' && set -x && \ - $(MKDIR) $(@D)/tmp.$(@F).$$$$ && \ - $(foreach f,$^,$(call _am_addfile,$(topsrcdir),$(@D)/tmp.$(@F).$$$$,$f) &&) \ - $(MV) $(@D)/tmp.$(@F).$$$$ $@ || $(RM) -r $(@D)/tmp.$(@F).$$$$ - -include $(topsrcdir)/common.once.tail.mk - -# For some reason I can't explain, RM doesn't really get set with ?= -CP ?= cp -MKDIR ?= mkdir -MKDIRS ?= mkdir -p -MV ?= mv -RM = rm -f -RMDIRS ?= rmdir -p -TAR ?= tar -TRUE ?= true - -.PHONY: noop -endif diff --git a/automake.txt b/automake.txt deleted file mode 100644 index 935af5f..0000000 --- a/automake.txt +++ /dev/null @@ -1,164 +0,0 @@ -Luke's AutoMake -=============== - -Yo, this document is incomplete. It describes the magical -automake.{head,tail}.mk Makefiles and how to use them, kinda. - -I wrote a "clone" of automake. I say clone, because it works -differently. Yeah, I need a new name for it. - -High-level overview -------------------- - -Now, what this does for you is: - -It makes it _easy_ to write non-recursive Makefiles--and ones that are -similar to plain recursive Makefiles, at that! (search for the paper -"Recursive Make Considered Harmful") As harmful as recursive make is, -it's historically been difficult to to write non-recursive Makefiles. -This makes it easy. - -It also makes it easy to follow the GNU standards for your makefiles: -it takes care of this entire table of .PHONY targets for you: - -| this | and this | are aliases for this | -|------+------------------+--------------------------------------------------------| -| all | build | $(outdir)/build | -| | install | $(outdir)/install | -| | uninstall | $(outdir)/uninstall | -| | mostlyclean | $(outdir)/mostlyclean | -| | clean | $(outdir)/clean | -| | distclean | $(outdir)/distclean | -| | maintainer-clean | $(outdir)/maintainer-clean | -| | check | $(outdir)/check (not implemented for you) | -| | dist | $(topoutdir)/$(PACKAGE)-$(VERSION).tar.gz (not .PHONY) | - -(You are still responsible for implementing the `$(outdir)/check` -target in each of your Makefiles.) - -What you have to do is: - -In each source directory, you write a `Makefile`, very similarly to if -you were writing for plain GNU Make, with - - topoutdir ?= ... - topsrcdir ?= ... - include $(topsrcdir)/automake.head.mk - - # your makefile - - include $(topsrcdir)/automake.tail.mk - -And in the top-level source directory, Write your own helper makefiles -that get included: - - `common.once.head.mk`: before parsing any of your Makefiles - - `common.each.head.mk`: before parsing each of your Makefiles - - `common.each.tail.mk`: after parsing each of your Makefiles - - `common.each.tail.mk`: after parsing all of your Makefiles - -The `common.*.mk` makefiles are nice for including generic pattern -rules and variables that aren't specific to a directory. - -You're probably thinking that this sounds too good to be true! -Unfortunately, there are two major deviations from writing a plain -recursive Makefile: - - 1. all targets and prerequisites (including .PHONY targets!) need to - be prefixed with - `$(srcdir)`/`$(outdir)`/`$(topsrcdir)`/`$(topoutdir)`. - * sub-gotcha: this means that if a pattern rule has a - prerequisite that may be in srcdir or outdir, then it must be - specified twice, once for each case. - 2. if a prerequisite is in a directory "owned" by another Makefile, - you must filter the pathname through `am_path`: - `$(call am_path,YOUR_PATH)`. Further, that path must NOT contain - a `..` segment; if you need to refer to a sibling directory, do it - relative to `$(topoutdir)` or `$(topsrcdir)`. - -Telling automake about your program ------------------------------------ - -You tell automake what to do for you by setting some variables. They -are all prefixed with `am_`; this prefix may be changed by editing the -`_am` variable at the top of `automake.head.mk`. - -The exception to this is the `am_path` variable, which is a macro that -is used to make a list of filenames relative to the appropriate -directory, because unlike normal GNU (Auto)Make, `$(outdir)` isn't -nescessarily equal to `.`. See above. - -There are several commands that generate files; simply record the list -of files that each command generates as the following variable -variables: - -| Variable | Create Command | Delete Command | Description | Relative to | -|--------------+----------------+-----------------------------+-----------------------------------+-------------| -| am_src_files | emacs | rm -rf . | Files that the developer writes | srcdir | -| am_gen_files | ??? | make maintainer-clean | Files the developer compiles | srcdir | -| am_cfg_files | ./configure | make distclean | Users' compile-time configuration | outdir | -| am_out_files | make all | make mostlyclean/make clean | Files the user compiles | outdir | -| am_sys_files | make install | make uninstall | Files the user installs | DESTDIR | - -In addition, there are two more variables that control not how files -are created, but how they are deleted: - -| Variable | Affected command | Description | Relative to | -|----------------+------------------+------------------------------------------------+-------------| -| am_clean_files | make clean | A list of things to `rm` in addition to the | outdir | -| | | files in `$(am_out_files)`. (Example: `*.o`) | | -|----------------+------------------+------------------------------------------------+-------------| -| am_slow_files | make mostlyclean | A list of things that (as an exception) should | outdir | -| | | _not_ be deleted. (otherwise, `mostlyclean` | | -| | | is the same as `clean`) | | - -Finally, there are two variables that express the relationships -between directories: - -| Variable | Description | -|------------+---------------------------------------------------------| -| am_subdirs | A list of other directories (containing Makefiles) that | -| | may be considered "children" of this | -| | directory/Makefile; building a phony target in this | -| | directory should also build it in the subdirectory. | -| | They are not necesarily actually subdirectories of this | -| | directory in the filesystem. | -|------------+---------------------------------------------------------| -| am_depdirs | A list of other directories (containing Makefiles) that | -| | contain or generate files that are dependencies of | -| | targets in this directory. They are not necesarily | -| | actually subdirectories of this directory in the | -| | filesystem. Except for files that are dependencies of | -| | files in this directory, things in the dependency | -| | directory will not be built. | - -Tips, notes ------------ - -I like to have the first (non-comment) line in a Makefile be: - - include $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk - -(adjusting the number of `../` sequences as nescessary). Then, my -(user-editable) `config.mk` is of the form: - - ifeq ($(topsrcdir),) - topoutdir := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) - topsrcdir := $(topoutdir) - - # your configuration - - endif - -If the package has a `./configure` script, then I have it modifiy -topsrcdir as necessary, as well as modifying whatever other parts of -the configuration. All of the configuration lives in `config.mk`; -`./configure` doesn't modify any `Makefile`s, it just generates -`config.mk`, and copies (or (sym?)link?) every `$(srcdir)/Makefile` to -`$(outdir)/Makefile`. - ----- -Copyright (C) 2016 Luke Shumaker - -This documentation file is placed into the public domain. If that is -not possible in your legal system, I grant you permission to use it in -absolutely every way that I can legally grant to you. diff --git a/build-aux/Makefile.README.mk b/build-aux/Makefile.README.mk new file mode 100644 index 0000000..fe9010a --- /dev/null +++ b/build-aux/Makefile.README.mk @@ -0,0 +1,20 @@ +# This Makefile is a minimal stub that exists to allow the +# `at-modules` set of Make targets to print documentation for the +# present Autothing modules. +# +# This file is part of the documentation for Autothing. +# +# Copyright (C) 2017 Luke Shumaker +# +# This documentation file is placed into the public domain. If that +# is not possible in your legal system, I grant you permission to use +# it in absolutely every way that I can legally grant to you. + +dist.pkgname = autothing +dist.version = 1.0 +gnuconf.pkgname = autothing + +topoutdir ?= . +topsrcdir ?= . +include $(topsrcdir)/build-aux/Makefile.head.mk +include $(topsrcdir)/build-aux/Makefile.tail.mk diff --git a/build-aux/Makefile.README.old.txt b/build-aux/Makefile.README.old.txt new file mode 100644 index 0000000..b4ea562 --- /dev/null +++ b/build-aux/Makefile.README.old.txt @@ -0,0 +1,35 @@ +Obsolete +======== + +The following was written for previous versions of Autothing. I'm +leaving it here for now because I'll likely canibalize it for other +bits of documentation, either for Autothing itself, the `files` +module, or the `dist` module. + +High-level overview +------------------- + +It also makes it easy to follow the GNU standards for your makefiles: +it takes care of this entire table of .PHONY targets for you: + +| this | and this | are aliases for this | +|------+------------------+--------------------------------------------------------| +| all | build | $(outdir)/build | +| | install | $(outdir)/install | +| | uninstall | $(outdir)/uninstall | +| | mostlyclean | $(outdir)/mostlyclean | +| | clean | $(outdir)/clean | +| | distclean | $(outdir)/distclean | +| | maintainer-clean | $(outdir)/maintainer-clean | +| | check | $(outdir)/check (not implemented for you) | +| | dist | $(topoutdir)/$(PACKAGE)-$(VERSION).tar.gz (not .PHONY) | + +(You are still responsible for implementing the `$(outdir)/check` +target in each of your Makefiles.) + +---- +Copyright (C) 2016 Luke Shumaker + +This documentation file is placed into the public domain. If that is +not possible in your legal system, I grant you permission to use it in +absolutely every way that I can legally grant to you. diff --git a/build-aux/Makefile.README.txt b/build-aux/Makefile.README.txt new file mode 100644 index 0000000..f67ede2 --- /dev/null +++ b/build-aux/Makefile.README.txt @@ -0,0 +1,447 @@ +# -*- Mode: markdown -*- + +Autothing 3: The smart way to write GNU Makefiles +================================================= + +Autothing is a thing that does things automatically. + +Ok, more helpfully: Autothing is a pair of .mk Makefile fragments +(`Makefile.head.mk` and `Makefile.tail.mk`) that you can `include` +from your Makefiles to make them easier to write; specifically, it +makes it _easy_ to write non-recursive Makefiles--and ones that are +similar to plain recursive Makefiles, at that! + +To many people, talking about GNU Make directly is a non-starter +because it means giving up the many other features that things like +GNU Automake provide. Other projects like GNU Automake were created +to plaster over differences between make(1) implementations; however, +this isn't all that Automake provides, it also makes it easy to do +complex things that users want, or the GNU Coding Standards require. +That's silly; the implementation of these features should be +orthogonal to plastering over the differences between Make +implementations. So, in addition to the Automake core, Automake is +distributed with several "modules" that implement similar feature sets +to what Automake provides. + +Autothing does depend on GNU Make; other make(1) implementations will +not work. However, if you are open to adding GNU Make as a +dependency, then Autothing should obviate the need for GNU Automake, +while also making your Makefiles better. + +Non-recursive? +-------------- + + (For those of you who aren't up on Makefile jargon) + +When you have a project that spans multiple directories, you'll +probably want to split up the Makefile, having the appropriate parts +in each sub-directory. There are a number of strategies you can use +to approach this. + +One of the more prevelant strategies (so much so that GNU make +includes special support for it) is to write "recursive Makefiles"; +that is, have Make rules that include commands like + + other-directory/libfoo.so: + $(MAKE) -C other-directory libfoo.so + +or + + other-directory/libfoo.so + cd other-directory && $(MAKE) libfoo.so + +This approach is popular because it is both very easy to implement, +and is supported by a wide variety of Make implementations. But, it +also introduces a wide variety of issues; so much so that a rather +famous paper was written about it: "Recursive Make Considered Harmful" +(Miller, 1997). + +For all of the arguments against it, and all of the alternative +approaches, recusive Makefiles are hard to beat because they are just +so easy to write, and the alternatives... aren't. UNTIL NOW! + +Instead of having rules that spawn a separate Make process in another +directory for targets in that directory, Autothing lets you provide a +list of directories that include targets that targets in this +directory might depend on, and Autothing will automagically include +the Makefile in that other directory into *this* instance of the Make +program. + + Peter Miller (1997) "Recursive Make Considered Harmful" + <http://aegis.sourceforge.net/auug97.pdf> + +An example Makefile / Introduction +---------------------------------- + +Write your Makefiles of the form: + + # Initialize basic information about how your project is structured. + topsrcdir ?= ... + topoutdir ?= ... + + # Include the Autothing entry point + include $(topsrcdir)/build-aux/Makefile.head.mk + + # Now write your Makefile very similarly to how you normally + # would. Just make sure that outputs are relative to $(outdir) + # and inputs relative to $(srcdir). + $(outdir)/%.o: $(srcdir)/%.c: + $(CC) -c -o $@ $< + $(outdir)/hello: $(outdir)/hello.o + + # If any of the dependencies of files here are outputs of a + # Makefile in another directory, list those directories here. + at.subdirs = ... + + # This part is kind of a pain: define a list of ouput targets that + # this Makefile produces. + at.targets = $(outdir)/%.o $(outdir)/hello + + # Include the Autothing exit point + include $(topsrcdir)/build-aux/Makefile.tail.mk + +This is similar to, but not quite, the comfortable way that you probably +already write your Makefiles. + +It is recommended that Autothing lives inside of the "build-aux" +directory in the top level of your project sources; "build-aux" is a +standard directory for auxiliary build programs and tools. + +What does Autothing do for me? +------------------------------ + +There are two fundamental things that Autothing provides: + + 1. Variable namespacing + 2. Tools for dealing with paths + +The first is important because globals are bad for composability. + +The second is important because GNU Make is too dumb to know that +`foo/bar/../baz` == `foo/baz`. + +Then, there's something that maybe doesn't belong, but I didn't have the heart +to cut it out: + + 3. A module (plugin) system, which allows for modules to provide + additional feature sets. + +The module system is "important" because there are very often common bits that +you want to be included in every Makefile, and this gives some structure to +that. + +Let's step through each of those features. + +## Variable namespacing + +When you write a Makefile, you quite likely use (global) variables. +When you have a project that uses multiple Makefiles, each Makefile +might have the same variable names, but with different values +(especially if converting from recursive Make). + +You could be very disciplined and carefully name your variables so +that they don't conflict. This is difficult and error prone normally, +but becomes neigh-on-impossible if you are converting a large-ish +project from recursive Make. + +So, Autothing provides a solution. If you provide Autothing with a +list of targets defined in your Makefile (via the `at.targets` +variable), Autothing will make any variables you defined local to that +Makefile; they will be present when making targets listed in +`at.targets`, but will be hidden from other Makfiles that get +included. + +Any variables defined before `Makefile.head.mk` is included are +treated as truly global; all Makefiles included will have access to +them. + +## Tools for dealing with paths + +As stated above, GNU Make is too dumb to realize that `foo/bar/../baz` +== `foo/baz`; so one has to be reasonably careful about path +normalization. For dealing with path normalization problems that +arise because of the way Autothing inclusions work, several global +functions are provided for dealing with paths. + +`$(call at.is_subdir,a,b)` returns whether `b` is a sub-directory of +`a` (including `a` as a sub-directory of itself). +`at.is_strict_subdir` does the same, but does not treat `a` as a +sub-directory of itself. (These function names mimic the terms +"subset" and "strict subset" in mathematics.) These use an empty +string for "false" and a non-empty string for "true". + +`$(call at.path,files...)` is a generic path-normalization routine. +The outputs of the other `at.*` functions are already normalized, and +do not need to be passed through this. Files immediately inside of +`$(srcdir)` or `$(outdir)` (without another directory name after the +variable) are already normalized, and do not need to be passed through +this function either. However, it is always safe to pass a path +through this function, so if in doubt, call `at.path`. + +`$(call at.relbase,dir,files...)` and its cousin `at.relto` take a +directory and a list of files, and transform each of the filenames to +be relative to the directory, if the file is inside of the directory. +Where they differ is that if the file is not inside of the directory; +`at.relbase` transforms it into an absolute path, while `at.relto` +prepends as many `../` segments as necessary to make it relative to +the directory. (These function names mimic the `--relative-base` and +`--relative-to` flags of the `realpath` utility that is part of GNU +coreutils.) + +If `$(srcdir)` and `$(outdir)` are the same, then `$(call +at.out2src,files...)` is a no-op, but otherwise it takes a (possibly +relative) path in `$(outdir)`, and transforms it to the equivalent +filename in `$(srcdir)`. + +`$(call at.addprefix,dir,files...)` takes a directory and a list of +filenames, and looks at each filename; if it is an absolute path, it +passes it through (well, "only" normalizes it); if the filename is a +relative path, it is joined with the given base directory. + +## Modules to provide feature sets + +The module system serves two purposes + + 1. Allow your developers to share logic between Makefiles in multiple + directories. + 2. Allow your developers to import "standard" modules implementing + common feature sets, so they don't have to. + +Distributed along with autothing are some "standard" modules that +provide commonly desired functionality from Makefiles; tricky little +things that your developers shouldn't have to implement themselves for +every project; the things that GNU Automake would take care of if you +used Automake (a piece of software that Autothing hopes to replace). + +The module system is conceptually quite simple: have 4 directories for +`.mk` makefile snippets that get included at certain points: + + Makefile.once.head/*.mk + + Makefile.each.head/*.mk + a/Makefile + Makefile.each.tail/*.mk + + Makefile.each.head/*.mk + b/Makefile + Makefile.each.tail/*.mk + + Makefile.each.head/*.mk + c/Makefile + Makefile.each.tail/*.mk + + Makefile.once.tail/*.mk + +Deciding which of the 4 directories to put your snippets in... you'll +figure it out pretty quickly once you start playing with it. + +Beyond these 4 directories, Autothing itself imposes no structure, but +there are some conventions that are followed by the distributed along +with Autothing, and I recommend that your developers follow. + +Each of the `.mk` files is name `NN-MODULE.mk` where NN is a number +(to affect the order that the module files are evaluated in, in case +of dependencies between them), and MODULE is the module name. Each +module has "public" variables prefixed with `MODULE.`, and "private" +variables prefixed with `_MODULE.` (again, "MODULE" being the module +name). For example, the "groups" parameter of the "files" module is +configured via the `files.groups` variable. Within this convention, +Autothing presents itself as a pseudo-module named "at"; that is, +public Autothing variables are prefixed with `at.`. + +If you follow these conventions, then the "mod" module distributed +along with Autothing can display information about the modules that a +project uses, and documentation on each module. Running the command +`make at-modules` (implemented by the "mod" module) will produce a +list of the modules present in a project, and short descriptions of +them: + + $ make at-modules + Autothing modules used in this project: + - dist `dist` target for distribution tarballs (more) + - files Keeping track of groups of files (more) + - gitfiles Automatically populate files.src.src from git (more) + - gnuconf GNU standard configuration variables (more) + - mod Display information about Autothing modules (more) + - nested Easy nested .PHONY targets (more) + - quote Macros to quote tricky strings (more) + - texinfo The GNU documentation system (more) + - var Depend on the values of variables (more) + - write-atomic `write-atomic` auxiliary build script (more) + - write-ifchanged `write-ifchanged` auxiliary build script (more) + +The "(more)" at the end of a line indicates that there is further +documentation for that module, which can be produced by running the +command `make at-modules/MODULE_NAME`. See the output of `make +at-modules/mod` for instructions on how to produce this further +documentation for modules you develop. + +Besides the "mod" module, the set modules distributed along with +Autothing primarily exists to provide the bits of (sometimes somewhat +tricky) functionality required of Makefiles by the GNU Coding +Standards. Run the `at-modules` commands above for documentation on +each of them. + +Formal interface +---------------- + +System requirements: + - A version of GNU Make that supports `undefine` (ie, version 3.82 + and above). + + If the user attempts to use your Autothing-using Makefile with an + older version of GNU Make, `Makefile.head.mk` will print an error + message and refuse to proceed: + + $ make-3.81 + build-aux/Makefile.head.mk:58: *** Autothing: We need a version of Make that supports 'undefine'. Stop. + +Inputs: + - In each `Makefile`: + - Before `Makefile.head.mk`: + - Variable (mandatory) : `topoutdir` + - Variable (mandatory) : `topsrcdir` (must not be a subdirectory of `$(topoutdir)`) + - Variable (optional) : `at.Makefile` (Default: `Makefile`) + - Between `Makefile.head.mk` and `Makefile.tail.mk`: + - Variable: `at.targets` (Default: empty) + - Variable: `at.subdirs` (Default: empty) + - Files: + - `${topsrcdir}/build-aux/Makefile.{each,once}.{head,tail}/*.mk` + + Unfortunately, a limitation of Autothing is that it does require a + designated "top" directory; it can't be used to have a sub-project + that can also be totally separate and built alone. In your + Makefiles, before you include `Makefile.head.mk`, you must tell + Autothing what the top directory is by setting `topoutdir` and + `topsrcdir`. + + If you wish for your per-directory Makefiles to have a name other + than `Makefile` (such as `GNUmakefile` or `makefile`, which GNU Make + also looks for by default; or another name for project-specific + reasons), Autothing supports this by setting the `at.Makefile` + variable. Unfortunately, Autothing does not support having a list + of filenames to try; so one must be consistent about the filename + throughout the project. + + In the body of each Makefile, you may set the `at.targets` variable + to list which targets should have access to the variables defined in + the body of that Makefile. + + In the body of each Makefile, you may set the `at.subdirs` variable + to list of directories which have their own Makefile which produces + targets that targets in this directory depend on. Directories + listed in `at.subdirs` may be relative or absolute; if relative, + they are interpreted as relative to `$(outdir)`. + +Outputs: + - Global: + - Variable (function): `$(call at.is_subdir, parent, child)` + - Variable (function): `$(call at.is_strict_subdir, parent, child)` + - Variable (function): `$(call at.relbase, parent, children...)` + - Variable (function): `$(call at.relto, parent, children...)` + - Variable (function): `$(call at.path, paths...)` + - Variable (function): `$(call at.out2src, paths...)` + - Variable (function): `$(call at.addprefix, prefix, paths...)` + - Variable : `$(at.nl)` # a single newline + - Per-directory: + - Variable: `$(outdir)` + - Variable: `$(srcdir)` + + For dealing with path normalization problems that arise because of + the way Autothing inclusions work, several global functions are + provided for dealing with paths; see the above "Tools for dealing + with paths" section for documentation on each of these functions. + + For convenience, it also provides `$(at.nl)` which is a single + newline, as newlines are very difficult to type in Make variable + values. + +Tips, notes +----------- + +If you use Autoconf (or similar), I recommend having a file at +`$(topsrcdir)/config.mk.in` of the form + + ifeq ($(origin topsrcdir),undefined) + topoutdir := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + topsrcdir := $(topoutdir)/@top_srcdir@ + + # Any other global variables you might want to set + + endif + +Then have `./configure` generate `$(topoutdir)/config.mk` from it by +placing `AC_CONFIG_FILES([config.mk])` in your `configure.ac`. I +recommend that you have `config.mk` be the _only_ Makefile edited by +`./configure`; which will require manual support to have `./configure` +link/copy the Makefiles unedited into `$(topoutdir)`; you can do this +by placing something like this in your `configure.ac`: + + AC_OUTPUT([], [], [ + if test "$srcdir" != .; then + find "$srcdir" -name Makefile -printf '%P\n' \ + | while read -r filename; do + mkdir -p "\$(dirname "\$filename")" + ln -srfT "$srcdir/\$filename" "\$filename" + done + fi + ]) + +This will allow you to write your Makefiles in the form: + + include $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk + include $(topsrcdir)/build-aux/Makefile.head.mk + + # your Makefile here + + include $(topsrcdir)/build-aux/Makefile.tail.mk + +Where you only need to adjust the number of `../` segments in the +first line based on how deep that directory is. + +Further development +------------------- + +Most of the modules distributed along with Autothing have the goal of +combining to provide the things that the GNU Coding Standards require. +Between `gnuconf`, `dist`, `files`, and `texinfo`; the GNU Coding +Standards for Makefiles are nearly entirely satisfied. However, there +are a few targets that are required, but aren't implemented by a +module (yet!): + + - `install-strip` + - `TAGS` + - `check` + - `installcheck` (optional, but recommended) + +TODO +---- + + - Write documentation on `srcdir`, `outdir`, and out-of-tree builds; + I don't think discussions involving the separate `srcdir` and + `outdir` make much sense without that context. + +Bugs/Limitations +---------------- + + - This documentation file is almost three times as long as the code + that it documents. + + - The "parse time" for projects with hundreds of sub-directories + (each having a Makefile) can be slow (ex: a project with 166 + directories has a parse time of around 12 seconds on my box). I + blame GNU Make's garbage collector; I don't think it was ever + designed to deal with as much "garbage" as Autothing's variable + namespacing throws at it. + + - Requires a designated "top" directory; see discussion above. + + - Does not support varying per-directory Makefile names; see + discussion above. + +---- +Copyright (C) 2016-2017 Luke Shumaker + +This documentation file is placed into the public domain. If that is +not possible in your legal system, I grant you permission to use it in +absolutely every way that I can legally grant to you. diff --git a/build-aux/Makefile.each.head/.gitignore b/build-aux/Makefile.each.head/.gitignore new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/build-aux/Makefile.each.head/.gitignore diff --git a/build-aux/Makefile.each.head/00-dist.mk b/build-aux/Makefile.each.head/00-dist.mk new file mode 100644 index 0000000..924d79a --- /dev/null +++ b/build-aux/Makefile.each.head/00-dist.mk @@ -0,0 +1,23 @@ +# 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/>. + +mod.dist.depends += files + +ifeq ($(outdir),$(topoutdir)) +files.out.int += $(addprefix $(dist.pkgname)-*,$(dist.exts) .tar /) .tmp.$(dist.pkgname)-*/ +endif + +$(outdir)/dist: $(addprefix $(topoutdir)/$(dist.pkgname)-$(dist.version),$(dist.exts)) +.PHONY: $(outdir)/dist diff --git a/build-aux/Makefile.each.head/00-files.mk b/build-aux/Makefile.each.head/00-files.mk new file mode 100644 index 0000000..c4820cf --- /dev/null +++ b/build-aux/Makefile.each.head/00-files.mk @@ -0,0 +1,32 @@ +# 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/>. + +files.src.src ?= +files.src.int ?= +files.src.cfg ?= +files.src.gen ?= + +files.out.slow ?= +files.out.int ?= +files.out.cfg ?= + +# define files.out.$(group) files.sys.$(group) for every files.group +$(eval $(foreach t,$(files.groups),files.out.$t ?=$(at.nl)files.sys.$t ?=$(at.nl))) + +# define files.src, files.out, and files.sys aggregates +$(eval \ + files.src = $$(sort $(foreach _files.v,$(filter files.src.%,$(.VARIABLES)),$$($(_files.v))))$(at.nl)\ + files.out = $$(sort $(foreach _files.v,$(filter files.out.%,$(.VARIABLES)),$$($(_files.v))))$(at.nl)\ + files.sys = $$(sort $(foreach _files.v,$(filter files.sys.%,$(.VARIABLES)),$$($(_files.v))))) diff --git a/build-aux/Makefile.each.head/00-gitfiles.mk b/build-aux/Makefile.each.head/00-gitfiles.mk new file mode 100644 index 0000000..b872912 --- /dev/null +++ b/build-aux/Makefile.each.head/00-gitfiles.mk @@ -0,0 +1,20 @@ +# 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/>. + +ifeq ($(abspath $(topsrcdir)),$(abspath $(srcdir))) +files.src.gen += $(gitfiles.file) +endif + +files.src.src += $(_gitfiles.dir.src) diff --git a/build-aux/Makefile.each.head/00-nested.mk b/build-aux/Makefile.each.head/00-nested.mk new file mode 100644 index 0000000..4325825 --- /dev/null +++ b/build-aux/Makefile.each.head/00-nested.mk @@ -0,0 +1,16 @@ +# 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/>. + +nested.subdirs ?= diff --git a/build-aux/Makefile.each.head/00-texinfo.mk b/build-aux/Makefile.each.head/00-texinfo.mk new file mode 100644 index 0000000..88aaeb5 --- /dev/null +++ b/build-aux/Makefile.each.head/00-texinfo.mk @@ -0,0 +1,16 @@ +# 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/>. + +texinfo.docs ?= diff --git a/build-aux/Makefile.each.tail/.gitignore b/build-aux/Makefile.each.tail/.gitignore new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/build-aux/Makefile.each.tail/.gitignore diff --git a/build-aux/Makefile.each.tail/00-dist.mk b/build-aux/Makefile.each.tail/00-dist.mk new file mode 100644 index 0000000..b023e80 --- /dev/null +++ b/build-aux/Makefile.each.tail/00-dist.mk @@ -0,0 +1 @@ +_dist.files := $(strip $(_dist.files) $(call at.addprefix,$(srcdir),$(filter-out $(files.src.int),$(files.src)))) diff --git a/build-aux/Makefile.each.tail/00-mod.mk b/build-aux/Makefile.each.tail/00-mod.mk new file mode 100644 index 0000000..d6514dd --- /dev/null +++ b/build-aux/Makefile.each.tail/00-mod.mk @@ -0,0 +1,44 @@ +# 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/>. + +$(outdir)/at-variables $(outdir)/at-variables-local: _mod.VARIABLES := $(filter-out $(call quote.pattern,$(_at.VARIABLES)),$(.VARIABLES)) +$(outdir)/at-variables-global: + @printf '%s\n' $(call quote.shell-each,$(sort $(.VARIABLES))) +$(outdir)/at-variables-local: + @printf '%s\n' $(call quote.shell-each,$(sort $(_mod.VARIABLES))) +$(outdir)/at-variables $(outdir)/at-values: + @printf '%s\n' $(call quote.shell-each,$(sort $(.VARIABLES),$(_mod.VARIABLES))) +$(outdir)/at-variables/%: + @printf '%s\n' $(call quote.shell,$($*)) +$(outdir)/at-values/%: + @printf '%s\n' $(call quote.shell,$(value $*)) +.PHONY: $(addprefix $(outdir)/, at-variables-global at-variables-local at-variables at-values) +at.targets += $(addprefix $(outdir)/, at-variables-global at-variables-local at-variables at-values at-variables/% at-values/%) + +$(outdir)/at-modules: + @printf 'Autothing modules used in this project:\n' + @printf ' - %s\n' $(foreach _mod.tmp,$(_mod.modules),$(call quote.shell,$(_mod.tmp) $(mod.$(_mod.tmp).description) $(if $(mod.$(_mod.tmp).doc),(more))))|column -t -s $$'\t' +$(addprefix $(outdir)/at-modules/,$(_mod.modules)): $(outdir)/at-modules/%: + @printf 'Name : %s\n' $(call quote.shell,$*) + @printf 'Description : %s\n' $(call quote.shell,$(mod.$*.description)) + @echo 'Depends on :' $(sort $(mod.$*.depends)) + @echo 'Files :' + @printf ' %s\n' $(call quote.shell-each,$(call at.relto,$(topsrcdir),$(sort $(mod.$*.files) $(wildcard $(topsrcdir)/build-aux/Makefile.*/??-$*.mk)))) + @echo 'Documentation :' + @printf '%s\n' $(call quote.shell,$(mod.$*.doc)) | sed -e 's/^# / /' -e 's/^#//' + +$(outdir)/at-noop: +.PHONY: $(outdir)/at-noop +at.targets += $(outdir)/at-noop diff --git a/build-aux/Makefile.each.tail/00-var.mk b/build-aux/Makefile.each.tail/00-var.mk new file mode 100644 index 0000000..954defb --- /dev/null +++ b/build-aux/Makefile.each.tail/00-var.mk @@ -0,0 +1,22 @@ +# 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.depends += files quote write-ifchanged + +$(outdir)/.var.%: _var.FORCE + @printf '%s' $(call quote.shell,$($*)) | sed 's/^/#/' | $(WRITE_IFCHANGED) $@ +-include $(wildcard $(outdir)/.var.*) + +files.out.int += .var.* diff --git a/build-aux/Makefile.each.tail/10-files.mk b/build-aux/Makefile.each.tail/10-files.mk new file mode 100644 index 0000000..e22b216 --- /dev/null +++ b/build-aux/Makefile.each.tail/10-files.mk @@ -0,0 +1,57 @@ +# 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/>. +# Add some more defaults to the *_files variables + +$(eval \ + $(foreach _files.var,$(filter files.src files.src.%,$(.VARIABLES)),\ + _$(_files.var) = $$(call at.addprefix,$$(srcdir),$$($(_files.var)))$(at.nl))\ + $(foreach _files.var,$(filter files.out files.out.%,$(.VARIABLES)),\ + _$(_files.var) = $$(call at.addprefix,$$(outdir),$$($(_files.var)))$(at.nl))\ + $(foreach _files.var,$(filter files.sys files.sys.%,$(.VARIABLES)),\ + _$(_files.var) = $$(addprefix $$(DESTDIR),$$($(_files.var)))$(at.nl))) + +_files.all = $(_files.src) $(_files.out) $(_files.sys) + +at.targets += $(subst *,%,$(_files.all)) + +# Creative targets +$(outdir)/$(files.generate): $(_files.src.gen) $(_files.src.cfg) +$(outdir)/install: $(_files.sys.$(files.default)) +$(outdir)/installdirs: $(sort $(dir $(_files.sys))) +$(eval \ + $(foreach _files.g,$(files.groups),\ + $$(outdir)/$(_files.g): $$(_files.out.$(_files.g))$(at.nl))\ + $(foreach _files.g,$(filter-out $(files.default),$(files.groups)),\ + $$(outdir)/install-$(_files.g): $$(_files.sys.$(_files.g))$(at.nl))) + +# Destructive targets +# +# We do our on $(srcdir) / $(outdir) prefixing here because +# at.addprefix (while necessary for dependency lists) doesn't preserve +# trailing slashes, which we care about here; while also not caring +# about the path normalization that at.addprefix does. +_files.uninstall = $(addprefix $(DESTDIR),$(files.sys)) +_files.mostlyclean = $(addprefix $(srcdir)/,$(filter-out $(files.out.slow) $(files.out.cfg),$(files.out))) +_files.clean = $(addprefix $(srcdir)/,$(filter-out $(files.out.cfg),$(files.out))) +_files.distclean = $(addprefix $(srcdir)/, $(files.out)) +_files.maintainer-clean = $(files.distclean) $(addprefix $(srcdir)/,$(filter-out $(files.src.cfg) $(files.src.src),$(files.src))) +_files.$(files.vcsclean) = $(files.distclean) $(addprefix $(srcdir)/,$(filter-out $(files.src.src),$(files.src))) +$(addprefix $(outdir)/,uninstall mostlyclean clean distclean maintainer-clean $(files.vcsclean)): %: %-hook + $(call _files.XARGS,$(RM) -- {}, $(sort $(filter-out %/,$(_files.$(@F)))) ) + $(call _files.XARGS,$(RM) -r -- {}, $(sort $(filter %/,$(_files.$(@F)))) ) + $(call _files.XARGS,$(RMDIR_P) -- {} 2>/dev/null || true,$(filter-out ./,$(sort $(dir $(_files.$(@F)))))) +$(addprefix $(outdir)/,maintainer-clean $(files.vcsclean)): _files.maintainer-clean-warning +$(foreach t,uninstall mostlyclean clean distclean maintainer-clean $(files.vcsclean), $(outdir)/$t-hook):: +.PHONY: $(foreach t,uninstall mostlyclean clean distclean maintainer-clean $(files.vcsclean), $(outdir)/$t-hook) diff --git a/build-aux/Makefile.each.tail/10-nested.mk b/build-aux/Makefile.each.tail/10-nested.mk new file mode 100644 index 0000000..667ec6f --- /dev/null +++ b/build-aux/Makefile.each.tail/10-nested.mk @@ -0,0 +1,21 @@ +# 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/>. + +$(eval $(foreach _tmp.nested,$(nested.targets),\ + $$(outdir)/$(_tmp.nested): $$(addsuffix /$(_tmp.nested),$$(call at.addprefix,$$(outdir),$$(nested.subdirs)))$(at.nl))) +.PHONY: $(addprefix $(outdir)/,$(nested.targets)) + +at.subdirs += $(nested.subdirs) +at.targets += $(addprefix $(outdir)/,$(nested.targets)) diff --git a/build-aux/Makefile.each.tail/11-texinfo.mk b/build-aux/Makefile.each.tail/11-texinfo.mk new file mode 100644 index 0000000..1ee5843 --- /dev/null +++ b/build-aux/Makefile.each.tail/11-texinfo.mk @@ -0,0 +1,38 @@ +# 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/>. + +$(outdir)/info : $(addsuffix .info,$(texinfo.docs)) +files.src.gen += $(addsuffix .info,$(texinfo.docs)) +files.out.dvi += $(addsuffix .dvi ,$(texinfo.docs)) +files.out.html += $(addsuffix .html,$(texinfo.docs)) +files.out.pdf += $(addsuffix .pdf ,$(texinfo.docs)) +files.out.ps += $(addsuffix .ps ,$(texinfo.docs)) + +files.sys.all += $(foreach f,$(texinfo.docs), $(infodir)/$f.info ) +files.sys.dvi += $(foreach f,$(texinfo.docs), $(dvidir)/$f.dvi ) +files.sys.html += $(foreach f,$(texinfo.docs), $(htmldir)/$f.html ) +files.sys.pdf += $(foreach f,$(texinfo.docs), $(pdfdir)/$f.pdf ) +files.sys.ps += $(foreach f,$(texinfo.docs), $(psdir)/$f.ps ) + +$(outdir)/%.info: $(srcdir)/%.texi; $(MAKEINFO) -o $(@D) $< +$(outdir)/%.info: $(outdir)/%.texi; $(MAKEINFO) -o $(@D) $< +$(outdir)/%.dvi : $(srcdir)/%.texi; $(TEXI2DVI) -o $(@D) $< +$(outdir)/%.dvi : $(outdir)/%.texi; $(TEXI2DVI) -o $(@D) $< +$(outdir)/%.html: $(srcdir)/%.texi; $(TEXI2HTML) -o $(@D) $< +$(outdir)/%.html: $(outdir)/%.texi; $(TEXI2HTML) -o $(@D) $< +$(outdir)/%.pdf : $(srcdir)/%.texi; $(TEXI2PDF) -o $(@D) $< +$(outdir)/%.pdf : $(outdir)/%.texi; $(TEXI2PDF) -o $(@D) $< +$(outdir)/%.ps : $(srcdir)/%.texi; $(TEXI2PS) -o $(@D) $< +$(outdir)/%.ps : $(outdir)/%.texi; $(TEXI2PS) -o $(@D) $< diff --git a/build-aux/Makefile.head.mk b/build-aux/Makefile.head.mk new file mode 100644 index 0000000..6ac3d49 --- /dev/null +++ b/build-aux/Makefile.head.mk @@ -0,0 +1,116 @@ +# 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/>. + +at.Makefile ?= Makefile +_at.MAKEFILE_LIST ?= +_at.MAKEFILE_LIST := $(strip $(_at.MAKEFILE_LIST) $(lastword $(filter %/$(at.Makefile),$(abspath $(MAKEFILE_LIST))))) + +# This bit only gets evaluated once, at the very beginning +ifeq ($(origin _at.NO_ONCE),undefined) + +# Internal functions ################################################### + +# These 4 functions are all $(call _at.func,parent,child) +_at.is_strict_subdir = $(filter $(abspath $1)/%,$(abspath $2)) +_at.is_subdir = $(filter $(abspath $1)/%,$(abspath $2)/.) +_at.relbase = $(strip \ + $(if $(call _at.is_subdir,$1,$2), \ + $(patsubst %/.,%,$(patsubst $(abspath $1)/%,%,$(abspath $2)/.)), \ + $(abspath $2))) +_at.relto = $(strip \ + $(if $(call _at.is_subdir,$1,$2), \ + $(patsubst %/.,%,$(patsubst $(abspath $1)/%,%,$(abspath $2)/.)), \ + ../$(call _at.relto,$(dir $(abspath $1)),$2))) + +# These 3 functions only take one operand; we define public multi-operand +# versions below. +_at.path = $(strip $(or \ + $(if $(call _at.is_subdir, . ,$1), $(call _at.relto, . ,$1) ), \ + $(if $(call _at.is_subdir,$(topoutdir),$1),$(patsubst %/.,%,$(topoutdir)/$(call _at.relto,$(topoutdir),$1))), \ + $(if $(call _at.is_subdir,$(topsrcdir),$1),$(patsubst %/.,%,$(topsrcdir)/$(call _at.relto,$(topsrcdir),$1))), \ + $(abspath $1))) +_at.out2src = $(call _at.path,$(strip \ + $(if $(call _at.is_subdir,$(topoutdir),$1), \ + $(topsrcdir)/$(call _at.relto,$(topoutdir),$1), \ + $1))) +_at.addprefix = $(call _at.path,$(if $(filter-out /%,$2),$1/$2,$2)) + +_at.rest = $(wordlist 2,$(words $1),$1) +_at.reverse = $(if $1,$(call _at.reverse,$(_at.rest))) $(firstword $1) + +_at.target_variable = $(_at.target_variable.$(flavor $2)) +_at.target_variable.recursive = $1: private $2 = $(subst $(at.nl),$$(at.nl),$(value $2)) +_at.target_variable.simple = $1: private $2 := $$($2) + +_at.quote-pattern = $(subst %,\%,$(subst \,\\,$1)) + +# Sanity checking ###################################################### +ifeq ($(filter undefine,$(.FEATURES)),) +$(error Autothing: We need a version of Make that supports 'undefine') +endif +ifeq ($(topsrcdir),) +$(error Autothing: topsrcdir must be set (and non-empty) before including Makefile.head.mk) +endif +ifeq ($(topoutdir),) +$(error Autothing: topoutdir must be set (and non-empty) before including Makefile.head.mk) +endif +ifneq ($(call _at.is_strict_subdir,$(topoutdir),$(topsrcdir)),) +$(error Autothing: topsrcdir=$(topsrcdir) must not be a subdirectory of topoutdir=$(topoutdir)) +endif + +# External provisions ################################################## + +# These 4 functions are all $(call _at.func,parent,child) +at.is_subdir = $(_at.is_subdir) +at.is_strict_subdir = $(_at.is_strict_subdir) +#at.relbase = $(if $2,$(shell realpath -sm --relative-base=$1 -- $2)) +at.relbase = $(foreach _at.tmp,$2,$(call _at.relbase,$1,$(_at.tmp))) +#at.relto = $(if $2,$(shell realpath -sm --relative-to=$1 -- $2)) +at.relto = $(foreach _at.tmp,$2,$(call _at.relto,$1,$(_at.tmp))) + +at.path = $(foreach _at.tmp,$1,$(call _at.path,$(_at.tmp))) +at.out2src = $(foreach _at.tmp,$1,$(call _at.out2src,$(_at.tmp))) +at.addprefix = $(foreach _at.tmp,$2,$(call _at.addprefix,$1,$(_at.tmp))) + +define at.nl + + +endef + +# Include modules ###################################################### +include $(sort $(wildcard $(topsrcdir)/build-aux/Makefile.once.head/*.mk)) +_at.tmp_targets = +_at.tmp_subdirs = +_at.VARIABLES = +_at.VARIABLES := $(.VARIABLES) + +endif # _at.NO_ONCE + +# This bit gets evaluated for each Makefile + +outdir := $(call _at.path,$(dir $(lastword $(_at.MAKEFILE_LIST)))) +ifeq ($(call _at.is_subdir,$(topoutdir),$(outdir)),) +$(error Autothing: not a subdirectory of topoutdir=$(topoutdir): $(outdir)) +endif + +srcdir := $(call _at.out2src,$(outdir)) +ifeq ($(call _at.is_subdir,$(topsrcdir),$(srcdir)),) +$(error Autothing: not a subdirectory of topsrcdir=$(topsrcdir): $(srcdir)) +endif + +at.subdirs = +at.targets = + +include $(sort $(wildcard $(topsrcdir)/build-aux/Makefile.each.head/*.mk)) diff --git a/build-aux/Makefile.once.head/.gitignore b/build-aux/Makefile.once.head/.gitignore new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/build-aux/Makefile.once.head/.gitignore 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/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..55c41cb --- /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),$(subst {},$(strip $2),$1)) + +_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-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))) diff --git a/build-aux/Makefile.once.tail/.gitignore b/build-aux/Makefile.once.tail/.gitignore new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/build-aux/Makefile.once.tail/.gitignore diff --git a/build-aux/Makefile.once.tail/00-dist.mk b/build-aux/Makefile.once.tail/00-dist.mk new file mode 100644 index 0000000..59a7dc3 --- /dev/null +++ b/build-aux/Makefile.once.tail/00-dist.mk @@ -0,0 +1,31 @@ +# 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/>. + +# NB: intentionally resolve symlinks (tack on the -P flag to `cp` to +# not resolve them). The GNU Coding Standards say to avoid symlinks +# in tarballs. +_dist.copyfile = $(MKDIR_P) $(dir $2) && $(CP) -T $1 $2 +_dist.addfile = $(call _dist.copyfile,$3,$2/$(call at.relto,$1,$3)) +$(topoutdir)/$(dist.pkgname)-$(dist.version): $(_dist.files) + $(RM) -r $@ $(@D)/.tmp.$(@F) + $(MKDIR) $(@D)/.tmp.$(@F) + $(foreach f,$^,$(call _dist.addfile,$(topsrcdir),$(@D)/.tmp.$(@F),$f)$(at.nl)) + $(MV) $(@D)/.tmp.$(@F) $@ || $(RM) -r $(@D)/.tmp.$(@F) + +# TODO: The tar rule isn't reproducible, it should be. +$(topoutdir)/$(dist.pkgname)-$(dist.version).tar: %.tar: % + $(TAR) cf $@ -C $(<D) $(<F) +$(topoutdir)/$(dist.pkgname)-$(dist.version).tar.gz: %.gz: % + $(GZIP) $(GZIPFLAGS) < $< > $@ diff --git a/build-aux/Makefile.tail.mk b/build-aux/Makefile.tail.mk new file mode 100644 index 0000000..2e4adc6 --- /dev/null +++ b/build-aux/Makefile.tail.mk @@ -0,0 +1,40 @@ +# 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/>. + +# This bit gets evaluated for each Makefile processed + +include $(call _at.reverse,$(sort $(wildcard $(topsrcdir)/build-aux/Makefile.each.tail/*.mk))) + +_at.tmp_targets := $(at.targets) +_at.tmp_subdirs := $(call at.addprefix,$(outdir),$(at.subdirs)) + +# Clean the environment +$(eval \ + $(foreach _at.tmp_variable,$(filter-out $(call _at.quote-pattern,_at.tmp_variable $(_at.VARIABLES)),$(.VARIABLES)),\ + $(call _at.target_variable,$(_at.tmp_targets),$(_at.tmp_variable))$(at.nl)\ + undefine $(_at.tmp_variable)$(at.nl))) + +# Recurse +$(foreach _at.NO_ONCE,y,\ + $(foreach _at.tmp,$(call at.path,$(addsuffix /$(at.Makefile),$(_at.tmp_subdirs))),\ + $(if $(filter-out $(_at.MAKEFILE_LIST),$(abspath $(_at.tmp))),\ + $(eval include $(_at.tmp))))) + +# This bit only gets evaluated once, after all of the other Makefiles are read +ifeq ($(origin _at.NO_ONCE),undefined) + +include $(call _at.reverse,$(sort $(wildcard $(topsrcdir)/build-aux/Makefile.once.tail/*.mk))) + +endif # _at.NO_ONCE diff --git a/build-aux/write-atomic b/build-aux/write-atomic new file mode 100755 index 0000000..ab2a417 --- /dev/null +++ b/build-aux/write-atomic @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# 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/>. + +outfile=$1 +tmpfile="$(dirname "$outfile")/.tmp.${outfile##*/}.tmp" + +cat > "$tmpfile" || { r=$?; rm -f "$tmpfile"; exit $r; } +mv -f "$tmpfile" "$outfile" diff --git a/build-aux/write-ifchanged b/build-aux/write-ifchanged new file mode 100755 index 0000000..84dfd6e --- /dev/null +++ b/build-aux/write-ifchanged @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Copyright (C) 2015 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/>. + +outfile=$1 +tmpfile="$(dirname "$outfile")/.tmp.${outfile##*/}.tmp" + +cat > "$tmpfile" || exit $? +if cmp -s "$tmpfile" "$outfile"; then + rm -f "$tmpfile" || : +else + mv -f "$tmpfile" "$outfile" +fi diff --git a/config.mk.in b/config.mk.in new file mode 100644 index 0000000..be95ab4 --- /dev/null +++ b/config.mk.in @@ -0,0 +1,198 @@ +# 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/>. + +# This is based on §7.2 "Makefile Conventions" of the July 25, 2016 +# release of the GNU Coding Standards. +# +# Grep for '^##' in this file to see which Autoconf macros it depends +# on. + +dist.pkgname = @PACKAGE_TARNAME@ +gnuconf.pkgname = @PACKAGE_NAME@ + +# 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? + +## AC_PROG_AWK +## AC_PROG_GREP +## AC_PROG_EGREP +## AC_PROG_SED + +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. + +## AC_PROG_INSTALL # @INSTALL@ @INSTALL_PROGRAM@ @INSTALL_SCRIPT@ @INSTALL_DATA@ +## AC_PROG_LEX # @LEX@ @LEXLIB@ +## AC_PROG_RANLIB +## AC_PROG_YACC +## AC_PROG_CC +# +# TODO: What causes Autoconf to define @AR@? + +AR = @AR@ +ARFLAGS = +BISON = bison +BISONFLAGS = +CC = @CC@ +CFLAGS = @CFLAGS@ # CFLAGS instead of CCFLAGS +FLEX = flex +FLEXFLAGS = +INSTALL = @INSTALL@ +# There is no INSTALLFLAGS[0] +LD = ld +LDFLAGS = @LDFLAGS@ +LDCONFIG = ldconfig # TODO[1] +LDCONFIGFLAGS = +LEX = @LEX@ +LFLAGS = #LFLAGS instead of LEXFLAGS +#MAKE +MAKEINFO = makeinfo +MAKEINFOFLAGS = +RANLIB = @RANLIB@ +RANLIBFLAGS = +TEXI2DVI = texi2dvi +TEXI2DVIFLAGS = +YACC = @YACC@ +YFLAGS = # YFLAGS instead of YACCFLAGS + +CPPFLAGS = @CPPFLAGS@ + +LN_S = @LN_S@ + +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.) + +# 7.2.3: Variables for Specifying Commands +# ---------------------------------------- + +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +# 7.2.5: Variables for Installation Directories +# --------------------------------------------- + +# Root for the installation +prefix = @prefix@ +exec_prefix = @exec_prefix@ +# Executable programs +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +# Data files (Autoconf won't support runstatedir until version 2.70) +datarootdir = @datarootdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +runstatedir = $(localstatedir)/run +# Specific types of files +includedir = @includedir@ +oldincludedir = @oldincludedir@ +docdir = @docdir@ +infodir = @infodir@ +htmldir = @htmldir@ +dvidir = @dvidir@ +pdfdir = @pdfdir@ +psdir = @psdir@ +libdir = @libdir@ +lispdir = $(datarootdir)/emacs/site-lisp +localedir = @localedir@ + +mandir = @mandir@ +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 = |