2009-11-17

CMake Cross-Compiling

I don't know if I already mentioned, but I'm writing and ODBC driver at work. A colleague of mine proposed that the driver is open sourced since it is not our main business. I hope it is, but I'm keeping my hopes high. In the mean time I can share what I have learnt.

The driver is an ODBC-RESTful bridge, that is, ODBC requests are transformed into HTTP Restful requests. Although the initial goal of the driver was to be Linux only we had to change it because of the wonderful reporting tool chosen. So I had to port it to Windows. I wont go on the tiny details on how to write portable C code (basically using #ifdefs) but on using CMake and cross-compiling. You see I went and tried to use Microsoft Visual Studio Express, the latest version, but the compiler was so slow, the IDE was, well, horrible and the Operating System is a stone in my shoe, even if executed in a virtual machine. So I decided to put MinGW to a good use and cross compile, that is, to compile on linux a windows executable. Well, in this case a DLL, since ODBC drivers are DLLs.

I'm liking CMake more everyday and cross-compilation is one of the things I liked. So, this is how you can do it. The instructions here are really boring because I'm using kubuntu at work. I need to allocate some time to get gentoo into the company's laptop. Gentoo rules in cross-compilation, not to mention a lot more things - I still have a 9 year old lappy with gentoo that I use for my private work. The crazy thing is that I always upgraded it: never reinstalled it. But back to cross-compilation.
In kubuntu (and I suppose all debian derivatives) if you want to build a windows executable you have to install mingw32. It is composed of 3 packages: mingw32, mingw32-binutils and mingw32-runtime. This will setup a /usr/i586-mingw32msvc/ folder with all the tools.

The solution I found to get CMake to use these tools is to create a toolchain file. This CMake file will contain all the definitions for the new platform. Here is small sample of a Toolchain-windows.cmake file.
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_C_COMPILER   i586-mingw32msvc-gcc)

SET(CMAKE_CXX_COMPILER i586-mingw32msvc-g++)

# Define paths to search for libraries
SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc/)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# Don't search in native paths, just the specified root paths
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Now to get a windows build what I do is create a folder side by side with the projects folder. For instance, if the project is in the folder A with all the CMake and source files I create a A-Windows, go into it and run:
cmake -DCMAKE_TOOLCHAIN_FILE=../Toolchain-windows.cmake ..
make
And I get my windows version of the software. Of course you will have to port your code to windows. Remeber the #ifdef WIN32 and, if you need to add more libraries to your executable do something like this on the CMakeLists.txt file:
if ( "${CMAKE_SYSTEM_NAME}" MATCHES "Windows" )
        set (LIBS ${LIBS}wsock32)
endif ( "${CMAKE_SYSTEM_NAME}" MATCHES "Windows" )
And try to have fun. At least you can do most of your development on a decent platform with decent tools.