This chapter provides an introduction not CMake's key concepts. As you start working with CMake, you. Will run into a variety of concepts such as targets, generators, and commands. In CMake, these concepts are implemented as C++ classes and are referenced in many of CMake's commands. Understanding these concepts will provide you with the working knowledge you need to create effective CMakeLists files.
Before going into detail about CMake's classes, it is worth understanding their basic relationships. At the lowest level are source files; these correspond to typical C or C++ source code files. Source files are combined int targets. A target is typically an executable or library. A directory represents a directory in the source tree and typically has a CMakeLists file and one-or-more targets associated with it. Every directory has a local generator that is responsible for generating the Makefiles or project for the directory. All of the local generators share a common global generator that oversees the build process. Finally, the global generator is created and driven by the cmake class itself.
Figure 1 shows the basic structure of CMake. We will now consider CMake's concepts in a bit more detail. CMake's execution begins by creating an instance of the make class and passing command line arguments to it. This class manages the overall configuration process and holds information that is global to the build process, such as the cache values. One of the first things the cake class does is to create the correct global generator based on the user's selection of which generator to use (such as Visual Studio 10, Borland Makefiles, or UNIX Makefiles). At this point, the cmake class passes control to the global generator it read by invoking the configure and generate methods.
The global generator is responsible for managing the configuration and generation of all the Makefiles (or project files) for a project. In practice, most of the work is actually done by local generators that are created by the global generator. One local generator is created for each directory of the project that is processed. So while a project will have only one global generator, it may have many local generators. For example, under Visual Studio 7, the global generator creates a solution file for the entire project while the local generators create a project file for each target in their directory.
In the case of the "Unix Make files" generator, the local generators create most of the Makefiles and the global generator simply orchestrates the process and create the main top-level Makefile. Implementation details vary widely among generators. Visual Studio 6 make use of .dsp and .dsw file templates and perform variable replacements on them. The generators for Visual Studio 7 and later directly generate the XML output without using any file templates. The Makefile generators including UNIX, NMake, Borland, etc. use a set of rule templates and replacements to generate their Makefiles.
Each local generator has an instance of the class cmMakefile, which is where the results of parsing the cMakeLists files are stored. For each directory in a project there will be a single cmMakefile instance, which is why the cmMakefile class is often referred to as the directory. This is clearer for build systems that do not use Makefiles. That instance will hold all of the information from parsing the directory's CMakeLists file. One way to think of the cmMake file class is as a structure that starts out initialized with a few variables from its parent directory, and is then filled in as the CMakeLists file is processed. Reading the CMakeLists file is simply a matter of CMake executing the commands it finds in the order it encounters them.
Each command in CMake is implemented as a separate C++ class, and has two main parts.
- The first part of a command is the InitialPass method, which receives the arguments and the
instance for the directory currently being processed and performs its operations.
command processes its arguments and if the arguments are correct, it calls a method on the1cmMakefile
to set the variable.
- The results of the command are always stored in the
instance; information is never stored in a command.
- The last part of a command is the FinalPass. The FinalPass of a command is executed after all commands (for the entire Came project) have had their InitialPass invoked. Most commands do not have a FinalPass, but in some rare cases a command must do something with global information that may not be available during the initial pass.
Once all of the CMakeLists file have been processed, the generators use the information collected into the
instances to produce the appropriate files for the target build system (such as Makefiles).