The STLplus library collection is intended to be portable between operating systems and compilers. At present, this means Windows/Unix/MacOSX systems and Gnu gcc/Microsoft/Borland compilers. Whether this will be extended to other operating systems and compilers is a moot point, since the library requires a good implementation of C++ templates.
In all cases you need to unpack the software into a directory which from now on will be referred to as "the STLplus3 directory". This directory contains a subdirectory for each of the libraries (e.g. "containers") and a subdirectory for the documentation in "docs" and error messages in "messages".
The simplest approach is to simply build all of the libraries - using libraries stand-alone takes a bit more work.
As far as is reasonable, the STLplus libraries have been designed to be used separately. However, some of the libraries use the STLplus containers and portability libraries to make them easier to code and to make them portable too. Also, two of the libraries (persistence and strings) provide additional functionality for the containers and portability libraries and therefore depend on them. The following table lists the dependencies:
| Library | Depends on |
|---|---|
| containers | |
| persistence | containers, portability |
| portability | |
| subsystems | containers, portability |
| strings | containers, portability |
The bold dependencies are required, or hard dependencies. If a library has a hard dependency, then you cannot use it stand-alone - you must incorporate both the library and all of its hard dependencies into your project.
The italicised dependencies are optional, or soft dependencies. They are on by default, but can be switched off if the required library is not installed. For example, if you want to use the persistence library as a stand-alone library for making C++ types persistent but are not interested in the containers library, then that can be done.
The key to building a library without the soft dependency on the containers library is to build using the following compiler directive:
These compiler directives must be used to build the library - for example, to make the portability library stand-alone, build it with these compiler directives. The same directives must also be used to build any file in your program that includes headers from the library. The simplest way to do this is to enable the directives for the whole project.
You can merge the libraries together into one large library - known as a monolithic build of
STLplus. The simplest way of doing this is to use a shell - DOS shell on Windows, bash shell on
Linux or other Unix - and cd to the stlplus3/source directory. There, run the script
make_monolithic. This copies all of the source code into the directory. Then you will
find there are alternative project files and build scripts in the source directory to allow you to
use STLplus as a monolithic library.
The rest of the documentation is based on the assumption that you are using STLplus as a library collection, but should be easy to relate to the us of the monolithic build instead.
If you are using Gnu gcc as your compiler, then I supply a set of make rules with
STLplus that will not only build this project but any other projects you are using too. In
each of the STLplus source directories is a Makefile. This is usually quite small. The
simplest Makefile contains the following:
include ../../makefiles/gcc.mak
The makefiles module is required and can be downloaded from the same place that you
got the STLplus library. It contains the gcc.mak makefile rules which automatically
adjust to any project provided that it is organised in a certain way.
The STLplus Makefile assumes that the makefiles module is in the same parent
directory as the stlplus3 module. This is recommended, but if you wish to
use a different configuration, you will need to edit the include path in the Makefile to reflect
the change.
At the top level of the STLplus library collection is another Makefile which will build all of the libraries in one go. It contains the following:
include ../../makefiles/subdirectories.mak
The subdirectories.mak rules simply call make recursively on each
subdirectory which contains a Makefile.
The makefiles module is a generic build system which provides a standard set of make
rules for compiling and linking virtually any libraries and applications. It is not specific to
STLplus. You are free to use it as the build system for your own projects if you prefer. It is
designed to be as simple as possible to use whilst allowing multi-library projects and different
build configurations - it currently supports a Debug build, a Release build and a Gprof (code
profiling) build. You do not have to use it of course - you can write your own Makefile. However,
you are recommended to use these makefiles to build STLplus.
To build the STLplus library collection, first start a command-line shell. Then change directory to the STLplus3 directory. Then simply run one of the following commands:
You can build all three of these variants of the library without them interfering since the object files are stored in separate subdirectories for each build.
In all three cases the build creates an archive which is called lib<library>.a, where
<library> is the name of the library - e.g. libportability.a for the portability library. This
is stored in a subdirectory of the library directory which is build-specific. Refer to the porting page and look for the Build Name column in the table. As an example,
the build for DEC Alpha running Linux has the Build Name LINUX-alpha. This then has an extra
suffix added depending on the variant:
So, for example, the debug variant of the DEC Alpha build will be stored in a subdirectory called
LINUX-alpha-debug.
When you use my makefile system in a multi-library project, the make system will automatically
select the correct version of lib<library>.a depending on the configuration
chosen for the build. For example, if you build an application dependent on the portability library
and you are on a DEC Alpha platform and building the debug variant, the build system will automatically
link with LINUX-alpha-debug/libportability.a.
Once you have built the STLplus library collection, you can incorporate any of its libraries into
another project. If you want, you can build your own projects with the makefiles
module. However, this is not necessary - see the section on general
guidelines - Using The Libraries.
To use the STLplus libraries as part of another project, you need to create a Makefile for that project that will make the stlplus headers available and will link in the appropriate archive files for each of the libraries that you are using. The recommended way of doing this is to use the standard gcc.mak makefile provided as part of the makefiles module.
I'll assume that your project is in another directory next to (i.e. at the same level in the filesystem) as the STLplus directory. I'll also assume you are using the makefiles module and that this is also installed alongside. Finally, I'll assume that your source code is in a subdirectory of the project directory, for example in a subdirectory called "source".
Here is an example Makefile to build an object library from source that includes the STLplus portability and containers libraries:
LIBRARIES = ../../stlplus3/portability ../../stlplus3/containers include ../../makefiles/gcc.mak
This is stored in a file called Makefile in the source code directory of the project.
The LIBRARIES variable is a space-separated list of libraries to include in
the project. It should point to the source code directory of each library, i.e. where the .hpp and
.cpp files are to be found.
The makefiles module's rules will build the current directory and
will add the LIBRARIES as extra include paths during compilation. Since this
Makefile only builds an object library, there is no link step.
Note: the LIBRARIES variable should list the libraries in their dependency order (see the section on dependencies) with the higher-level libraries first and their required libraries after them. For example, the subsystems library should be listed before the portability library.
When using this generic makefile, there are some rules to follow to make it work.
The current directory, i.e. the one containing the Makefile, may be called source, in which case
the directory above that is used as the name of the library. If the current directory is not called
source, then the directory name is taken to be the library name. For example, if you call your
project test and store the source in a folder test/source then the
makefile system will generate an object library called libtest.a
To build a program rather than a library requires just one more line to be added to the Makefile. Here is an example Makefile that builds a program:
IMAGE = client LIBRARIES = ../../stlplus3/portability ../../stlplus3/containers include ../../makefiles/gcc.mak
The IMAGE variable tells the make system first that a program is being built and second where the linked program should be placed and what it should be called. In this case there is no path to the IMAGE so it will be built in the current directory. The name of the program will be client (in fact, on Windows, client.exe, but the .exe extension should never be specified).
A common variant is to link all programs into a common "bin" directory at the same level of directory as the library directories. This is two levels up from the source directory:
IMAGE = ../../bin/client LIBRARIES = ../../stlplus3/portability ../../stlplus3/containers include ../../makefiles/gcc.mak
The overall directory structure is now:
One final trick worth noting is that the IMAGE variable can be used to put different operating system programs into different subdirectories by using the PLATFORM variable. For example, here's a variant on the Makefile shown earlier for the client program:
IMAGE = ../../bin/${PLATFORM}/client
LIBRARIES = ../../stlplus3/portability ../../stlplus3/containers
include ../../makefiles/gcc.mak
This will put Cygwin binaries in ../../bin/CYGWIN and Linux binaries into ../../bin/LINUX.
Furthermore, the IMAGE variable can put each different build into a different subdirectory by using the SUBDIR variable instead of PLATFORM. The SUBDIR variable includes a prefix for the platform and the suffix for the different build configuration, so the debug build will be called CYGWIN-i686-debug for the Cygwin build and LINUX-i686-debug for the Linux build.
The STLplus library collection can alternatively be built on Windows using the native Microsoft Visual Studio compiler. The STLplus library includes a Visual Studio workspace for Visual Studio 6 - which can be converted automatically into a target file for Visual Studio 7 (.NET) or 8 (2005). It also includes a solution file for Visual Studio 9 (2008). Furthermore, each library in the collection has its own project file which can be incorporated into any other workspace or solution. So individual libraries can be incorporated stand-alone in this way.
Beware that there is a terminology problem here - Microsoft call a library a project and a project a workspace or solution, and so on. I will try to remember to use Microsoft terminology here.
The STLplus library collection comes with a Visual Studio 6 workspace file
(stlplus3.dsw) and a Visual Studio 9 solution file (stlplus3.sln) which
are kept in the top-level directory. You can open either by double-clicking it.
The workspace can now be built. This will build all of the libraries in the collection. First, select the configuration you wish to build - Debug or Release. Then, for each project, make it the current project by selecting menu item Project->Set Current Project. You can build all of them one at a time or use the batch build. In Visual Studio 9 you can simply build the solution and it builds all the projects.
The Debug configuration is for use in debug builds, the Release is for use in release builds (no debug information). At this stage, if you wish, you can select other configurations and build them too. Each configuration is stored separately so they do not overwrite each other.
Note: the supplied project file will build STLplus so that it uses the multi-threaded DLL versions of the C runtime library (msvcrt.dll). The default when you create a new project in Visual Studio 6 however is to use the single-threaded versions. You will need to adjust the project settings, either for STLplus or for your application so that all projects use the same settings. The symptom that will tell you that you have this problem is that, when you link your application, every symbol in the C runtime library will result in an error message from the linker saying that it is multiply defined.
Once you have built the STLplus library collection, you can then use it in other projects. This is done by loading the workspace or project file for your project (or create a new one if you haven't done so yet). Then add the STLplus project files for those libraries that you want to use in the new project.
You now need to set up an include path for the C++ compiler and a project dependency for the linker.
Note: These instructions are for Visual Studio 6. Visual Studio 9 (2008) is similar but all the dialogs have been redesigned - the principles however are the same.
To set up the include path, select the project that you wish to have access to the stlplus
libraries. Then select the menu item Project->Settings. A mind-bogglingly complicated dialog will
pop up. Select the configuration popup menu in the top left and choose All Configurations. Then
select the C++ tab from the set of tabs at the top of the right-hand pane. Then select the Category
popup menu just below the tabs and select Preprocessor. This has a text field called
Additional include directories. Type in the path to each of the subdirectories for each of
the STLplus libraries that you are using, separated by commas. You have to type this because
Microsoft didn't think to give you a directory selection dialog to help you here. However, you can
use relative paths such as ..\..\stlplus3\portability. Click OK to
dismiss the mind-boggling dialog.
To set up the linker dependency, select the menu item Project->Dependencies. The project you wish to set up dependencies for will be selected in the popup menu at the top and the other projects, including the STLplus libraries, will be listed in the list entry below that. Click on each of the STLplus libraries that you will be using so that a tick appears. This makes the selected project depend on those libraries and therefore will cause any program built with the selected project link with the stlplus archives. Click on OK to dismiss the dependencies dialog.
Note: you should only set up a dependency on an application project, not on a project that just creates a library. Sadly, Microsoft think a dependency on a library file should be resolved by copying the contents of the library into the dependent library, giving you two copies of the object code. This will subsequently cause a link error. The symptom is that the functions from STLplus will be reported as multiply defined.
To test the configuration, try including an STLplus header in your code and calling a function (or creating a class) from the library. You should be able to compile and link the project successfully.
The most common error is to get the include path wrong or to forget to set the include path for all configurations. This can be detected by the compiler giving an error on a #include line in your code that includes the STLplus header. If this happens, redo the include path step above.
The second most common error is to simply forget to set up the linker dependency, since this does not prevent compilation from working. This will manifest itself by a series of linker errors due to missing symbols. If this happens, repeat the linker dependency step above.
The final common error is to have different projects with different run-time library selections. This manifests itself by linker errors whereby standard library functions are multiply defined in different libraries. To fix this, select the menu item Project->Settings and select a specific Configuration (you cannot do this for All Configurations. For example, select the Debug configuration. Then select the C++ tab at the top right and then select the popup menu immediately below the tag, choosing the Code Generation option. There are four popup menus here and the top right of them is labelled Use Run-time Library. This should be the same for all projects - check this by clicking on different projects in the left hand pane whilst watching the contents of the run-time library popup. If there are inconsistencies, correct them. For a debug build, always pick a debug library, but you can then choose whether it is a single-threaded static library, a multi-threaded static library or a multi-threaded DLL. Choose the same for all projects. Then change the configuration to Release and check them too. This time, choose the non-debug versions of the run-time library. When you are happy that you have consistency, click OK to dismiss the dialog and try building again.
In the default project file supplied with STLplus, the Debug configuration links with the Debug Multi-Threaded DLL and the Release configuration links with the Multi-Threaded DLL. You can either adopt the same conventions or change your copy of the stlplus project file.
The last two sections described the simplest case of building the whole collection with my supplied build files. This section explains how the libraries are built so you can incorporate it into your own build system should you choose to. If you are happy with my build system, then there is no need to read any more of this document.
The first and most important thing that you need to know about STLplus is that it is just source code. There is no magic to it - all you need to do is to compile the .cpp files for each library with a compiler that is up to the job and the library is ready to use.
Then, once all of the library collection is built, you can include any of the headers by putting the library directories in your compiler's include path.
Similarly, when you link your application (or library), make sure the object files created from compiling STLplus are linked into your application.
To make life easier, bundle the compiled object files for each library into an archive (using the 'ar' command on Unix for example). Then you only have to make sure the archive is linked into your application. You could even bundle together all the object files for all the libraries in the collection to make a single big archive.
You can even drop all the source files into one directory and compile them all into a monolithic library - it will work just the same.
That is all. There really is nothing to it. The reason I keep on about this ease of use is that I've had nightmare scenes with other code libraries which require mind-bogglingly complicated procedures to build and use them which tend to fail on unconventional systems such as the Cygwin Unix-emulator on Windows which I use a lot. So I want to let you know that STLplus is not like this - it is trivially easy to build.
The STLplus library collecion is designed to be built in either debug or release variants. If you use the make utilities provided, these are set up with the two variants already. However, if you want to do it yourself, here are examples of the options to use. The examples are for the Gnu gcc compiler, but the same principles can be applied to any other compiler.
release build: gcc -I. -D<platform> -funsigned-char -DNDEBUG -O3 -c <source file> -o <object file> debug build: gcc -I. -D<platform> -funsigned-char -g -c <source file> -o <object file>
In this description, the following are specific to the recommended way of building STLplus:
-D.char can be either
unsigned or signed and this is compiler and platform
dependent. This has caused problems in the past, so I have decided to force the
signedness of char to unsigned for all platforms.
Again let me reiterate that these compiler switches are specific to the gcc compiler used in this example. However, the principles explained here should be used to build the library for any compiler. You just need to find the correct compiler switches that will achieve these principles for your compiler of choice.
Note: if you are building an application in debug mode, you should link with debug builds of the libraries. Similarly, if you are building an application in release mode, you should link with release builds of the libraries. This is because both the application and STLplus itself include the STLplus headers and there can be subtle differences in implementation between release and debug builds.
As stated above, different platforms are identified by the -D directive so that differences between operating systems can be handled. The following table shows the different platform values currently used and which ones are actually used to make a difference.
| Directive | Used | Comment |
|---|---|---|
| _WIN32 | yes | All native Windows builds using Visual Studio and MinGW |
| CYGWIN | yes | Near-Posix-compliant Unix-emulation build on Windows using Cygwin version of gcc compiler |
| MINGW | no | Native Windows build using MinGW version of gcc compiler |
| LINUX | no | Posix-compliant Unix build on Gnu/Linux with gcc |
| SOLARIS | yes | Near-Posix-compliant Unix build on Solaris with gcc |
| FREEBSD | no | Posix-compliant Unix build on FreeBSD using gcc |
| OPENBSD | no | Posix-compliant Unix build on OpenBSD using gcc |
| NETBSD | no | Posix-compliant Unix build on NetBSD using gcc |
| MACOS | no | Posix-compliant Unix build on MacOS-X (Darwin) using gcc |
Where it says "yes" in the Used column, the directive must be provided to build correctly. Where it says "no", there is no need to provide the directive and you will get a Posix-compliant build.
To use the STLplus libraries for compilation, simply make sure that the directory containing the STLplus source files for each of the libraries you are using are in your include path. For example the following would include the containers and portability libraries:
gcc -I$STLPLUS3/containers -I$STLPLUS3/portability ...
This assumes that the environment variable STLPLUS3 points to the STLplus directory. You will have to define the variable with the correct path if you want to do it this way. Alternatively, just give the full path in the -I option.
For linking, you need to simply include the lib<library>.a archives in the link. For a debug build of your program, link with the debug build of the STLplus library. For a release build, link with the release build of STLplus. For example:
ld ... $STLPLUS3/portability/<target_dir>/libportability.a $STLPLUS3/containers/<target_dir>/libcontainers.a ...
In this case, <target_dir> will be something like LINUX-alpha-debug for a
debug build and LINUX-alpha-release for a release build.
Note: when linking, you should list the libraries in their dependency order (see the section on dependencies) with the higher-level libraries first and their required libraries after them. For example, the subsystems library should be listed before the portability library.
You can build Unix command-line tools and libraries on Windows using the Gnu gcc compiler if you first install the Cygwin system. This system is a Unix-emulation layer which provides a Unix-like systems interface to the Windows operating system. For example, you access the file system as if it was a Unix file-system, create subprocesses using the Unix functions fork and exec, create pipes using Unix pipe and so on. This is a great way of porting Unix utilities to Windows, but has the disadvantage that you have to use Unix-like paths instead of Windows-like paths. I use Cygwin to develop the Unix version of STLplus whilst actually sitting at a Windows-based PC. For a native Windows version, see the next section.
You need to install Cygwin before you can build the Cygwin version of the STLplus library. Then simply follow the instructions for building STLplus with Gnu tools.
The Cygwin development environment introduced in the last section also allows native Windows applications to be built using the Gnu compiler. Unlike Unix-emulation builds, this does not use the Unix emulation layer and you therefore access operating services through the Windows system calls directly. This kind of build is known as a CygMing build.
Note: version 3.2 and later of gcc works very well in this mode. Prior versions were incomplete and I don't support them. Version 4 no longer supports this mode as far as I can tell, so use the MinGW compiler instead.
You build native applications with the Cygwin gcc compiler by specifying a special compiler switch (-mno-cygwin) for both compilation and linking.
The compiler is pre-configured with _WIN32 enabled when used in CygMing mode, so programs and libraries (such as STLplus) that use this switch will automatically build correctly.
The following settings are used in addition to the standard rules for the Cygwin builds:
compile : same as Cygwin plus: -mno-cygwin link : same as Cygwin plus: -mno-cygwin
The standard Makefile system I supply can be switched into native compilation mode when compiling on Cygwin (and only then) by setting the environment variable CYGMING to the value "on". This name is a reflection of the fact that the ability to compile native Windows applications comes from a combination of the Cygwin project and the Mingw project (Mingw standas for "minimum Gnu on Windows"). The CYGMING variable can be set in the command line to make:
make CYGMING=on
This is a one-off setting. To make the setting more permanent, change the environment of the shell you're running:
export CYGMING=on make
The MinGW development environment also allows native Windows applications to be built using the Gnu compiler. This accesses operating services through the Windows system calls directly. It is also simpler to install and use than Cygwin.
The compiler is pre-configured with _WIN32 enabled, so programs and libraries (such as STLplus) that use this switch will automatically build correctly.
The standard Makefile system I supply will compile out of the box with MinGW if it is run in the MSys environment.
Note:The makefile system will mis-identify the compiler as a Cygwin build if you run the MinGW compilers in the Cygwin shell, but it will in fact build correctly as a MinGW build.
STLplus is designed to be portable to any Unix system, well at least any Posix-compliant Unix system, but this is only true when using the Gnu gcc compiler. Native compilers on the various flavours of Unix are not supported. This is not a realistic goal when there are so many variations between compilers.
The only problem you may have is that your version of Unix is not recognised by the makefiles module. You can test this by running make and seeing if you get an error message.
If you do get an error, you can easily add support for your platform. The key is the first executable code in the makefiles/gcc.mak file:
OS := $(shell uname -s) ifneq ($(findstring CYGWIN,$(OS)),) ...
This executes the 'uname' system command and then tries to identify the operating system by recognising a substring of the return value. This is then used to set PLATFORM to a simplified name for that platform. For example, the current version of Cygwin that I'm using has a uname of "CYGWIN_NT-5.0". The code shown above recognises the Cygwin build and sets PLATFORM to be the simplified form "CYGWIN". In general, the PLATFORM value should be a short representation of the operating system name in uppercase and with no punctuation since it is passed to the compiler as a macro. Different names should be used for different versions of the operating system that use different object code and are not binary compatible. Binary compatible versions of an operating system should be mapped onto the same short name. Thus, support for all Linux systems can be handled by one variant:
# Build on Linux ifneq ($(findstring Linux,$(UNAME)),) PLATFORM := LINUX endif
In fact, support for Linux and Solaris has already been added in this way. Further platforms will be added as I try them.
The PLATFORM name is used as the prefix to the subdirectory used to store object code. Thus the Cygwin debug build is stored in CYGWIN-i686-debug whilst the Linux debug build is stored in LINUX-i686-debug. This organisation means that the same disk can be mounted on different operating systems and built without the different operating systems conflicting with each other. It also keeps the different kinds of build (e.g. release or debug) in separate directories.
The PLATFORM value is also passed to the compiler as a macro definition in the form -D<platform>, where <platform> is the name of the platform (e.g. -DLINUX). This means that if it proves necessary to differentiate between platforms to get any part of the C++ code working, then this is done by adding "#ifdef LINUX" or whatever compiler switches to the code. The macro _WIN32 is defined for native Windows builds regardless of the compiler - if this is not set then the default is to assume a vanilla Unix build. To date, only very minor differences have been found between different Unix platforms. However, if you use a different build system it is a good idea to pass this parameter to the compiler (e.g. -DLINUX) in case future updates to the library do need to have these switches. Check the ../../makefiles/gcc.mak file for the values currently supported, even if you don't plan to use my make system.