Build system
This document describes the Aldor build process, i.e. the Makefiles and scripts used to build the supporting tools, the Aldor compiler, and its libraries.
First of all, it should be noted that in general, convention is chosen over flexibility. The directory structure requirements are rather strict, in order to impose a common pattern on all library authors. This pattern can then be used by scripts and automated tools to perform actions with little or no configuration.
Compiler
The Aldor compiler has a layered design (see compiler internals for more details). This layering is represented in the build process by putting the object files (.o) for each layer in a separate convenience library (.a/.lib file). In general, code from one layer should not use code from a layer above it, and not include headers from that layer. Currently, this is violated in several instances.
The compiler is written in C and uses a LALR(1) macro-grammar to generate its
parser. The tool
zacc
in
aldor/tools/unix
expands macros in
axl.z
and
produces
axl_y.c
by calling
yacc
on the expanded grammar.
Compiler messages databases are generated by
aldor/tools/unix/msgcat
, which
produces
comsgdb.c
and
comsgdb.h
from
comsgdb.msg
.
Libraries
The structure of an Aldor library follows a pattern:
- Makefile.am: Dispatches into include, src and test.
- include: Aldor header files installed along with the library.
- Makefile.am: Installs Aldor header files.
- src: Aldor and C code for the library.
- Makefile.am: Dispatches sub-library builds and builds main library.
- common.mk: Common variables for all sub-libraries.
- */: Subdirs containing Aldor sources.
- test: Test programs for the library.
- Makefile.am: List of test programs and their expected outcome.
- */: Subdirs containing test program sources.
Other subdirectories can be added, but the build scripts expect at least the three above to exist. By convention, we recommend the following names for optional directories:
- doc: Library documentation, usually in LaTeX form.
- tools: Extra programs, not installed with the library, but
used to generate sources or perform more complex build
tasks. These must be built
before
src
. - utility: Extra programs built for and/or with the library. Must
be built
after
src
.
The following is a high level view of the library build. A more in-depth explanation of what the build scripts and helpers do will follow in another section.
Root: Makefile.am
The root Makefile.am should be mostly empty, and only dispatch into sub-directories. For most complete libraries with documentation, it will look similar to this:
SUBDIRS = doc include src test
Sources: src/Makefile.am
Each Aldor library consists of one or more sub-libraries that are built in
dependency order. This order must be stated explicitly in the source
src/Makefile.am
for the library by listing them in the
SUBDIRS
variable.
SUBDIRS = part1 part2
Second in the Automake file should be the file name of the library being
built. We call our demo library here
libsample.a
.
lib_LIBRARIES = libsample.a
After this, we list all the C sources, including those generated from Aldor
code. Extra support code for the C side should also be listed in this
variable. The variable name is the above library name with non-alphanumeric
characters such as
-
and
.
replaced by underscores
_
.
libsample_a_SOURCES = \ part1/doma.c \ part1/domb.c \ part2/domc.c \ part2/domd.c \ #
Note that Automake does not accept trailing backslashes, so you may either end the list with a comment or omit the last backslash. The order of this list is irrelevant, as there are no dependencies between these files; they can be built in parallel.
Library name
Next, the library name must be repeated without the
lib
prefix and the
.a
suffix. This name must be equal to the current directory. I.e. if the file you
are creating is
lib/sample/Makefile.am
, then
libraryname
must be
sample
.
This name is used to build the Aldor side of the library, i.e. the .al file,
in this case
libsample.al
.
libraryname = sample
Due to Automake limitations, it is not possible to use
$(libraryname)
in the
definition of
lib_LIBRARIES
.
Often, the headers provided by and included in the library being built contain code that is conditionalised on whether they are used to build the library or they are being used to build code against a completed library. The reason for this is that the header will import the Aldor Library (.al file) automatically when you include it in client code, but while building the library, this file does not yet exist.
By default, the symbol defined by the build system that tells the header
whether it is currently being built is named
Build
followed by the
capitalised
$(libraryname)
and
Lib
, so that in our case, the symbol would
be
BuildSampleLib
. If you want to override the name between
Build
and
Lib
, you must define
Libraryname
.
E.g.:
Libraryname = Demo
will define
BuildDemoLib
, and not
BuildSampleLib
while compiling Aldor
code for this library.
Default Makefile
Most libraries will want to include the default Automake rule file that
produces and installs the Aldor library. This file resides in the
lib
under
the
aldor
build root.
include ../../buildlib.am
Usually, this will be the last line of your
src/Makefile.am
. Other rules and
variables can follow it. The following variables are defined by
buildlib.am
,
and thus additions to them must be done with
+=
.
-
datalibdir
: Installation directory for.al
file. -
datalib_DATA
: Files to be installed into$(datalibdir)
. -
aldorsrcdir
: Aldor compiler source directory with runtime headers. -
aldorexedir
: Contains built Aldor compiler binaryaldor
. -
AM_CFLAGS
: C compiler flags. -
CLEANFILES
: Removes the.al
file onmake clean
.
Extra files
The library is automatically installed in the appropriate place for the Aldor
compiler to be able to find it with
#library
. If you would like to install
other files in the same directory,
Sub-libraries: src/*/Makefile.in
A sub-library Makefile is not an Automake file, but rather a simple Makefile
preprocessed by
config.status
, generated by
configure
. It starts with a
common boilerplate that is required since we're not using Automake here, but
we want to be integrated with the Automake-based build.
(TODO: move this to an extra file in the same directory (perhaps
prelude.mk.in
), so it can be updated automatically)
@SET_MAKE@ VPATH = @srcdir@ # For AM_V_* AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ builddir := @builddir@ abs_builddir := @abs_builddir@ top_builddir := @top_builddir@ abs_top_builddir:= @abs_top_builddir@ srcdir := @srcdir@ abs_srcdir := @abs_srcdir@ top_srcdir := @top_srcdir@ abs_top_srcdir := @abs_top_srcdir@
The boilerplate is followed by a list of Aldor source files without the
.as
suffix.
library = doma domb
Lastly, the common build variables for the library are included. A relative
path using explicit
../..
should not be used, as that would break vpath (out
of tree) builds.
include $(top_srcdir)/lib/sample/src/common.mk
src/common.am
The purpose of this extraction is to minimise reduncancy by defining common
variables only once. The only required variable in this file is
libraryname
,
whose purpose was described in the earlier section "Library name".
libraryname := sample
Commonly, libraries will want to define their Aldor optimisation and debug flags, more generally speaking its compiler flags.
AXLFLAGS := -Q8 -Zdb
Finally, at the end of a library's
common.mk
, the main build machinery for
Aldor sub-libraries is included.
include $(top_srcdir)/lib/buildlib.mk
This file is always included, unless you have very specific needs, which require you to completely define your own. We recommend against this, and rather file a feature request describing your special needs. Although our design is purposefully inflexible and based on convention, we do want to be able to build any kind of Aldor library.
src/*/Makefile.deps
Next to each
Makefile.in
in a sub-library's directory, a dependency file is
required. We are unfortunately unable to correctly generate these from the
sources, for now, since it requires us to preprocess the Aldor sources with
the same flags used during the build.
For each source name
dom
listed in
library
above, there is an optional
dom_deps
, containing its dependencies within the sub-library. If the
sub-library itself depends on another sub-library from the same combined
library, these should be listed in
library_deps
.
(TODO: this is bad, it reserves the source name
library.as
)
The following fragment might be for part2 of our sample library, which depends
on part1, and in which
domd
depends on
domc
. Note that although files in
part2 may depend on files in part1, these dependencies are not listed
explicitly, but rather the complete part1 is imported.
# Intra-sublib dependencies domd_deps := domc # Sublib dependencies library_deps := part1
Testing
Libraries are tested using test programs whose return value signals the
success or failure of a test. Each program with name
$P
is in its own
subdirectory
$P
with an Aldor source file
$P/$P.as
and an output reference
file
$P/$P.ref
. Each test directory also contains a
.gitignore
file of
this format:
/$P /$P.c /$P-aldormain.c
Makefile.am contains a list of libraries required for the tests, a list of test directories, a list of tests known to fail, and an include directive for the common test code.
libraries = aldor sample AXLTESTS = \ domatest1 \ domatest2 \ # # Known to fail: XFAIL_TESTS = \ domatest2 \ # # Common code include ../../testprog.am
After the include, one may add other C sources required for the tests to run, as well as dependencies between tests, if one test uses the Aldor object of another.
domatest2_domatest2_SOURCES += domatest2/support.c domatest2/domatest2.c: domatest1/domatest1.c