Blog Series Tags

CMake The Beautiful Beast

CMake is a mix of things. It’s a cross platform makefile generator that makes porting your C/C++ code from one OS to another or from one compiler to another inside the same OS really simple. However it complicates things a bit as well as now you need to write an extra “CMakeLists.txt” file for each of your code directories in order to allow CMake to generate those files for you. It doesn’t really help that the CMake documentation is rather dense and that there are a number of caveats that you really don’t see until you get to actually implementing it. Learning CMake therefore can be a harrowing experience and sometimes you might be tempted to give up half way and stick to the warm consolation of the Visual Studio IDE. That’s where this guide will hopefully help you as a starting point in your CMake journey that is not too steep to learn.

Source vs Binary

CMake separates your project into two major parts, SOURCE and BINARY. SOURCE is everything that you would code and is built into the BINARY which is the final compiled program and it’s resources that you would run. In CMake it’s possible to have one directory for the SOURCE portion of your project and one directory for the BINARY portion. This is unlike some tools like Visual Studio for example, which creates the binary files (the .exe’s and .dll’s) right inside the project folder. This apart from being an annoyance when you try to put your files under revision control is probably not a very good way of doing things overall. For example, with CMake you can have one SOURCE directory have multiple BINARY directories that can use two different compilers for testing purposes.

Hello Cross platform World

Let’s take a simple hello world example. Consider a project with just 1 file - main.cpp that looks like this:

int main(int argc, char** argv)
    std::cout << "Hello World" << std::endl;

Now you could trivially compile this with g++ like so:

g++ main.cpp -o main 

and with Visual Studio’s C++ compiler (from the Visual Studio Command Prompt) like so:

cl main.cpp /o main.exe

However this is as trivial as a project gets. Real software will require you to include third party headers, link in their respective static libraries and set a myriad of compiler definitions and options. So if you want your code to compile across platforms, your going to have to create one build file for each platform. For Microsoft Windows that would be a Visual Studio project, for Unix a makefile. This can quickly become tedious as the number of things you need to do cross-platform increases. This is where CMake comes in. It allows you to create a single build configuration file that it then uses to generate different kinds of builds for each platform that your interested in.

Here’s a simple CMake file that will allow you to compile our hello world project:

#The minimum version of CMake this project requires
cmake_minimum_required(VERSION 2.8)
# Project Name
project (Main) 
# Sources, we use the files 
file(GLOB Main_SOURCES *.cpp) 
# Executable 
add_executable(main ${Main_SOURCES}) 

We put this in a file names CMakeLists.txt in the same place as we put our main.cpp file. It’s probably a good idea to create a sub directory for this (such as CMakePlayground) and inside that to create a src folder to put all of the sources in, so that: [CMakePlayground]\src will contain the main.cpp file and the CMakeLists.txt file which contains the CMake script above.

Now download and install CMake if you don’t have it already We’ve almost done here. Start up CMake and you will be greeted by two pretty text boxes. One labelled “Where is the source code:” and the other labelled “Where to build the binaries:“.

Put [CMakePlayground]\src in the source code dialog (you can browse to it if you like by clicking the “Browse Source” button. Next create a binary directory for your project (I would suggest [CMakePlayground]\build) and select that as your binary directory. Now click the Configure button at the bottom left hand corner of the UI. It will open a dialog that will give you the option of choosing the build tool that you wish to use. Clicking the drop down list for under the text “Specify the generator for this project.” will show you a bunch of different build tools.

What you see here depends on your operating system. If your on Windows you would see a bunch of different Visual Studio versions along with NMake and a couple of other options. On Linux you would see Unix Makefiles and on Mac OS X you will get an option to generate an XCode project. Pick what you like and click “Finish”.

After some crunching it will present to you a screen painted red with the blood of many slain wait… Sorry wrong article. It will present you with some name value pairs of options that you don’t need to worry about right now. If you click “configure” again it will become all white - do so and click “Generate”. That’s it. Now you can go to the build folder and use whatever the tool that you defined to build your project.

For Visual Studio it would be by opening a solution. For Linux Makefiles it would be by switching to the build directory with the terminal and typing make. This should result in your project being built with the executables placed inside the build directory. The importance of going to all this trouble to get a project to build of course is that it then becomes trivial to actually compile it on any other platform. You just fire up CMake, load your source directory and pick the tool chain of choice and your ready to go. However there’s much more to see here to make use of CMake for all the complicated little things that a software project goes through such as external libraries and code generation. Expect more in the next post.

This is a post in the CMake series.