Getting Started with CMake

CMake is a sophisticated, cross-platform, open-source build system developed by Kitware in 2001. CMake is the name used to refer to the entire family of tools: CMake, CTest, CDash, and CPack. These tools are used to…

  • CMake – An intelligent build system used to build simple, to very elaborate projects.
  • CTest, CDash – These are used to test and debug your projects.
  • CPack – A packaging tool that finalizes your project for distribution.

CMake simplifies the potentially monstrous build system into a few easy to write files. It is targeted towards C and C++ and is usable with various compiler/OS support. At the risk of over simplifying things, CMake looks at your project and sees a ‘file system’. You tell it where all your files are at, what you want it to do with them, and it does it. In a nut shell it’s really that easy. More elaborately however, CMake is wonderful for it’s design to support complex directory hierarchies. When you use CMake it will locate include files, libraries, executables, other optional build directives, then link everything for you. No more messy Makefiles.

CMake basically requires one thing, a CMakeLists.txt file. We’ll start with a simple example.

Here is a very simple program I wrote in C called fib.c which lists the Fibonacci Sequence up to a given value. That value is passed to the main function when it is called.

# include "stdio.h"
# include "stdlib.h"

int main( int argc, char** argv) {
	if ( argc > 2 || argc == 1 ) {
		printf("Fibonacci takes one postitive integer greater\
                         than two as it's argument\n");
		return EXIT_SUCCESS;
	}
	int a, b;
	a = 0;
	b = 1;
	printf( "%d", b );
	for( int i = 0; i + a <= atof( argv[1] ); b = i ) {
		i = a + b;
		a = b;
		printf( ", %d", i );
	}
	printf("\n");
	return EXIT_SUCCESS;
}

So let's say you'd like to compile this and give it a go. We could just compile it directly with one line...

        gcc -std=c99 fib.c

Notice we need a -std flag. We set it to c99 because loop initial declarations are only allowed in c99 mode. Alternatively you could just change that in your gcc compiler to use by default. Another option would be to use a Makefile..... Nah... Or we could use CMake. I declare the winner to be CMake.

Download

Let's make sure we have CMake on our systems, I'm using Ubuntu 10.04.

      sudo apt-get install cmake cmake-curses-gui

The cmake-curses-gui provides a somewhat-helpful-gui (a lot like the Windows version) if that's what you're into. There is pretty much no setup required here, we just need to make our CMakeLists.txt file in the main directory of our project, then run CMake from our build folder.

Setup Project

fib is the name of the folder/main directory, where the fib.c file is, as well as the soon to be disclosed CMakeLists.txt file. It's a good programming practice to do all of your builds in a build folder. Not doing so clutters your project folder with a bunch of confusing files. You'll see this after we run cmake. So let's set this up.

       mkdir /where/you/want/your/project/fib
        cd fib
        mkdir build

So this is what your project file system looks like.

        fib
       /
    build

Now use your favorite text editor (should be vim ;-) ) to create your own fib.c file, as well as a CMakeLists.txt file in your fib directory.

CMake Syntax

Here is the CMakeLists.txt file used to compile the fib.c program.

#Specify the version being used aswell as the language
cmake_minimum_required(VERSION 2.6)
#Name your project here
project(fibonacci)

#Sends the -std=c99 flag to the gcc compiler
add_definitions(-std=c99)
#This tells CMake to fib.c and name it fibonacci
add_executable(fibonacci fib.c)

The basic syntax of CMake consists of three things; comments, commands, and white spaces. A comment is made by beginning a line with the '#' character

       #Chocolate Curry is my favorite

And a command is constructed with the command name, opening parenthesis, whitespace separated arguments, and a closing parenthesis.

        command(arg1 agr2 agr3 ...)

The basic data type in CMake is a string. You can even create lists of strings using the set command.

        set(VAR a b c)

This creates variable VAR which is composed of three strings a, b, and c. Referencing a variable should look familiar to most of you. ${VAR} is the correct syntax to refer to the list of strings VAR at a later time. For instance these three command calls are the same.

        command(${VAR})
        command(a b c)
        command(a;b;c)

You can also separate strings with semicolons. Placing quotations around anything will allow it to be read as a string. For instance, the following command

        command("${VAR}")

will read in "${VAR}" not "a b c". CMake syntax also provides some useful flow control options. First is the if else logic structure.

        # some_command will be called if the variable's value is not:
        # empty, 0, N, NO, OFF, FALSE, NOTFOUND, or -NOTFOUND.
        if(var)
           some_command(...)
        endif(var) 

They also provide looping commands, foreach and while.

        set(VAR a b c)
        # loop over a, b,c with the variable f
        foreach(f ${VAR})
            message(${f})
        endforeach(f) 

Simple function and macro constructions are also supported.

        # define a macro hello
        macro(hello MESSAGE)
            message(${MESSAGE})
        endmacro(hello)
        # call the macro with the string "hello world"
        hello("hello world")
        # define a function hello
        function(hello MESSAGE)
            message(${MESSAGE})
        endfunction(hello)

Lastly CMake also supports all of your common Regular Expressions

  • ^ Matches at beginning of a line or string
  • $ Matches at end of a line or string
  • . Matches any single character other than a newline
  • [ ] Matches any character(s) inside the brackets
  • [^ ] Matches any character(s) not inside the brackets
  • [-] Matches any character in range on either side of a dash
  • * Matches preceding pattern zero or more times
  • + Matches preceding pattern one or more times
  • ? Matches preceding pattern zero or once only
  • () Saves a matched expression and uses it in a later replacement

For a more detailed description of CMake syntax go here.

Building The Project

So back to the CMakeLists.txt file to build our example

#Specify the version being used as well as the language
cmake_minimum_required(VERSION 2.6)
#Name your project here
project(fibonacci)

#Sends the -std=c99 flag to the gcc compiler
add_definitions(-std=c99)
#This tells CMake to fib.c and name it fibonacci
add_executable(fibonacci fib.c)

CMake is case insensitive, thus it does not distinguish between command() and COMMAND(). I prefer all lowercase because it is faster to type. so here is the breakdown of the CMakeLists.txt

  • cmake_minimum_required(VERSION 2.6) - This signifies the version of CMake that you're using and allows you to pass the language into documentation.
  • project(fibonacci) - This allows you to name your project and you can later on refer to the project as a whole using this string.
  • add_definitions(-std=c99) - This command sends arguments to the compiler, which CMake will choose for you unless otherwise told so.
  • add_executable(fibonacci fib.c) - This does the magic. Here CMake takes fib.c, and using all of the libraries it was handed (none in this simple example) compiles it into the output file named fibonacci.

Beautiful, we're almost done. Now we want to compile things. Once run for the first time CMake will configure itself to your system, and place the binaries (your output files) into the directory you called it from. This is where we cd into the build folder, and run

        cmake ..

The ' .. ' argument is the same as the one used in BASH, it tells CMake to execute from the CMakeLists.txt in the previous directory. This call just produced your Makefile, so let's finish it off with the last command.

        make

Now if you ls into the build folder you'll see all kinds of stuff.

  • CMakeCache.txt - Think of this as a configuration file. It has many advanced settings to optimize the build process for large projects. (Such as building the Linux Kernel! ;-) )
  • CMakeFiles (directory) - This has a lot of the stuff CMake uses under the hood to build your project. I recommend you poke around through there and take a look at stuff...
  • cmake_install.cmake - Your install file. We didn't use one in this program.
  • fibonacci - Hooray it's our program!
  • Makefile - remember your last command 'make'? This is the Makefile produced by Cmake, this is really what it all came down to.

You've Now built a program using CMake. If you'd like to see a more sophisticated example of Cmake look for my series on OpenCV under the Computer Vision tab. I use Cmake there to link all of the OpenCV libraries, and even make some of my own.

Strengthen Your CMake Muscles Here

  • CMake Documentaion is a great source for basic tutorials and examples.
  • The Wiki Page has a lot of community support and is frequently updated. Check it out for learning cool tricks and shortcuts in CMake.
This entry was posted in CMake. Bookmark the permalink.

33 Responses to Getting Started with CMake

  1. Boo CMake says:

    Not nearly detailed enough to be useful. With this much description, Qt’s qmake is easier. Having said that, I don’t like CMake much anyway; too many separate, arbitrary Things you Just Have to Know. At least that’s my impression. Like, ‘add_definitions(-std=c99)’. Really? Does that name jump out at you as how to add flags to a compiler? And is ‘set(VAR a b c)’ any more intuitive than VAR=a b c or some such? Beh on the article, and on CMake. Yet I know CMake is taking the build-world by storm.

  2. Nathan Crock says:

    Well this is a “Getting Started with CMake” tutorial, but thank you for the feedback. I appreciate that you actually read it. If anyone would like to know CMake inside and out, I provided links at the bottom of the post for more documentation.

  3. dude says:

    Thanks for the tutorial. You will always find critics who search around the web trying to promote their opinions and pet projects. Your tutorial is fine. There is tons of documentation out there on the web. You’re tutorial cuts to the chase with a nice small project to get a feel for it. Then people can seek advanced stuff elsewhere. Thanks for the effort :) .

  4. You may want to take a look at my tutorial: Learning CMake

  5. Sean Hodges says:

    Nice article, my only suggestion would be to add a link to the valuable documentation (http://www.cmake.org/cmake/help/cmake-2-8-docs.html) so you can easily find out “how to add flags to a compiler”, and how to “set(VAR a b c)” etc :)

  6. Nathan Crock says:

    Hey thanks Sean! Ya, I’ve got a link to that page under the “Strengthen your CMake Muscles Here” Section. Definitely a handy reference site!

  7. Uni says:

    Hi Nathan

    I’m a CV newbie and would be asking basic question(s) if you don’t mind. The tutorial was great and easy to understad, but I don’t get one thing. Why use CMake, when one has other options like Visual C++ and/or Turbo C (these we did in university). Since we just need to code, compile and run it using the two I mentioned, what’s the deal with writing extra stuff and THEN running the c file.. ? I don’t really get why one should use CMake… what’s the advantage here?

    Thanks so much. I’m just starting with OpenCV and I’m glad to find your website :) !

  8. Pingback: Matrix Multiplication + OpenCL = ??? | mathnathan

  9. pixor says:

    Thank you for your work.
    Nice light weight tutorial allowing you to see how cmake works before investing time to read longer and more detailed docs.

  10. Rich says:

    For what you are doing here, what works better than any of the options for me is to make a bash script called make.sh:

    #!/usr/bin/env bash
    gcc -std=c99 fib.c -o fibonacci

    But of course it’s not cross-platform blah blah blah. :-)

  11. Rich says:

    PS — thanks for the good little quick start-up tutorial on CMake, I know that was your purpose and it worked for me.

  12. Alan Koski says:

    I thought it was a very good tutorial. It was the first one I looked at to learn cmake and it taught me a lot. thanks.

  13. kevin chan says:

    Thanks for your simple description of Cmake for the starters. But it is a pity that you did not give out an example on the usage of cmake in MS windows.

  14. Nathan Crock says:

    You’re right. I share and contribute what I know and what I’m good at, unfortunately that is not windows. I’m sure there will be a windows expert out there that will write an excellent intro to Cmake. Perhaps it will be you!

  15. PierreLI says:

    Hi, thanks for your article, I read your great article and try your example in my PC under Ubuntu10.04. However, I have a question, when I’m building the example file with cmake, I cannt use gdb to debug it, as: “gdb fibonacci”, it reminds that “no debugging symbols found…”. Can u tell
    me why such things happened? Thank you!

  16. Nathan Crock says:

    That’s interesting. I do not have a similar problem. Perhaps try adding this to your CMakeLists.txt file

    set(CMAKE_BUILD_TYPE Debug)

  17. Bernhard says:

    Thanks for your tutorial. It’s too simple for my needs but it is the first tutorial I’ve read about CMake and it provides a nice overview.

    Best
    Bernhard

  18. Komal says:

    Nice article. Simple and short one is great for quick start.

  19. arjun says:

    Hi Nathan,

    Thank you very much for your tutorial which helped me start with CMake. In my project, I would like to Link 2 files from different directories and I am unable to find the proper command. Can you help me with a command and example.

    Thanks in advance,

    Arjun

  20. Nathan Crock says:

    Hey Arjun,

    Thanks for reading my article. You say link, so I assume you’re trying to plug some shared or dynamic library into a current project. (You can always compile a library with CMake before this linking example if it hasn’t yet been compiled).

    Say you’ve got your target program “TARGET.cpp”,
    CMAKE EXAMPLE: add_executable( target TARGET.cpp )
    and your library “LIBRARY.so”,
    CMAKE EXAMPLE: set( LIBS LIBRARY.so )

    Linking your target with your libraries is a one liner.
    target_link_libraries( target LIBS )

    Hope that helps

  21. Brian Chen says:

    Thank you. So far the best tutorial on the web!

  22. Vulcan says:

    This works great as a simple intro. Most of the other tutorials seem to assume too much. Thanks for getting me started.

    Also, I strongly recommend Pau Garcia’s link posted above (http://www.elpauer.org/stuff/learning_cmake.pdf).

  23. Ramshankar says:

    I actually found this useful, because I setup CMake in the top-level directory and it was generating files and polluting it, this tutorial made me realize I can use “cmake ..” and do everything in one clean “build/” folder. BTW, just started with cmake a few hours ago, got a basic program with library detection and dependencies working. Just needed your tutorial for minor tweaks but still very useful. Thanks!

  24. a. sesto says:

    This is another useless tutorial on CMake. CMake is not a tool for compiling a single .c file: it is a tool for automating the compilation of complex projects. It looks like everyone chat about CMake, but no one seems to know how to use it.

    So far, no one has ever written a single explaining how to use CMake for compiling projects with multiple executables, or object files spread across several directories that refer each other.

    CMake for a single executable does not make sense. It is useless and no one can really appreciate the power of CMake in complex projects.

  25. Eduardo says:

    Actually this didn’t work “out of the box” in Windows. I had to a) add the path to SDK in Visual Studio and b) delete the C in the line:

    cmake_minimum_required(VERSION 2.6 C)

    In any case, the tutorial is great; you get things working in 5 minutes and that’s a great incentive to keep learning more about cmake.

  26. Joe Landau says:

    Nice tutorial, thanks.

    The example failed on my system (Ubuntu 12); Cmake did not accept the “C” that you added at the end of the minimum_required (minimum what? I have no idea) statement–unknown argument, it said. On removing this, Cmake worked.

  27. Nathan Crock says:

    Thanks for the info Joe! I will update the post. I should really create a new one on the new features of CMake. Happy coding!

  28. Nathan Crock says:

    Thanks for the feed back Eduardo! Sorry it didn’t work for you, it is an old post and I don’t natively work in Windows… But I’m glad it helped you in some way! Good luck with CMake and happy coding!

  29. lyes says:

    thank you very much, it was clear and useful

  30. Atcold says:

    Yup, nice tutorial (even if I agree with a. sesto that it does not make much sense to use this utility for compiling one single file). Moreover I had the same bug Joe Landau mentioned and I had to remove the C to make it work without errors.

  31. Alex G. says:

    As a beginner with CMake, I do believe this tutorial serves its purpose perfectly. I’m trying to pull away from the safe IDE for a bit to familiarize myself with a few command line tools, and this was exactly what I needed – just a bare minimum example to get my bearings. I think you’ve saved me a lot of headache. :)

  32. cmake .. – didn’t work. I had to use:

    cmake -G ‘Unix Makefiles’ ..

  33. Fran says:

    Thanks, it’s a good tutorial to start, that’s why is called “getting-started”, don’t forge it and speak about complex projects

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>