Be strict or…

…you may have to eat the C++ programming language standard (may be with the C one together, brrr) half-baked or even raw.

GEOS 3.0.0 does not compile using GCC 4.3.3. The compiler complains, surprisingly, about missing functions like std::memcpy (GEOS core is written in C++, not C):

DoubleBits.cpp: In static member function 'static double geos::index::quadtree::DoubleBits::powerOf2(int)':
DoubleBits.cpp:51: error: 'memcpy' was not declared in this scope
DoubleBits.cpp: In constructor 'geos::index::quadtree::DoubleBits::DoubleBits(double)':
DoubleBits.cpp:94: error: 'memcpy' was not declared in this scope

StringTokenizer.cpp: In member function 'int geos::io::StringTokenizer::nextToken()':
StringTokenizer.cpp:75: error: 'strtod' was not declared in this scope
StringTokenizer.cpp: In member function 'int geos::io::StringTokenizer::peekNextToken()':
StringTokenizer.cpp:123: error: 'strtod' was not declared in this scope

These functions come from the C/C++ Standard Library, so how they could be missing? They are because the files reported above do not include standard header <cstring>. GEOS 3.0.0 had used to compiled using GCC without problems, what happened? GCC is just being aligned to the standards closer and closer, so it becomes strict and unforgiving.

There is a lot of C/C++ code of FOSS written in sloppy way being compiled in relaxed mode without use of strict compilation flags. Having in mind number of bugs reported after GCC 4.3 was released, I presume dark clouds are coming again with just released GCC 4.4.0 and upcoming 4.5.0. It’s always a good idea to not to trust chain or implicit inclusion of standard headers – wherever std::malloc is used <cstdlib> must be included, same about std::vector and <vector> and so on.

By the way, this particular bug in GEOS was spotted using GCC 4.3, reported, patched and fix was released as GEOS 3.0.3.

Detecting Visual C++ version in NMAKE makefile

Traditionally when building GDAL/OGR, GEOS or libLAS using NMAKE users specify version of Visual C++ compiler being used as value of MSVC_VER macro. This macros is not required but it’s recommended, so NMAKE can compose best possible set of compilation and linking flags for particular version of Visual C++. For instance, command specifying Visual C++ 8.0 (Visual Studio 2005) looks like this:

nmake -f makefile.vc MSVC_VER=1400

Recently, I hacked libLAS makefiles (and GEOS makefiles too), so Visual C++ version can be determined (semi-)automatically. NMAKE 1.62 or higher reports its version as value of _NMAKE_VER macro. The solution is to defined compiler version based on version of NMAKE tool:

Update 2009-04-03: Added _NMAKE_VER number 9.00.21022.08

!IF "$(_NMAKE_VER)" == ""
MSVC_VER = 4.0
!ERROR *** Prehistoric version of Visual C++
!ELSEIF "$(_NMAKE_VER)" == "162"
MSVC_VER = 5.0
!ERROR *** Prehistoric version of Visual C++
!ELSEIF "$(_NMAKE_VER)" == "6.00.8168.0"
MSVC_VER = 6.0
MSC_VER = 1200
!ERROR *** Prehistoric version of Visual C++
!ELSEIF "$(_NMAKE_VER)" == "7.00.9466"
MSVC_VER = 7.0
MSC_VER = 1300
!ELSEIF "$(_NMAKE_VER)" == "7.10.3077"
MSVC_VER = 7.1
MSC_VER = 1310
!ELSEIF "$(_NMAKE_VER)" == "8.00.50727.42"
MSVC_VER = 8.0
MSC_VER = 1400
!ELSEIF "$(_NMAKE_VER)" == "8.00.50727.762"
MSVC_VER = 8.0
MSC_VER = 1400
!ELSEIF "$(_NMAKE_VER)" == "9.00.21022.08"
MSVC_VER = 9.0
MSC_VER = 1500
!ELSEIF "$(_NMAKE_VER)" == "9.00.30729.01"
MSVC_VER = 9.0
MSC_VER = 1500
!ELSE
MSVC_VER = 0.0
MSC_VER = 0
!ENDIF

Later macros MSVC_VER and MSC_VER can be used to report Visual C++ version:

!IF "$(MSVC_VER)" == "0.0" && "$(MSC_VER)" == "0"
!MESSAGE *** Cannot determined Visual C++ version
!ERROR *** Aborting make job
!ELSE
!MESSAGE *** Using Microsoft NMAKE version $(_NMAKE_VER)
!MESSAGE *** Using Microsoft Visual C++ version $(MSVC_VER)
!MESSAGE *** Using Microsoft C/C++ version $(MSC_VER)
!ENDIF

This is not a rocket science, but it seems to work well and it frees users from manual specification of Visual C++ version. I’m not sure how the NMAKE version numbers vary across Visual Studio versions and builds. It would be good collect these version numbers to make the solution reliable. So, I’d be thankful if readers using Visual Studio 2002, 2003, 2005 and 2008 or newer :-) could report their NMAKE versions directly to me or post them as comments below.

libgeotiff lesson for today

Doing final tests of libLAS on Linux (Ubuntu 7.04), before Hobu will release 1.0.0, I attempted to build it with latest libgeotiff 1.2.5. I moved my fingers on keyboard and did ./configure && make, shortly then I saw strange looking error message:

/usr/bin/ld: makegeo: hidden symbol `__stack_chk_fail_local' in /usr/lib/libc_nonshared.a(stack_chk_fail_local.oS) is referenced by DSO
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: ld returned 1 exit status

Google is your friend, so in a few seconds I knew what’s going wrong. ./configure sets Makefile to call ld -shared. However, it does not work with GCC 4, because ld linker does not include all required references to other shared libraries. Simply, GCC linker driver seems to handle shared references better, than bare ld.

The conclusion is, that if you use GCC 4.x and you want to build libgeotiff, configure it this way:

./configure --with-ld-shared="gcc -shared"

Update July 31, 2008: Another solution is to add -fno-stack-protector option to CFLAGS and CXXFLAGS. Regarding Ubuntu Linux, this issue seems to be related to enabled SSP support (see also Ubuntu Wiki) available in GCC 4.1.

Yet another argument for -Wall always on

Yes, I’m religious about writing correct and standard C/C++ code and the decalogue of my religion tells do not ignore compiler warnings. Yet another pinch to the vast jar of examples is about getting detailed warning on mixed types in printf format specifiers:

#include <stdio .h>
int main (void)
{
printf ("%d", 0.0);
printf ("%lu", 0u);
printf ("%lu", sizeof 0);
return 0;
}

Building the test above with following three commands will answer why it’s a good idea to help the compiler to help us: