Portability poem

Meaning of PortabilityNumber of OSGeo stack software written by C/C++ camp have to run on Microsoft Windows systems. I think I wouldn’t be dead wrong if said that most of hackers from OSGeo Community work on Unix systems (Linux, Mac OS X) but there is large number of users who work on Windows.

Conclusion? Portability. Google is bursting at the seams of the essays about how to write portable code in C or C++ language. I’d add a little poem to the collection.

Principles of Portability

  • Obey the standards, because they are not just dumb rules.
  • Make a list of compilers that must be supported. Learn about their differences.
  • If possible, use GCC 4+ and Visual C++ 7.1+.
  • Using old compilers? If possible, use C89 but avoid C99.
  • Prefer GCC 4.3 and Visual C++ 8.0+, so you get C++0x support. C++0x “brings C++ more in line with the C99″ – Wikipedia, so portability is much easier.
  • Write code in C or in C++, but do not write both at the same time.
  • Avoid (direct) use of C POSIX Library.
  • Never ever disable any warnings compiler throw. Fix them.
  • Be pedantic. Compile in highest strict mode possible.
  • If possible, do not use compiler-specific features.
  • Do not make platform/architecture specific assumptions about memory addressing, memory layout, etc.
  • First understand why, then cast the hack.
  • Personal preferences are evil. Make decisions based on reasoning.
  • (Re)Use good code that already exist. Boost C++ Libraries won’t bite you!
  • KIMS (Keep it modular, stupid) and let modules to loose coupling but keep cohesion in architecture, design as well as in development cycle (releases, inter-modular dependencies).

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.

Visual C++ Toolkit 2003 still in use

Charles Petzold's TattooIn 2004, Microsoft published Visual C++ Toolkit 2003 – full version of Visual C++ 2003 optimizing compiler (version 1310) available free of charge. It was the first free, good and almost complete implementation of C++ programming language by Microsoft. It is quite old but still used by many developers.

The Toolkit is fairly complete, but you can not avoid a few hacks if you want to use it :-) So, I’ve decided to collect them all in one place to help building projects like GEOS, libLAS or GDAL/OGR with the Visual C++ Toolkit 2003.

Installation

First, installation of the following packages is required:

  1. Microsoft .NET Framework SDK 1.1
  2. Microsoft Platform SDK for Windows Server 2003 R2
  3. Microsoft Visual C++ Toolkit 2003 (no longer available from Microsoft website, just be persistent cuiling for it)

Hacks

This is list of hacks like installation of missing components and fixing a project makefiles:

  1. The .NET Framework SDK 1.1 installation (listed above) is required in order to get C Run-Time libraries installed: msvcrt.lib and msvcrtd.lib. The .NET SDK installer will copy these files (and a few other components) to directories located in:

    C:\Program Files\Microsoft Visual Studio .NET 2003
    
  2. Surprisingly, import library for C++ Run-Time Library msvcp71.dll is not included in the Visual C++ Toolkit 2003 distribution. Missing files can be downloaded from CERN server: msvcprt.lib and msvcprt.def. Copy them into

    C:\Program Files\Microsoft Visual C++ Toolkit 2003\lib
    
  3. The Toolkit does not include lib.exe utility – Microsoft Library Manager. Fortunately, lib.exe is just a simple wrapper on Microsoft Incremental Linker – link.exe. So, in your NMAKE makefiles replace lib.exe (or lib) command with:

    link.exe /lib
    

    Alternatively, you can build custom lib.exe wrapper using lib.c program. Recently, I’ve fixed NMAKE makefiles of GEOS (r2190) and libLAS (r876) projects using the former option.

Environment

Most of articles about Visual C++ Toolkit 2003 and Platform SDK installation procedure suggest to permanently update environment variables like INCLUDE, LIB and PATH. Personally, I don’t like this approach. Instead, I write a simple SET_MSVC71.BAT script which I execute in console window before I run NMAKE to build a software project using Visual C++ Toolkit 2003.

The script I use consists of three commands:

@echo off
CALL "C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\SetEnv.Cmd"
CALL "C:\Program Files\Microsoft Visual C++ Toolkit 2003\vcvars32.bat"
CALL "C:\Program Files\Microsoft.NET\SDK\v1.1\Bin\sdkvars.bat"

Copy this script to location that is available from the PATH.

Sample build – libLAS

Below, a few simple steps are presented of using Visual C++ Toolkit 2003 and environment configured as presented above to build libLAS project. The same procedure should work for projects like GEOS or GDAL/OGR.

  1. Run Command Prompt (cmd.exe)
  2. Configure environment by executing SET_MSVC71.BAT script:

    C:\> SET_MSVC71.BAT
    

    Check if basic commands are available: cl.exe, nmake.exe, link.exe.

  3. Go to libLAS source code directory:

    C:\> cd dev\liblas\trunk
    
  4. Run NMAKE command to build libLAS library and utilities:

    C:\dev\liblas\trunk> nmake /f makefile.vc
    

Good luck!