Commits

Michael Forbes committed 36efb58

Initial version.

Comments (0)

Files changed (19)

.makefiles/Makefile

+# Simple makefile with common rules.
+
+makefiles_dir = .
+include rst2html.mk

.makefiles/Makefile.example

+## -*- mode: Makefile; fill-column: 80 -*-
+## Makefile based on the discussions here:
+## http://mad-scientist.net/make/multi-arch.html#explicitpath
+## http://gpwiki.org/index.php/Makefile
+
+## Conventions:
+# You need to do nothing but specify the libraries if you:
+# 1) Place all your "main" programs in $(mains_dir)=src/mains/
+# 2) Place all your source files and headers under $(src_dir)=src/
+# 3) You do not need to make libraries/archives.
+
+## Limitations:   
+## - Executables "name" must have corresponding source file "name.*"
+
+######## Project specifics
+# This section contains the names of source files, libraries etc. that will need
+# to be customized for each project.
+
+# LIBRARIES
+use_blacs =     false
+use_lapack =    false
+use_scalapack = false
+use_fft =       false
+use_pthread =   false
+use_math =      true
+use_armadillo = false
+use_gsl =       false
+use_boost =     false
+
+# FLAGS
+#DEBUG ?= false
+#OMP_NUM_THREADS = 1 
+#VERBOSITY = 1
+
+###########################################################################
+# You may not need to change anything else below. Some defaults are listed
+# below.  For further options, see the README file or the variables defined 
+# in common.mk with ?= (will not overwrite your customizations) or += (will
+# add to but not overwrite your customizations).
+
+# TARGETS
+# List additional targets here.  You will need to add libraries manually
+#targets = libname.a(name.o)
+
+# PATHS
+# Add these if needed (but let me know so I can add them to platform.mk)
+#include_dirs += $(PWD)		# Will have -I prepended
+#lib_dirs +=			# Will have -L prepended
+#libraries +=			# Will have -l prepended
+
+# FILES TO CLEAN
+# These are files to be removed by "make clean".
+#tmp_files = run/out
+
+# These are the defaults.
+build_dir = build
+src_dir = src
+main_dirs = src/mains
+makefiles_dir = makefiles
+
+.PHONY: all doc
+
+# Modify this if you like to change the default rule.
+all: $(targets)
+
+doc:
+	cd doc; make html
+
+# Now include dependencies etc.
+include $(makefiles_dir)/common.mk

.makefiles/README.rst

+.. -*- rst -*- -*- restructuredtext -*-
+
+.. This file should be written using the restructure text
+.. conventions.  It will be displayed on the bitbucket source page and
+.. serves as the documentation of the directory.
+
+Makefiles
+=========
+
+A collection of Makefiles and related tools supporting the following features:
+
+* Simple conversion of ``README.rst`` files to ``README.html`` files using
+  docutils.
+* A fairly complete automatic build system.
+
+Common Conventions
+==================
+Each new component can provide the following (replacing ``*`` with the component
+name):
+
+* ``help.*``: Component specific help (should simply be a list of targets and
+  descriptions).
+* ``clean.*``: Component specific clean commands.
+* ``debug.*``: Component specific debug commands.
+
+To hook these into the common functionality (provided by ``help.mk``) these
+should be added to ``help.targets``, ``clean.targets``, and ``debug.targets``.
+See ``rst2html.mk`` for a simple example.
+
+RST2HTML
+========
+A simple use (I have started using this for all my projects) is to include a
+top-level ``Makefile`` of the form::
+
+   makefiles_dir = .makefiles
+   include .makefiles/rst2html.mk
+
+
+Automatic Build System
+======================
+Most of the files here are for an automatic build system using `GNU make`_
+with the following behaviour:
+
+* Automatic location of source files and generation of prerequisites (using
+  compiler flags).
+* All build products go in a separate folder (typically called ``build``) that
+   can be simply removed to clean up.
+* Optional flat or nested structure in this directory.  (In the latter case,
+   the executables are sym-linked to the top-level of the build directory.)
+
+Typical usage is to install this package into a directory ``makefiles`` in your
+project, and then copy ``Makefile.example`` to the top level ``Makefile``,
+editing as appropriate.
+
+Components
+----------
+``makefiles/common.mk``:
+  Factoring of common platform independent functionality such as
+  generic compiler flags and common library locations (relative to
+  ``$HOME`` for example.)
+``makefiles/platforms.mk``:
+  Platform dependent overrides, library location etc.  Right now this
+  this is geared towards the computers I use, but should be easy to
+  modify.
+``makefiles/rules.mk``:
+  Customized rules to support output in the build directory, linking,
+  etc. without using ``$(VPATH)``.  Also has some Fortran 90 rules.
+``makefiles/distribute_setup.py``:
+  Provided so that the top-level ``setup.py`` can use the new distribute_
+  project for distributing python.
+
+These files should not have to be modified on a per-project basis (if
+you need to make a modification, try to make it general and let me
+know so I can include the modification here).  All project-specific
+information should be specified in a ``Makefile`` at the top level of
+the project that is based on ``Makefile.example``.
+
+
+Limitations
+===========
+
+* Executable names must be the same as the source file containing ``main()``.
+* Executable names must not start with ``lib`` (we filter these out when
+  generating the phony targets.)
+* There are no shortcuts for specifying library targets: you must include the
+  full path of both the library and the object files such as::
+
+   targets += $(build_dir)/libname.a($(build_dir)/obj/dirname/name.o)
+
+Usage
+=====
+
+Simply place the three ``.mk`` files in a folder called ``makefiles`` (can be
+changed) and suitably modify ``Makefile.example`` as your ``Makefile`` in the
+top level directory. If you use the following structure, then all you need to
+change in the ``Makefile`` is the list of libraries required by defining the
+appropriate ``$(use_*)`` flags to ``true``:
+
+``src/``:
+  All code should go here.
+``src/mains/``:
+  All code that defines ``main()`` should go here: one source file for each
+  desired executable (of the same name).
+
+Since I might update this, I would recommend that you use mercurial to checkout
+a version controlled copy of this project.  It is probably a good idea to do
+this as a subrepository_ so that your project records the version being used.
+Here is how:
+
+* If you use http access to bitbucket then do something like this::
+
+    cd project_dir
+    hg clone https://bitbucket.org/mforbes/makefiles makefiles
+    echo "makefiles = https://bitbucket.org/mforbes/makefiles" >> .hgsub
+    hg add .hgsub
+    hg com -m "Added makefiles as a subrepository."
+    cp makefiles/Makefile.example Makefile
+    emacs Makefile
+    hg add Makefile
+    hg com -m "Customized Makefile."
+
+* If you use ssh access to bitbucket (which has the advantage that you can use a
+  key-pair for password-less log in) then do something like this::
+
+    cd project_dir
+    hg clone ssh://hg@bitbucket.org/mforbes/makefiles makefiles
+    echo "makefiles = ssh://hg@bitbucket.org/mforbes/makefiles" >> .hgsub
+    hg add .hgsub
+    hg com -m "Added makefiles as a subrepository."
+    cp makefiles/Makefile.example Makefile
+    emacs Makefile
+    hg add Makefile
+    hg com -m "Customized Makefile."
+
+.. _subrepository: http://mercurial.selenic.com/wiki/Subrepository
+
+Variables
+=========
+
+Specifying your Build Structure
+-------------------------------
+
+**build_dir** = ``build``:
+   All output will be placed in this directory.  You can simply remove this to
+   clean up (and this is what ``make clean`` will do).  Note: I sometimes allow
+   environmental variables to change this so that I can build different versions
+   of the project in different places (but I call all directories ``build*`` for
+   easy cleaning).
+**exe_dir** = ``$(build_dir)``:
+   Unless doing a flat build, all executables will be sym-linked here.
+**obj_dir** = ``$(build_dir)/obj``:
+   Unless doing a flat build, everything will be built in this directory with
+   the same directory structure as in ``$(src_dir)``
+**flat_build**:
+   If ``true``, then all source directories will be added to ``$(VPATH)`` and
+   the directory names will be stripped from all object files and executable
+   files.  This means that the build directory will contain only files (no
+   folders).
+
+Specifying your Sources
+-----------------------
+
+**src_dir**:
+   If this is defined, then it will be assumed that all source files live under
+   this directory.  If not using a flat build, then this directory prefix will
+   be stripped before placing files into the ``$(build_dir)``.  If this is not
+   defined, then it will be defined to be the directory from which ``make`` was
+   run (and converted to an absolute path).
+**src_dirs**:
+   These directories will be searched to find source files.  If not defined,
+   then all directories in ``$(src_dir)`` will be searched using ``find``.
+**main_dirs**:
+   Locations of sources containing ``main()`` functions.  If this is defined,
+   then all files with an extension in ``$(o_exts)`` will be added (without the
+   extension) to ``$(targets)``.
+**targets**:
+   List of targets: executable programs or libraries.  Libraries should be
+   specified as ``$(build_dir)/libname.a(file1.o, file2.o, ...)`` where the
+   files in the parenthesis will be included in the library (archive).  This
+   will also be used to generate some automatic dependencies and in implicit
+   rules, so it is important that the executable files have the same name as the
+   corresponding ``.o`` file that contains the ``main`` function.  (See also
+   ``all_object_files`` below.)
+**makefiles_dir**: (default ``makefiles``)
+   Specifies the location of the ``*.mk`` files.
+
+Flags
+-----
+
+These are variables that are intended to be defined upon invocation, for example
+``make DEBUG=true``.  This means that within the makefiles, the variable
+``$(DEBUG)`` will be defined to the value ``true``:
+
+**DEBUG**:
+   Adds options like ``-g`` to the various flags and disables optimizations (see
+   ``common.mk``).
+**WALL**:
+   If ``true``, then no compiler warnings will be suppressed.  Typically, I
+   suppress some non-critical warnings in ``platform.mk``.  This will re-enable
+   all warnings.
+
+Any other variables that you define like ``make VAR=val`` will be treated as a
+macro to pass to the preprocessor.  I.e. ``CPPFLAGS += -DVAR=val``.
+
+Libraries and Headers
+---------------------
+
+The following may need to be modified if you use libraries that I have not
+explicitly coded (see Libraries_ below):
+
+**include_dirs**:
+   List of directories containing header files that will be added to
+   ``$(CPPFLAGS)`` with ``-I`` prepended.
+**lib_dirs**: 
+   List of directories containing libraries that will be added to ``$(LDLIBS)``
+   with ``-L`` prepended.
+**libraries**:
+   List of libraries that will be added to ``$(LDLIBS)`` with the ``-l``
+   prefix.  Note: if a library has name ``mylib`` then the library file will
+   typically be called ``libmylib.a`` for a static library or ``libmylib.so``
+   for a dynamic library.
+
+Compiler Options
+----------------
+
+**warning_flags**:
+
+**debug_flags**:
+
+**optimize_flags**:
+   Will be added to ``$(CFLAGS)``, ``$(CXXFLAGS)``, and ``$(FFLAGS)``.  Also
+   supported are **cwarning_flags**, **cxxwarning_flags**, and
+   **fwarning_flags**; **cdebug_flags**, **cxxdebug_flags**, and
+   **fdebug_flags**; and **coptimize_flags**, **cxxoptimize_flags**, and
+   **foptimize_flags** which will be added to only the respective ``$(*FLAGS)``
+   variable.
+
+Generated Lists
+---------------
+
+The following variables govern the automatic source-file and prerequisite
+generation functionality.  These are typically set by ``common.mk`` based
+on a search of the files in the current source files, but these can be
+overridden if needed.
+
+**o_exts**:
+   List of extensions used to generate object files.  This is used to
+   automatically generate the list of sources.
+**h_exts**:
+   List of extensions used on header files.  Used to determine
+   ``$(include_dirs)`` automatically.
+**source_files**:
+   List of source files.  Typically this is generated automatically by finding
+   all files with an extension in ``$(o_exts)`` found in the
+   directories specified in ``$(src_dirs)``.
+**main_files**:
+   List of object files containing ``main``.  Generated from ``$(main_dir)`` if
+   defined.  Used to generate ``$(targets)``.
+**all_object_files**:
+   List of all object files obtained by combining ``$(main_files)`` and
+   ``$(source_files)`` with the directories removed in the latter and the
+   extensions replaced by ``.o``.  Note: since this includes all
+   ``$(main_files)``, it should not be given to the linker.  It is used for
+   generating the dependencies only.
+**object_files**:
+   List of object files to pass to the linker.  Obtained from
+   ``$(all_object_files)`` by removing ``$(main_files)``.  These are treated as
+   dependencies for all targets.  Note that the associated object file in
+   ``$(main_files)`` is implicitly included (and thus needs to have the same
+   name as the executable) so that only one ``main`` symbol is defined per
+   executable.
+**depend_files**:
+   List of ``*.d`` files generated from ``$(all_object_files)`` by replacing
+   ``.o`` with ``.d``.  These files will be included and are automatically
+   generated by the compiler
+**generate_depends**:
+   Should be set to the incantation (typically ``-MMD`` or ``-Wp,-MMD``) to get
+   your compilers to generate the local (no system) dependency ``*.d`` files
+   automatically.
+
+.. _Libraries:
+
+Libraries
+=========
+
+I have provided some support for the following libraries.  To use these, just
+set the appropriate flag to ``true``:
+
+**use_blacs**:
+
+**use_lapack**:
+
+**use_scalapack**:
+
+**use_fft**:
+
+**use_pthread**:
+
+**use_math**:
+
+**use_armadillo**:
+   C++ header library for linear algebra that uses the underlying LAPACK and
+   BLAS operations.  `My fork of armadillo`_ has a few extra functions.
+
+**use_gsl**:
+   `GNU Scientific Library`_.
+**use_boost**:
+   `BOOST C++ Libraries`_.  I typically only use the headers.
+
+Conventions
+===========
+
+* I use lowercase variable names.  Names in CAPS refer to variables used by the
+  implicit rules (see this by running ``make -p``) or by compile options (such
+  as DEBUG) meant to be defined in the make command line (such as ``make
+  DEBUG=true``).
+* Variables that end in ``_dirs`` are lists of directories.  These *do not*
+  contain ``-I`` or ``-L`` (which will be added using the ``$(addprefix)``
+  function).
+* Variables in the ``makefiles`` directory are generally set using ``?=`` or
+  ``+=`` so that variables set by the user are maintained.  (The ``?=`` form
+  only has effect if the variable was not previously defined.)
+* Variables starting with an underscore ``_*`` are "private".  Don't use.
+
+VPATH
+=====
+
+One issue I struggled with was how to use ``$(VPATH)`` and the related ``vpath``
+command.  These allows ``make`` to locate dependencies (the former provides a
+general search path while the latter allows the user to specify specific paths
+for each file type).  The main advantage of this approach is that you can use
+the implicit rules, and often do not need to add a new rule for a different
+compiler.  The problem is that the implicit rules expect the source files and
+object files to be located in the same directory (or on ``$(VPATH)``) which
+prevents us from organizing the ``$(build_dir)``.   For example, if you have a
+program that is built from ``src/mains/prog.c``, then the implicit rules will
+make ``build/prog.o`` and ``build/prog`` and you don't have much control.
+(There can also be simplifications in specifying perquisites, but as we will use
+the compilers to explicitly generate the dependencies, this is not relevant.)
+
+Rules
+-----
+
+To maintain control of the build directory and to simplify the structure of the
+makefiles, I have chosen to include a set of rules via ``rules.mk``.  I made
+these from the output of ``make -p`` by simply modifying the paths.  Thus, the
+typical implicit C compiling rule looks like::
+
+  %.o: %.c
+  #  commands to execute (built-in):
+	$(COMPILE.c) $(OUTPUT_OPTION) $<
+
+I have modified this to have the form::
+
+  $(obj_dir)/%.o : $(src_dir)/%.c
+	$(MKDIR) $(dir $@)
+  	$(COMPILE.c) $(OUTPUT_OPTION) $<
+	$(SYMLINKEXE)
+
+In this way, the source files in ``$(src_dir)`` are translated into object files
+in ``$(build_dir)``.  The ``$(SYMLINKEXE)`` command will do the symlinks if
+needed for a non-flat build.
+
+References
+==========
+
+Although the final solution does not use the techniques described here, I leared
+much from `Paul D. Smith's approach`_, (which might be useful for allowing
+target dependent output) and the `gpwiki`_.
+
+.. _gpwiki: http://gpwiki.org/index.php/Makefile
+.. _My fork of armadillo: https://bitbucket.org/mforbes/armadillo/
+.. _GNU Scientific Library: http://www.gnu.org/software/gsl/
+.. _BOOST C++ Libraries: http://www.boost.org/
+.. _GNU make: http://www.gnu.org/software/make/manual/
+.. _Paul D. Smith's approach: http://mad-scientist.net/make/multi-arch.html#explicitpath
+.. _distribute: http://packages.python.org/distribute/

.makefiles/__gmsl

+# ----------------------------------------------------------------------------
+#
+# GNU Make Standard Library (GMSL)
+#
+# A library of functions to be used with GNU Make's $(call) that
+# provides functionality not available in standard GNU Make.
+#
+# Copyright (c) 2005-2010 John Graham-Cumming
+#
+# This file is part of GMSL
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 
+# Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# Neither the name of the John Graham-Cumming nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# ----------------------------------------------------------------------------
+
+# This is the GNU Make Standard Library version number as a list with
+# three items: major, minor, revision
+
+gmsl_version := 1 0 12
+
+# Used to output warnings and error from the library, it's possible to
+# disable any warnings or errors by overriding these definitions
+# manually or by setting GMSL_NO_WARNINGS or GMSL_NO_ERRORS
+
+__gmsl_name := GNU Make Standard Library
+__gmsl_warning = $(warning $(__gmsl_name): $1)
+__gmsl_error = $(error $(__gmsl_name): $1)
+
+ifdef GMSL_NO_WARNINGS
+__gmsl_warning :=
+endif
+ifdef GMSL_NO_ERRORS
+__gmsl_error :=
+endif
+
+# If GMSL_TRACE is enabled then calls to the library functions are
+# traced to stdout using warning messages with their arguments
+
+ifdef GMSL_TRACE
+__gmsl_tr1 = $(warning $0('$1'))
+__gmsl_tr2 = $(warning $0('$1','$2'))
+__gmsl_tr3 = $(warning $0('$1','$2','$3'))
+else
+__gmsl_tr1 :=
+__gmsl_tr2 :=
+__gmsl_tr3 :=
+endif
+
+# Figure out whether we have $(eval) or not (GNU Make 3.80 and above)
+# if we do not then output a warning message, if we do then some
+# functions will be enabled.
+
+__gmsl_have_eval := $(false)
+__gmsl_ignore := $(eval __gmsl_have_eval := $(true))
+
+# If this is being run with Electric Cloud's emake then warn that
+# their $(eval) support is incomplete.
+
+ifdef ECLOUD_BUILD_ID
+$(warning You are using Electric Cloud's emake which has incomplete $$(eval) support)
+__gmsl_have_eval := $(false)
+endif
+
+# See if we have $(lastword) (GNU Make 3.81 and above)
+
+__gmsl_have_lastword := $(lastword $(false) $(true))
+
+# See if we have native or and and (GNU Make 3.81 and above)
+
+__gmsl_have_or := $(if $(filter-out undefined,  \
+    $(origin or)),$(call or,$(true),$(false)))
+__gmsl_have_and := $(if $(filter-out undefined, \
+    $(origin and)),$(call and,$(true),$(true)))
+
+ifneq ($(__gmsl_have_eval),$(true))
+$(call __gmsl_warning,GNU Make $(MAKE_VERSION) does not support $$$$(eval): some functions disabled)
+endif
+
+__gmsl_dollar := $$
+
+# ----------------------------------------------------------------------------
+# Function:  gmsl_compatible
+# Arguments: List containing the desired library version number (maj min rev)
+# Returns:   $(true) if this version of the library is compatible
+#            with the requested version number, otherwise $(false)
+# ----------------------------------------------------------------------------
+gmsl_compatible = $(strip                                                 \
+    $(if $(call gt,$(word 1,$1),$(word 1,$(gmsl_version))),               \
+        $(false),                                                         \
+        $(if $(call lt,$(word 1,$1),$(word 1,$(gmsl_version))),           \
+            $(true),                                                      \
+            $(if $(call gt,$(word 2,$1),$(word 2,$(gmsl_version))),       \
+                $(false),                                                 \
+                $(if $(call lt,$(word 2,$1),$(word 2,$(gmsl_version))),   \
+                    $(true),                                              \
+                    $(call lte,$(word 3,$1),$(word 3,$(gmsl_version))))))))
+
+# ###########################################################################
+# LOGICAL OPERATORS
+# ###########################################################################
+
+# not is defined in gmsl
+
+# ----------------------------------------------------------------------------
+# Function:  and
+# Arguments: Two boolean values
+# Returns:   Returns $(true) if both of the booleans are true
+# ----------------------------------------------------------------------------
+ifneq ($(__gmsl_have_and),$(true))
+and = $(__gmsl_tr2)$(if $1,$(if $2,$(true),$(false)),$(false))
+endif
+
+# ----------------------------------------------------------------------------
+# Function:  or
+# Arguments: Two boolean values
+# Returns:   Returns $(true) if either of the booleans is true
+# ----------------------------------------------------------------------------
+ifneq ($(__gmsl_have_or),$(true))
+or = $(__gmsl_tr2)$(if $1$2,$(true),$(false))
+endif
+
+# ----------------------------------------------------------------------------
+# Function:  xor
+# Arguments: Two boolean values
+# Returns:   Returns $(true) if exactly one of the booleans is true
+# ----------------------------------------------------------------------------
+xor = $(__gmsl_tr2)$(if $1,$(if $2,$(false),$(true)),$(if $2,$(true),$(false)))
+
+# ----------------------------------------------------------------------------
+# Function:  nand
+# Arguments: Two boolean values
+# Returns:   Returns value of 'not and'
+# ----------------------------------------------------------------------------
+nand = $(__gmsl_tr2)$(if $1,$(if $2,$(false),$(true)),$(true))
+
+# ----------------------------------------------------------------------------
+# Function:  nor
+# Arguments: Two boolean values
+# Returns:   Returns value of 'not or'
+# ----------------------------------------------------------------------------
+nor = $(__gmsl_tr2)$(if $1$2,$(false),$(true))
+
+# ----------------------------------------------------------------------------
+# Function:  xnor
+# Arguments: Two boolean values
+# Returns:   Returns value of 'not xor'
+# ----------------------------------------------------------------------------
+xnor =$(__gmsl_tr2)$(if $1,$(if $2,$(true),$(false)),$(if $2,$(false),$(true)))
+
+# ###########################################################################
+# LIST MANIPULATION FUNCTIONS
+# ###########################################################################
+
+# ----------------------------------------------------------------------------
+# Function:  first (same as LISP's car, or head)
+# Arguments: 1: A list
+# Returns:   Returns the first element of a list
+# ----------------------------------------------------------------------------
+first = $(__gmsl_tr1)$(firstword $1)
+
+# ----------------------------------------------------------------------------
+# Function:  last
+# Arguments: 1: A list
+# Returns:   Returns the last element of a list
+# ----------------------------------------------------------------------------
+ifeq ($(__gmsl_have_lastword),$(true))
+last = $(__gmsl_tr1)$(lastword $1)
+else
+last = $(__gmsl_tr1)$(if $1,$(word $(words $1),$1))
+endif
+
+# ----------------------------------------------------------------------------
+# Function:  rest (same as LISP's cdr, or tail)
+# Arguments: 1: A list
+# Returns:   Returns the list with the first element removed
+# ----------------------------------------------------------------------------
+rest = $(__gmsl_tr1)$(wordlist 2,$(words $1),$1)
+
+# ----------------------------------------------------------------------------
+# Function:  chop
+# Arguments: 1: A list
+# Returns:   Returns the list with the last element removed
+# ----------------------------------------------------------------------------
+chop = $(__gmsl_tr1)$(wordlist 2,$(words $1),x $1)
+
+# ----------------------------------------------------------------------------
+# Function:  map
+# Arguments: 1: Name of function to $(call) for each element of list
+#            2: List to iterate over calling the function in 1
+# Returns:   The list after calling the function on each element
+# ----------------------------------------------------------------------------
+map = $(__gmsl_tr2)$(strip $(foreach a,$2,$(call $1,$a)))
+
+# ----------------------------------------------------------------------------
+# Function:  pairmap
+# Arguments: 1: Name of function to $(call) for each pair of elements
+#            2: List to iterate over calling the function in 1
+#            3: Second list to iterate over calling the function in 1
+# Returns:   The list after calling the function on each pair of elements
+# ----------------------------------------------------------------------------
+pairmap = $(strip $(__gmsl_tr3)\
+          $(if $2$3,$(call $1,$(call first,$2),$(call first,$3))     \
+                        $(call pairmap,$1,$(call rest,$2),$(call rest,$3))))
+
+# ----------------------------------------------------------------------------
+# Function:  leq
+# Arguments: 1: A list to compare against...
+#            2: ...this list
+# Returns:   Returns $(true) if the two lists are identical
+# ----------------------------------------------------------------------------
+leq = $(__gmsl_tr2)$(strip $(if $(call seq,$(words $1),$(words $2)),     \
+          $(call __gmsl_list_equal,$1,$2),$(false)))
+
+__gmsl_list_equal = $(if $(strip $1),                                       \
+                        $(if $(call seq,$(call first,$1),$(call first,$2)), \
+                            $(call __gmsl_list_equal,                       \
+                                $(call rest,$1),                            \
+                                $(call rest,$2)),                           \
+                            $(false)),                                      \
+                     $(true))
+
+# ----------------------------------------------------------------------------
+# Function:  lne
+# Arguments: 1: A list to compare against...
+#            2: ...this list
+# Returns:   Returns $(true) if the two lists are different
+# ----------------------------------------------------------------------------
+lne = $(__gmsl_tr2)$(call not,$(call leq,$1,$2))
+
+# ----------------------------------------------------------------------------
+# Function:  reverse
+# Arguments: 1: A list to reverse
+# Returns:   The list with its elements in reverse order
+# ----------------------------------------------------------------------------
+reverse =$(__gmsl_tr1)$(strip $(if $1,$(call reverse,$(call rest,$1)) \
+                        $(call first,$1)))
+
+# ----------------------------------------------------------------------------
+# Function:  uniq
+# Arguments: 1: A list from which to remove repeated elements
+# Returns:   The list with duplicate elements removed without reordering
+# ----------------------------------------------------------------------------
+uniq = $(strip $(__gmsl_tr1)$(if $1,$(call uniq,$(call chop,$1)) \
+            $(if $(filter $(call last,$1),$(call chop,$1)),,$(call last,$1))))
+
+# ----------------------------------------------------------------------------
+# Function:  length
+# Arguments: 1: A list
+# Returns:   The number of elements in the list
+# ----------------------------------------------------------------------------
+length = $(__gmsl_tr1)$(words $1)
+
+# ###########################################################################
+# STRING MANIPULATION FUNCTIONS
+# ###########################################################################
+
+# Helper function that translates any GNU Make 'true' value (i.e. a
+# non-empty string) to our $(true)
+
+__gmsl_make_bool = $(if $(strip $1),$(true),$(false))
+
+# ----------------------------------------------------------------------------
+# Function:  seq
+# Arguments: 1: A string to compare against...
+#            2: ...this string
+# Returns:   Returns $(true) if the two strings are identical
+# ----------------------------------------------------------------------------
+seq = $(__gmsl_tr2)$(if $1,$(if $2,$(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),$(false),$(true)),$(call not,$(call __gmsl_make_bool,$1))),$(call not,$(call __gmsl_make_bool,$2)))
+
+# ----------------------------------------------------------------------------
+# Function:  sne
+# Arguments: 1: A string to compare against...
+#            2: ...this string
+# Returns:   Returns $(true) if the two strings are not the same
+# ----------------------------------------------------------------------------
+sne = $(__gmsl_tr2)$(call not,$(call seq,$1,$2))
+
+# ----------------------------------------------------------------------------
+# Function:  split
+# Arguments: 1: The character to split on
+#            2: A string to split
+# Returns:   Splits a string into a list separated by spaces at the split
+#            character in the first argument
+# ----------------------------------------------------------------------------
+split = $(__gmsl_tr2)$(strip $(subst $1, ,$2))
+
+# ----------------------------------------------------------------------------
+# Function:  merge
+# Arguments: 1: The character to put between fields
+#            2: A list to merge into a string
+# Returns:   Merges a list into a single string, list elements are separated
+#            by the character in the first argument
+# ----------------------------------------------------------------------------
+merge = $(__gmsl_tr2)$(strip $(if $2,                                     \
+            $(if $(call seq,1,$(words $2)),                               \
+                $2,$(call first,$2)$1$(call merge,$1,$(call rest,$2)))))
+
+ifdef __gmsl_have_eval
+# ----------------------------------------------------------------------------
+# Function:  tr
+# Arguments: 1: The list of characters to translate from 
+#            2: The list of characters to translate to
+#            3: The text to translate
+# Returns:   Returns the text after translating characters
+# ----------------------------------------------------------------------------
+tr = $(strip $(__gmsl_tr3)$(call assert_no_dollar,$0,$1$2$3)              \
+     $(eval __gmsl_t := $3)                                               \
+     $(foreach c,                                                         \
+         $(join $(addsuffix :,$1),$2),                                    \
+         $(eval __gmsl_t :=                                               \
+             $(subst $(word 1,$(subst :, ,$c)),$(word 2,$(subst :, ,$c)), \
+                 $(__gmsl_t))))$(__gmsl_t))
+
+# Common character classes for use with the tr function.  Each of
+# these is actually a variable declaration and must be wrapped with
+# $() or ${} to be used.
+
+[A-Z] := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z #
+[a-z] := a b c d e f g h i j k l m n o p q r s t u v w x y z #
+[0-9] := 0 1 2 3 4 5 6 7 8 9 #
+[A-F] := A B C D E F #
+
+# ----------------------------------------------------------------------------
+# Function:  uc
+# Arguments: 1: Text to upper case
+# Returns:   Returns the text in upper case
+# ----------------------------------------------------------------------------
+uc = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(call tr,$([a-z]),$([A-Z]),$1)
+
+# ----------------------------------------------------------------------------
+# Function:  lc
+# Arguments: 1: Text to lower case
+# Returns:   Returns the text in lower case
+# ----------------------------------------------------------------------------
+lc = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(call tr,$([A-Z]),$([a-z]),$1)
+
+# ----------------------------------------------------------------------------
+# Function:  strlen
+# Arguments: 1: A string
+# Returns:   Returns the length of the string
+# ----------------------------------------------------------------------------
+__gmsl_characters := A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+__gmsl_characters += a b c d e f g h i j k l m n o p q r s t u v w x y z
+__gmsl_characters += 0 1 2 3 4 5 6 7 8 9
+__gmsl_characters += ` ~ ! @ \# $$ % ^ & * ( ) - _ = +
+__gmsl_characters += { } [ ] \ : ; ' " < > , . / ? |
+
+# Aside: if you read the above you might think that the lower-case
+# letter x is missing, and that that's an error.  It is missing, but
+# it's not an error.  __gmsl_characters is used by the strlen
+# function.  strlen works by transforming every character and space
+# into the letter x and then counting the x's.  Since there's no need
+# to transform x into x I omitted it.
+
+# This results in __gmsl_space containing just a space
+
+__gmsl_space := 
+__gmsl_space +=
+
+strlen = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(strip $(eval __temp := $(subst $(__gmsl_space),x,$1))$(foreach a,$(__gmsl_characters),$(eval __temp := $$(subst $$a,x,$(__temp))))$(eval __temp := $(subst x,x ,$(__temp)))$(words $(__temp)))
+
+# This results in __gmsl_newline containing just a newline
+
+define __gmsl_newline
+
+
+endef
+
+# This results in __gmsl_tab containing a tab
+
+__gmsl_tab :=	#
+
+# ----------------------------------------------------------------------------
+# Function:  substr
+# Arguments: 1: A string
+# 	     2: Start position (first character is 1)
+#	     3: End position (inclusive)
+# Returns:   A substring.  
+# Note:      The string in $1 must not contain a �
+# ----------------------------------------------------------------------------
+
+substr = $(__gmsl_tr3)$(call assert_no_dollar,$0,$1$2$3)$(strip $(eval __temp := $$(subst $$(__gmsl_space),� ,$$1))$(foreach a,$(__gmsl_characters),$(eval __temp := $$(subst $$a,$$a$$(__gmsl_space),$(__temp))))$(eval __temp := $(wordlist $2,$3,$(__temp))))$(subst �,$(__gmsl_space),$(subst $(__gmsl_space),,$(__temp)))
+
+endif # __gmsl_have_eval
+
+# ###########################################################################
+# SET MANIPULATION FUNCTIONS
+# ###########################################################################
+
+# Sets are represented by sorted, deduplicated lists.  To create a set
+# from a list use set_create, or start with the empty_set and
+# set_insert individual elements
+
+# This is the empty set
+empty_set := 
+
+# ----------------------------------------------------------------------------
+# Function:  set_create
+# Arguments: 1: A list of set elements
+# Returns:   Returns the newly created set
+# ----------------------------------------------------------------------------
+set_create = $(__gmsl_tr1)$(sort $1)
+
+# ----------------------------------------------------------------------------
+# Function:  set_insert
+# Arguments: 1: A single element to add to a set
+#            2: A set
+# Returns:   Returns the set with the element added
+# ----------------------------------------------------------------------------
+set_insert = $(__gmsl_tr2)$(sort $1 $2)
+
+# ----------------------------------------------------------------------------
+# Function:  set_remove
+# Arguments: 1: A single element to remove from a set
+#            2: A set
+# Returns:   Returns the set with the element removed
+# ----------------------------------------------------------------------------
+set_remove = $(__gmsl_tr2)$(filter-out $1,$2)
+
+# ----------------------------------------------------------------------------
+# Function:  set_is_member
+# Arguments: 1: A single element 
+#            2: A set
+# Returns:   Returns $(true) if the element is in the set
+# ----------------------------------------------------------------------------
+set_is_member = $(__gmsl_tr2)$(if $(filter $1,$2),$(true),$(false))
+
+# ----------------------------------------------------------------------------
+# Function:  set_union
+# Arguments: 1: A set
+#            2: Another set
+# Returns:   Returns the union of the two sets
+# ----------------------------------------------------------------------------
+set_union = $(__gmsl_tr2)$(sort $1 $2)
+
+# ----------------------------------------------------------------------------
+# Function:  set_intersection
+# Arguments: 1: A set
+#            2: Another set
+# Returns:   Returns the intersection of the two sets
+# ----------------------------------------------------------------------------
+set_intersection = $(__gmsl_tr2)$(filter $1,$2)
+
+# ----------------------------------------------------------------------------
+# Function:  set_is_subset
+# Arguments: 1: A set
+#            2: Another set
+# Returns:   Returns $(true) if the first set is a subset of the second
+# ----------------------------------------------------------------------------
+set_is_subset = $(__gmsl_tr2)$(call set_equal,$(call set_intersection,$1,$2),$1)
+
+# ----------------------------------------------------------------------------
+# Function:  set_equal
+# Arguments: 1: A set
+#            2: Another set
+# Returns:   Returns $(true) if the two sets are identical
+# ----------------------------------------------------------------------------
+set_equal = $(__gmsl_tr2)$(call seq,$1,$2)
+
+# ###########################################################################
+# ARITHMETIC LIBRARY
+# ###########################################################################
+
+# Integers a represented by lists with the equivalent number of x's.
+# For example the number 4 is x x x x.  The maximum integer that the
+# library can handle as _input_ is __gmsl_input_int which is defined
+# here as 65536
+
+__gmsl_sixteen := x x x x x x x x x x x x x x x x
+__gmsl_input_int := $(foreach a,$(__gmsl_sixteen),         \
+                        $(foreach b,$(__gmsl_sixteen),     \
+                            $(foreach c,$(__gmsl_sixteen), \
+                                $(__gmsl_sixteen)))))
+
+# ----------------------------------------------------------------------------
+# Function:  int_decode
+# Arguments: 1: A number of x's representation
+# Returns:   Returns the integer for human consumption that is represented
+#            by the string of x's
+# ----------------------------------------------------------------------------
+int_decode = $(__gmsl_tr1)$(words $1)
+
+# ----------------------------------------------------------------------------
+# Function:  int_encode
+# Arguments: 1: A number in human-readable integer form
+# Returns:   Returns the integer encoded as a string of x's
+# ----------------------------------------------------------------------------
+int_encode = $(__gmsl_tr1)$(wordlist 1,$1,$(__gmsl_input_int))
+
+# The arithmetic library functions come in two forms: one form of each
+# function takes integers as arguments and the other form takes the
+# encoded form (x's created by a call to int_encode).  For example,
+# there are two plus functions:
+#
+# plus        Called with integer arguments and returns an integer
+# int_plus    Called with encoded arguments and returns an encoded result
+#
+# plus will be slower than int_plus because its arguments and result
+# have to be translated between the x's format and integers.  If doing
+# a complex calculation use the int_* forms with a single encoding of
+# inputs and single decoding of the output.  For simple calculations
+# the direct forms can be used.
+
+# Helper function used to wrap an int_* function into a function that
+# takes a pair of integers, perhaps a function and returns an integer
+# result
+__gmsl_int_wrap = $(call int_decode,$(call $1,$(call int_encode,$2),$(call int_encode,$3)))
+__gmsl_int_wrap1 = $(call int_decode,$(call $1,$(call int_encode,$2)))
+__gmsl_int_wrap2 = $(call $1,$(call int_encode,$2),$(call int_encode,$3))
+
+# ----------------------------------------------------------------------------
+# Function:  int_plus
+# Arguments: 1: A number in x's representation
+#            2: Another number in x's represntation
+# Returns:   Returns the sum of the two numbers in x's representation
+# ----------------------------------------------------------------------------
+int_plus = $(strip $(__gmsl_tr2)$1 $2)
+
+# ----------------------------------------------------------------------------
+# Function:  plus (wrapped version of int_plus)
+# Arguments: 1: An integer
+#            2: Another integer
+# Returns:   Returns the sum of the two integers
+# ----------------------------------------------------------------------------
+plus = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_plus,$1,$2)
+
+# ----------------------------------------------------------------------------
+# Function:  int_subtract
+# Arguments: 1: A number in x's representation
+#            2: Another number in x's represntation
+# Returns:   Returns the difference of the two numbers in x's representation,
+#            or outputs an error on a numeric underflow
+# ----------------------------------------------------------------------------
+int_subtract = $(strip $(__gmsl_tr2)$(if $(call int_gte,$1,$2), \
+                $(filter-out xx,$(join $1,$2)),                 \
+                $(call __gmsl_warning,Subtraction underflow)))
+
+# ----------------------------------------------------------------------------
+# Function:  subtract (wrapped version of int_subtract)
+# Arguments: 1: An integer
+#            2: Another integer
+# Returns:   Returns the difference of the two integers,
+#            or outputs an error on a numeric underflow
+# ----------------------------------------------------------------------------
+subtract = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_subtract,$1,$2)
+
+# ----------------------------------------------------------------------------
+# Function:  int_multiply
+# Arguments: 1: A number in x's representation
+#            2: Another number in x's represntation
+# Returns:   Returns the product of the two numbers in x's representation
+# ----------------------------------------------------------------------------
+int_multiply = $(strip $(__gmsl_tr2)$(foreach a,$1,$2))
+
+# ----------------------------------------------------------------------------
+# Function:  multiply (wrapped version of int_multiply)
+# Arguments: 1: An integer
+#            2: Another integer
+# Returns:   Returns the product of the two integers
+# ----------------------------------------------------------------------------
+multiply = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_multiply,$1,$2)
+
+# ----------------------------------------------------------------------------
+# Function:  int_divide
+# Arguments: 1: A number in x's representation
+#            2: Another number in x's represntation
+# Returns:   Returns the result of integer division of argument 1 divided
+#            by argument 2 in x's representation
+# ----------------------------------------------------------------------------
+int_divide = $(__gmsl_tr2)$(strip $(if $2,                                 \
+                 $(if $(call int_gte,$1,$2),                               \
+                     x $(call int_divide,$(call int_subtract,$1,$2),$2),), \
+                 $(call __gmsl_error,Division by zero)))
+
+# ----------------------------------------------------------------------------
+# Function:  divide (wrapped version of int_divide)
+# Arguments: 1: An integer
+#            2: Another integer
+# Returns:   Returns the integer division of the first argument by the second
+# ----------------------------------------------------------------------------
+divide = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_divide,$1,$2)
+
+# ----------------------------------------------------------------------------
+# Function:  int_max, int_min
+# Arguments: 1: A number in x's representation
+#            2: Another number in x's represntation
+# Returns:   Returns the maximum or minimum of its arguments in x's
+#            representation
+# ----------------------------------------------------------------------------
+int_max = $(__gmsl_tr2)$(subst xx,x,$(join $1,$2))
+int_min = $(__gmsl_tr2)$(subst xx,x,$(filter xx,$(join $1,$2)))
+
+# ----------------------------------------------------------------------------
+# Function:  max, min
+# Arguments: 1: An integer
+#            2: Another integer
+# Returns:   Returns the maximum or minimum of its integer arguments
+# ----------------------------------------------------------------------------
+max = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_max,$1,$2)
+min = $(__gmsl_tr2)$(call __gmsl_int_wrap,int_min,$1,$2)
+
+# ----------------------------------------------------------------------------
+# Function: int_gt, int_gte, int_lt, int_lte, int_eq, int_ne
+# Arguments: Two x's representation numbers to be compared
+# Returns:   $(true) or $(false)
+#
+# int_gt    First argument greater than second argument
+# int_gte   First argument greater than or equal to second argument
+# int_lt    First argument less than second argument 
+# int_lte   First argument less than or equal to second argument
+# int_eq    First argument is numerically equal to the second argument
+# int_ne    First argument is not numerically equal to the second argument
+# ----------------------------------------------------------------------------
+int_gt = $(__gmsl_tr2)$(call __gmsl_make_bool,      \
+                          $(filter-out $(words $2), \
+                              $(words $(call int_max,$1,$2))))
+int_gte = $(__gmsl_tr2)$(call __gmsl_make_bool,     \
+                           $(call int_gt,$1,$2)$(call int_eq,$1,$2))
+int_lt = $(__gmsl_tr2)$(call __gmsl_make_bool,      \
+                          $(filter-out $(words $1), \
+                              $(words $(call int_max,$1,$2))))
+int_lte = $(__gmsl_tr2)$(call __gmsl_make_bool,     \
+                           $(call int_lt,$1,$2)$(call int_eq,$1,$2))
+int_eq = $(__gmsl_tr2)$(call __gmsl_make_bool,      \
+                          $(filter $(words $1),$(words $2)))
+int_ne = $(__gmsl_tr2)$(call __gmsl_make_bool,      \
+                          $(filter-out $(words $1),$(words $2)))
+
+# ----------------------------------------------------------------------------
+# Function: gt, gte, lt, lte, eq, ne
+# Arguments: Two integers to be compared
+# Returns:   $(true) or $(false)
+#
+# gt    First argument greater than second argument
+# gte   First argument greater than or equal to second argument
+# lt    First argument less than second argument 
+# lte   First argument less than or equal to second argument
+# eq    First argument is numerically equal to the second argument
+# ne    First argument is not numerically equal to the second argument
+# ----------------------------------------------------------------------------
+gt = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_gt,$1,$2)
+gte = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_gte,$1,$2)
+lt = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_lt,$1,$2)
+lte = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_lte,$1,$2)
+eq = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_eq,$1,$2)
+ne = $(__gmsl_tr2)$(call __gmsl_int_wrap2,int_ne,$1,$2)
+
+# increment adds 1 to its argument, decrement subtracts 1.  Note that
+# decrement does not range check and hence will not underflow, but
+# will incorrectly say that 0 - 1 = 0
+
+# ----------------------------------------------------------------------------
+# Function:  int_inc
+# Arguments: 1: A number in x's representation
+# Returns:   The number incremented by 1 in x's representation
+# ----------------------------------------------------------------------------
+int_inc = $(strip $(__gmsl_tr1)$1 x)
+
+# ----------------------------------------------------------------------------
+# Function:  inc
+# Arguments: 1: An integer
+# Returns:   The argument incremented by 1
+# ----------------------------------------------------------------------------
+inc = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_inc,$1)
+
+# ----------------------------------------------------------------------------
+# Function:  int_dec
+# Arguments: 1: A number in x's representation
+# Returns:   The number decremented by 1 in x's representation
+# ----------------------------------------------------------------------------
+int_dec = $(__gmsl_tr1)$(strip $(if $(call sne,0,$(words $1)), \
+              $(wordlist 2,$(words $1),$1),                    \
+              $(call __gmsl_warning,Decrement underflow)))
+
+# ----------------------------------------------------------------------------
+# Function:  dec
+# Arguments: 1: An integer
+# Returns:   The argument decremented by 1
+# ----------------------------------------------------------------------------
+dec = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_dec,$1)
+
+# double doubles its argument, and halve halves it
+
+# ----------------------------------------------------------------------------
+# Function:  int_double
+# Arguments: 1: A number in x's representation
+# Returns:   The number doubled (i.e. * 2) and returned in x's representation
+# ----------------------------------------------------------------------------
+int_double = $(strip $(__gmsl_tr1)$1 $1)
+
+# ----------------------------------------------------------------------------
+# Function:  double
+# Arguments: 1: An integer
+# Returns:   The integer times 2
+# ----------------------------------------------------------------------------
+double = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_double,$1)
+
+# ----------------------------------------------------------------------------
+# Function:  int_halve
+# Arguments: 1: A number in x's representation
+# Returns:   The number halved (i.e. / 2) and returned in x's representation
+# ----------------------------------------------------------------------------
+int_halve = $(__gmsl_tr1)$(strip $(subst xx,x,$(filter-out xy x y, \
+                             $(join $1,$(foreach a,$1,y x)))))
+
+# ----------------------------------------------------------------------------
+# Function:  halve
+# Arguments: 1: An integer
+# Returns:   The integer divided by 2
+# ----------------------------------------------------------------------------
+halve = $(__gmsl_tr1)$(call __gmsl_int_wrap1,int_halve,$1)
+
+ifdef __gmsl_have_eval
+# ###########################################################################
+# ASSOCIATIVE ARRAYS
+# ###########################################################################
+
+# ----------------------------------------------------------------------------
+# Function:  set
+# Arguments: 1: Name of associative array
+#            2: The key value to associate
+#            3: The value associated with the key
+# Returns:   None
+# ----------------------------------------------------------------------------
+set = $(__gmsl_tr3)$(call assert_no_dollar,$0,$1$2$3)$(eval __gmsl_aa_$1_$(__gmsl_space)_$2_gmsl_aa_$1 = $3)
+
+# ----------------------------------------------------------------------------
+# Function:  get
+# Arguments: 1: Name of associative array
+#            2: The key to retrieve
+# Returns:   The value stored in the array for that key
+# ----------------------------------------------------------------------------
+get = $(strip $(__gmsl_tr2)$(call assert_no_dollar,$0,$1$2)$(__gmsl_aa_$1_$(__gmsl_space)_$2_gmsl_aa_$1))
+
+# ----------------------------------------------------------------------------
+# Function:  keys
+# Arguments: 1: Name of associative array
+# Returns:   Returns a list of all defined keys in the array
+# ----------------------------------------------------------------------------
+keys = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(sort $(patsubst _%_gmsl_aa_$1,%, \
+                  $(filter _%_gmsl_aa_$1,$(.VARIABLES))))
+
+# ----------------------------------------------------------------------------
+# Function:  defined
+# Arguments: 1: Name of associative array
+#            2: The key to test
+# Returns:   Returns true if the key is defined (i.e. not empty)
+# ----------------------------------------------------------------------------
+defined = $(__gmsl_tr2)$(call assert_no_dollar,$0,$1$2)$(call sne,$(call get,$1,$2),)
+
+endif # __gmsl_have_eval
+
+ifdef __gmsl_have_eval
+# ###########################################################################
+# NAMED STACKS
+# ###########################################################################
+
+# ----------------------------------------------------------------------------
+# Function:  push
+# Arguments: 1: Name of stack
+#            2: Value to push onto the top of the stack (must not contain
+#               a space)
+# Returns:   None
+# ----------------------------------------------------------------------------
+push = $(__gmsl_tr2)$(call assert_no_dollar,$0,$1$2)$(eval __gmsl_stack_$1 := $2 $(if $(filter-out undefined,\
+    $(origin __gmsl_stack_$1)),$(__gmsl_stack_$1)))
+
+# ----------------------------------------------------------------------------
+# Function:  pop
+# Arguments: 1: Name of stack
+# Returns:   Top element from the stack after removing it
+# ----------------------------------------------------------------------------
+pop = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(strip $(if $(filter-out undefined,$(origin __gmsl_stack_$1)), \
+    $(call first,$(__gmsl_stack_$1))                                       \
+    $(eval __gmsl_stack_$1 := $(call rest,$(__gmsl_stack_$1)))))
+
+# ----------------------------------------------------------------------------
+# Function:  peek
+# Arguments: 1: Name of stack
+# Returns:   Top element from the stack without removing it
+# ----------------------------------------------------------------------------
+peek = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(call first,$(__gmsl_stack_$1))
+
+# ----------------------------------------------------------------------------
+# Function:  depth
+# Arguments: 1: Name of stack
+# Returns:   Number of items on the stack
+# ----------------------------------------------------------------------------
+depth = $(__gmsl_tr1)$(call assert_no_dollar,$0,$1)$(words $(__gmsl_stack_$1))
+
+endif # __gmsl_have_eval
+
+# ###########################################################################
+# DEBUGGING FACILITIES
+# ###########################################################################
+
+# ----------------------------------------------------------------------------
+# Target:    gmsl-print-%
+# Arguments: The % should be replaced by the name of a variable that you
+#            wish to print out.
+# Action:    Echos the name of the variable that matches the % and its value.
+#            For example, 'make gmsl-print-SHELL' will output the value of
+#            the SHELL variable
+# ----------------------------------------------------------------------------
+gmsl-print-%: ; @echo $* = $($*)
+
+# ----------------------------------------------------------------------------
+# Function:  assert
+# Arguments: 1: A boolean that must be true or the assertion will fail
+#            2: The message to print with the assertion
+# Returns:   None
+# ----------------------------------------------------------------------------
+assert = $(if $1,,$(call __gmsl_error,Assertion failure: $2))
+
+# ----------------------------------------------------------------------------
+# Function:  assert_exists
+# Arguments: 1: Name of file that must exist, if it is missing an assertion
+#               will be generated
+# Returns:   None
+# ----------------------------------------------------------------------------
+assert_exists = $(call assert,$(wildcard $1),file '$1' missing)
+
+# ----------------------------------------------------------------------------
+# Function:  assert_no_dollar
+# Arguments: 1: Name of a function being executd
+#            2: Arguments to check
+# Returns:   None
+# ----------------------------------------------------------------------------
+assert_no_dollar = $(call assert,$(call not,$(findstring $$,$2)),$1 called with a dollar sign in argument)

.makefiles/common.mk

+## -*- mode: Makefile; fill-column: 80 -*-
+##
+## Common project-independent rules and flags.  Include this from your
+## main Makefile *after* your default target (or later).
+
+include $(makefiles_dir)/gmsl
+
+# Common flags
+SHELL = /bin/sh
+warning_flags ?= -Wall
+
+# Include platform specific stuff
+include $(makefiles_dir)/platform.mk
+
+# This passes the -MMD option directly to the preprocessor (-Wp does
+# not pass it to the compiler).  This generates dependency files (*.d)
+# with only yje source header information (-MD includes system
+# headers).  Both gcc and intel compilers support this.
+#generate_depends ?= -Wp,-MMD
+generate_depends ?= -MMD
+
+# These are the types of files that will generate .o object files.
+o_exts ?= .c .cpp .f90 .F90 .cc
+h_exts ?= .h .hpp
+
+# Determines if $(build_dir) will have the same folder structure as $(src_dir).
+flat_build ?= false
+
+# All paths are relative to $(CURDIR)
+_relative := true
+_curr_dir := $(realpath $(CURDIR))
+ifeq ($(_relative), true)
+  _cleanpath = $(foreach _f,$(1),$(patsubst $(_curr_dir)/%,%,$(realpath $(_f))))
+else
+  _cleanpath = $(foreach _f,$(1),$(realpath $(_f)))
+endif
+
+src_dir ?= $(CURDIR)
+build_dir ?= $(CURDIR)/build
+
+# Clean up paths and make build directory.
+src_dir := $(call _cleanpath,$(src_dir))
+
+_msg := $(shell [ -d $(build_dir) ] || mkdir -p $(build_dir) || echo fail)
+ifneq ($(_msg),)
+  $(error Could not make build_dir="$(build_dir)")
+endif
+
+build_dir := $(call _cleanpath,$(build_dir))
+obj_dir ?= $(build_dir)/obj
+exe_dir ?= $(build_dir)
+
+##############################################
+# Here is the code that finds the sources etc.
+
+# Find source directories if not specified
+ifndef src_dirs
+  src_dirs := $(shell find $(src_dir) -type d)
+  src_dirs += $(main_dirs)
+endif
+
+# Find sources: Search in $(src_dirs) for files with extensions in $(o_exts)
+source_files ?= $(foreach                       \
+  _d,$(src_dirs),$(foreach                      \
+    _e,$(o_exts),$(wildcard $(_d)/*$(_e))))
+source_files := $(call _cleanpath,$(source_files))
+
+# Find headers: Search in $(src_dirs) for files with extensions in $(h_exts)
+header_files ?= $(foreach                       \
+  _d,$(src_dirs),$(foreach                      \
+    _e,$(h_exts),$(wildcard $(_d)/*$(_e)))))
+header_files := $(call _cleanpath,$(header_files))
+
+# Add to $(include_dirs)
+include_dirs += $(dir $(header_files))
+include_dirs := $(call _cleanpath,$(include_dirs))
+include_dirs := $(call uniq,$(include_dirs))
+
+# Find source files for main (executables)
+ifdef main_dirs
+  # Find executables:
+  main_source_files := $(strip $(foreach \
+    _d,$(main_dirs),$(foreach \
+      _e,$(o_exts),$(wildcard $(_d)/*$(_e)))))
+endif
+
+# Function to change paths to be in obj_dir
+_to_obj_dir = $(addprefix $(obj_dir)/,$(foreach \
+  _f,$(1),$(patsubst $(src_dir)/%,%,$(_f))))
+
+# Create object files for main
+_main_object_files := $(addsuffix .o,$(basename $(main_source_files)))
+_main_object_files := $(call _to_obj_dir,$(_main_object_files))
+
+targets += $(basename $(_main_object_files))
+
+# Get all object files.
+ifndef all_object_files
+  all_object_files = $(_main_object_files)
+  all_object_files += \
+    $(call _to_obj_dir,$(addsuffix .o,$(basename $(source_files))))
+endif
+
+# Remove main object files.
+object_files ?= $(filter-out $(_main_object_files),$(all_object_files))
+
+# Provide support for a flat_build with VPATH 
+# (all output at top level in$(build_dir)
+ifeq ($(flat_build),true)
+  obj_dir := $(build_dir)
+  src_dir :=
+  VPATH += $(realpath $(src_dirs)) $(realpath $(obj_dir))
+  object_files := $(addprefix $(build_dir)/,$(notdir $(object_files)))
+  all_object_files := $(addprefix $(build_dir)/,$(notdir $(all_object_files)))
+  targets := $(addprefix $(build_dir)/,$(notdir $(targets)))
+endif 
+
+# Load generated dependency files
+depend_files ?= $(all_object_files:.o=.d)
+
+-include $(depend_files)
+
+# Generic compiler options
+DEBUG ?= false
+MAKEOVERRIDES := $(filter-out DEBUG=%,$(MAKEOVERRIDES))
+ifeq ($(DEBUG), true)
+  debug_flags += -g
+else
+  optimization_flags += -O3
+  ifeq ($(use_boost), true)
+     optimization_flags += -DBOOST_DISABLE_ASSERTS
+  endif 
+  # -DNDEBUG Kenny uses!
+endif
+
+# Add flags that the user has defined.
+CPPFLAGS += $(foreach _v,$(MAKEOVERRIDES),-D$(_v))
+
+# Compiler flags.
+CFLAGS += $(warning_flags) $(cwarning_flags)
+CFLAGS += $(debug_flags) $(cdebug_flags)
+CFLAGS += $(optimize_flags) $(coptimize_flags)
+
+CXXFLAGS += $(warning_flags) $(cxxwarning_flags)
+CXXFLAGS += $(debug_flags) $(cxxdebug_flags)
+CXXFLAGS += $(optimize_flags) $(cxxoptimize_flags)
+
+FFLAGS += $(warning_flags) $(fwarning_flags)
+FFLAGS += $(debug_flags) $(fdebug_flags)
+FFLAGS += $(optimize_flags) $(foptimize_flags)
+
+CPPFLAGS += $(generate_depends)
+CPPFLAGS += $(addprefix -I,$(include_dirs))
+LDLIBS += $(addprefix -L,$(lib_dirs))
+LDLIBS += $(addprefix -l,$(libraries))
+
+# Use c++ for linking
+LINK.o = $(LINK.cc)
+
+####### Load all Pattern Rules
+
+all : $(targets)
+
+include $(makefiles_dir)/help.mk
+include $(makefiles_dir)/rules.mk
+
+####### Cleaning, Syntax checking, etc.
+.PHONY : clean clean.build
+clean.build:
+	rm -rf $(build_dir) $(tmp_files)
+clean: clean.build
+
+.PHONY: check-syntax TAGS
+# This is used for syntax checking in emacs.  Must define $(chk_sources)
+chk_sources ?= $(source_files)
+check-syntax:
+	$(CXX) $(CPPFLAGS) -Wall -Wextra -pedantic -fsyntax-only $(chk_sources)
+
+# Emacs etags file.
+TAGS: 
+	cd $(src_dir); find . \( -name \*.c -o \
+                  -name \*.h -o \
+                  -name \*.cpp -o \
+                  -name \*.hpp \) | xargs etags
+
+.PHONY: debug.build debug_makefile
+debug.build:
+	@echo generate_depends="$(generate_depends)"
+	@echo o_exts="$(o_exts)"
+	@echo h_exts="$(h_exts)"
+	@echo flat_build="$(flat_build)"
+	@echo VPATH="$(VPATH)"
+	@echo src_dir="$(src_dir)"
+	@echo build_dir="$(build_dir)"
+	@echo obj_dir="$(obj_dir)"
+	@echo src_dirs="$(src_dirs)"
+	@echo source_files="$(source_files)"
+	@echo header_files="$(header_files)"
+	@echo include_dirs="$(include_dirs)"
+	@echo main_dirs="$(main_dirs)"
+	@echo main_source_files="$(main_source_files)"
+	@echo _main_object_files="$(_main_object_files)"
+	@echo targets="$(targets)"
+	@echo all_object_files="$(all_object_files)"
+	@echo object_files="$(object_files)"
+	@echo depend_files="$(depend_files)"
+	@echo debug_flags="$(debug_flags)"
+	@echo optimization_flags="$(optimization_flags)"
+	@echo warning_flags="$(warning_flags)"
+	@echo MAKEOVERRIDES="$(MAKEOVERRIDES)"
+
+debug_makefile: debug.build

.makefiles/distribute_setup.py

+#!python
+"""Bootstrap distribute installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+    from distribute_setup import use_setuptools
+    use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import os
+import sys
+import time
+import fnmatch
+import tempfile
+import tarfile
+from distutils import log
+
+try:
+    from site import USER_SITE
+except ImportError:
+    USER_SITE = None
+
+try:
+    import subprocess
+
+    def _python_cmd(*args):
+        args = (sys.executable,) + args
+        return subprocess.call(args) == 0
+
+except ImportError:
+    # will be used for python 2.3
+    def _python_cmd(*args):
+        args = (sys.executable,) + args
+        # quoting arguments if windows
+        if sys.platform == 'win32':
+            def quote(arg):
+                if ' ' in arg:
+                    return '"%s"' % arg
+                return arg
+            args = [quote(arg) for arg in args]
+        return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
+
+DEFAULT_VERSION = "0.6.27"
+DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
+SETUPTOOLS_FAKED_VERSION = "0.6c11"
+
+SETUPTOOLS_PKG_INFO = """\
+Metadata-Version: 1.0
+Name: setuptools
+Version: %s
+Summary: xxxx
+Home-page: xxx
+Author: xxx
+Author-email: xxx
+License: xxx
+Description: xxx
+""" % SETUPTOOLS_FAKED_VERSION
+
+
+def _install(tarball, install_args=()):
+    # extracting the tarball
+    tmpdir = tempfile.mkdtemp()
+    log.warn('Extracting in %s', tmpdir)
+    old_wd = os.getcwd()
+    try:
+        os.chdir(tmpdir)
+        tar = tarfile.open(tarball)
+        _extractall(tar)
+        tar.close()
+
+        # going in the directory
+        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+        os.chdir(subdir)
+        log.warn('Now working in %s', subdir)
+
+        # installing
+        log.warn('Installing Distribute')
+        if not _python_cmd('setup.py', 'install', *install_args):
+            log.warn('Something went wrong during the installation.')
+            log.warn('See the error message above.')
+    finally:
+        os.chdir(old_wd)
+
+
+def _build_egg(egg, tarball, to_dir):
+    # extracting the tarball
+    tmpdir = tempfile.mkdtemp()
+    log.warn('Extracting in %s', tmpdir)
+    old_wd = os.getcwd()
+    try:
+        os.chdir(tmpdir)
+        tar = tarfile.open(tarball)
+        _extractall(tar)
+        tar.close()
+
+        # going in the directory
+        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+        os.chdir(subdir)
+        log.warn('Now working in %s', subdir)
+
+        # building an egg
+        log.warn('Building a Distribute egg in %s', to_dir)
+        _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
+
+    finally:
+        os.chdir(old_wd)
+    # returning the result
+    log.warn(egg)
+    if not os.path.exists(egg):
+        raise IOError('Could not build the egg.')
+
+
+def _do_download(version, download_base, to_dir, download_delay):
+    egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
+                       % (version, sys.version_info[0], sys.version_info[1]))
+    if not os.path.exists(egg):
+        tarball = download_setuptools(version, download_base,
+                                      to_dir, download_delay)
+        _build_egg(egg, tarball, to_dir)
+    sys.path.insert(0, egg)
+    import setuptools
+    setuptools.bootstrap_install_from = egg
+
+
+def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+                   to_dir=os.curdir, download_delay=15, no_fake=True):
+    # making sure we use the absolute path
+    to_dir = os.path.abspath(to_dir)
+    was_imported = 'pkg_resources' in sys.modules or \
+        'setuptools' in sys.modules
+    try:
+        try:
+            import pkg_resources
+            if not hasattr(pkg_resources, '_distribute'):
+                if not no_fake:
+                    _fake_setuptools()
+                raise ImportError
+        except ImportError:
+            return _do_download(version, download_base, to_dir, download_delay)
+        try:
+            pkg_resources.require("distribute>="+version)
+            return
+        except pkg_resources.VersionConflict:
+            e = sys.exc_info()[1]
+            if was_imported:
+                sys.stderr.write(
+                "The required version of distribute (>=%s) is not available,\n"
+                "and can't be installed while this script is running. Please\n"
+                "install a more recent version first, using\n"
+                "'easy_install -U distribute'."
+                "\n\n(Currently using %r)\n" % (version, e.args[0]))
+                sys.exit(2)
+            else:
+                del pkg_resources, sys.modules['pkg_resources']    # reload ok
+                return _do_download(version, download_base, to_dir,
+                                    download_delay)
+        except pkg_resources.DistributionNotFound:
+            return _do_download(version, download_base, to_dir,
+                                download_delay)
+    finally:
+        if not no_fake:
+            _create_fake_setuptools_pkg_info(to_dir)
+
+def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+                        to_dir=os.curdir, delay=15):
+    """Download distribute from a specified location and return its filename
+
+    `version` should be a valid distribute version number that is available
+    as an egg for download under the `download_base` URL (which should end
+    with a '/'). `to_dir` is the directory where the egg will be downloaded.
+    `delay` is the number of seconds to pause before an actual download
+    attempt.
+    """
+    # making sure we use the absolute path
+    to_dir = os.path.abspath(to_dir)
+    try:
+        from urllib.request import urlopen
+    except ImportError:
+        from urllib2 import urlopen
+    tgz_name = "distribute-%s.tar.gz" % version
+    url = download_base + tgz_name
+    saveto = os.path.join(to_dir, tgz_name)
+    src = dst = None
+    if not os.path.exists(saveto):  # Avoid repeated downloads
+        try:
+            log.warn("Downloading %s", url)
+            src = urlopen(url)
+            # Read/write all in one block, so we don't create a corrupt file
+            # if the download is interrupted.
+            data = src.read()
+            dst = open(saveto, "wb")
+            dst.write(data)
+        finally:
+            if src:
+                src.close()
+            if dst:
+                dst.close()
+    return os.path.realpath(saveto)
+
+def _no_sandbox(function):
+    def __no_sandbox(*args, **kw):
+        try:
+            from setuptools.sandbox import DirectorySandbox
+            if not hasattr(DirectorySandbox, '_old'):
+                def violation(*args):
+                    pass
+                DirectorySandbox._old = DirectorySandbox._violation
+                DirectorySandbox._violation = violation
+                patched = True
+            else:
+                patched = False
+        except ImportError:
+            patched = False
+
+        try:
+            return function(*args, **kw)
+        finally:
+            if patched:
+                DirectorySandbox._violation = DirectorySandbox._old
+                del DirectorySandbox._old
+
+    return __no_sandbox
+
+def _patch_file(path, content):
+    """Will backup the file then patch it"""
+    existing_content = open(path).read()
+    if existing_content == content:
+        # already patched
+        log.warn('Already patched.')
+        return False
+    log.warn('Patching...')
+    _rename_path(path)
+    f = open(path, 'w')
+    try:
+        f.write(content)
+    finally:
+        f.close()
+    return True
+
+_patch_file = _no_sandbox(_patch_file)
+
+def _same_content(path, content):
+    return open(path).read() == content
+
+def _rename_path(path):
+    new_name = path + '.OLD.%s' % time.time()
+    log.warn('Renaming %s into %s', path, new_name)
+    os.rename(path, new_name)
+    return new_name
+
+def _remove_flat_installation(placeholder):
+    if not os.path.isdir(placeholder):
+        log.warn('Unkown installation at %s', placeholder)
+        return False
+    found = False
+    for file in os.listdir(placeholder):
+        if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
+            found = True
+            break
+    if not found:
+        log.warn('Could not locate setuptools*.egg-info')
+        return
+
+    log.warn('Removing elements out of the way...')
+    pkg_info = os.path.join(placeholder, file)
+    if os.path.isdir(pkg_info):
+        patched = _patch_egg_dir(pkg_info)
+    else:
+        patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
+
+    if not patched:
+        log.warn('%s already patched.', pkg_info)
+        return False
+    # now let's move the files out of the way
+    for element in ('setuptools', 'pkg_resources.py', 'site.py'):
+        element = os.path.join(placeholder, element)
+        if os.path.exists(element):
+            _rename_path(element)
+        else:
+            log.warn('Could not find the %s element of the '
+                     'Setuptools distribution', element)
+    return True
+
+_remove_flat_installation = _no_sandbox(_remove_flat_installation)
+
+def _after_install(dist):
+    log.warn('After install bootstrap.')
+    placeholder = dist.get_command_obj('install').install_purelib
+    _create_fake_setuptools_pkg_info(placeholder)
+
+def _create_fake_setuptools_pkg_info(placeholder):
+    if not placeholder or not os.path.exists(placeholder):
+        log.warn('Could not find the install location')
+        return
+    pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
+    setuptools_file = 'setuptools-%s-py%s.egg-info' % \
+            (SETUPTOOLS_FAKED_VERSION, pyver)
+    pkg_info = os.path.join(placeholder, setuptools_file)
+    if os.path.exists(pkg_info):
+        log.warn('%s already exists', pkg_info)
+        return
+
+    if not os.access(pkg_info, os.W_OK):
+        log.warn("Don't have permissions to write %s, skipping", pkg_info)
+
+    log.warn('Creating %s', pkg_info)
+    f = open(pkg_info, 'w')
+    try:
+        f.write(SETUPTOOLS_PKG_INFO)
+    finally:
+        f.close()
+
+    pth_file = os.path.join(placeholder, 'setuptools.pth')
+    log.warn('Creating %s', pth_file)
+    f = open(pth_file, 'w')
+    try:
+        f.write(os.path.join(os.curdir, setuptools_file))
+    finally:
+        f.close()
+
+_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
+
+def _patch_egg_dir(path):
+    # let's check if it's already patched
+    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+    if os.path.exists(pkg_info):
+        if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
+            log.warn('%s already patched.', pkg_info)
+            return False
+    _rename_path(path)
+    os.mkdir(path)
+    os.mkdir(os.path.join(path, 'EGG-INFO'))
+    pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+    f = open(pkg_info, 'w')
+    try:
+        f.write(SETUPTOOLS_PKG_INFO)
+    finally:
+        f.close()
+    return True
+
+_patch_egg_dir = _no_sandbox(_patch_egg_dir)
+
+def _before_install():
+    log.warn('Before install bootstrap.')
+    _fake_setuptools()
+
+
+def _under_prefix(location):
+    if 'install' not in sys.argv:
+        return True
+    args = sys.argv[sys.argv.index('install')+1:]
+    for index, arg in enumerate(args):
+        for option in ('--root', '--prefix'):
+            if arg.startswith('%s=' % option):
+                top_dir = arg.split('root=')[-1]
+                return location.startswith(top_dir)
+            elif arg == option:
+                if len(args) > index:
+                    top_dir = args[index+1]
+                    return location.startswith(top_dir)
+        if arg == '--user' and USER_SITE is not None:
+            return location.startswith(USER_SITE)
+    return True
+
+
+def _fake_setuptools():
+    log.warn('Scanning installed packages')
+    try:
+        import pkg_resources
+    except ImportError:
+        # we're cool
+        log.warn('Setuptools or Distribute does not seem to be installed.')
+        return
+    ws = pkg_resources.working_set
+    try:
+        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
+                                  replacement=False))
+    except TypeError:
+        # old distribute API
+        setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
+
+    if setuptools_dist is None:
+        log.warn('No setuptools distribution found')
+        return
+    # detecting if it was already faked
+    setuptools_location = setuptools_dist.location
+    log.warn('Setuptools installation detected at %s', setuptools_location)
+
+    # if --root or --preix was provided, and if
+    # setuptools is not located in them, we don't patch it
+    if not _under_prefix(setuptools_location):
+        log.warn('Not patching, --root or --prefix is installing Distribute'
+                 ' in another location')
+        return
+
+    # let's see if its an egg
+    if not setuptools_location.endswith('.egg'):
+        log.warn('Non-egg installation')
+        res = _remove_flat_installation(setuptools_location)
+        if not res:
+            return
+    else:
+        log.warn('Egg installation')
+        pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
+        if (os.path.exists(pkg_info) and
+            _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
+            log.warn('Already patched.')
+            return
+        log.warn('Patching...')
+        # let's create a fake egg replacing setuptools one
+        res = _patch_egg_dir(setuptools_location)
+        if not res:
+            return
+    log.warn('Patched done.')
+    _relaunch()
+
+
+def _relaunch():
+    log.warn('Relaunching...')
+    # we have to relaunch the process
+    # pip marker to avoid a relaunch bug
+    if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
+        sys.argv[0] = 'setup.py'
+    args = [sys.executable] + sys.argv
+    sys.exit(subprocess.call(args))
+
+
+def _extractall(self, path=".", members=None):
+    """Extract all members from the archive to the current working
+       directory and set owner, modification time and permissions on
+       directories afterwards. `path' specifies a different directory
+       to extract to. `members' is optional and must be a subset of the
+       list returned by getmembers().
+    """
+    import copy
+    import operator
+    from tarfile import ExtractError
+    directories = []
+
+    if members is None:
+        members = self
+
+    for tarinfo in members:
+        if tarinfo.isdir():
+            # Extract directories with a safe mode.
+            directories.append(tarinfo)
+            tarinfo = copy.copy(tarinfo)
+            tarinfo.mode = 448 # decimal for oct 0700
+        self.extract(tarinfo, path)
+
+    # Reverse sort directories.
+    if sys.version_info < (2, 4):
+        def sorter(dir1, dir2):
+            return cmp(dir1.name, dir2.name)
+        directories.sort(sorter)
+        directories.reverse()
+    else:
+        directories.sort(key=operator.attrgetter('name'), reverse=True)
+
+    # Set correct owner, mtime and filemode on directories.
+    for tarinfo in directories:
+        dirpath = os.path.join(path, tarinfo.name)
+        try:
+            self.chown(tarinfo, dirpath)
+            self.utime(tarinfo, dirpath)
+            self.chmod(tarinfo, dirpath)
+        except ExtractError:
+            e = sys.exc_info()[1]
+            if self.errorlevel > 1:
+                raise
+            else:
+                self._dbg(1, "tarfile: %s" % e)
+
+def _build_install_args(argv):
+    install_args = []
+    user_install = '--user' in argv
+    if user_install and sys.version_info < (2,6):
+        log.warn("--user requires Python 2.6 or later")
+        raise SystemExit(1)
+    if user_install:
+        install_args.append('--user')
+    return install_args
+
+def main(argv, version=DEFAULT_VERSION):
+    """Install or upgrade setuptools and EasyInstall"""
+    tarball = download_setuptools()
+    _install(tarball, _build_install_args(argv))
+
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
+# ----------------------------------------------------------------------------
+#
+# GNU Make Standard Library (GMSL)
+#
+# A library of functions to be used with GNU Make's $(call) that
+# provides functionality not available in standard GNU Make.
+#
+# Copyright (c) 2005-2010 John Graham-Cumming
+#
+# This file is part of GMSL
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 
+# Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# Neither the name of the John Graham-Cumming nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# ----------------------------------------------------------------------------
+
+# Determine if the library has already been included and if so don't
+# bother including it again
+
+ifndef __gmsl_included
+
+# Standard definitions for true and false.  true is any non-empty
+# string, false is an empty string. These are intended for use with
+# $(if).
+
+true  := T
+false :=
+
+# ----------------------------------------------------------------------------
+# Function:  not
+# Arguments: 1: A boolean value
+# Returns:   Returns the opposite of the arg. (true -> false, false -> true)
+# ----------------------------------------------------------------------------
+not = $(if $1,$(false),$(true))
+
+# Prevent reinclusion of the library
+
+__gmsl_included := $(true)
+
+# Try to determine where this file is located.  If the caller did
+# include /foo/gmsl then extract the /foo/ so that __gmsl gets
+# included transparently
+
+ifneq ($(MAKEFILE_LIST),)
+__gmsl_root := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
+
+# If there are any spaces in the path in __gmsl_root then give up
+
+ifeq (1,$(words $(__gmsl_root)))
+__gmsl_root := $(patsubst %gmsl,%,$(__gmsl_root))
+else
+__gmsl_root :=
+endif
+
+include $(__gmsl_root)__gmsl
+
+else
+
+include __gmsl
+
+endif
+
+endif # __gmsl_included
+

.makefiles/help.mk

+# This should be the first target.
+help: help.help
+
+help.help:
+	@echo "Please use \`make <target>\` where <target> is one of:"
+

.makefiles/platform.mk

+## -*- mode: Makefile; fill-column: 80 -*-
+## Platform detection and flag setting.
+
+# These are default values that may be overwritten later
+mmfhome ?= $(wildcard ~mforbes)
+boost_dir ?= $(mmfhome)/usr/apps/boost/current
+
+# Compilers
+CPP = cpp
+CC = mpicc
+CXX = mpic++
+FC = mpif90
+
+# Setup the hostname for platform specific information and should be largely
+# independent of the project.
+HOSTNAME = $(shell hostname -a 2> /dev/null || hostname)
+host := UNKNOWN
+host := $(if $(findstring jaguar, $(HOSTNAME)),JAGUAR,$(host))
+host := $(if $(findstring athena, $(HOSTNAME)),ATHENA,$(host))
+host := $(if $(findstring freedom, $(HOSTNAME)),NERSC,$(host))
+host := $(if $(findstring franklin, $(HOSTNAME)),NERSC,$(host))
+host := $(if $(findstring hyak, $(HOSTNAME)),HYAK,$(host))
+uname = $(shell uname)
+host := $(if $(findstring Darwin, $(uname)),MACBOOK,$(host))
+host := $(if $(findstring Medtner, $(uname)),MACBOOK,$(host))
+
+###### athena specific modifications
+ifeq ($(host), ATHENA)
+  kennyhome = /share/home/rochekj
+  mmfhome = /share/home/mforbes
+  ifeq ($(use_fft), true)
+    ifeq ($(use_pthread), true)
+      include_dirs += $(kennyhome)/fftw312-pt/include/
+      lib_dirs += $(kennyhome)/fftw312-pt/lib/
+      LDLIBS += -lfftw3_threads
+    else
+      include_dirs += $(kennyhome)/fftw312/include/
+      lib_dirs += $(kennyhome)/fftw312/lib/
+      LDLIBS += -lfftw3
+    endif
+  endif
+  gsl_inc_dir ?= $(mmfhome)/usr/apps/gsl/current/include/
+  gsl_lib_dir ?= $(mmfhome)/usr/apps/gsl/current/lib/
+
+  include_dirs += $(mmfhome)/usr/apps/boost/current/include/
+
+  include_dirs += /opt/intel/mkl/10.0.1.014/include
+  lib_dirs += /opt/intel/cmkl/10.0.1.014/lib/em64t
+
+  FFLAGS += -cxxlib 
+endif
+
+###### hyak specific modifications
+ifeq ($(host), HYAK)
+  # Source intel compiler variables.
+  #. /sw/intel/Compiler/prod/bin/iccvars.sh intel64
+  #. /sw/intel/Compiler/prod/bin/ifortvars.sh intel64
+  #. /sw/intel/impi/prod/bin64/mpivars.sh intel64
+  #export PATH=/sw/mpich_intel/bin:${PATH}
+  #export LD_LIBRARY_PATH=/sw/mpich_intel/lib:${LD_LIBRARY_PATH}
+
+  #mpif90 -c  -I/sw/intel/Compiler/11.1/072/mkl/include
+  #-I/gscratch/bkrs/roche/include -I/sw/mpich
+  #_intel/include/ td-slda-nuclear-solver-read-gp-cio.f90 ;
+  #mpif90 -o xtdslda td-slda-nuclear-solver-read-gp-cio.o extra-io.o
+  #liberf.o f-betim.o get-rnd-wf
+  #.o fposio-wf.o -L/gscratch/bkrs/roche/lib -lfftw3
+  #-L/sw/intel/Compiler/11.1/072/mkl/lib/em64t -
+  #lmkl_scalapack_lp64 -lmkl_blacs_intelmpi_lp64 -lmkl_intel_lp64
+  #-Wl,--start-group -lmkl_sequenti
+  #al -lmkl_core -Wl,--end-group -lmpich -lpthread -lm
+
+  kennyhome ?= /usr/lusers/k8r
+  mmfhome ?= /usr/lusers/mforbes
+  ifeq ($(use_fft), true)
+    include_dirs += $(kennyhome)/fftw322-pt-intl-6gb-icc/include/