Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'build-aux')
-rw-r--r--build-aux/Makefile.2.in217
-rw-r--r--build-aux/Makefile.am182
-rw-r--r--build-aux/m4/calcdsl.m4105
-rwxr-xr-xbuild-aux/progtest-runner54
-rwxr-xr-xbuild-aux/suppmk-gen40
5 files changed, 598 insertions, 0 deletions
diff --git a/build-aux/Makefile.2.in b/build-aux/Makefile.2.in
new file mode 100644
index 0000000..10f17a0
--- /dev/null
+++ b/build-aux/Makefile.2.in
@@ -0,0 +1,217 @@
+# @configure_input@
+#
+# Compiles packages written in the Calc DSL.
+#
+# Copyright (C) 2018 R-T Specialty, LLC.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Note that this build process is unconventional in order to avoid the startup
+# costs that would be associated with executing dslc with each and every package
+# (see the other Makefile for more information). Therefore, everything is
+# written to .cqueue for later processing by dslc.
+#
+# The issue of re-building based on timestamps---which Make would normally take
+# care of exclusively---must also be given special care now that we are handling
+# the building separately from Make. Each enqueued request also touches the
+# destination file to update its timestamp, ensuring that it is seen by Make as
+# modified (as if it were compiled) and therefore will trigger the building of
+# the targets that depend upon it. In the case of the object files (xmlo), a
+# temporary file is created when it is enqueued. As part of the queued request
+# for compilation is a request to delete this temporary file. In the event that
+# the build fails, this temporary file will be seen and will force a rebuild of
+# the file, despite its timestamp.
+#
+# The same issue does not exist for xmle, js, and html files, since they have
+# linear dependency trees and dslc will rm the file on failure, which
+# obliterates the timestamp.
+# #
+
+path_rates := $(path_suppliers)/rates
+path_map := map
+path_c1map := $(path_map)/c1
+path_dsl := rater
+path_ui := ui
+path_suppliers := suppliers
+path_lv := lovullo
+path_srv := srv
+
+src_suppliers := $(wildcard $(path_suppliers)/*.xml)
+src_map := $(wildcard $(path_map)/*.xml)
+src_c1map := $(wildcard $(path_c1map)/*.xml)
+
+dest_summary_html := $(patsubst \
+ $(path_suppliers)/%.xml, \
+ $(path_suppliers)/%.html, \
+ $(src_suppliers))
+dest_standalone := $(patsubst \
+ $(path_suppliers)/%.xml, \
+ $(path_suppliers)/%.js, \
+ $(src_suppliers))
+dest_map := $(patsubst \
+ $(path_map)/%.xml, \
+ $(path_map)/%.xmle, \
+ $(src_map))
+dest_c1map := $(patsubst \
+ $(path_c1map)/%.xml, \
+ $(path_c1map)/%.php, \
+ $(src_c1map))
+
+compiled_suppliers := $(src_suppliers:.xml=.xmlo)
+linked_suppliers := $(src_suppliers:.xml=.xmle)
+
+comma := ,
+extless_supp_delim := $(subst .xml,,$(subst .xml ,$(comma),$(src_suppliers)))
+
+cqueue=.cqueue
+
+ant = @ANT@ -e
+
+.DELETE_ON_ERROR:
+
+.PHONY: default clean \
+ interp-rate-tables summary-html c1map \
+ standalones program-ui program-ui-immediate program-data-copy \
+ do-build version FORCE
+
+# these files will never be deleted when Make considers them to be intermediate
+# (e.g. when building summary pages), since they are still needed or take a
+# while to build
+.PRECIOUS: %.js %.xml %.xmle %.xmlo
+
+SHELL = /bin/bash -O extglob
+
+default: program-ui c1map FORCE
+
+program-ui: standalones ui/package.js ui/Program.js program-ui-immediate
+program-ui-immediate: ui/html/index.phtml
+
+include suppliers.mk
+
+# starts with a fresh cqueue
+prexmlo:
+ @>$(cqueue)
+
+summary-html: $(dest_summary_html) ;
+
+%.html: %.js
+ @echo "summary $*.xmle $@" >>.cqueue
+ @touch $@
+
+standalones: $(dest_standalone)
+%.xmle: %.xmlo
+ @echo "link $< $@" >>.cqueue
+ @touch $@
+%.js: %.xmle
+ @echo "standalone $< $@" >>.cqueue
+ @touch $@
+
+# C1 XML
+c1map: $(dest_c1map)
+%.php: %.xml
+ @echo "c1map $< $@" >>.cqueue
+ @touch $@
+
+%.dot: %.xmlo
+ @echo "dot $< $@" >> .cqueue
+%.dote: %.xmle
+ @echo "dot $< $@" >> .cqueue
+
+%.svg: %.dote
+ dot -Tsvg "$<" > "$@"
+%.svg: %.dot
+ dot -Tsvg "$<" > "$@"
+
+%.xml: %.dat
+ rater/tools/tdat2xml $< > $@
+
+%.xml: %.typelist
+ rater/tame/build-aux/list2typedef $(*F) < $< > $@
+
+%.csvo: %.csvm
+ rater/tools/csvm2csv $< > $@
+%.csvo: %.csvi
+ rater/tools/csvi $< > $@
+%.csvo: %.csv
+ cp $< $@
+
+%.xml: %.csvo
+ rater/tools/csv2xml $< > $@
+
+version: .version.xml
+.version.xml: FORCE
+ git log HEAD^.. -1 --pretty=format:'<version>%h</version>' > .version.xml
+
+ui/program.expanded.xml: ui/program.xml | .version.xml
+ @echo "progui-expand $< $@" >> .cqueue
+ui/Program.js: ui/program.expanded.xml ui/package.js
+ @echo "progui-class $< $@ include-path=../../../ui/" >> .cqueue
+ui/html/index.phtml: ui/program.expanded.xml
+ @echo "progui-html $< $@ out-path=./" >> .cqueue
+ui/package-dfns.xmlo: ui/package-dfns.xml
+ui/package-dfns.xml: ui/program.expanded.xml
+ @echo "progui-pkg $< $@" >> .cqueue
+ui/package-map.xmlo: ui/package-map.xml
+ui/package-map.xml: ui/program.expanded.xml ui/package-dfns.xml
+ @echo "progui-pkg-map $< $@" >> .cqueue
+
+# for the time being, this does not depend on clean-rate-tables because $(ant) will
+specs:
+ $(MAKE) -C doc/specs
+ #
+# this will eventually go away once we don't have X-repo klugery
+
+# for the time being, this does not depend on clean-rate-tables because ant will
+# run it
+clean:
+ find $(path_suppliers) $(path_map) $(path_c1map) common/ rater/core rater/lv \( \
+ -name '*.xmlo' \
+ -o -name '*.xmle' \
+ -o -name '*.js' \
+ -o -name '*.html' \
+ -o -name '*.dep' \
+ -o -name '*.tmp' \
+ \) -exec rm -v {} \;
+ rm -rf $(path_ui)/package-dfns.* \
+ $(path_ui)/package-map.* \
+ $(path_ui)/program.expanded.xml \
+ $(path_ui)/include.js \
+ $(path_ui)/Program.js \
+ $(path_ui)/html
+ find . -path '*/tables/*.csvm' -o -path '*/territories/*.dat' \
+ | sed 's/\.csvm$$/\.xml/; s/\.dat$$/\.xml/' \
+ | xargs rm -fv
+
+# generates a Makefile that will properly build all package dependencies; note
+# that territory and rate packages also have includes; see top of this file for
+# an explanation
+suppliers.mk:
+ $(ant) pkg-dep \
+ && mv $(path_ui)/program.dep $(path_ui)/package-dfns.dep
+ xmlo_cmd='@echo "validate $$(patsubst %.tmp,%.xml,$$<) $$@" >> .cqueue \
+ && echo "compile $$(patsubst %.tmp,%.xml,$$<) $$@" >> .cqueue \
+ && echo "rm $$(patsubst %.xmlo,%.tmp,$$@)" >> .cqueue \
+ && touch $$@ \
+ && touch -d +1sec $$(patsubst %.xmlo,%.tmp,$$@) >> .cqueue' \
+ ./rater/tools/gen-make common/ $(path_suppliers)/ $(path_dsl)/ $(path_map)/ $(path_ui)/ >$@
+
+me-a-sandwich:
+ @test $$EUID -eq 0 \
+ && echo 'You actually ran me as root? Are you insane!?' \
+ || echo 'Make it yourself.'
+
+# simply forces a job to run, thereby forcing the invocation of the secondary
+# Makefile (this is not explicitly required, because of prepare, but signifies
+# intent and is self-documenting)
+FORCE: ;
diff --git a/build-aux/Makefile.am b/build-aux/Makefile.am
new file mode 100644
index 0000000..4ddec3b
--- /dev/null
+++ b/build-aux/Makefile.am
@@ -0,0 +1,182 @@
+# @configure_input@
+#
+# TAME Makefile
+#
+# Copyright (C) 2018 R-T Specialty, LLC.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# This fragment exists as a kluge to provide support for running a command
+# after all targets have been run (in this case, dslc).
+#
+# A list of everything to be compiled is output into .cqueue, which is then
+# picked up by dslc; this avoids the overhead of starting the JVM,
+# recompiling XSL stylesheets, etc, which is quite substantial.
+#
+# !!! Unfortunately, this does not yet support parallel job execution.
+
+path_rates := $(path_suppliers)/rates
+path_map := map
+path_c1map := $(path_map)/c1
+path_dsl := rater
+path_ui := ui
+path_tests := test
+path_suppliers := suppliers
+path_lv := lovullo
+path_srv := srv
+path_lvroot := lvroot
+path_intralov_root := "intralov-root/@program@"
+
+.PHONY: FORCE prepare program-data-copy lvroot program-ui-immediate test
+
+JAVA_HEAP_SIZE ?= 5120M
+JAVA_STACK_SIZE ?= 5M
+
+.DELETE_ON_ERROR:
+
+# less verbose output; all to runlog
+define saneout
+ time -f 'total time: %E' awk ' \
+ BEGIN { e=0; w=0; } \
+ { printf "[%d] ", systime() >> ".runlog"; print >> ".runlog"; } \
+ /^~~~~\[begin /,/^~~~~\[end / { next } \
+ /^rm / { next } \
+ /^Exception|^\t+at / { \
+ if ( /^E/ ) { \
+ print; \
+ print "Stack trace written to .runlog"; \
+ } \
+ next; \
+ } \
+ /[Ww]arning:|[Nn]otice:/ { printf "\033[0;33m"; w++; out=1; } \
+ /[Ff]atal:/ { printf "\033[0;31m"; out=1; } \
+ /!|[Ee]rror:/ { printf "\033[0;31m"; e++; out=1; } \
+ /internal:/ { printf "\033[0;35m"; out=1; } \
+ /internal error:/ { printf "\033[1m"; out=1; } \
+ /^[^[]/ || out { print; printf "\033[0;0m"; out=0; } \
+ END { printf "%d error(s); %d warning(s).\n", e, w; } \
+ '
+endef
+
+define _go
+ touch .cqueue \
+ && ( test -s .cqueue || echo "Nothing to be done for \`$@'." ) \
+ && echo "$(JAVA_HEAP_SIZE) $(JAVA_STACK_SIZE)" \ \
+ && CLASSPATH="$(RATER_CLASSPATH):rater/src/dslc.jar" \
+ $(JAVA) -Xmx$(JAVA_HEAP_SIZE) -Xss$(JAVA_STACK_SIZE) \
+ com.lovullo.dslc.DslCompiler < .cqueue 2>&1 \
+ | $(saneout); \
+ exit $${PIPESTATUS[0]}; \
+ @>.cqueue
+endef
+
+SHELL = /bin/bash -O extglob
+
+all: program-data-copy
+
+program-ui-immediate:
+ @>.cqueue
+ @$(MAKE) --no-print-directory -f Makefile.2 program-ui-immediate
+ @$(MAKE) program-data-copy
+ @$(_go)
+
+program-data-copy:
+ @>.cqueue
+ @$(MAKE) --no-print-directory -f Makefile.2 standalones program-ui c1map
+ @$(_go)
+ mkdir -p "$(path_lv)/src/node/program/rater/programs/@program@"
+ mkdir -p "$(path_lv)/src/node/program/classify"
+ mkdir -p "$(path_lv)/src/node/program/ui/custom"
+ mkdir -p "$(path_lv)/src/_gen/scripts/program/@program@"
+ mkdir -p "$(path_lv)/src/_gen/views/scripts/quote/@program@"
+ mkdir -p "$(path_lv)/src/lib/c1/interfaces/c1/contract/@program@"
+ mkdir -p "$(path_lv)/misc/rater/programs"
+ mkdir -p "$(path_lv)/src/www/scripts/program"
+ cp -v .version.xml \
+ "$(path_lv)/misc/rater/programs/.version-@program@.xml"
+ cp -v "$(path_ui)/custom.js" \
+ "$(path_lv)/src/www/scripts/program/@program@.js"
+ cp -v "$(path_ui)/"!(custom|package|include).js \
+ "$(path_lv)/src/node/program/ui/custom/"
+ cp -v "$(path_srv)/rater.js" \
+ "$(path_lv)/src/node/program/rater/programs/@program@.js"
+ cp -v "$(path_ui)/package.js" \
+ "$(path_lv)/src/node/program/classify/@program@.js"
+ cp -v "$(path_ui)/"{Program,include,package}.js \
+ "$(path_lv)/src/_gen/scripts/program/@program@/"
+ cp -vr "$(path_ui)/html/"* \
+ "$(path_lv)/src/_gen/views/scripts/quote/@program@/"
+ cp -v "$(path_suppliers)/"*.js \
+ "$(path_lv)/src/node/program/rater/programs/@program@"
+ test ! -d "$(path_c1map)" || cp -v "$(path_c1map)/"*.php \
+ "$(path_lv)/src/lib/c1/interfaces/c1/contract/@program@/"
+ ant -f "$(path_lv)/build.xml" js-mod-order
+
+# TODO: merge this and the above
+lvroot: prepare
+ mkdir -p "$(path_lvroot)/src/node/program/rater/programs/@program@"
+ mkdir -p "$(path_lvroot)/src/node/program/classify"
+ mkdir -p "$(path_lvroot)/src/node/program/ui/custom"
+ mkdir -p "$(path_lvroot)/src/_gen/scripts/program/@program@"
+ mkdir -p "$(path_lvroot)/src/_gen/views/scripts/quote/@program@"
+ mkdir -p "$(path_lvroot)/src/www/scripts/program"
+ mkdir -p "$(path_lvroot)/src/lib/c1/interfaces/c1/contract/@program@"
+ cp -v "$(path_srv)/rater.js" \
+ "$(path_lvroot)/src/node/program/rater/programs/@program@.js"
+ cp -v "$(path_suppliers)/"*.js \
+ "$(path_lvroot)/src/node/program/rater/programs/@program@"
+ cp -v "$(path_ui)/package.js" \
+ "$(path_lvroot)/src/node/program/classify/@program@.js"
+ cp -v "$(path_ui)/"{Program,include,package}.js \
+ "$(path_lvroot)/src/_gen/scripts/program/@program@/"
+ cp -vr "$(path_ui)/html/"* \
+ "$(path_lvroot)/src/_gen/views/scripts/quote/@program@/"
+ cp -v "$(path_ui)/custom.js" \
+ "$(path_lvroot)/src/www/scripts/program/@program@.js"
+ cp -v "$(path_ui)/"*Ui.js \
+ "$(path_lvroot)/src/node/program/ui/custom/"
+ test ! -d "$(path_c1map)" || cp -v "$(path_c1map)/"*.php \
+ "$(path_lvroot)/src/lib/c1/interfaces/c1/contract/@program@/"
+
+intralov-root: summary-html
+ mkdir -p "$(path_intralov_root)/"{rater/scripts,suppliers}
+ ln -fL $(path_dsl)/summary.css "$(path_intralov_root)/rater"
+ ln -fL $(path_dsl)/scripts/*.js "$(path_intralov_root)/rater/scripts/"
+ ln -fL $(path_suppliers)/*.{html,js} "$(path_intralov_root)/suppliers"
+
+
+# because of the crazy wildcard target below, we want to ignore
+# some Automake-generated stuff
+%.am:
+%.m4:
+%.ac:
+
+%: prepare
+ @if [[ "$@" != [Mm]akefile ]]; then \
+ $(MAKE) --no-print-directory -f Makefile.2 $@; \
+ $(_go); \
+ fi
+
+clean:
+ $(MAKE) --no-print-directory -f Makefile.2 clean
+
+prepare: FORCE
+ @>.cqueue
+
+test: check
+check-am: standalones ui/package.js
+ @$(path_dsl)/build-aux/progtest-runner $(path_suppliers) $(path_tests)
+ @$(path_dsl)/build-aux/progtest-runner ui/package.xml $(path_tests)/ui
+
+FORCE: ;
diff --git a/build-aux/m4/calcdsl.m4 b/build-aux/m4/calcdsl.m4
new file mode 100644
index 0000000..18f8ab5
--- /dev/null
+++ b/build-aux/m4/calcdsl.m4
@@ -0,0 +1,105 @@
+# Common build configuration for TAME-based build systems
+#
+# Copyright (C) 2017 R-T Specialty, LLC.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# To use, include this in your configure.ac:
+# m4_define(`calc_root', path/to/calc/root)
+# m4_include([path/to/calc/root/build-aux/m4/calcdsl.m4])
+##
+
+# We use an M4 value (calc_root, specifically); this allows us to cleanly
+# reference it
+m4_pattern_allow([defn])
+
+# Initialize Automake, indicating that we use non-standard conventions
+AC_CONFIG_AUX_DIR(m4_defn(`calc_root')/build-aux)
+AM_INIT_AUTOMAKE([foreign])
+
+# Configuration values that can be provided via environment variables or the
+# command line at configure- or build-time.
+AC_ARG_VAR([JAVA], [The Java executable])
+AC_ARG_VAR([ANT], [Apache Ant])
+AC_ARG_VAR([DSLC_JAR], [Path to DSL Compiler JAR])
+AC_ARG_VAR([TAME], [Path to TAME])
+AC_ARG_VAR([RATER_CLASSPATH], [DSL Compiler Saxon class path])
+AC_ARG_VAR([PROGUI_TEST_PATH], [Path to JavaScript tests for Program UI])
+
+# Required version of TAME
+AC_SUBST([tame_needed_ver], [1.0.0])
+
+# Auto-discover Java and Ant paths
+AC_CHECK_PROGS(JAVA, [java])
+AC_CHECK_PROGS(ANT, [ant])
+
+AS_IF([test "$JAVA"],,
+ [AC_MSG_ERROR([missing java])])
+AS_IF([test "$ANT"],,
+ [AC_MSG_ERROR([missing ant])])
+
+# Automake runs before shell is available, thus the separate m4 variable
+CALCROOT="m4_defn(`calc_root')"
+
+# Checks to ensure that dslc is built, and gives instructions on how to
+# build it otherwise. We do not want to build that for them---that can be
+# added to a bootstrap script, but isn't permissible in build scripts.
+AS_IF([test ! "$DSLC_JAR"],
+ [AC_CHECK_FILE([$CALCROOT/src/dslc.jar],
+ [AC_SUBST([DSLC_JAR], [$CALCROOT/src/dslc.jar])],
+ [AC_MSG_ERROR(
+ [Please run `make` in $CALCROOT to build the DSL compiler.])])],
+ [])
+
+# TAME is the compiler (whereas dslc invokes it, keeps things in memory, etc)
+AS_IF([test ! "$TAME"],
+ [AC_CHECK_FILE([$CALCROOT/tame],
+ [AC_SUBST([TAME], [$CALCROOT/tame])],
+ [AC_MSG_ERROR(
+ [TAME not found])])],
+ [])
+
+AC_MSG_CHECKING([TAME version])
+
+AC_SUBST_FILE([tame_version])
+tame_version=$( cat "$TAME/VERSION" )
+
+# We get subtle errors or potential compiler bugs if the TAME version is
+# incorrect; check for >= the required version
+AS_VERSION_COMPARE([$tame_version], [$tame_needed_ver],
+ [
+ AC_MSG_RESULT([$tame_version])
+ AC_MSG_ERROR([TAME version $tame_needed_ver or greater required])
+ ],
+ [AC_MSG_RESULT([$tame_version])],
+ [AC_MSG_RESULT([$tame_version (>$tame_needed_ver)])])
+
+# @program@ in *.in files will be replaced with the program name provided by AC_INIT
+AC_SUBST([program], AC_PACKAGE_NAME)
+
+# Final files to be output by `configure'. The path before the colon is the
+# destination name; after the colon is the source.
+AC_CONFIG_FILES(Makefile:m4_defn(`calc_root')/build-aux/Makefile.in
+ Makefile.2:m4_defn(`calc_root')/build-aux/Makefile.2.in)
+
+# Generate configure script
+AC_OUTPUT
+
+# we want this to run as part of the configure script, not during M4
+# expansion
+"$CALCROOT/build-aux/suppmk-gen"
+
+AC_MSG_NOTICE([complete
+
+You may now run `make` to build.])
diff --git a/build-aux/progtest-runner b/build-aux/progtest-runner
new file mode 100755
index 0000000..306cddc
--- /dev/null
+++ b/build-aux/progtest-runner
@@ -0,0 +1,54 @@
+#!/bin/bash
+# Run test cases for supplier
+#
+# Copyright (C) 2018 R-T Specialty, LLC.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+declare path_suppliers="${1?Missing supplier path}"
+declare path_tests="${2?Missing supplier test path}"
+
+declare -i result=0
+
+declare suppliers
+
+# if a file was provided, use it as the sole supplier; otherwise,
+# treat it as a directory of suppliers
+if [ -f "$path_suppliers" ]; then
+ suppliers=( "$path_suppliers" )
+ path_suppliers=$( dirname "$path_suppliers" )
+else
+ suppliers=( "$path_suppliers"/*.xml )
+fi
+
+# run tests for each supplier individually
+for supplier in "${suppliers[@]}"; do
+ base=$( basename "$supplier" .xml )
+ tests=$( find -L "$path_tests"/"$base"/ -name '*.yml' )
+
+ echo
+ echo "$path_suppliers/$base"
+ sed 's/./=/g' <<< "$path_suppliers/$base"
+
+ test -n "$tests" || {
+ echo "error: missing test cases for $base!" >&2
+ exit 1
+ }
+
+ rater/tame/progtest/bin/runner "$path_suppliers/$base.js" $tests \
+ || result=1
+done
+
+exit $result
diff --git a/build-aux/suppmk-gen b/build-aux/suppmk-gen
new file mode 100755
index 0000000..36d5717
--- /dev/null
+++ b/build-aux/suppmk-gen
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Configuration script to be run before `make'
+#
+# Copyright (C) 2018 R-T Specialty, LLC.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+echo "Generating suppliers.mk..."
+# TODO: kluge; do properly.
+rm -f suppliers.mk
+make suppliers.mk
+
+# XXX: paths are hard-coded here!
+while read csv; do
+ csvbase="${csv%%.*}"
+ echo "$csvbase.xmlo: $csvbase.xml"
+ echo "$csvbase.xml: $csvbase.csvo"
+done < <( find suppliers common -regex '^.+\.csv.?$' ) \
+ >> suppliers.mk
+
+while read tdat; do
+ tbase="${tdat%%.*}"
+ echo "$tbase.xmlo: $tbase.xml rater/core/tdat.xmlo"
+ echo "$tbase.xml: $tdat"
+ echo -e "\trater/tools/tdat2xml \$< > \$@"
+done < <( find suppliers common -regex '^.+territories/.+\.dat$' ) \
+ >> suppliers.mk
+