Chapter 12
Portability Issues

Michael Hoffmann (hoffmann@inf.ethz.ch)
Stefan Schirra (stschirr@mpi-sb.mpg.de)
Sylvain Pion (Sylvain.Pion@sophia.inria.fr)

This chapter gives an overview of issues related to the configuration of CGAL that allow you to answer such questions as:

Also addressed here are issues related to writing code for non-standard-compliant compilers. Compilers have made a lot of progress toward the C++-standard recently. But still they do not fully implement it. There are a few features you may assume; others you may not assume. Especially you may assume that the compiler

Still, there are many bugs (sometimes known as ``features'') left in the compilers. Have a look at the list of (non-obsolete) workarounds in Section 12.5.1 to get an idea of which ``features'' are still present.

12.1   Checking for LEDA or GMP support

In the makefiles included for the compilation of every CGAL program (i.e., those to which the environment variable CGAL_MAKEFILE refers), we define command line switches that set the flags

CGAL_USE_LEDA, CGAL_USE_GMP
iff CGAL is configured with LEDA or GMP support, respectively.

12.2   Using Boost

CGAL code can rely on Boost libraries to some extent.

Boost was installed with CGAL Release 3.1, and is no longer installed, as it is already distributed with Linux and cygwin.

Since portability and backward compatibility are a concern in CGAL, we have decided that the list of Boost libraries usable in CGAL will be decided by the CGAL editorial board. The requirements are higher when it appears in the user visible interface than when Boost code is used only internally. Requirements are even lower for code that is not released such as the test-suite. Boost libraries already accepted in the C++ Standard Library Technical Report will be the first easy candidates (these are marked [TR1] in the list below).

Finally, the policy is that if a better alternative exists in Boost and is allowed, then CGAL code must use it instead of a CGAL version (which probably must be deprecated and phased out), trying not to break backward compatibility too much.

Here follows a list of Boost libraries allowed for use in CGAL (those with question marks are not decided yet) :

12.3   Using the version-number and configuration macros and flags

Here is a short example on how these macros can be used. Assume you have some piece of code that depends on whether you have LEDA-4.0 or later.

#ifdef CGAL_USE_LEDA
#include <LEDA/basic.h>
#endif

#if defined(CGAL_USE_LEDA) && __LEDA__ >= 400
... put your code for LEDA 4.0 or later ...
#else
... put your code for the other case ...
#endif 

12.4   Identifying compilers and architectures

Every compiler defines some macros that allow you to identify it; see the following table.

Borland 5.4 __BORLANDC__ 0x540
Borland 5.5 __BORLANDC__ 0x550
Borland 5.5.1 __BORLANDC__ 0x551
GNU 3.2.1 __GNUC__ 3
GNU 3.2.1 __GNUC_MINOR__ 2
GNU 3.2.1 __GNUC_PATCHLEVEL__ 1
Microsoft VC7.1 _MSC_VER 1310
Microsoft VC8.0 _MSC_VER 1400
Intel 7.0 __INTEL_COMPILER ???
SGI 7.3 _COMPILER_VERSION 730
SUN 5.0 __SUNPRO_CC 0x500
SUN 5.3 __SUNPRO_CC 0x530

There are also flags to identify the architecture.

SGI __sgi
SUN __sun
Linux __linux

12.5   Known problems and workarounds

For (good) reasons that will not be discussed here, it was decided to use C++ for the development of CGAL. An international standard for C++ has been sanctioned in 1998 [C++98] and the level of compliance varies widely between different compilers, let alone bugs.

12.5.1   Workaround flags

In order to provide a uniform development environment for CGAL that looks more standard compliant than what the compilers provide, a number of workaround flags and macros have been created. Some of the workaround macros are set in <CGAL/config.h> using the macros listed in Section 12.4 to identify the compiler. But most of them are set in the platform-specific configuration files

<CGAL/config/os-compiler/CGAL/compiler_config.h>
where os-compiler refers to a string describing your operating system and compiler that is defined as follows.

<arch>_<os>-<os-version>_<comp>-<comp-version>

<arch>
is the system architecture as defined by ``uname -p'' or ``uname -m'',
<os>
is the operating system as defined by ``uname -s'',
<os-version>
is the operating system version as defined by ``uname -r'',
<comp>
is the basename of the compiler executable (if it contains spaces, these are replaced by "-"), and
<comp-version>
is the compiler's version number (which unfortunately can not be derived in a uniform manner, since it is quite compiler specific).

Examples are mips_IRIX64-6.5_CC-n32-7.30 or sparc_SunOS-5.6_g++-2.95. For more information, see the CGAL installation guide.

This platform-specific configuration file is created during installation by the script install_cgal. The flags listed below are set according to the results of test programs that are compiled and run. These test programs reside in the directory

$(CGAL_ROOT)/config/testfiles
where $(CGAL_ROOT) represents the installation directory for the library. The names of all testfiles, which correspond to the names of the flags, start with ``CGAL_CFG_'' followed by For any of these files a corresponding flag is set in the platform-specific configuration file, iff either compilation or execution fails. The reasoning behind this sort of negative scheme is that on standard-compliant platforms there should be no flags at all.

Currently (CGAL-3.1-I-33), we have the following configuration test files (and flags). The short descriptions that are given in the files are included here. In some cases, it is probably necessary to have a look at the actual files to understand what the flag is for. This list is just to give an overview. See the section on troubleshooting in the installation guide for more explanation of some of these problems and known workarounds. Be sure to have a look at Installation/config/testfiles/ to have an uptodate version of this list.

CGAL_CFG_CCTYPE_MACRO_BUG
 
This flag is set if a compiler defines the standard C library functions in cctype (isdigit etc.) as macros. According to the standard they have to be functions.

CGAL_CFG_LONGNAME_BUG
 
This flag is set if a compiler (or assembler or linker) has problems with long symbol names.

CGAL_CFG_MATCHING_BUG_3
 
This flag is set, if the compiler does not match function arguments of pointer type correctly, when the return type depends on the parameter's type (e.g., sun C++ 5.3).

CGAL_CFG_MATCHING_BUG_4
 
This flag is set, if a compiler cannot distinguish the signature of overloaded function templates, which have arguments whose type depends on the template parameter. This bug appears for example on Sunpro 5.3 and 5.4.

CGAL_CFG_NET2003_MATCHING_BUG
 
This flag is set, if the compiler does not match a member definition to an existing declaration. This bug shows up on VC 7.1 Beta (cl1310).

CGAL_CFG_NO_BIG_ENDIAN
 
The byte order of a machine architecture distinguishes into big-endian and little-endian machines. This flag is set if it is a little-endian machine.

CGAL_CFG_NO_KOENIG_LOOKUP
 
This flag is set if the compiler does not support the operator Koenig lookup. That is, it does not search in the namespace of the arguments for the function.

CGAL_CFG_NO_LIMITS
 
This flag is set if a compiler does not know the limits.

CGAL_CFG_NO_LOCALE
 
This flag is set if a compiler does not know the locale classic.

CGAL_CFG_NO_LONG_LONG
 
The long long built-in integral type is not part of the ISO C++ standard, but many compilers support it nevertheless, since it is part of the ISO C standard. This flag is set if it is supported.

CGAL_CFG_NO_STDC_NAMESPACE
 
This flag is set if a compiler does not put the parts of the standard library inherited from the standard C library in namespace std (only tests for the symbols used in CGAL).

CGAL_CFG_NO_TMPL_IN_TMPL_DEPENDING_FUNCTION_PARAM
 
This flag is set of a compiler does not support member functions that have parameter types that are dependent on the template parameter list of the class and are implemented outside of the class body (e.g., g++ 2.95.2).

CGAL_CFG_NO_TMPL_IN_TMPL_PARAM
 
Nested templates in template parameter, such as ``template < template <class T> class A>'' are not supported by any compiler. This flag is set if they are not supported.

CGAL_CFG_OUTOFLINE_TEMPLATE_MEMBER_DEFINITION_BUG
 
This flag is set, if a compiler does not support the definition of member templates out of line, i.e., outside class scope. The solution is to put the definition inside the class. This is a feature of SunPRO 5.5.

12.5.2   Macros connected to workarounds/compilers

Some macros are defined according to certain workaround flags. This is done to avoid some #ifdefs in our actual code.

CGAL_CLIB_STD
set to std, if CGAL_CFG_NO_STDC_NAMESPACE is not set and empty, otherwise.
CGAL_LITTLE_ENDIAN
set, iff CGAL_CFG_NO_BIG_ENDIAN is set.
CGAL_BIG_ENDIAN
set, iff CGAL_CFG_NO_BIG_ENDIAN is not set.

12.5.3   Various other problems and solutions

Templated member functions

For SunPRO C++ member function templates with dependent return type must be defined in the body of the class.

Function parameter matching

The function parameter matching capacities of Visual C++are rather limited. Failures occur when your function bar is like

  bar(std::some_iterator<std::some_container<T>>....) ...
  ...
  bar(std::some_iterator<std::some_other_container<T>>....) ...
VC++ fails to distinguish that these parameters have different types. A workaround is to add some dummy parameters that are defaulted to certain values, and this affects only the places where the functions are defined, not the places where they are called. This may not be true anymore for recent VC++ versions.

typedefs of derived classes
Microsoft VC++ does not like the following sorts of typedefs that are standard
class A : public B::C {
        typedef B::C C;
};
It says that the typedef is "redefinition". So such typedefs should be enclosed by
#ifndef _MSC_VER

#endif
This may not be true anymore for recent VC++ versions.

parse error in constructions
The following program will produce a parse error with g++ 3.1.

#include <CGAL/Segment_circle_2.h> 

typedef CGAL::Segment_circle_2<double> Curve; 
typedef Curve::Segment                 Segment; 
typedef Curve::Point                   Point; 

int main()
{
  Segment s1(Point(0,0), Point(1,1));
  Curve curve(Segment(Point(0,0), Point(1,1))); // parse error
  
  // ...
  return 0;
}

This is a well-known bug in the Gnu compiler (see http://gcc.gnu.org/bugs.html#parsing). The workaround is to split :

Curve curve(Segment(Point(0,0), Point(1,1)));

into, e.g., :

   Segment s (Point(0,0), Point(1,1));
   Curve rude_curve(s);