The GABI Library has been designed to be relatively portable to a variety of machines, systems and complers. Basic configuration is by specifying these three elements, either as environment variables, command line settings, or in the Defaults.mk file, e.g.:
make ARCH=sparc SYST=solaris COMP=gcc3(Note that the makefiles provided only work with GNU make; on some installations, you may have to use
gmake
instead of
make
.
With very few exceptions (mostly historical), the code contains no
#ifdef
or other such filth; these options are used to
select subdirectories — including subdirectories for
parts of the makefile. Similarly, generated files (objects,
libraries, executables) will be found in subdirectories, so it is
quite possible to maintain several different configurations on a
single file system. These three options provide a very fine
grained choice of the configuration (although they do leave one or
two points open).
For many things, such fine grained configuration is too much of a
good thing. There are only two major versions of iostreams, for
example; why have to maintain separate code for each of the
$ARCH/$SYST/$COMP
variants, when two versions suffice.
(Originally, I only developped under Unix, and the many variants
were simply links. This doesn't work for Windows or other OS's,
however.) For this reason, we have introduced the concept of
variants. For each configuration, the system dependant part of the
makefile (Makefiles/conf/$ARCH/$SYST/$COMP/system.mk
)
defines which version is relevant for that particular architecture,
for each variant. The different versions are then maintained in
different directories, as with the different configurations, but
there will typically be only two or three different versions, and
not one per configuration triplet.
Since many of the system dependancies are particular to a given system (Solaris, Linux, etc.), a given architecure (Intel, Sparc, etc.), or a given compiler (g++, Sun CC), each of these elements of the configuration is also treated as a variant.
Note that directories for the variants are only present in the source tree, and in the copies of the include files in the generated sections (directories include and sources). Since the variants are defined uniquely by the configuration triplet, one directory per triplet is sufficient for objects, libraries and executables. (There are, in fact, several additional directories for these files as well, according to the compiler options, e.g.: debug, optimized, with or without thread support, and as a statically or dynamically linked library.)
The parameters concerning the configuration are:
name | meaning | currently supported values | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
arch |
The hardware architecture. |
|
||||||||
syst |
The type of OS. This will generally be more precise than
the system variant.
|
| ||||||||
comp |
The compiler. In this case, we generally need versioning information as well. For historical reasons, this is somewhat mixed with the name. |
|
In general, we define $(configPath)
to correspond to
arch/syst/comp
in the makefiles.
Each variant also corresponds to a single
pathname component, defined as
variant.type
, e.g.
system.posix
, iostreams.standard
, etc.
accessible via the macro $(variantPath)
.
Est-que c'est vraiment ce qu'on veut, ou est-ce qu'il ne vaut pas
mieux d'utiliser les sous-répertoires, comme avant ?
Quelque chose du genre iostreams/classic
.
In terms of maintained directories, it is necessary to distinguish
between directories which contain binary information, and those
with sources or other text. In the case of directories with
binary data (work
, objects
,
lib
and bin
, all of the data will be in
the configuration specific sub-directory, e.g.
lib/$(configPath)
, etc. No global or variant
specific directories are used. In the case of directories with
(copies of) sources or text (sources
or
include
), all of the files will be found in a final
sub-directory gb
, which appears explicitly in the
include directive, as a sort of namespace management of our
include files. Under each of these directories, there is not only
a gb
direct, but also a
$(configPath)/gb
, and for each variant, a
$(variantPath)/gb
.
To start with, the three components of the configuration triplet are
all considered variants, i.e.: arch
, syst
and comp
The different variants are specified in the platform specific
makefile, for each system.
sysFamily
)
While the basic organization uses the precise system (e.g.
Solaris, AIX, MS-Windows) as part of the basic configuration, for
the most part, it can be said that we support two basic systems:
Posix and (MS-)Windows. We thus have the system variants
posix
and windows
(which result in
directories sysFamily.posix
and
sysFamily.windows
).
Note that this is different from syst
above, which
gives the precise system, and can also be used as a variant.
(Typically, this will be the case when there is a problem with one
particular system -- for example, for some reason, Solaris doesn't
support the Posix function pthread_rwlock_timedwrlock
,
which is used in the implementation of timed mutexes. So we
implement them differently for Solaris, in the solaris variant. The
configuration based variants are included before the others, so the
compiler will pick up the specific Solaris implementation, rather
than the "standard" Posix implementation.)
iostreams
)
Many environments still in use don't support the standard IO
streams correctly; we've even had problems with VC++ 6.0
here, because of bugs in the compiler. The result is that we have
two versions, classic
and standard
,
giving directories iostreams.classic
and
iostreams.standard
.
(In fact, it's slightly worse, and we have a variant
wclassic
for Windows as well.)
There are actually two threading models built per system. The
first is an unthreaded model which is common to all
configurations, and goes under the name nothreads
.
The currently supported threading models for threaded operation
are winthreads
and pthreads
.
This really could be incorporated into the system parameter, except that I suspect that there will be cases where it can't be: in the past, for example, Solaris has had their own interpretation of threads.
The information here is no longer correct. The idea is nice in
theory, but means that users of the library must specify far too
many -I
options, most of which contain configuration
specific information. So we've changed the policy, giving ourself a
little less flexibility, but making it easier on the user.
A certain order of the above directories has been rigorously followed: within any hierarchy, the configuration directory is included first, then the configuration based variants, then the directories with the variants, then the base directory. In this way, it is possible to furnish a default version of the include file, or a default version for a specific variant, and override it with a configuration specific include file.
Similarly, we use a vpath directive in the makefile, with the same basic ordering of the files, so that a particular configuration or system can easily replace an entire source file. Note: we do not use the VPATH pseudo target, so that exported headers will not be copied over to the root include.
All source files start with an include of gb/Global.hh
;
this file includes a configuration specific file which is
automatically generated by the makefiles from the configuration
information in them. The results is that a macro named
GB_dependentInclude
defined. This macro takes two
parameters, the first the name of the variant, and the second a
filename. The name of the variant must be literally one of the
following: conf
, arch
, syst
,
comp
, sysFamily
, threads
or
iostreams
. (conf
is used for the complete
configuration triplet.)
Thus, for a dependent include, the source file will contain something like:
#include GB_dependentInclude( threads, gb/Mutex.hh )
Such include statements are normally reserved for our own library
includes and implementation. The library itself will provide an
include file gb/Mutex.hh
which will forward to the
appropriate dependent include, so this is largely transparent to the
user.
When the user compiles, he must specify four include directories, e.g.:
-I$GABIROOT/include/$ARCH/$SYST/$COMP -I$GABIROOT/include -I$GABIROOT/sources/$ARCH/$SYST/$COMP -I$GABIROOT/sources
The library path is:
-L$GABIROOT/lib/$ARCH/$SYST/$COMP