Tag Archives: CMake

Portable C++ Applications with Non-Portable Build Systems

A common setup I see in open source projects is to use makefiles as a way to build its source code.  The code itself is standard C++ (and thus portable to different compilers and operating systems), however that does me no good if I have to struggle to get it to compile on my platform (Windows in particular). This is the same as me handing off my third party library to a Linux developer with Visual Studio projects in it. They can’t really do anything with that. The trouble I have to go through to install Cygwin and learn the required build steps and tools isn’t worth the time to me.

Why is it that as software engineers we neglect our build systems? I strongly believe the build system is just as important as the code itself, especially for open source middleware projects (Take OpenSSL for example). A build system should address what I believe are the two most important ideas. First, the build system has to allow the developer to build the source using the development environment/tools of their choosing. Second, the build system needs to be easily automated (for not only generating automatic builds but for automated testing too).

Makefile scripts can certainly address the second point, however the first point they do not address. If I am a Windows developer and decide to contribute to an open source code base dominated mostly by Linux developers, I’m a bit out of luck in the “convenience” department. Working out of VIM/EMACS and ‘make’ suits a Linux developer, especially if they don’t have a GUI frontend for their OS. However, on Windows I have Visual Studio and I would love the ability to take advantage of using that IDE (or any IDE for that matter). Not only does this benefit the Windows developers, but it encourages more people to join in on the project because we can jump straight into worrying about the code and not have to deal with a frustrating and confusing build pipeline.

This philosophy on build systems is something I’ve acquired over the years after I was introduced to CMake. It’s a fantastic tool that you can use to generate scripts/projects for the build tools of your choice. For example, I can take the same CMake scripts and generate makefiles on Linux and Visual Studio project files on Windows. This is such an obviously great thing to have, I am quite frankly appalled that more projects (both open source and proprietary, such as products you will find at software companies) don’t use them. It’s been a struggle so far to get people to migrate to CMake at the company I’m working for now, but it’s not because they fail to find the value in the tool itself. It’s just a matter of migrating over (which is a whole process in itself, especially for a large company). Fortunately it’s a lot easier to migrate to something like this in an open source project where things are not as strict and risk is lower, so I hope to see more things moving towards CMake in the future. The least I can do is blog about what I feel is important and share information about CMake itself. Hopefully this will help spread the word.

CMake

For many years after college, I was used to maintaining Visual Studio projects. Once I got into portable programming, it became pretty obvious that I wouldn’t be able to use Visual Studio on every platform, such as Linux or Mac. I began looking at more portable build systems, such as SCons. While these systems were indeed portable, they had one major downside. They required that you sacrifice what kind of editor or IDE you like to work in. For example, I would have to create a Visual Studio Makefile project and maintain that separately for Windows just so I could use Visual Studio + SCons. However, this defeated the purpose (i.e. I was still maintaining platform-specific projects).

In about 2006, I found out about a build system called CMake. I would describe it in my own words, but I think a quote from the CMake about page would explain it better:

CMake is an extensible, open-source system that manages the build process in an operating system and in a compiler-independent manner. Unlike many cross-platform systems, CMake is designed to be used in conjunction with the native build environment. Simple configuration files placed in each source directory (called CMakeLists.txt files) are used to generate standard build files (e.g., makefiles on Unix and projects/workspaces in Windows MSVC) which are used in the usual way. CMake can compile source code, create libraries, generate wrappers and build executables in arbitrary combinations. CMake supports in-place and out-of-place builds, and can therefore support multiple builds from a single source tree. CMake also supports static and dynamic library builds. Another nice feature of CMake is that it generates a cache file that is designed to be used with a graphical editor. For example, when CMake runs, it locates include files, libraries, and executables, and may encounter optional build directives. This information is gathered into the cache, which may be changed by the user prior to the generation of the native build files.

I’ve been using CMake ever since and I absolutely love it. It allows you to choose the IDE or build system you would like to use on that particular platform. So for example, on Windows I could have CMake generate Visual Studio projects for me. On Linux, I can have it generate Makefile projects. On Mac, I could have it generate XCode project files. It requires little configuration for simple setups, however when you get into cross-compiling (Such as generating XCode projects for iPhone development) it requires a little (or sometimes even a lot) more work to set things up, since CMake can’t assume as much about the target platform.

One thing that surprises people that I talk with about CMake is that it is actually quicker to setup a basic project (e.g. “Hello World”) using CMake than it is to do with Visual Studio. Literally, to setup a “Hello World” project in CMake, I would do something like this:

add_executable( helloworld main.cpp )

The CMake code above can be used to generate a Visual Studio project on Windows that has one source file, main.cpp. This is the minimum required, however to make the project generation a little bit better, you would do:

cmake_minimum_required( VERSION 2.6.4 )

project( helloworld )

add_executable( helloworld main.cpp )

The code above is improved in two ways:

  1. The function cmake_minimum_required() is used to ensure that the script is being parsed by the expected version range of CMake. Newer version of CMake might remove features, change syntax, or add new features. We want to make sure our script notifies the user if they are using an unexpected version.
  2. The project() function is basically Windows-specific. It is a way of telling CMake to create a solution file for Visual Studio. (extension .sln). This is useful to have, but obviously not a requirement.

CMake is definitely one of the most useful and amazing tools I’ve ever used. I’ll be recommending it wherever I go!