ISOcxx: The C++ Portability Package

Last update:  May 22, 2002, by Walter Brown

Contents


Introduction

ISOcxx is a software package to incorporate fixes to C++ development platforms to account for environments that do not comply with the ISO C++ language and library standard.  Such a development environment is defined, for purposes of this package, by an aggregation composed of the following five elements:

Project History

The C++ Portability Project at Fermilab grew out of informal discussions between Chris Green and Walter Brown in November, 1998.  These discussions were formalized into a draft proposal submitted to the C++ Working Group, chaired by Marc Mengel, which endorsed the proposal with minor clarifications.  After editing by Mark Fischler pursuant to the C++WG's suggestions, the proposal was then submitted to Ruth Pordes, Associate Head of the Computing Division, in mid December, 1998.

At Ruth's request, Leslie Groer began work on the project, first known as the Defects Project, late in February, 1999.  Subsequently, the project name was changed to the Portability Project.  It later came to be known more specifically as the C++ Portability Project and was given the abbreviation ISOcxx (International Standards Organization C++) for internal use.

After Leslie accepted alternate employment on May 1, 1999, the project was assigned to Walter Brown for completion.  Walter began full-time work on the project late that month.  Development continued through much of 1999, interrupted only by Walter's (presumably unrelated!) heart attack.  Ongoing maintenance has largely consisted of additional defects that the package can detect and cure.

Many individuals at Fermilab contributed to the list of defects this project addresses.  In particular, the pioneering work of Robert Kennedy is gratefully acknowledged, as are early contributions from David Adams, Chris Green, Scott Snyder, Gordon Watts, the Zoom project (Mark Fischler, Walter Brown, Philippe Canal, John Marraffino), and adaptations based on such non-Fermi sources as the Blitz++ project (Todd Veldhuizen), CLHEP (Evgueni Tchernaiev, et al.), and STLport (Boris Fomitchev).

Contributions to the Portability Project are invited and welcomed.  Questions, concerns, suggested improvements, additional defects, or other extensions to this package may be sent to zoom-support@fnal.gov.  If reporting a new defect, please furnish a (small!) program that demonstrates the defect in isolation, together (if possible) with a suggested cure; kindly also identify the specific environment than first manifested the defect.


Project Goals

 The goals of the C++ Portability Project are to:
  1. document known features and defects of C++ development environments for supported Run II platforms;
  2. provide, to the extent possible, C++ standard-compliant fixes and workarounds that serve as cures for known defects' consequences;
  3. provide a framework for testing known defects and for testing compliance code proposed as cures for defects;
  4. provide a centralized source of information regarding known problems and possible cures for various platforms; and
  5. provide a framework for easily adding newly-discovered defects and new (or improved) defect cures to the package.
The package is designed to be used independently but, for Run II projects, will interface with the Fermilab SoftRelTools (SRT) package for environment definitions.

Usage by Client Software

Overview

Client source code interfaces with the portability package via several practices that provide the desired objective of maximally portable C++ software.  These practices relate to:
    1. the package's header,
    2. client coding technique,
    3. compilation and linking details, and
    4. optional interaction via defect presence symbols.

Mandatory Header

All client source code first connects to the portability package by inserting, at the top of each source file, the directive:
#include "ISOcxx/ISOcxx.h"
Optionally, this directive may be code-guarded to improve compilation speed slightly under some circumstances:
#ifndef ISOcxx_H_INCLUDED
# include "ISOcxx/ISOcxx.h"
#endif
In every client source file, any code ahead of this directive will not receive the full benefits of any of the package's available cures.  Therefore, it is strongly recommended that the directive come first.  (Leading comments are, of course, ok.)

As of late Jan., 2001, inclusion of any standard C++ header will implicitly include the ISOcxx/ISOcxx.h header.  This enhancement was undertaken to facilitate the process of adapting non-ISOcxx code to this package; the header's explicit inclusion is still recommended as shown above.

Coding Practices

As stated above, much of the portability package's compliance code is transparent;  inspection of client source code does not reveal (beyond the presence of the mandatory ISOcxx/ISOcxx.h header) any trace of this form of compliance code.  Such code typically takes the form of replacements for keywords or library headers in which defects have been demonstrated.  Implicit activation of such code is made possible via the cooperation of the header described above and the compilation and linking practices described below.

Unfortunately, not all known defects can be cured transparently.  In these cases, the compliance code does require client code cooperation to achieve its cure.  This cooperation often takes the form of specific macro calls in lieu of (or in addition to) otherwise standard C++, in addition to use of the mandatory header and application of the recommended compilation and linking practices.

Finally, some known defects do not have associated compliance code.  We therefore recommend to avoid the use of the language or library feature that engenders such defects.  If such avoidance is undesirable, it may be possible for client software to provide two code fragments, one that operates in the presence of the defect while the other operates in the defect's absence.  The package-provided defect presence symbols can be used by client code at compile time to distinguish between the two cases.

Compilation and Linking Practices

Compilation and linking practices are, by their nature, heavily dependent on the environment.  Because the portability package is designed to bridge any gaps between an environment and the C++ language standard, it is typically necessary to make certain adjustments to the compilation and link commands to enable seamless cooperation between the package and the environment.

The main adjustment to the compilation command is to the flags governing the order in which directories are searched to locate system header files.  In particular, ISOcxx directories must be searched for these headers ahead of any other (environment-specific) directory.

To date, no adjustments have been needed to the link command.  It is conceivable that an environment supported in the future may need some adjustments to the flags governing the run-time libraries linked with the client object code.  In particular, the client application may need to be linked against an ISOcxx library (likely named libISOcxx.a) and, if so, the library may have to be linked in a specific order relative to any other libraries.  At present, however, there is no need for such a library.

Because SRT is already environment-dependent, client code compiled and linked via SRT's facility needs little or no adjustment as described above.  The following line, however, should be added to each GNUmakefile processed via SRT:

USE_ISOCXX=true
Absent SRT, and since the needed adjustments will inherently vary by environment, they can not be detailed here.  However, the following general form is recommended:
 
CXX= 
CPPFLAGS= 
CXXFLAGS= 
LDFLAGS= 
LIBS=
      name of compiler (compilation command) 
all flags affecting preprocessing (e.g., -D and -I
all other flags affecting compilation (e.g., debug and optimization levels) 
all flags controlling linking (e.g., -L but not -l
all libraries to be linked (e.g., -l flags)
 
These are used in a command such as:
$CXX $CPPFLAGS $CXXFLAGS sourcefile ... $LDFLAGS $LIBS

Defect Presence Symbols

The portability package shares its knowledge of the presence or absence of each defect in a given environment.  For each defect, the package provides a unique symbol that is defined if and only if the defect is present in the environment.  In addition, the package provides for each defect a unique symbol that is defined if and only if the defect is absent in the environment.

The former symbols all have the form DEFECT_*, while the latter symbols take the form ISOcxx_*.  Documentation for each defect (see the Defects Database) will clearly identify the pair of symbols with which the defect is associated.  Via these symbols, client code has the compile-time ability to interrogate the status of any defects of interest, and to take direct control of any defect's cure via client code conditioned on the presence of any corresponding symbol.

Extensions to C++ are treated similarly.  If detected in a given environment, a unique symbol identifying the language extension is defined.  All such extension symbols have the form EXTENSION_*.  No symbol is defined to denote the absence of a language extension.


Package Installation

Overview

Installation is necessary, of course, before first using the portability package.  Less obvious, however, is that the package must be re-installed whenever any component of the environment changes, no matter how trivially.

The behavior of the portability package is tied to the environment in which it is built, which must be identical in every respect to the environment in which it is employed.  A change in a single command-line switch, for example, may very well be sufficient to produce a radical change in the behavior of the package.

When using SRT

The portability package is built and installed via SRT by issuing the command:
gmake ISOcxx.include
which will run a script (named configure) that systematically attempts to compile and execute all of ISOcxx's defect test programs in the SRT-defined environment.  The consolidated results of this environment-testing process is recorded in ISOcxx/ISOcxx.h, a file which is the primary public interface to ISOcxx client software (see below) and which is installed in a directory (within SRT's tmp directory hierarchy) that is automatically searched whenever  such client software is built via SRT.

Absent SRT

Outside a Fermilab SRT environment, it is necessary to build the portability package by running the configure script (found in the package's top-level directory) by hand.  Then, the resulting ISOcxx/ISOcxx.h file must be installed in a suitable directory that is implicitly or explicitly searched when client software is built without SRT.  (The ISOcxx package has not as yet been tested outside the SRT environment; more detailed instructions will be provided here once such testing has been completed.)

Messages during Installation

The installation process consists primarily of a sequence of attempts to compile, link, and execute the various test programs defining the defects this package addresses.  For each such attempt, there is printed a message of the form:
checking <defect>... <status>
in which <defect> identifies the test under consideration, and <status> identifies the result of the test.  In many cases, <defect> includes the name of the specific test program being attempted.  The primary <status> information messages are:
  • ok (the defect is not present in the local environment),
  • defective (the defect is present),
  • cured (the compliance code for this defect is efficacious), and
  • PROBLEM! (the compliance code does not cure the defect as expected).
  • The last of these may arise while attempting to maintain the package (by porting to a new environment or by extending the defect coverage in a known environment), but is not expected otherwise.

    Internal Package Organization

    Overview

    The portability package is maintained via the use of the autoconf utility (version 2.13 or higher).  This software is designed to automate the production of scripts that, in turn, are run to customize a package to its local environment.  For ISOcxx purposes, the script produced in this way is named configure, and may be found in the ISOcxx package's top-level directory.  Note that autoconf is not needed to distribute, build, install, or use ISOcxx; autoconf (and its prerequisite software, m4) is only needed for package maintenance.

    Adding a New Defect

    A package maintainer who wishes to enhance the package by adding a new defect and associated compliance code may do so via the following steps.  Note that these steps are only needful to enhance the package; such enhancement is not a routine part of package installation or use.
    1. decide on the desired DEFECT_* and ISOcxx_* symbols that will uniquely identify the presence and absence, respectively, of the new defect;
    2. modify ISOcxx/ISOcxx.h.in so as to incorporate these symbols (typically via two prototype #undef directives);
    3. modify ISOcxx/Tests/final.cc so as to incorporate these symbols into the portability package's internal consistency test;
    4. devise one or more test programs whose compilation/linking/execution (or failure of same) demonstrates the defect;
    5. modify the package's GNUmakefile (if in the SRT environment) so as to reflect the portability package's new dependency on the new test program(s);
    6. modify configure.in so as to incorporate these tests and set the defect presence symbols according to the tests' results (note that for some defects, the testing sequence may be critical and so the order of tests needs careful attention);
    7. run autoconf to produce a generic configure script that incorporates the new defect test(s);
    8. run the configure script on several platforms to validate that the new tests behave everywhere as expected;
    9. install any compliance code in the package's ISOcxx directory, as appropriate: typically, macros to cure language defects are installed in ISOcxxSyntax.hh (and uninstalled in ISOcxxUnsyntax.hh), while cures for library defects are installed in the relevant library header(s);
    10. modify configure.in once more, if needed, to incorporate retesting with the compliance code in place;
    11. rerun the configure script on all platforms to validate that the compliance code behaves as expected in curing the defect wherever detected;
    12. modify the package documentation by (a) adding descriptions of the defect and its cure to the appropriate section of the ISOcxx Defects Database, (b) incorporating the new defect presence symbol into the ISOcxx Defect Summary, and (c) updating this document as may be appropriate; and finally
    13. check in the changed package to the CVS repository from which it is maintained.


    Advice for Portable Coding

    Do not define variables in control structures' predicates.

    Avoid both the  using namespace  directive and the  using declaration in a header file.