TITLE: C++ porting guidelines (Newsgroups: gnu.g++.help,comp.std.c++, 6 Nov 98) WIERINGA: David Wieringa > We're porting some software to C++ (from another language) under the > Solaris 2.5 operating system. We will probably also port this to AIX > in the future. > [snip] > > Can anyone give me ideas where we might run into porting problems? (as > far as the C++ language and standard library go) I haven't been able > to keep up with the changes to the standard, but I do believe I > remember some things changing names and such (eg some stream classes). TRIBBLE: dtribble@technologist.com Where I work, we write C++ code that is designed to run on several operating systems (currently, several flavors of Unix and Win/NT, with more in the furture). Thus we must code in a common subset of C++ that all of our target platforms support; I like to call this subset "GCD-C++", meaning "greatest common denominator C++". We have a coding guidelines document that lists the do's and don't's; you should probably do the same. Here are some basic points to remember: A FEW GOTCHAS OF C++ PORTABILITY - Nested classes are not fully supported by all compilers, so we don't use them. - Only simple templates are supported. (No specializations or partializations, nor template classes containing other template classes.) Template instantiation is also anemic, so we keep our template classes fairly simple, and use helper implementation classes to do most of the actual work. - We must simulate the 'bool' type (using typedefs or macros) on some platforms. - We must simulate the 'static_cast' operators et al with macros on some platforms. - We implement 'new(nothrow)' by hand on some platforms. - Some new keywords are entirely absent and can't be simulated very well (such as: explicit, typename, typeid, mutable), so we don't use them. It is a good idea to #define them as invalid token sequences, though, to prevent their accidental use on systems that don't support them. - Support for exceptions is so anemic, we can't use them at all. (And hence the need for 'new(nothrow)'.) This means that constructors and destructors should be kept simple, so that they don't do anything that would otherwise cause an exception. - Namespaces are not supported on most of our platforms, so we either 1) use them only on those systems that support them by wrapping them in '#if HAS_NAMESPACE' conditionals, or 2) don't use namespaces at all. - The STL is nonexistent on at least one of our platforms, so we implement our own small set of STL-like classes. - We keep source filenames relatively short (less than 25 chars) and all lower case. - We keep static initializers simple, avoiding dynamic initializations where possible. - We don't make too many assumptions about the sizes of data types, especially 'int', 'long', and pointers. - We don't make too many assumptions about the alignment of data types, but always assume that the most restrictive alignments are in effect. - We don't assume any particular byte order within data types. - We don't assume that 'char' is signed or unsigned. - We use 'inline' sparingly. - We don't assume that the standard library is thread-safe. - We avoid OS-specific system calls (e.g., fork()). We prefer to wrap these kinds of calls into a class that has platform-specific implementation files, thus isolating the rest of our code from the gory details and allowing it to be more portable. We put the portions of the language that must be simulated into a common header file (which we call "compiler.hpp") whose contents are platform-specific. Every C++ source file must #include this header. As time goes by, we hope to increase the scope of GCD-C++ (and to diminish the size of the "compiler.hpp" header), but we expect it to take at least two years for all our compiler vendors to catch up to the full standard.