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:
- Is LEDA/GMP there? (Section 12.1)
- What version of CGAL am I running? (Section )
- Which compiler is this? (Section 12.4)
- Does the compiler support Koenig lookup? (Section 12.5.1)
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
- supports namespaces
- supports member templates
- support for std::iterator_traits.
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) :
- Operators - Templates ease arithmetic classes and iterators
- ? Any - Safe, generic container for single values of different value
types (what's the relation with variant)
- Concept check - Tools for generic programming
- ? Bind [TR1] and mem_fn - Generalized binders for
function/object/pointers and member functions (overlaps with STL
Extensions)
- ? Graph - Generic graph components and algorithms
- ? Interval - Extends the usual arithmetic functions to mathematical intervals (overlaps with CGAL::Interval_nt)
- Iterators - Iterator construction framework, adaptors, concepts, and more
- MPL - Template metaprogramming framework of compile-time algorithms, sequences and metafunction classes
- Optional - Discriminated-union wrapper for optional values
- Property map - Concepts defining interfaces which map key objects to value objects
- ? Random [TR1] - A complete system for random number generation
(overlaps with support library)
- ? Rational - A rational number class (overlaps with CGAL::Quotient)
- ? Ref [TR1] - A utility library for passing references to generic functions
- ? Smart Pointers [TR1] - Five smart pointer class templates
- ? Static assertions - Static assertions (compile time assertions)
- Tuple [TR1] - Ease definition of functions returning multiple values, and more
- ? Type traits [TR1] - Templates for fundamental properties of types
- ? Variant - Safe, generic, stack-based discriminated union container
(how does it relate to any ?)
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
- either a description of a bug ending with
``_BUG''
- or a description of a feature starting with
``NO_''.
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);