Getting Started with CMake


Since it’s summer, and I’m going to be working on it anyways, I’ve decided the best use of my time is by configuring my Tora-Engine math library to use CMake, CTest, CDash, and CPack. The following tutorials will cover my commits in setting up the build system for the Tora Math Library, and discuss a bit about how CMake works.

What is CMake?

CMake is not actually a single piece of software. It’s more accurate to say that CMake is a software suite. In it’s entirety, CMake consists of four separate parts; CMake, CTest, CDash, and CPack. Each of these things help with a different part of the build chain, or adds additional information to the process.

The reason CMake is so widely used though, isn’t always for the entire software suite; many people use CMake just for the CMake portion of the build chain. You don’t have to use CTest, CDash, or CPack. It’s a very powerful tool that allows you to immediately prepare your code for cross-platform development. But using all of these tools together can really help, as you’ll see. Here’s what each of these tools do;

  • CMake – Configures and Generates solution/project/makefiles for the developer or end-user to use.
  • CTest – Builds, times, and runs applications that are marked testable, and reports results to CDash.
  • CDash – A web dashboard for managing and allowing user-friendly viewing of CTest results.
    (Example Dashboard: http://open.cdash.org/)
  • CPack – Packages the software into a distributable format. (.zip/.tar.gz/.msi/.dmg/etc.)

Where Can I Get CMake?

On Linux systems, CMake usually comes as a part of the development tools. You can test to see if you have CMake simply by running command -v cmake. If it spits out nothing, you might want to apt-get, pacman, yum, zypper or (insert package manager of choice) cmake and see if you can easily download it. In Arch, cmake is a part of the extra repositories, so it should be fairly easy to install.

On Windows or OS X systems, you can find installers on the CMake website. Be sure to download the binary installers and not the source. – Though the source is definitely available.
(http://www.cmake.org/cmake/resources/software.html)

Note: There is good reason CMake must be installed and not packaged with your repo. We have a code base that we want to be cross-platform, it is unwise to package all possible binaries for all possible OSes with your code base. If you are packaging Premake or CMake with your source, you’re pandering to the OSes that you provide the binaries for. CMake is an external dependency, and should be treated as such.

CMake Scripting Language

Unlike almost every other build tool on the planet, CMake opted to not support an existing scripting language, and instead to make their own. The reason is because the needs of a build system are specific, and a custom scripting language allowed them to “trim the fat” so to speak. It’s a smart choice, but probably the sole reason why people are afraid to start with CMake, as you must commit to learning a new scripting language.

The scripting language feels very bash-like to me, because the common way we access variables is through ${VARIABLE_NAME}, which is expanded within a function call to be exactly the contents of that variable. Therefor, if MY_VARIABLE is set to 5, typing "${MY_VARIABLE}" will expand to "5". (Note: Expansion only occurs within a function call.) Logic can be preformed within scripts, just keep in mind that all of the logic you are preforming is based in the Configuration step of all the steps above. CMake scripts tend to only run in Configuration unless otherwise stated.

So if I want to check if a file exists, I can write something like so;

If you are going to be writing any CMake scripts, you should have documentation ready.
(http://www.cmake.org/cmake/help/documentation.html)

Starting a CMake Project

Even though we didn’t cover much, we have enough information to jump right in and create a simple CMake project. Let’s begin by setting the directory structure for our project. As you can see from the following commit, our math library has it’s basic directory structure and files. This is actually enough information to generate a solution file, but not enough information to build, as we are creating a templated math library.
(https://github.com/tora-engine/math/tree/54c8c8dcae71676c074243bfb45c2e3209a12b88)

Our directory structure:

    • /
    • /CMakLists.txt
    • /tora/
    • /tora/math/
    • /tora/math/CMakeLists.txt
    • /tora/math/version.h

Notice the directory setup? I have created the directory structure how I want end-users to access the code. I now have clean and correct absolute directory access to the Tora math library. If I had just made a folder called “src” with version.h inside it, I’d have to include the “src” folder, and access would be different than what I wanted. Of course this is all preference, but definitely something you should think about when setting up your projects.

Each configuration CMake script is named “CMakeLists.txt” by definition of CMake. We have two; the root-level CMake script, and the math library script. Since in my example there is no source code to produce either a library or application (I did not have the math library add_executable or add_library), we will create a simple test application so that we have something to compile. Later this will be our application that CTest will have marked as a testable application, and will report information to CDash from. But for now, it’s just a basic return 0; application.
(https://github.com/tora-engine/math/tree/6b5c415a3ab1f9bb02b36f4f42d6e9ba6e62382f)

Our Added Files:

    • /tests/
    • /tests/test_runner.cpp
    • /tests/CMakeLists.txt

At this point, we are able to build an application on multiple platforms. The application doesn’t do much of anything, it just simply runs and returns 0. Let’s discuss all (3) of the CMakeLists.txt we made and what they do. Let’s cover the order in which the CMakeLists.txt scripts will be run.

1. /CMakeLists.txt – It is implied the user should run root scripts first.
(It’s good practice to have configuration scripts in root so the user doesn’t have to dig for them.)

cmake_minimum_required – Allows us to assert that the user must be using a minimal version of 2.8 for configuring this project.
project – Creates the solution/makefile/project that we can begin to add targets to it.
include_directories – Adds the following two directories to the include path for the project. (source for standard headers, binary for configured headers)
add_subdirectory – Opens the relative folder provided, and runs the CMakeLists.txt script inside.
option – Presents the user with an option they can change at configure-time. By default, this option is ON.

2. /tora/math/CMakeLists.txt – Since add_subdirectory(tora/math) is called before add_subdirectory(tests)

configure_file – Takes a file “${CMAKE_CURRENT_SOURCE_DIR}/version.h.in” and parses it, expanding ${CMAKE_VARIABLES}, then saves it to “${CMAKE_CURRENT_BINARY_DIR}/version.h”
set – Sets a variable so that you can have access to it later. (Assigning to a variable)
add_library – Not actually used in our example, because we are creating an all-header template math library. But would create a static library target.

3. /tests/CMakeLists.txt – Only looked at if TORA_MATH_TESTS option is set to ON. Otherwise, this file is not considered.

set – Sets a variable so that you can have access to it later. (Assigning to a variable)
add_executable – Creates an executable target, that can be built and run.
target_link_libraries – Tells a target that it must link with the following libraries. (Can either be a .lib/.a or a target produced at some point by CMakeLists.txt)

Configuring and Generating

Now that we have everything set up – we can simply configure and generate the project so we can build our sample application. If you did not try to make your own CMakeLists.txt scripts, feel free to check out the source provided, and try to run CMake yourself to see the output.

Command Line

There is a very cute command that you can run in order to configure/generate from command line. Assuming we are in the repository, we can run the following commands;

This will create our project files in the build directory that we made. We create the directory, move into the directory and run cmake on the previous directory.

GUI

We can also opt to configure/generate from a GUI that CMake provides. (Named cmake-gui)

CMakeSnapshotIn order to use the GUI, all you need to do is provide the path to the Source, where you want it to put the Binaries, and then you can Configure and Generate respectively. CMake will spit out project files in the binary directory provided. (Also notice how we can toggle TORA_MATH_TESTS?)

What Does All This Do?

Well, nothing much yet. We’ve set up our math library so that it creates a solution and a single executable. I highly suggest making your own sample CMake file, and trying to get at least something to configure/generate/compile with CMake. It can be a very powerful program, as you will see in future posts.

Cheers!~

Leave a comment

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