Contents
CHAPTER 1 WHY CMAKE? 1
11 The History of CMake 3
1.2 Why Not Use Autoconf? 3
13 Why Not Use JAM, qmake, SCons, or ANT? 4
14 Why Not Script It Yourself? 4
1.5 On What Platforms Does CMake Run? 5
CHAPTER 2 GETTING STARTED 7
2.1 Getting and Installing CMake on Your Computer 7
UNIX and Mac Binary Installations 7
Windows Binary Installation 7
2.2 Building CMake Yourself 8
23 Basic CMake Usage and Syntax 8
2.4 Hello World for CMake 9
2.5 How to Run CMake? 10
Running CMake’s Qt Interface i
Running the ccmake Curses Interface 13
Running CMake from the Command Line Is
Specifving the Compiler to CMake 15
Dependency Analysis 16
2.6 Editing CMakeLists Files 17
2.7 Setting Initial Values for CMake 17
2.8 Building Your Project 19
CHAPTER 3 KEY CONCEPTS 21
3.1 Main Structures 21
3.2 Targets 24
3.3 Source Files 25
34 Directories, Generators, Tests, and Properties 26
3.5 Variables and Cache Entries 27
3.6 Build Configurations 32
CHAPTER 4 WRITING CMAKELISTS FILES. 33
41 Make Syntax 33
4.2 Basic Commands 34
43 Flow Control 35
44 Regular Expressions 4245 Checking Versions of CMake 44
4.6 Using Modules 45
Using CMake with SWIG 48
Using CMake with Ot 49
Using CMake with FLTK 50
47 Policies 50
Updating a Project For a New Version of CMake 53
48° Linking Libraries 57
Specifying Optimized or Debug Libraries with a Target 59
49 Shared Libraries and Loadable Modules 59
4.10 Shared Library Versioning 64
4.11 Installing Files 66
Installing Prerequisite Shared Libraries 76
4.12 Advanced Commands 82
CHAPTER 5 SYSTEM INSPECTION 85
5.1 Using Header Files and Libraries 85
5.2 System Properties 87
53 Finding Packages 92
54 Built-in Find Modules 93
55 How to Pass Parameters to a Compilation? 95
5.6 How to Configure a Header File 97
5.7 Creating CMake Package Configuration Files 99
CHAPTER 6 CUSTOM COMMANDS AND TARGETS 103
61 Portable Custom Commands 103
6.2 Using add_custom_command on a Target 105
How to Copy an Executable Once it is Built? 106
63 Using add_custom_command to Generate a File 107
Using an Executable to Build a Source File 107
64 Adding a Custom Target 108
65 Specifying Dependencies and Outputs i
6.6 When There Isn’t One Rule For One Output 112
A Single Command Producing Multiple Outputs 112
Having One Output That Can Be Generated By Different Commands 112
CHAPTER7 __ CONVERTING EXISTING SYSTEMS TO CMAKE 115
7A Source Code Directory Structures 115
72 Build Directories 117
13 Useful CMake Commands When Converting Projects 119
74 Converting UNIX Makefiles 1207S Converting Autoconf Based Projects 121
16 Converting Windows Based Workspaces 123
CHAPTER 8 CROSS COMPILING WITH CMAKE 125
8.1 Toolchain Files 126
Finding External Libraries, Programs and Other Files 128
8.2 System Inspection 130
Using Compile Checks 131
8.3 Running Executables Built in the Project 133
8.4 Cross Compiling Hello World 136
8.5 Cross Compiling for a Microcontroller 140
8.6 Cross Compiling an Existing Project 143
8.7 Cross Compiling a Complex Project - VTK 145
8.8 Some Tips and Tricks 147
CHAPTER 9 PACKAGING WITH CPACK 149
9.1 CPack Basics 149
Simple Example 150
What Happens When CPack.cmake Is Included? 151
Adding Custom CPack Options 152
Options Added by CPack 153
9.2 CPack Source Packages 154
9.3 Pack Installer Commands 154
9.4 CPack for Windows Installer NSIS 156
CPack Variables Used by CMake for NSIS 156
Creating Windows Short Cuts in the Start Menu 161
Advanced NSIS CPack Options 161
Setting File Extension Associations With NSIS 162
Installing Microsoft Run Time Libraries 163
CPack Component Install Support 163
9.5 CPack for Cygwin Setup 173
9.6 CPack for Mac OS X PackageMaker 176
9.7 CPack for Mac OS X Drag and Drop 178
9.8 CPack for Mac OS X X11 Applications 180
9.9 CPack for Debian Packages 182
9.10 CPack for RPM 183
9.11 CPack Files 183
CHAPTER 10 AUTOMATION & TESTING WITH CMAKE 185
10.1 Testing with CMake, CTest, and CDash 185
10.2 How Does CMake Facilitate Testing? 186vi
10.3 Additional Test Properties 187
10.4 Testing Using CTest 189
10.5 Using CTest to Drive Complex Tests 191
10.6 Handling a Large Number of Tests 192
10.7 Producing Test Dashboards 194
Adding CDash Dashboard Support to a Project 196
+ Client Setup 199
10.8 Customizing Dashboards for a Project 202
Dashboard Submissions Settings 202
Filtering Errors and Warnings 203
Adding Notes to a Dashboard 205
10.9 Setting up Automated Dashboard Clients 206
Settings for Continuous Dashboards 210
Variables Available in CTest Scripts 212
10.10 Advanced CTest Scripting 212
Limitations of Traditional CTest Scripting 213
Extended CTest Scripting 213
10.11 Setting up a Dashboard Server 218
CDash Server 218
Advanced Server Management 220
Build Groups 223
Email 225
Sites 226
Graphs 227
Adding Notes to a Build 228
Logging 229
Test Timing 229
Mobile Support 230
Backing up CDash 230
Upgrading CDash 231
CDash Maintenance 232
10.12 Subprojects 233
Using ctest_submit with PARTS and FILES 236
Splitting Your Project into Multiple Subprojects 237
CHAPTER 11 PORTING CMAKE TO NEW PLATFORMS AND LANGUAGES241
LLL The Determine System Process 241
2 The Enabie Language Process 242
11.3 Porting to a New Platform 244
14 Adding a New Language 246
11S Rule Variable Listing 247
General Tag Variables 247
Language Specific Information 24811.6 Compiler and Platform Examples 248
Como Compiler 248
Borland Compiler 249
11.7 Extending CMake 250
Creating a Loaded Command 250
Using a Loaded Command 251
CHAPTER 12___ TUTORIALS 255
12.1 A Basic Starting Point (Step 1) 255
Adding a Version Number and Configured Header File 256
12.2 Adding a Library (Step 2) 258
12.3. Installing and Testing (Step 3) 260
12.4 Adding System Introspection (Step 4) 262
12.5. Adding a Generated File and Generator (Step 5) 263
12.6 Building an Installer (Step 6) 267
12.7 Adding Support for a Dashboard (Step 7) 268
APPENDIX A - VARIABLES 269
Variables That Change Behavior 269
Variables That Describe the System 272
Variables for Languages 274
Variables That Control the Build 278
Variables That Provide Information 280
APPENDIX B ~ COMMAND LINE REFERENCE 287
CMake Command Line Options 287
CMake Generators 292
CTest Command Line Options 294
CPack Command Line Options 298
CPack Generators 299
APPENDIX C — LISTFILE COMMANDS 301
Current Commands 301
Compatibility Commands 366
APPENDIX D ~ SELECTED MODULES 373
CMake Modules
viiviii
APPENDIX E - PROPERTIES 4u1
Properties of Global Scope 411
Properties on Directories 414
Properties on Targets 417
Properties on Tests 431
Properties on Source Files 431
Properties on Cache Entries 434
APPENDIX F - CMAKE POLICIES 437
INDEX 447Chapter 1
Why CMake?
If you have ever maintained the build and installation process for a software package, you will
be interested in CMake. CMake is an open source build manager for software projects that
allows developers to specify build parameters in a simple portable text file format. This file is
then used by CMake to generate project files for native build tools including Integrated
Development Environments such as Microsoft Visual Studio or Apple’s Xcode, as well as
UNIX, Linux, NMake, and Borland style Makefiles. CMake handles the difficult aspects of
building software such as cross platform builds, system introspection, and user customized
builds, in a simple manner that allows users to easily tailor builds for complex hardware and
software systems.
For any project, and especially cross platform projects, there is a need for a unified build
system. Many projects today ship with both a UNIX Makefile (or Makefile.in) and a
Microsoft Visual Studio workspace. This requires that developers constantly try to keep both
build systems up to date and consistent with each other. To target additional build systems.
such as Borland or Xcode requires even more custom copies of these files, creating an even
bigger problem. This problem is compounded if you try to support optional components, such
as including JPEG support if libjpeg is available on the system. CMake solves this by
consolidating these different operations into one simple easy to understand file format.
If you have multiple developers working on a project, or multiple target platforms, then the
software will have to be built on more than one computer. Given the wide range of installed
software and custom options that are involved with setting up a modern computer, the chances
are that two computers running the same OS will be slightly different. CMake provides many
benefits for single platform multi-machine development environments including:2 Why CMake?
e — The ability to automatically search for programs, libraries, and header files that may be
required by the software being built. This includes the ability to consider environment
variables and Window’s registry settings when searching.
© The ability to build in a directory tree outside of the source tree, This is a usefull feature
found on many UNIX platforms; CMake provides this feature on Windows as well. This
allows a developer to remove an entire build directory without fear of removing source
files.
¢ — The ability to create complex custom commands for automatically generated files such
as Qt's moc (qt.nokia.com), The Insight Toolkit’s CABLE wrappers
(public. kitware.com/Cable/HTML/Index.html) and SWIG (www.swig.org) wrapper
generators. These commands are used to generate new source files during the build
process that are in turn compiled into the software.
* — The ability to select optional components at configuration time. For example, several of
VTK’s libraries are optional, and CMake provides an easy way for users to select which
libraries are built.
© — The ability to automatically generate workspaces and projects from a simple text file,
This can be very handy for systems that have many programs or test cases, each of
which requires a separate project file, typically a tedious manual process to create using
an IDE.
* — The ability to easily switch between static and shared builds. CMake knows how to
create shared libraries and modules on all platforms supported. Complicated platform-
specific linker flags are handled, and advanced features like built in run time search
paths for shared libraries are supported on many UNIX systems.
e Automatic generation of file dependencies and support for parallel builds on most
platforms
When developing cross platform software, CMake provides a number of additional features:
¢ The ability to test for machine byte order and other hardware specific characteristics.
e A single set of build configuration files that work on all platforms. This avoids the
problem of developers having to maintain the same information in several different
formats inside a project.
e — Support for building shared libraries on all platforms that support it.
¢ The ability to configure files with system dependent information such as the location of
data files and other information. CMake can create header files that contain information
such as paths to data files and other information in the form of #define macros. System
specific flags can also be placed in configured header files. This has advantages over
command line ~D options to the compiler because it allows other build systems to use
the CMake built library without having to specify the exact same command line options
used during the build.The History of CMake 3
1.1. The History of CMake
CMake development began in 1999 as part of the Insight Toolkit (ITK, www.itk.org) funded
by the US National Library of Medicine. ITK is a large software project that works on many
platforms and can interact with many other software packages. To support this, a powerful,
yet easy to use, build tool was required. Having worked with build systems for large projects
in the past, the developers designed CMake to address these needs. Since then CMake has
continuously grown in popularity, with many projects and developers adopting it for its ease
of use and flexibility. Since 1999 CMake has been under active development and has matured
to the point where it is a proven solution for a wide range of build issues. The most telling
example of this is the successful adoption of CMake as the build system of the K Desktop
Environment (KDE), arguably the largest open source software project in existence.
One of the recent additions to CMake is the inclusion of software testing support in the form
of CTest. Part of the process of testing sofiware involves building the software, possibly
installing it, and determining what parts of the sofiware are appropriate for the current system.
This makes CTest a logical extension of CMake as it already has most of this information. In
a similar vein, a new CMake feature is CPack, which is designed to support cross platform
distribution of sofiware. It provides a cross platform approach to creating native installations
for your software, making use of existing popular packages such as NSIS, RPM, Cygwin, and
PackageMaker.
Other recent additions to CMake include support for Apple’s Xcode IDE and support for
Microsoft’s Visual Studio 10. With CMake, once you write your input files you get support
for new compilers and build systems for free because the support for them is built into new
releases of CMake, not tied to your software distribution. Another recent addition to CMake is
support for cross compiling to other operating systems or embedded devices. Many
commands in CMake now properly handle the differences between the host system and the
target platform when cross compiling.
1.2 Why Not Use Autoconf?
Before developing CMake its authors had experience with the existing set of available tools.
Autoconf combined with automake provides some of the same functionality as CMake, but to
use these tools on a Windows platform requires the installation of many additional tools not
found natively on a Windows box. In addition to requiring a host of tools, autoconf can be
difficult to use or extend and impossible for some tasks that are easy in CMake. Even if you
do get autoconf and its required environment running on your system, it generates Makefiles
that will force users to the command line. CMake on the other hand provides a choice,
allowing developers to generate project files that can be used directly from the IDE to which
Windows and Xcode developers are accustomed.4 Why CMake?
While autoconf supports user specified options, it does not support dependent options where
‘one option depends on some other property or selection. For example. in CMake you could
have a user option to enable multithreading be dependent on first determining if the user’s
system has multithreading support. CMake provides an interactive user interface, making it
easy for the user to see what options are available and how to set them
For UNIX users, CMake also provides automated dependency generation that is not done
directly by autoconf. CMake’s simple input format is also easier to read and maintain than a
combination of Makefile.in and configure.in files. The ability of CMake to remember and
chain library dependency information has no equivalent in autoconf/automake.
1.3. Why Not Use JAM, qmake, SCons, or ANT?
Other tools such as ANT, qmake, SCons, and JAM have taken different approaches to solving
these problems and they have helped us to shape CMake. Of the four, qmake, is the most
similar to CMake although it lacks much of the system interrogation that CMake provides.
Qmake's input format is more closely related to a traditional Makefile. ANT, JAM and SCons.
are also cross-platform although they do not support generating native project files. They do
break away from the traditional Makefile oriented input with ANT using XML, JAM using its
own language, and SCons using Python. A number of these tools run the compiler directly, as
opposed to letting the system’s build process perform that task. Many of these tools require
other tools such as Python or Java to be installed before they will work.
1.4. Why Not Script It Yourself?
Some projects use existing scripting languages such as Perl or Python to configure build
processes. Although similar functionality can be achieved with systems like this, over-use of
tools can make the build process more of an Easter egg hunt than a simple-to-use build
system. When building your software package users are forced to find and install version
4.3.2 of this, and 3.2.4 of that, before they can even start the build process. To avoid that
problem, it was decided that CMake would require no more tools than the software it was
being used to build would require. At a minimum using CMake requires a C compiler, that
compiler's native build tools, and a CMake executable. CMake was written in C++, requires
only a C++ compiler to build and precompiled binaries are available for most systems.
Scripting it yourself also typically means you will not be generating native Xcode or Visual
Studio workspaces, making Mac and Windows builds limited.On What Platforms Does CMake Run? 5
1.5 On What Platforms Does CMake Run?
CMake runs on a wide variety of platforms including Microsoft Windows, Apple Mac OS X,
and most UNIX or UNIX-like platforms. At the time of the writing of this book CMake was
tested nightly on the following platforms: Windows 98/2000/XP/Vista/7, AIX, HPUX, IRIX,
Linux, Mac OS X, Solaris, OSF, QNX, CYGWIN, MinGW, and FreeBSD. You can check
www.cmake.org for a current list of tested platforms.
Likewise, CMake supports most common compilers. It supports the GNU compiler on all
CMake supported platforms. Other tested compilers include Visual Studio 6 through 10, Intel
C, SGI CC, Mips Pro, Borland, Sun CC and HP aCC. CMake should work for most UNIX-
style compilers out of the box. If the compiler takes arguments in a strange way, then see the
section Porting CMake to New Platform on page 241 for information on how to customize
CMake for a new compiler.Chapter 2
Getting Started
2.1. Getting and Installing CMake on Your Computer
Before using CMake you will need to install or build the CMake binaries on your system. On
many systems you may find that CMake is already installed, or is available for install with the
standard package manager tool for the system. Cygwin, Debian, FreeBSD, Mac OS X Fink,
and many others all have CMake distributions. If your system does not have a CMake
package, you can find CMake precompiled for most commen architectures at
www.cmake.org. If you do not find binaries for your system precompiled, then you can build
CMake from source. To build CMake you will need a modern C++ compiler.
UNIX and Mac Binary Installations
If your system provides CMake as one of its standard packages, follow your system’s package
installation instructions. If your system does not have CMake, or has an out of date version of
CMake, you can download precompiled binaries from www.cmake.org. The binaries from
www.cmake.org come in the form of a compressed tar file. The tar file contains a README
file and an enclosed tar file. The README file contains a manifest of the files contained in
the enclosed tar file, and some instructions. To install, simply extract the enclosed tar file into
a destination directory (typically /usr/local). However, it can be any directory, and does
not require root privileges for installation.
Windows Binary Installation
For Windows CMake has a NullSoft install file available for download from www.cmake.org,
To install this file, simply run the executable on the windows machine on which you want to
install CMake. You will be able to run CMake from the Start Menu after it is installed.8 Getting Started
2.2 Building CMake Yourself
if binaries are not available for your system, or if binaries are not available for the version of
CMake you wish to use, you can build CMake from the source code. You can obtain the
‘CMake source code by following the instructions at www.cmake.org. Once you have the
source code it can be built in two different ways. If you have a version of CMake on your
system you can use it to build other versions of CMake. Generally the current development
version of CMake can always be built from the previous release of CMake. This is how new
versions of CMake are built on most Windows systems.
The second way to build CMake is by running its bootstrap build script. To do this you
change directory into your CMake source directory and type
./bootstrap
make
make install
The make install step is optional since CMake can run directly from the build directory if
desired. On UNIX, if you are not using the GNU C++ compiler, you need to tell the bootstrap
script which compiler you want to use. This is done by setting the environment variable Cxx
before sunning bootstrap. If you need to use any special flags with your compiler, set the
CXXFLAGS environment variable. For example, on the SGI with the 7.3X compiler, you would
build CMake like this:
cd CMake
(setenv CXX CC; setenv CXXFLAGS "-LANG:std"; ./bootstrap)
make
make install
2.3 Basic CMake Usage and Syntax
Using CMake is simple. The build process is controlled by creating one or more CMakeLists
files (actually CMakeLists.txt but this guide will leave off the extension in most cases) in each
of the directories that make up a project. The CMakeLists files should contain the project
description in CMake's simple language. The language is expressed as a series of commands.
Bach command is evaluated in the order that it appears in the CMakeLists file. The commands.
have the form
command (args.Hello World for CMake 9
where command is the name of the command, and args is a white-space separated list of
arguments. (Arguments with embedded white-space should be double quoted.) CMake is case
insensitive to command names as of version 2.2. So where you see command you could use
COMMAND or Command instead. Older versions of CMake only accepted uppercase commands.
CMake supports simple variables that can be either strings or lists of strings. Variables are
referenced using a ${VAR} syntax. Multiple arguments can be grouped together into a list
using the set command. All other commands expand the lists as if they had been passed into
the command with white-space separation. For example, set (Foo a b c) will result in
setting the variable Foo to a b c, and if Foo is passed into another command
command (${Foo}) it would be equivalent to command (a b c). If you want to pass a list of
arguments to a command as if it were a single argument simply double quote it. For example
command ("${Foo}") would be invoked passing only one argument equivalent to command (
"abo" )
System environment variables and Windows registry values can be accessed directly in
CMake. To access system environment variables the syntax $ENV{VAR} is used. CMake can
also reference registry entries in many commands using a syntax of the form
[HKEY_CURRENT_USER\\Software\\path1\\path2;key], where the paths are built
from the registry tree and key.
2.4 Hello World for CMake
For starters let us consider the simplest possible CMakeLists file. To compile an executable
from one source file the CMakeLists file would contain two lines:
project (Hello)
add_executable (Hello Hello.c)
To build the Hello executable you follow the process described in Running CMake (See
section 2.5) to generate the Makefiles or Microsoft project files. The project command
indicates what the name of the resulting workspace should be and the add_executable
command adds an executable target to the build process. That’s all there is to it for this simple
example. If your project requires a few files it is also quite easy, just modify the
add_executable line as shown below.
add_executable (Hello Hello.c File2.c File3.c File4.c)
add_executable is just one of many commands available in CMake. Consider the more
complicated example below.10 Getting Started
cmake_minimum required (2.6)
project (HELLO)
set (HELLO SRCS Hello.c File2.c File3.c)
if (WIN32)
set (HELLO _SRCS ${HELLO_SRCS} WinSupport.c)
else ()
set (HELLO_SRCS ${HELLO_SRCS} UnixSupport.c)
endif ()
add_executable (Hello ${HELLO_SRCS})
# look for the Tcl library
find_library (TCL_LIBRARY
NAMES tcl tclé4 tela3 tel82
PATHS /usr/lib /usr/local/lib
)
180
if (TCL_LIBRARY)
target link library (Hello ${TCL_LIBRARY})
endif ()
In this example the set command is used to group together source files into a list. The if
command is used to add either WinSupport.c or UnixSupport.c to this list based on whether or
not CMake is running on Windows, Finally, the add_executable command is used to build
the executable with the files listed in the variable HELLO_SR' The find library
command looks for the Tct library under a few different names and in a few different paths.
An if command checks if the TCL_LIBRARY was found and if so adds it to the link line for
the Hello executable target. Note the use of the # character to denote a comment line. All
characters from the # ta the end of the line are considered to be part of the comment.
2.5 How to Run CMake?
Once CMake has been installed on your system, using it to build a project is easy. There are
two main directories CMake uses when building a project: the source directory and the binary
directory. The source directory is where the source code for your project is located. This is
also where the CMakeLists files will be found. The binary directory is where you want
CMake to put the resulting object files, libraries, and executables. Typically CMake will not
write any files to the source directory, only the binary directory. If you want to you can set the
source and binary directories to be the same. This is known as an in-source build, in contrast
to an out-of-source build where they are different.How to Run CMake? 4
CMake supports both in-source and out-of-source builds on all operating systems. This means
that you can configure your build to be completely outside of the source code tree which
makes it very easy to remove all of the files generated by a build. Having the build tree differ
from the source tree also makes it easy to support having multiple builds of a single source
tree. This is useful when you want to have multiple builds with different options but just one
copy of the source code. Now let us consider the specifics of running CMake using its Qt
based GUI and command line interfaces.
Running CMake’s Qt Interface
CMake includes a Qt based user interface developed by Clinton Stimpson that can be used on
most platforms, including UNIX, Mac OS X, and Windows. This interface is included in the
CMake source code, but you will need an installation of Qt on your system in order to build it.
Agee ae)
File Tools Options Help
‘Where isthe source code: [Ci[Documents and Settings/Ken/My Documents/CMake/CMake | [frowse Source.
hereto buldthe binaries: |CfDecunens end Setings en DocmerisiCakeMakebnd >| [Browne Bld]
search [| ect {Simple ew P AddEntry)} % Remove Entry
“Nome is
ress Configure to update and display new values in red, then press Generate to generate selected buld files.
Generate Current Generator: Visual Studio 9 2008
Searching 16 bit integer
Check size of unsigned short
Check size of unsigned short - done
Using unsigned short
Check if the system is big endian - little endian
Locking for elf.h
Looking for elf.h ~ not found
Configuring done
€
Figure 1 — Qt based CMake GUI
On Windows the executable is named cmake-gui.exe and should be in your Start menu
under Program Files. There may also be a shortcut on your desktop, or if you built CMake
from source, it will be in the build directory. For UNIX and Mac users the executable is412 Getting Started
named cmake-gui and it can be found where you installed the CMake executables.A GUI will
appear similar to what is shown in Figure |. The top two entries are the source code and
binary directories. They allow you to specify where the source code is for what you want to
compile and where the resulting binaries should be placed. You should set these two values
first. If the binary directory you specify does not exist, it will be created for you. If the binary
directory has been configured by CMake before then it will automatically set the source tree.
The middle area is where you can specify different options for the build process. More
obscure variables may be hidden, but can be seen if you select "Advanced View" from the
view pulldown. You can search for values in the middle area by typing all or part of the name
into the Search box. This can be handy for finding specific settings or options in a large
project. The bottom area of the window includes the Configure and Generate buttons as well
as a progress bar and scrollable output window.
Once you have specified the source code and binary directories you should click the
Configure button, This will cause CMake to read in the CMakeLists files from the source
code directory and then update the cache area to display any new options for the project. If
you are running cmake-gui for the first time on this binary directory it will prompt you to
determine what generator you wish to use, as shown in Figure 2. This dialog also presents
options for customizing and tweaking the compilers you wish to use for this build.
Pater csi)
Specify the generator For this project
Use default native compilers
Specify native compilers
© Specify toolchain file for cross-compiling
© Specify options for cross-compiling
Figure 2 — Selecting a Generator
After the first configure you can adjust your cache settings if desired and click the Configure
button again. New values that were created by the configure process will be colored red. To
be sure you have seen all possible values you should click Configure until no values are redHow to Run CMake? 413
and you are happy with all the settings. Once you are done configuring, click the Generate
button, this will produce the appropriate files,
It is important that you make sure that your environment is suitable for running cmake-gui. If
you are using an IDE such as Visual Studio then your environment will be setup correctly for
you. If you are using NMake or MinGW then you need to make sure that the compiler can run
from your environment. You can either directly set the required environment variables for
your compiler or use a shell in which they are already set. For example, Microsoft Visual
Studio has an option on the start menu for creating a Visual Studio Command Prompt. This
opens up a command prompt window that has its environment already setup for Visual
Studio. You should run cmake-gui from this command prompt if you want to use NMake
Makefiles. The same approach applies to MinGW, you should run cmake-gui from a MinGW
shell that has a working compiler in its path.
When cmake-gui finishes it will have generated the build files in the binary directory you
specified. If Visual Studio was selected as the generator, a MSVC workspace (or solution) file
is created. This file's name is based on the name of the project you specified in the PROJECT
command at the beginning of your CMakeLists file. For many other generator types,
Makefiles are generated. The next step in this process is to open the workspace with MSVC.
Once open, the project can be built in the normal manner of Microsoft Visual C++. The
ALL_BUILD target can be used to build all of the libraries and executables in the package. If
you are using a Makefile build type, then you would build by running make or nmake on the
resulting Makefiles.
Running the ccmake Curses Interface
On most UNIX platforms, if the curses library is supported, CMake provides an executable
called cemake. This interface is a terminal-based text application that is very similar to the Qt
based GUI. To run cemake, change directory (cd) to the directory where you want the binaries
to be placed. This can be the same directory as the source code for what we call in-source
builds or it can be a new directory you create. Then run ccmake with the path to the source
directory on the command line. For in-source builds use "." for the source directory. This will
start the text interface as shown in Figure 3 (in this case the cache variables are from VTK
and most are set automatically).14 Getting Started
eee ae
isee/LooaL/b in’ jax
- fase/leoa ban Java
ero jase/include/pythen?. 3
ieee ‘ase/Lib/ python2. 3/contig/ Libppthon2. 3. 20
piety
Figure 3 - cemake running on UNIX
Brief instructions are displayed in the bottom of the window. If you hit the "c" key, it will
configure the project. You should always configure after changing values in the cache. To
change values, use the arrow keys to select cache entries, and then the enter key to edit them.
Boolean values will toggle with the enter key. Once you have set all the values as you like,
you can hit the "g" key to generate the Makefiles and exit. You can also hit "h" for help, "q"
to quit, and "t" to toggle the viewing of advanced cache entries. Two examples of CMake
usage on the UNIX platform follow for a hello world project called Hello. In the first
example, an in-source build is performed.
Hello
In the second example, an out-of-source build is performed
mkdir Hello-Linux
cd Hello-Linux
make ../Hello
makeHow to Run CMake? 15
Running CMake from the Command Line
From the command line, CMake can be run as an interactive question and answer session or
aS a non-interactive program. To run in interactive mode, just pass the "-i" option to CMake.
This will cause CMake to ask you for a value for each entry in the cache file for the project
CMake will provide reasonable defaults, just like it does in the GUI and curses based
interfaces. The process stops when there are no longer any more questions to ask. An example
of using the interactive mode af CMake is provided below.
§ cmake -i -G "NMake Makefiles" ../CMake
Would you like to see advanced options? [No]:
Please wait while cmake processes CMakeLists.txt files....
Variable Name: BUILD TESTING
Description: Build the testing tree.
Current Value: ON
New Value (Enter to keep current value):
Variable Name: CMAKE INSTALL PREFIX
Description: Install path prefix, prepended onto ins
directories.
Current Valu C:/Program Files/CMake
New Value (Enter to keep current value):
Please wait while cmake processes CMakeLists.txt files....
CMake complete, run make to build project.
Using CMake to build a project in non-interactive mode is a simple process if the project has
few or no options. For larger projects like VTK, using ccmake, cmake or cmake-gui is
recommended. Yo build a project with a non-interactive CMake, first change directory to
where you want the binaries to be placed. For an in-source build you then run cmake . and
pass in any options using the -pD flag. For out-of-source builds the process is the same except
you run cmake and also provide the path to the source code as its argument. Then type make
and your project should compile. Some projects will have install targets as well, you can type
make install to install them.
Specifying the Compiler to CMake
On some systems you may have more than one compiler to choose from or your compiler
may be in a non-standard place. In these cases you will need to specify to CMake where your
desired compiler is located. There are three ways to specify this; the generator can specify the
compiler, an environment variable can be set, or a cache entry can be set. Some generators are
tied to a specific compiler, for example the Visual Studio 6 generator always uses the16 Getting Started
Microsoft Visual Studio 6 compiler. For Makefile based generators CMake will try a list of
usual compilers until it finds a working compiler. The list can be found in the files:
Modules/CMakeDeterminCCompiler.cmake and
Modules/CMakeDetermineCXxCompiler.cmake
The lists can be preempted with environment variables that can be set before CMake is run.
The Cc environment variable specifies the C compiler while Cxx specifies the C++ compiler.
You can specify the compilers directly on the command line by using -
DCMAKE_CXX_COMPTLER=c1 for example. If those are not set, CMake will try the following
list of compilers:
ct+ gt CC aC cl bee xlc.
Once CMake has been run and picked a compiler, you can change the selection by changing
the cache entries CMAKE_CXX_COMPILER and CMAKE_C_COMPILER, although this is not
recommended. The problem with doing this is that the project you are configuring may have
already run some tests on the compiler to determine what it supports. Changing the compiler
does not normally cause these tests to be rerun which can lead to incorrect results. If you must
change the compiler, start over with an empty binary directory. The flags for the compiler and.
the linker can also be changed by setting environment variables. Setting LoFLAGs will
initialize the cache values for link flags, while CxxFLAGS and CFLAGS will initialize
CMAKE_CXX_FLAGS and CMAKE_C_FLAGS respectively.
Dependency Analysis
Make has powerful built-in dependency analysis capabilities for C and C++ source code
files. CMake also has limited support for Fortran and Java dependencies. Since Integrated
Development Environments (IDEs) support and maintain dependency information, CMake
skips this step for those build systems. However, Makefiles with a make program do not know
how to automatically compute and keep dependency information up-to-date. For these builds,
CMake automatically computes dependency information for C, C++ and Fortran files. Both
the generation and maintenance of these dependencies are automatically done by CMake.
Once a project is initially configured by CMake, users only need to run make, and CMake
does the rest of the work. CMake’s dependencies fully support parallel builds for
multiprocessor systems.
Although users do not need to know how CMake does this work, it may be useful to look at
the dependency information files for a project. This information for each target is stored in
four files called depend.make, flags.make, build.make, and DependInfo.cmake.
depend.make stores the depend information for all the object files in the directory.
flags .make contains the compile flags used for the source files of this target. If they change
then the files will be recompiled. DependInfo.cmake is used to keep the dependencyEditing CMakeLists Files 47
information up-to-date and contains information about what files are part of the project and
what languages they are in. Finally, the rules for building the dependencies are stored in
build.make. Ifa dependency is out of date then all of the dependencies for that target will
be recomputed, keeping the dependency information current.
2.6 Editing CMakeLists Files
CMakeLists files can be edited in almost any text editor. Some editors, such as Notepad++,
come with CMake syntax highlighting and indentation support built in. For editors such as
Emacs or Vim CMake includes indentation and syntax highlighting modes. These can be
found in the Does directory of the source distribution, or downloaded from the CMake web
site. The file cmake-mode.el is the Emacs mode, and cmake-indent.vim and cmake-
syntax.vim are used by Vim. Within Visual Studio the CMakeLists files are listed as part of
the project and you can edit them simply by double clicking on them. Within any of the
supported generators (Makefiles, Visual Studio, etc) if you edit a CMakeLists file and rebuild,
there are rules that will automatically invoke CMake to update the generated files (e.g.
Makefiles or project files) as required. This helps to assure that your generated files are
always in syne with your CMakeLists files.
Since CMake computes and maintains dependency information, the CMake executables must
always be available (though they don’t have to be in your PATH) when make or an IDE is
being run on CMake generated files. This means that if a CMake input file changes on disk,
your build system will automatically re-run CMake and produce up-to-date build files. For
this reason you generally should not generate Makefiles or projects with CMake and move
them to another machine that does not have CMake installed.
2.7 Setting Initial Values for CMake
While CMake works well in an interactive mode, sometimes you will need to setup cache
entries without running a GUL. This is common when setting up nightly dashboards or if you
will be creating many build trees with the same cache values. In these cases the CMake cache
can be initialized in two different ways. The first way is to pass the cache values on the
CMake command line using -DCACHE_VAR:TYPE=VALUE arguments. For example, consider
the following nightly dashboard script for a UNIX machine:
#!/bin/tcsh
cd ${HOME}
# wipe out the old binary tree and then create it again
om
rf Foo-Linux
mkdir Foo-Linux48 Getting Started
cd Foo-Linux
# run cmake to setup the cache
cmake -DBUILD TESTING:BOOL=ON
[options] [-- [native-options]]
Options:
= Project binary directory to be built.
--target
--config
--clean-first
Build instead of default targets.
‘or multi-configuration tools, choose <
Build target 'clean' first, then build.
(To clean only, use --target 'clean'.)
-- = Pass remaining options to the native tool.
So even if you are using Visual Studio as your generator you can type the following to build
your project from the command line if you wish.
cmake --build
That is all there is to installing and running CMake for simple projects. In the following
chapters we will consider CMake in more detail and how to use it on more complex software
projects.Chapter 3
Key Concepts
3.1. Main Structures
This chapter provides an introduction to CMake's key concepts. As you start working with
CMake you will run into a variety of cancepts 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 there are source files. These correspond to typical C or C++
source code files. Source files are combined into 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 files for that 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 4 shows the basic class 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 cmake class and
passing the 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 cmake class does is to create the correct global generator based on the
user's selection of what 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
created by invoking the configure and generate methods.22
emake
© controls the cmake process
* can be created and used in
various GUIs
Has one
emGlobalGenerator
abstract bas SS
* child classes responsible for
platform-specific build process
Has many
cmLocalGenerator
© abstract base class
© child classes responsible for
platform-specific build file
generation
Has one
Key Concepts
emGlobalUnixMakefileGenerator
cemGlobalVisualStudio6Generator
emGlobalVisualStudio7Generator
Derive from
emLocalUnixMakefileGenerator
cmLocalVisualStudio6Generator
cmLocalVisualStudio7Generator
emCommand
© abstract base class
© child classes responsible for
implementing all commands in
CMake.
cmMakefile
© Stores all of the information parsed
from a CMakeLists.txt file.
List of targets and variables
Optional flags
List of libraries
List of include paths
Parses CMakeLists.txt files
Derive from
emRemoveCommand
cmSetCommand
emAddTestCommand
Figure 4 - CMake InternalsMain Structures 23
The global generator is responsible for managing the configuration and generation of all of
the Makefiles (or project files) for a project. In practice most of the work is actually done by
local generators which 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 Makefiles" generator, the local generators create most of the
Maketiles and the global generator simply orchestrates the process and creates the main top-
level Makefile. Implementation details vary widely among generators. The Visual Studio 6
generators 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, ete use a
set of rule templates and replacements to generate their Makefiles.
; I
Sub f§ Sub2 f Sub3
Figure 5 - Sample Directory Tree
Each local generator has an instance of the class cmMakefile, cmMakefile is where the results
of parsing the CMakeLists files are stored. Specifically, for each directory in a project there
will be a single cmMakefile instance which is why the emMakefile 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 that directory's CMakeLists file (see Figure 5). One
way to think of the cmMakefile 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 in 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. The InitialPass method receives the
arguments and the cmMake file instance for the directory currently being processed, and then24 Key Concepts
performs its operations. In the case of the set comman4d, it processes its arguments and if the
arguments are correct it calls a method on the cmMake file to set the variable. The results of
the command are always stored in the cmMakefile 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 CMake project) have had their InitialPass
invoked. Most commands do not have a FinalPass, but in some rare cases a command must do
sqmething with global information that may not be available during the initial pass.
Once all of the CMakeLists files have been processed the generators use the information
collected into the cmMakefile instances to produce the appropriate files for the target build
system (such as Makefiles).
3.2 Targets
Now that we have discussed the overall process of CMake, let us consider some of the key
items stored in the cmMakefile instance. Probably the most important item is targets.
Targets represent executables, libraries, and utilities built by CMake. Every add_library,
add_executable, and add_custom_target command creates a target. For example, the
following command will create a target named foo that is a static library, with fool.c and
£002.c as source files.
add_library (foo STATIC fool.c foo2.c)
The name foo is now available for use as a library name everywhere else in the project, and
CMake will know how to expand the name into the library when needed. Libraries can be
declared to be of a particular type such as STATIC, SHARED, MODULE, or left undeclared.
STATIC indicates that the library must be built as a static library. Likewise SHARED indicates
it must be built as a shared library. MODULE indicates that the library must be created so that it
can be dynamically loaded into an executable. On many operating systems this is the same as
SHARED, but on other systems such as Mac OS X it is different. If none of these options are
specified this indicates that the library could be built as either shared or static. In that case
CMake uses the setting of the variable BUILD_SHARED_LIBS to determine if the library
should be SHARED or STATIC. If it is not set, then CMake defaults to building static libraries.
Likewise executables have some options. By default an executable will be a traditional
console application that has a main (int argc, const char*argv[]). If WIN32 is
specified after the executable name then the executable will be compiled as a MS Windows
executable and the operating system will call WinMain instead of main at startup. WIN32 has.
no effect on non-Windows systems.
In addition to storing their type, targets also keep track of general properties. These properties
can be set and retrieved using the set_target_properties and get_target_propertySource Files 25
commands, or the more general set_property and get_property commands. The most
commonly used property is LINK_FLAGS, which is used to specify link flags for a specific
target. Targets store a list of libraries that they link against which are set using the
target _link libraries command. Names passed into this command can be libraries, full
paths to libraries, or the name of a library from an add_1ibrary command. They also store
the link directories to use when linking, the install location for the target, and custom
commands to execute after linking.
For each library CMake creates, it keeps track of all the libraries on which that library
depends. Since static libraries do not link to the libraries on which they depend, it is important
for CMake to keep track of the libraries so they can be specified on the link line of the
executable being created. For example,
add_library (£00 foo.cxx)
target_link_libraries (f00 bar)
add_executable (foobar foobar.cxx)
target_link libraries (foobar foo)
This will link the libraries foo and bar into the executable foobar even, although only foo was
explicitly linked into foobar, With shared or DLL builds this linking is not always needed, but
the extra linkage is harmless. For static builds this is required. Since the foo library uses
symbols from the bar library, foobar will most likely also need bar since it uses foo.
3.3. Source Files
The source file structure is in many ways similar to a target. It stores the filename, extension,
and a number of general properties related to a source file. Like targets you can set and get
properties using set_source_files_properties and get urce_file_p
the more generic versions. The most common properties include:
erty, or
COMPILE_FLAGS
Compile flags specific to this source file. These can include source specific -D and —
I flags.
GENERATED
The GENERATED property indicates that the source file is generated as part of the
build process. In this case CMake will treat it differently for computation of
dependencies because the source file may not exist when CMake is first run26 Key Concepts
OBJECT_DEPENDS
Adds additional files on which this source file should depend. CMake automatically
performs dependency analysis to determine the usual C, C++ and Fortran
dependencies. This parameter is used rarely in cases where there is an
unconventional dependency or the source files do not exist at dependency analysis
time.
ABSTRACT
WRAP_EXCLUDE
CMake doesn't directly use these properties. Some loaded commands and extensions
to CMake look at these properties to determine how and when to wrap a C++ class
into languages such as Tel, Python, ete,
3.4 Directories, Generators, Tests, and Properties
In addition to targets and source files you may find yourself occasionally working with other
classes such as directories, generators, and tests. Normally such interactions take the shape of
setting or getting properties from these objects. All of these classes have properties associated
with them, as do source files and targets. A property is a key-value pair attached to a specific
object such as a target. The most generic way to access properties is through the
‘operty and property commands. These commands allow you to set or get a
property from any class in CMake that has properties. Some of the properties for targets and
source files have already been covered. Some useful properties for a directory include:
ADDITIONAL, MAKE_CLEAN_FILES
This property specifies a list of additional files that will be cleaned as a part of the
"make clean" stage. By default CMake will clean up any generated files that it knows
about, but your build process may use other tools that leave files behind. This
property can be set to a list of those files so that they also will be properly cleaned
up.
EXCLUDE FROM ALL
This property indicates if all the targets in this directory and all sub directories
should be excluded from the default build target. If it is not, then with a Makefile for
example typing make will cause these targets to be built as well. The same concept
applies to the default build of other generators.
LISTFILE_STACK
This property is mainly useful when trying to debug errors in your CMake scripts, It
returns a list of what list files are currently being processed, in order. So if one
CMakeLists file does an include command then that is effectively pushing the
included CMakeLists file onto the stack.Variables and Cache Entries 27,
A full list of properties supported in CMake can be obtained by running cmake with the -
help-property-list option. The generators and directories are automatically created for
you as CMake processes your source tree.
3.5 Variables and Cache Entries
CMakeLists files use variables much like any programming language. Variables are used to
store values for later use, and can be a single value such as "ON" or "OFF", or they can
represent a list such as (/usr/include /home/foo/include /usr/local/include)
A number of useful variables are automatically defined by CMake and are discussed in
Appendix A - Variables.
Variables in CMake are referenced using a ${VARIABLE) notation, and they are defined in
the order of execution of the set commands. Consider the following example:
# FOO is undefined
set (FOO 1)
# FOO is now set to 1
set (FOO 0)
# FOO is now set to 0
This may seem straightforward, but consider the following example:
set (FOO 1)
if (${FOO} LESS 2)
set 10 2)
else ($(FOO} LES:
set (FOO 3)
endif (${FOO} LESS 2)
2)
Clearly the if statement is true, which means that the body of the if statement will be
executed. That will set the variable FOO to 2, and so when the eise statement is encountered
FOO will have a value of 2. Normally in CMake the new value of Foo would be used, but the
else statement is a rare exception to the rule and always refers back to the value of the
variable when the if statement was executed. So in this case the body of the else clause will
not be executed. To further understand the scope of variables consider this example:28 Key Concepts
set (foo 1)
# process the dirl subdirectory
add_subdirectory (dirl)
# include and process the commands in filel.cmake
include (filel.cmake)
set (bar 2)
# process the dir2 subdirectory
add_subdirectory (dir2)
# anclude and process the commands
include (file2.cmake)
file2.cmake
In this example because the variable foo is defined at the beginning, it will be defined while
processing both dirt and dir2, In contrast oar will only be defined when processing dir2.
Likewise foo will be defined when processing both filel.cmake and file2.cmake, whereas
bar will only be defined while processing file2.cmake.
Variables in CMake have a scope that is a little different from most languages. When you set
a variable it is visible to the current CMakeLists file or function, as well as any subdirectory’s
CMakeLists files, any functions or macros that are invoked, and any files that are included
using the INCLUDE command. When a new subdirectory is processed (or a function called) a
new variable scope is created and initialized with the current value of all variables in the
calling scope. Any new variables created in the child scope, or changes made to existing
variables, will not impact the parent scope. Consider the following example:
function (£00)
message (${test}) # test is 1 here
set (test 2)
message ($(test}) € test is 2 here, but only in this scope
dfunction ()
set (test 1)
foo()
message (${test}) # test will still be 1 here
In some cases you might want a function or subdirectory to set a variable in its parent’s scope.
This is one way for CMake to return a value from a function, and it can be done by using the
PARENT SCOPE option with the set command. We can modify the prior example so that the
function foo changes the value of test in its parent’s scope as follow:Variables and Cache Entries 29
function (foo)
message (${test}) # test is 1 here
set (test 2 PARENT SCOPE)
message ($(test}) # test still 1 in this scope
endfunction()
set (test 1)
foo()
message (${test}) # test will now be 2 here
Variables can also represent a list of values. In these cases when the variable is expanded it
will be expanded into multiple values. Consider the following example:
# set a list of items
set (items_to_buy apple orange pear beer)
# loop over the items
foreach (item ${items_to_buy})
message ( "Don’t forget to buy one ${item}" )
endforeach ()
In some cases you might want to allow the user building your project to set a variable from
the CMake user interface. In that case the variable must be a cache entry. Whenever CMake is
run it produces a cache file in the directory where the binary files are to be written. The values
of this cache file are displayed by the CMake user interface. There are a few purposes of this
cache. The first is to store the user's selections and choices, so that if they should run CMake
again they will not need to reenter that information. For example, the option command
creates a Boolean variable and stores it in the cache.
option (USE_JPEG "Do you want to use the jpeg library")
‘The above line would create a variable called USE_JPEG and put it into the cache. That way
the user can set that variable from the user interface and its value will remain in case the user
should run CMake again in the future. To create a variable in the cache you can use
commands like option, find file, or you car use the standard set command with the
CACHE option.
set (USE_JPEG ON CACHE BOOL "include jpeg support?")
When you use the cache option you must also provide the type of the variable and a
documentation string. The type of the variable is used by the GUI te control how that variable30 Key Concepts
is set and displayed. Variable types include BOOL, PATH, FILEPATH, and sTRING. The
documentation string is used by the GUI to provide online help.
The other purpose of the cache is to store key variables that are expensive to determine. These
variables may not be visible or adjustable by the user. Typicaily these values are system
dependent variables such as CMAKE_WORDS_BIGENDIAN, which require CMake to compile
and run a program to determine their value. Once these values have been determined, they are
stored in the cache to avoid having to recompute them every time CMake is run. Generally
CMake tries to limit these variables to properties that should never change (such as the byte
order of the machine you are on). If you significantly change your computer, either by
changing the operating system, or switching to a different compiler, you will need to delete
the cache file (and probably all of your binary tree's object files, libraries, and executables).
Variables that are in the cache also have a property indicating if they are advanced or not. By
default when a CMake GUI is run (such as cemake or cmake-gui) the advanced cache entries
are not displayed. This is so that the user can focus on the cache entries that they should
consider changing. The advanced cache entries are other options that the user can modify, but
typically will not. It is not unusual for a large software project to have fifty or more options,
and the advanced property lets a software project divide them into key options for most users.
and advanced options for advanced users. Depending on the project there may not be any non-
advanced cache entries. To make a cache entry advanced the nark_as_advanced command
is used with the name of the variable (a.k.a. cache entry) to make advanced.
In some cases you might want to restrict a cache entry to a limited set of predefined options.
You can do this by setting the STRINGS property on the cache entry. The following
CMakeLists code illustrates this by creating a property named CRYPTOBACKEND as usual, and
then setting the STRINGS property on it to a set of three options.
set (CRYPTOBACKEND "OpenSSL" CACHE STRING
"Select a cryptography backend")
set_property (CACHE CRYPTOBACKEND PROPERTY STRINGS
"OpenSSL" "LibTomCrypt" "LibDE.
When cmake-gui is run and the user selects the CRYPTOBACKEND cache entry, they will be
presented with a pulldown to select which option they want, as shown in Figure 6.Variables and Cache Entries 31
1 Cihake 2.7.20090730,
Fle Tools Options Help
‘Whereis the source code: [C:/Dacuments and Settings/KenyMy Dacuments/CMahe/Test once Sure.
\Where to buld the binaries: |C:Joacuments and Settings/Ken/My Documents/CMake/Test ¥) [Browse build.
seach Gimee wen H Revove oy
Name Vale
CCMAKE_BACKWARDS_CONPATIBILITY 24
(CMAKE_INSTALL PREFIX {Program Files/Project
Spenss.
EXECUTABLE_OUTPUT_PATH OpenSSL
| RABY _CUTPUT_PATH
Press Configure to update and display new values inred, then press Generate to generate selected build fles
Curent Gneator: Wu tu $2008 Cc
Configuring done
Figure 6 — Cache Value Options in emake-gui
A few final points should be made concerning variables and their interaction with the cache.
If a variable is in the cache, it can still be overridden in a CMakeLists file using the set
command without the CACHE option. Cache values are checked only if the variable is not
found in the current crMakefile instance before CMakeLists file processing begins. The
set command will set the variable for processing the current CMakeLists file (and
subdirectories as usual) without changing the value in the cache.
# assume that FOO is set to ON in the cache
set (FOO OFF)
# sets foo to OFF for processing this CMakeLists file
# and subdirectories; the value in the cache stays ON
Once a variable is in the cache, its "cache" value cannot normally be modified from a
CMakeLists file. The reasoning behind this is that once CMake has put the variable into the
cache with its initial value, the user may then modify that value from the GUI. If the next
invocation of CMake overwrote their change back to the set value, the user would never be
able to make a change that CMake wouldn’t overwrite. Soa set (FOO ON CACHE BOOL
doc") command will typically only do something when the cache doesn't have the variable
in it. Once the variable is in the cache, that command will have no effect.32 Key Concepts.
In the rare event that you really want to change a cached variable's value you can use the
FORCE option in combination with the CACHE option to the set command. The FORCE option
will cause the set command to override and change the cache value of a variable.
3.6 Build Configurations
. Build configurations allow a project to be built in different ways for debug, optimized, or any
other special set of flags. CMake supports, by default, Debug, Release, MinSizeRel, and
RelWithDebInfo configurations. Debug has the basic debug flags tured on. Release has the
basic optimizations tumed on. MinSizeRel has the flags that produce the smallest object code,
but not necessarily the fastest code. RelWithDebinfo builds an optimized build with debug
information as well.
CMake handles the configurations in slightly different ways depending on what generator is
being used. The conventions of the native build system are followed when possible, This
means that configurations impact the build in different ways when using Makefiles versus
using Visual Studio project files.
The Visual Studio IDE supports the nation of Build Configurations. A default project in
Visual Studio usually has Debug and Release configurations. From the IDE you can select
build Debug, and the files will be built with Debug flags. The IDE puts all of the binary files
into directories with the aame of the active configuration. This brings about an extra
complexity for projects that build programs that need 1 be run as part of the build process
from custom commands, See the CMAKE_CFG_INTDIR variable and the custom commands
section for more information about how to handle this issue. The variable
CMAKE_ CONFIGURATION TYPES is used to tell CMake which configurations to put in the
workspace.
With Makefile based generators, only one configuration can be active at the time CMake is
run, and it is specified by the CVAKE_BUILD_TYPE variable. If the variable is empty then no
flags are added to the build. If the variable is set to the name of a configuration, then the
appropriate variables and rules (such as CMAKE_CXX_FLA\ ‘ConfigName>) are added to
the compile lines. Makefiles do not use special “configuration subdirectories for object files.
To build both debug and release trees, the user is expected to create multiple build directories
using the out of source build feature of CMake, and to set the CMAKE BUILD_TYPE# to the
desired selection for each build. For example,
# With source code in the directory MyProject
# to build MyProject-debug create that directory, ed into it and
(comake ../MyProject -DCMAKE BUILD TYPE: STRING=Debug)
# the same idea is used for the release tree MyProject-release
(cemake ../My®roject -DCMAKE BUILD_TYPE:STRING=Release)CMake Syntax 33,
Files
Writing CMakeLi
This chapter will cover the basics of writing effective CMakeLists files for your software. It
will cover all of the basic commands and issues you will need to handle most projects. It will
also discuss how to convert existing UNIX or Windows projects into CMakeLists files. While
CMake can handle extremely complex projects, for most projects you will find this chapter’s
contents will tell you all you need to know. CMake is driven by the CMakeLists.txt files
written for a software project. The CMakeLists files determine everything from what options
to put into the cache, to what source files to compile. In addition to discussing how to write a
CMakeLists file this chapter will also cover how to make them robust and maintainable. The
basic syntax of a CMakeLists.txt file and key concepts of CMake have already been discussed
in chapters 2 and 3. This chapter will expand on those concepts and introduce a few new ones.
4.1. CMake Syntax
CMakeLists files follow a simple syntax consisting of comments, commands, and white
space. A comment is indicated using the # character and runs from that character until the end
of the line. A command consists of the command name, opening parenthesis, white space
separated arguments and a closing parenthesis. All white space (spaces, line feeds, tabs) are
ignored except to separate arguments. Anything within a set of double quotes is treated as one
argument as is typical for most languages. The backslash can be used to escape characters
preventing the normal interpretation of them. The subsequent examples in this chapter will
help to clear up some of these syntactic issues. You might wonder why CMake decided to
have its own language instead of using an existing one such as Python, Java, or Tel. The main
reason is that we did not want to make CMake require an additional tool to run. By requiring
one of these other languages ail users of CMake would be required to have that language
installed, and potentially a specific version of that language. This is on top of the language34 Writing CMakeLists Files
extensions that would be required to do some of the CMake work, for both performance and.
capability reasons.
4.2 Basic Commands
While the previous chapters have already introduced many of the basic commands for
CMakeLists files, this chapter will review and expand on them, The first command the top-
level CMakeLists file should have is the PROJECT command. This command both names the
project and optionally specifies what languages will be used by if. Its syntax is as follows:
project (projectname [CXx] [C] [Java] [NONE])
If no languages are specified then CMake defaults to supporting C and C++. If the NONE
language is passed then CMake includes no language specific support. Whenever C++
janguage support is specified then C language support will also be loaded.
For each project command that appears in a project, CMake will create a top level IDE project
file. The project will contain all targets that are in the CMakeLists.txt file, and any of its
subdirectories as specified by the add_subdirectory command. If the
EXCLUDE_FROM_ALL option is used in the add subdirectory command, then the
generated project will not appear in the top level Makefile or IDE project file. This is useful
for generating sub projects that do not make sense as part of the main build process. Consider
that a project with a number of examples could use this feature to generate the build files for
each example with one run of CMake, but not have the examples built as part of the normal
build process.
‘The sex command is probably one of the most used commands since it is used for defining
and modifying variables and lists. Complimenting the set command are the remove and
separate arguments commands. The remove command can be used to remove a value
from a variable list, while the separate_arguments command can be used to take a single
variable value (as opposed to a list) and break it into a list based on spaces.
The add_executable and add_library commands are the main commands for defining
what libraries and executables to build, and what source files comprise them. For Visual
Studio projects the source files will show up in the IDE as usual, but any header files the
project uses will not be there. To have the header files show up as well you simply add them
to the list of source files for the executable or library. This can be done for all generators. Any
generators that do not use the header files directly (such as Makefile based generators) will
simply ignore them.Flow Control 35
4.3. Flow Control
In many ways writing a CMakeLists file is like a writing a program in a simple language.
Like most languages CMake provides flow control structures to help you along your way.
(CMake provides three flow control structures;
¢ conditional statements (e.g. i £)
© — looping constructs (e.g. foreach and while)
* procedure definitions (e.g. macro and function)
First we will consider the = command, In many ways the if command in CMake is just like
the if command in any other language. It evaluates its expression and based on that either
executes the code in its body or optionally the code in the e1se clause. For example:
if (FOO)
# do something here
else (FOO)
# do something else
endif (FOO)
One difference you might notice is that the conditional of the if statement is repeated in the
else and endié clauses. This is optional and in this book you will see examples of both
styles. You could just as well choose to write:
if (FOO)
# do something hi
else ()
# do something else
endif ()
When you include conditionals in the else and endif clause they are used to provide
additional error checking. As such they must exactly match the original conditional of the if
statement. The following code would not work:
set (FOO 1)
if (${FOO})
# do something
endif (1)
# ERROR, it doesn't match the original if conditional36 Writing CMakeLists Files
Fortunately CMake provides verbose error messages in the case where an if statement is not
properly matched with an endi. This should help you to track down any problems with
matching conditionals. Providing the conditionals on the ¢1se and endif commands also has
the added benefit of helping to document your CMakeLists file. With a long if statement it
can be easy to lose track of what if staternent the endif is closing. if statements can be
nested to any depth, and any command can be used inside of an if or else clause.
As with many other languages, CMake supports elseif so that you can sequentially test for
multiple conditions. For example:
if (MSVC80)
# do something here
elseif (MSVC90)
# do something e
elseif (APPLE)
# do something else
endif ()
The i¢ command has a limited set of operations that you can use. It does not support general
purpose C style expressions such as ${FOO} && ${BAR} || ${EUBAR}, instead it supports
a limited subset of expressions that should work for most cases. Specifically i £ supports:
if (variable)
True if the variable's value is not empty, 0, FALSE, OFF, or NOTFOUND,
if (NOT variable)
True if the variable's value is empty, 0, FALS:
OFF, or NOTFOUND
if (variable! AND variable2)
True if both variables would be considered true individually.
if (variablel OR variable2)
‘True if either variable would be considered true individually.
if (COMMAND command-name)
True if the given name is a command that can be invoked.
if (DEFINED variable)
True if the given variable has been set, regardless of what value it was set to.Flow Control 37
if (EXISTS file-name)
if (EXISTS directory-name)
True if the named file or directory exists.
if (IS_DIRECTORY name)
if (IS_ABSOLUTE name)
True if the given name is a directory, or absolute path respectively.
if (mamel IS_ NEWER_THAN name2)
True if the file specified by namel has a more recent modification time than the file
specified by name2.
if (variable MATCHES regex)
if (string MATCHES regex)
True if the given string or variable's value matches the given regular expression.
Options such as EQUAL, LESS, and GREATER are available for numeric comparisons.
STRLESS, STREQUAL, and STRGREATER can be used for lexicographic comparisons.
VERSION_LESS, VERSION_EQUAL, and VERSION_GREATER can be used to compare versions
of the form major!.minor[.patch[.tweak]]]. Similar to C and C++ these expressions
can be combined to create more powerful conditionals. For example consider the following
conditionals:
if ((1 LESS 2) AND (3 LESS 4))
message ("sequence of numbers")
endif (
if (1 AND 3 AND 4)
message ("series of true values")
endif (1 AND 3 AND 4)
if (NOT 0 AND 3 AND 4)
message ("a false value")
endif (NOT 0 AND 3 AND 4)
if (0 OR 3 AND 4)
message ("or statements")
endif (0 OR 3 AND 4)
if (EXISTS ${PROJECT_SOURCE_DIR}/Help.txt AND COMMAND IF)
message ("Help exists")
endif (EXISTS ${PROJECT_SOURC
; DIR}/Help.txt AND COMMAND IF)38 Writing CMakeLists Files,
set (fooba 0)
if (NOT DEFINED foobar)
message ("foobar is not defined")
endif (NOT DEFINED foobar)
if (NOT DEFINED fooba)
message ("fooba not defined")
endif (NOT DEFINED fooba)
In compound if statements there is an order of precedence that specifies the order that the
operations will be evaluated. For example, in the statement below, the NOT will be evaluated
first then the AND, not the other way around. Thus the statement will be false and the message
never printed. Had the AND been evaluated first the statement would be true.
if (NOT 0 AND 0)
message ("This line is never executed")
endif (NOT O AND 0)
CMake defines the order of operations such that parenthetical groups are evaluated first, then
EXISTS, COMMAND, DEFINED and similar prefix operators are evaluated, then any EQUAL,
LESS, GREATER, STREQUAL, STRLESS, STRGREATER, and MATCHES operators. The NoT
operators are evaluated next, and finally the AND and OR expressions will be evaluated. With
operations that have the same level of precedence, such as AND and or, they will be evaluated
from left to right. Once all of the expressions have been evaluated the final result will be
tested 10 see if it is true or false. CMake considers any of the following values to be true: on,
1, YES, TRUE, Y. The following values are all considered to be false: OFF, 0, NO, FALSE, N,
NOTFOUND, *-NOTFOUND, IGNORE. This test is case insensitive so true, True, and TRUE are
all treated the same.
Now let us consider the other flow contral commands. The foreach, while, macro, and
fanction commands are the best way to reduce the size of your CMakeLists files and keep
them maintainable. The foreach command enables you to execute a group of CMake
commands repeatedly on the members of a list. Consider the following example adapted from
VIK:
foreach (tfile
TestAnisotropicDiffusion2D
TestButterworthLoweass
TestButterworthHighPass
TestCityBlockDistanceFlow Control 39
TestConvolve
)
add_test (${tfile}-image ${VTK_EXECUTABLE}
${VTK_SOURCE_DIR}/Tests/rtImageTest.tcl
${VTK_SOURCE_DIR}/Tests/${tfile}.tcl
-D ${VIK_DATA_ROOT}
-V Baseline/Imaging/$({tfile} png
-A ${VTK_SOURCE_DIR}/Wrapping/Tcl
)
endforeach ( tfile )
The first argument of the foreach command is the name of the variable that will take on a
different value with each iteration of the loop. The remaining arguments are the list of values
over which to loop. In this example the body of the foreach loop is just one CMake
command, add_test. In the body of the foreach loop any time the loop variable (t file in
this example) is referenced it will be replaced with the current value from the list. In the first
iteration, occurrences of ${t file} will be replaced with TestAnisotropicDiffusion2D.
In the next iteration, ${tfile} will be replaced with TestButterworthLowPass. The
foreach loop will continue to loop until all of the arguments have been processed.
It is worth mentioning that foreach loops can be nested and that the loop variable is replaced.
prior to any other variable expansion. This means that in the body of a foreach loop you
can construct variable names using the loop variable. In the code below the loop variable
t£ile is expanded, and then concatenated with TEST_RESULT. That new variable name is
then expanded and tested to see if it matches FAILED.
if (${${tf£ile}} TEST RESULT} MATCHES FAILED)
message ("Test ${tfile} failed.")
endif ()
The while command provides for looping based on a test condition. The format for the test
expression in the while command is the same as that for the i£ command described earlier.
Consider the following example, which is used by CTest. Note that CTest updates the value of
CTEST_ELAPSED_TIME internally.
FESESAEEAA TERA CTPA PPAHAPEEAAEEAS ESSE EASES REESE EEE THEE
# run paraview and ctest test dashboards for 6 hours
¥
while (${CTEST_ELAPSED_TIME} LESS 36000)
set (STAR' fIME ${CTEST ELAPSED_TIME})
ctest_run_script ( "dashl_ParaView_vsTicontinuous.cmake" )
ctest_run_script ( "dashl_cmake_vs7lcontinuous.cmake" )40 Writing CMakeLists Files
endwhile ()
The foreach and while commands allow you to handle repetitive tasks that occur in
sequence, whereas the macro and function commands support repetitive tasks that may be
scattered throughout your CMakeLists files. Once a macro or function is defined it can be
used by any CMakeLists files processed after its definition.
A function in CMake is very much like a function in C or C++. You can pass arguments into,
it, and the arguments passed in become variables within the function. Likewise some standard
variables such as ARGC, ARGV, ARGN, and ARGVO, ARGV1, ete are defined. Within a function,
you are in a new variable scope, much like when you drop into a subdirectory using the
add_subdirectory command you are in a new variable scope. All the variables that were
defined when the function was called are still defined, but any changes to variables or new
variables only exist within the function. When the function returns those variables will go
away. Put more simply, when you invoke a function a new variable scope is pushed and when
it returns that variable scope is popped.
‘The first argument is the name of the function to define. All additional arguments are formal
parameters to the function.
function (DetermineTime _time)
# pass the result up to whatever invoked this
set (${_time} “1:23:45” PARENT_SCOPE)
endfunct ion ()
# now use the function we just defined
DetermineTime( current_time }
if( DEFINED current_time )
message (STATUS "The time is now: ${curret_time}")
endif ()
Note that in this example _time is used to pass the name of the return variable. The set
command is invoked with the value of _t ime, which in this example will be current_time.
Finally the set command uses the PARENT_SCOPE option to set that variable in the parent’s
scope instead of the local scope.
Macros are defined and called in the same manner as functions. The main differences are that
a macro does not push and pop a new variable scope. and the arguments to a macro are not
treated as variables but are string replaced prior to execution. This is very much like the
differences between a macro and a function in C or C++. The first argument is the name of
the macro to create. All additional arguments are formal parameters to the macro.Flow Control 44
# define a simple macro
macro (assert TEST COMMENT)
if (NOT ${TEST})
message ("Assertion failed: ${COMMENT}")
endif (NOT ${TEST})
endmacro (assert)
# use the macro
find_library (FOO_LIB foo /usr/local/lib)
assert ( ${FOO_LIB} “Unable to find library foo" )
The simple example above creates a macro called assert. The macro is defined to take two
arguments. The first argument is a value to test and the second argument is a comment to print
out if the test fails. The body of the macro is a simple if command with a message
command inside of it. The macro body ends when the endmacro command is found. The
macro can be invoked simply by using its name as if it were a command. In the above
example if FOO LIB was not found a message would be displayed indicating the error
condition.
The macro command also supports defining macros that take variable argument lists. This
can be useful if you want to define a macro that has optional arguments or multiple signatures.
Variable arguments can be referenced using ARGC and ARGVO, ARGV1, etc., instead of the
formal parameters. ARGVO represents the first argument to the macro, ARGV1 represents the
next, and so forth. You can even use a mixture of formal arguments and variable arguments,
as shown in the example below.
# define a macro that takes at least two arguments
# (the formal arguments) plus an optional third argument
macro (assert TEST COMMENT)
if (NOT ${TEST})
message ("Assertion failed: ${COMMENT}")
# if called with three arguments then also write the
# message to a file specified as the third argument
if (${ARGC} MATCHES 3)
file (APPEND ${ARGV2} “Assertion failed: ${COMMENT}")
endif (${ARGC} MATCHES 3)
endif (NOT ${TEST})
endmacro (ASSERT)42 Writing CMakeLists Files
# use the macro
find_library (FOO_LIB foo /usr/local/lib)
assert ( ${FOO_L1B} “Unable to find library foo" }
In this example the two required arguments are TEST and COMMENT. These required
arguments can be referenced by name, as they are in this example, or they can be referenced
‘using ARGVO and ARGV1. If you want to process the arguments as a list you can use the ARGV
and ARGN variables. ARGV (as opposed to ARGV, ARGV1, etc) is a list of all the arguments to
the macro, while ARGN is a list of all the arguments after the formal arguments. Inside your
macro you can use the fore. command to iterate over ARGV or ARGN as desired.
CMake has two commands for interrupting the processing flow. The break command will
break out of a foreach of while loop before it would normally end. The return command
will return from a function or listfile before the function or listfile has reached its end.
4.4 Regular Expressions
A few CMake commands, such as if and string, make use of regular expressions, or can
take a regular expression as an argument. In its simplest form, a regular-expression is a
sequence of characters used to search for exact character matches, However, many times the
exact sequence to be found is not known, or only a match at the beginning or end of a string is
desired. Since there are several different conventions for specifying regular expressions
CMake’s standard is described below. The description is based on the open source regular
expression class from Texas Instruments, which is used by CMake for parsing regular
expressions.
Regular expressions can be specified by using combinations of standard alphanumeric
characters and the following regular expression meta-characters:
“ 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.Regular Expressions 43
+ Matches preceding pattern one or more times.
2 Matches preceding pattern zero or once only.
0. Saves a matched expression and uses it in a later replacement.
(|) Matches either the left or right side of the bar.
Note that more than one of these meta-characters can be used in a single regular expression in
order to create complex search patterns. For example, the pattern [“ab1-9] indicates to match
any character sequence that does not begin with the characters "a” or “b" or numbers in the
series one through nine. The following examples may help clarify regular expression usage:
«The regular expression "“hello" matches a "hello" only at the beginning of a search
string. It would match "hello there", but not "hi,\nhello there".
© The regular expression "long$" matches a "long” onty at the end of a search string. It
would match "so long", but not "long ago".
° The regular expression "t..t.g" will match anything that has a "t", then any two
characters, another "t", any two characters, and then a "g". It would match "testing" or
"test again", but would not match "toasting".
¢ — The regular expression "[I-9ab]" matches any number one through nine, and the
characters "a" and "b". It would match "hello 1" or "begin", but would not match "no-
match",
© The regular expression "[“I-9ab]" matches any character that is not a number one
through nine, or an "a" or Tt would NOT match "lab2" or "b2345a", but would
match "no-match".
© The regular expression "br* " matches something that begins with a "b", is followed by
zero or more "r"'s, and ends in a space. It would match "brrrrr " and "b ", but would not
match "brrh ".
© The regular expression "br+ " matches something that begins with a "b", is followed by
one or more "r'’s, and ends in a space. It would match "brrrrr ", and "br ", but would not
match "b " or "brrh ",
© The regular expression "br? " matches something that begins with a "b", is followed by
zero or one "r"s, and ends in a space. It would match "br ", and "b ", but would not
match “rrr " or "orth",
© The regular expression "(..p)b" matches something ending with pb and beginning with
whatever the two characters before the first p encountered in the line were. It would find
"repb" in "rep drepaqrepb". The regular expression "(..p)a" would find "repa qrepb" in
"rep drepa qrepb"44 Writing CMakeLists Files.
* The regular expression "d(..p)" matches something ending with p, beginning with d, and
having two characters in between that are the same as the two characters before the first
p encountered in the line. It would match "drepa qrepb" in "rep drepa qrepb".
4.5 Checking Versions of CMake
CMake is an evolving program and as new versions are released, new features or commands
may be introduced. As a result, there may be instances where you might want to use a
command that is in a current version of CMake but not in previous versions. There are a
couple of ways to handle this. One option is to use the i ¢ command to check whether a new
command exists. For example:
# test if the command exists
if (COMMAND some_new_command)
# use the command
some_new_contmand ( ARGS...)
endif (COMMAND some_new_command)
The above approach should work in most cases, but if you need more information you can test
against the actual version of CMake that is being run by evaluating the CMAKE_VERSTON
variables, as in the following example:
# look for newer versions of CMake
if (${CMAKE VERSION} VERSION GREATER 1.6.1)
4 do something special here
endif ()
When writing your CMakeLists files you might decide that you do not want 10 support old
versions of CMake. To do this you can place the following command at the top of your
CMakeLists file:
cmake_minimum_required (VERSION 2.2)
This indicates that the person running CMake on your project must have at least CMake
version 2.2. If they are running an older version of CMake then an error message will be
displayed telling them that the project requires at least the specified version of CMake.Using Modules 45
Finally, in some cases a new release of CMake might come out that no longer supports some
commands you were using (although we try to avoid this). In these cases you can use CMake
policies, as discussed in section 4.7
4.6 Using Modules
Code reuse is a valuable technique in software development and CMake has been designed to
support it. Allowing CMakeLists files to make use of reusable modules enables the entire
CMake community to share reusable sections of code, For CMake these sections of code are
called modules and can be found in the Modules subdirectory of your CMake installation,
Modules are simply sections of CMake commands put into a file. They can then be included
into other CMakeLists files using the include command. For example, the following
commands will include the Fina?cl. module from CMake and then add the Tel library to the
target FOO.
include (FindTCL)
target_link libraries (FOO ${TCL_LIBRARY})
A module’s location can be specified using the full path to the module file, or by letting
CMake find the module by itself. CMake will look for modules in the directories specified by
CMAKE MODULE_PATE and if it cannot find it there, it will look in the Modules subdirectory
of CMake. This way projects can override modules that CMake provides, to customize them
for their needs. Modules can be broken into a few main categories:
Find Modules
These modules determine the location of software elements such as header files or
libraries.
System Introspection Modules
These modules test the system for properties such as the size of a float, support for
ANSI C++ streams, etc.
Utility Modules
These modules provide added functionality such as support for situations where one
CMake project depends on another and other convenience routines.
Now let us consider these three types of modules in more detail. CMake includes a large
number of Find modules. The purpose of a Find module is to locate software elements such as
header or library files. If they cannot be found then they provide a cache entry so that the user
can set the required properties. Consider the following module that finds the PNG library46
Writing CMakeLists Files
Find the native PNG includes and library
This module defines
PNG_INCLUDE_DIR, where to find png.h, etc.
PNG_LIBRARIES, the libraries to link against to use PNG.
PNG _DEFINITIONS - You should call
add_definitions (${PNG_DEFINITIONS}) before compiling code
that includes png library files.
PNG FOUND, If false, do not try to use PNG.
ee
*
also defined, but not for general use are
# PNG LIBRARY, where to find the PNG library.
# None of the above will be defined unless zlib can be found.
# PNG depends on Zlib
include ( FindZLIB.cmake )
if (ZLIB_FOUND)
find_path (PNG_PNG_INCLUDE_DIR png.h
/usr/local/include
/usr/include
)
find_library (PNG_LIBRARY png
/usr/lib
/usr/local/lib
)
if (PNG_LIBRARY)
if (PNG_PNG_INCLUDE_DIR)
# png.h includes zlib.h. Sigh.
set (PNG_INCLUDE_DIR
${PNG_PNG_INCLUDE DIR} ${ZLIB_INCLUDE_DIR} )
set (PNG_LIBRARIES ${PNG_LIBRARY} ${ZLIB_LIBRARY})
set (PNG_FOUND "YES")
if (CYGWIN)
if (BUILD_SHARED_LIBS)
# No need to define PNG_USE_DLL here, because
# it's default for Cygwin.
else (BUILD_SHARED_LIBS)Using Modules 47
set (PNG_DEFINITIONS -DPNG_STATIC)
endif (BUILD_SHARED LIBS)
endif (CYGWIN)
endif ()
endif ()
endif ()
The top of the module clearly documents what the module will do and what variables it will
set. Next it includes another module, the FindZLIB module, that determines if the ZLib
library is installed. Next, if ZLib is found, the find_path command is used to locate the
PNG include files. The first argument is the name of the variable to store the result in, the
second argument is the name of the header file to look for, the remaining arguments are paths
to search for the header file. If it is not found in the system path then the variable is set to
PNG_PNG_INCLUDE_DIR-NOTFOUND, allowing the user to set it.
Note that the paths to search for the PNG library can include hard coded directories, registry
entries, and directories made up of other CMake variables. The next command finds the actual
PNG library using the find_1library command. This command performs additional checks
to find a proper library name, such as adding "lib" in front of the name and ".so" at the end of
the name on Linux systems.
After the find calls, some CMake variables are set that developers using FindPNG can use in
their projects (such as the include paths, and library name). Finally PNG_FOUND is set
correctly, which lets developers know that the PNG library was properly found.
This structure is fairly common to all Find modules in CMake. Usually they are fairly short,
but in some cases, such as FindOpenGL they can be a few pages long. They are normally
independent of other modules, but there is no restriction on the use of other modules.
System introspection modules provide information about the target platform or compiler.
Many of these modules have names prefixed with Test or Check, such as TestBigEndian
and CheckTypeSize. Many of the system introspection modules actually try to compile code
in order to determine the correct result. In these cases the source code is usually named the
same as the module, but with a .c or .cxx extension. System introspection modules are
covered in more detail in chapter 5.
CMake includes a few Utility modules to help make using CMake a little easier.
CMakeExportBuildSettings and CMakeImportBuildSettings provide tools to help
verify that two C++ projects are compiled with the same compiler and key flags. The
CMakePrintSystemInformation module prints out a number of key CMake settings to aid
in debugging.48 Writing CMakeLists Files
Using CMake with SWIG
One example of how modules can be used is to look at wrapping your C/C++ code in another
language using SWIG. SWIG (Simplified Wrapper and Interface Generator) www.swig.org is
a tool that reads annotated C/C++ header files, and creates wrapper code (glue code) in order
to make the corresponding C/C++ libraries available to other programming languages such as
Tel, Python, or Java. CMake supports SWIG with the find_package command. Although
. SWIG can be used from CMake using custom commands, the SWIG package provides
several macros that make building SWIG projects with CMake simpler. To use the SWIG
macros, first you must call the find package command with the name SWIG. Then you
need to include the file referenced by the variable SWIG_USE_FILE. This will define several
macros and set up CMake to easily build SWIG based projects.
Two very useful macros are SWIG_ADP MODULE and SWIG_LINK_LIBRARIES.
SWIG_ADD_MODULE works much like the add_library command in CMake. The command
is invoked like this:
SWIG_ADD_MODULE (module name language sourcel source2 ... sourceN)
The first argument is the name of the module to create. The next argument is the target
language SWIG is producing a wrapper for. The rest of the arguments consist of a list of
source files used to create the shared module. The big difference is that SWIG . i interface
files can be used directly as sources. The macro will create the correct custom commands to
run SWIG, and generate the C or C++ wrapper code from the SWIG interface files. The
sources can also be regular C or C++ files that need to be compiled in with the wrappers.
The SWIG_LINK_LIBRARIES macro is used to link support libraries to the module. This
macro is used because depending on the language being wrapped by SWIG, the name of the
module may be different. The actual name of the module is stored in a variable called
SWIG MODULE_${name}_REAL_NAME where ${name} is the name passed into the
SWIG_ADD MODULE macro. For example, SWIG_ADD_MODULE(foo tcl foo.i) would
create a variable called SwIG_MODULE_foo_REAL_NAME which would contain the name of
the actual module created.
Now consider the following example that uses the SWIG example found in SWIG under
Examples/python/class.
# Find SWIG and include the use swig file
find_package (SWIG REQUIRED)
include (${SWIG_USE_FILE})
# Find python library and add include path for python headers
find package (PythonLibs)
include_directories (${PYTHON_INCLUDE_PATH})Using Modules 49
# set the global swig flags to empty
set (CMAKE_SWIG_FLAGS "")
# let swig know that example.i is c++ and add the -includeall
# flag to swig
set_source_files_properties (example.i PROPERTIES CPLUSPLUS ON)
set_source_files properties (example.i
PROPERTIES SWIG FLAGS "-includeall")
# Create the swig module called example
# using the example.i source and example.cxx
# swig will be used to create wrap _example.cxx from example.i
SWIG_ADD_MODULE (example python example. i example.cxx)
SWIG_LINK_LIBRARIES (example ${PYTHON_LIBRARIES})
This example first uses find_package to locate SWIG. Next it includes the
SWIG_USE_FILE defining the SWIG CMake macros. Then it finds the Python libraries and
sets up CMake to build with the Python library. Notice that the SWIG input file example.i is
used like any other source file in CMake, and properties are set on the file telling SWIG that
the file is C++ and that the SWIG flag —includeall should be used when running SWIG on that
source file. The module is created by telling SWIG the name of the module, the target
language and the list of source files. Finally, the Python libraries are linked to the module.
Using CMake with Qt
Projects using the popular widget toolkit Qt from Nokia, qt.nokia.com, can be built with
CMake. CMake supports multiple versions of Qt, including versions 3 and 4. The first step is
to tell CMake what version(s) of Qt to look for. Many Qt applications are designed to work
with Qt3 or Qt4, but not both. If your application is designed for Qt4 then you can use the
FindQt4 module, for Qt3 you should use the FindQt3 module. If your project can work with
either version of Qt then you can use the generic FindQt module. All of the modules provide
helpful tools for building Qt projects. The following is a simple example of building a project
that uses Qt4.
find package ( Qt4 )
if (QT4_FOUND)
include (${QT_USE_FILE})
# what are our ui files?
set (QTUI_SRCS qtwrapping.ui)
QT4_WRAP_UI (QTUI_H_ SRCS ${QTUI_SRCS})
QT4_WRAP_CPP (QT_MOC_SRCS TestMoc.h)50 Writing CMakeLists Files
add_library (myqtlib ${QTUI_H_SRCS} ${QT_MOC_SRCS})
target_link libraries (myqtlib ${QT_LIBRARIES} )
add_executable (qtwrapping qtwrappingmain.cxx)
target_link libraries (qtwrapping myqtlib)
endif (QT4 FOUND)
Using CMake with FLTK
CMake also supports the The Fast Light Toolkit (FLTK) with special FLTK CMake
commands. The FLTK_WRAP_UI command is used to run the fltk fluid program on a .fl file
and produce a C++ source file as part of the build. The following example shows how to use
FLTK with CMake.
find_package (FLTK)
if (FLTK_FOUND)
set (FLTK_SRCS
fltki.f1
)
FLTK_WRAP_UI (wraplibFLTK ${FLTK_SRCS})
add_library (wraplibFLTK ${wraplibFLTK_UI_SRCS} )
endif (FLTK_FOUND)
4.7 Policies
For various reasons, sometimes a new feature or change is made to CMake that is not fully
backwards compatible with older versions of CMake. This can create problems when
someone tries to use an old CMakeLists file with a new version of CMake. To help both end
users and developers through such issues, we have introduced policies. Policies are a
mechanism in CMake to help improve backwards compatibility and track compatibility issues
between different versions of CMake.
Design Goals
There were four main design goals for the CMake policy mechanism:
1. Existing projects should build with versions of CMake newer than that used by the
project authors.
* Users should not need to edit code to get the projects to build.
¢ Warnings may be issued but the projects should build.Policies 51
2. Correctness of new interfaces or bugs fixes in old interfaces should not be inhibited by
compatibility requirements. Any reduction in correctness of the latest interface is not fair
on new projects.
3. Every change made to CMake that may require changes to a project’s CMakeLists files
should be documented.
Each change should also have a unique identifier that can be referenced by warning
and error messages.
¢ The new behavior is enabled only when the project has somehow indicated it is
supported.
4. We must be able to eventually remove code that implements compatibility with ancient
CMake versions.
Such removal is necessary to keep the code clean and to allow for internal
refactoring.
e After such removal, attempts to build projects written for ancient versions must fail
with an informative message.
All policies in CMake are assigned a name of the form CMPNNNN where NNNN is an integer
value. Policies typically support both an old behavior that preserves compatibility with earlier
versions of CMake, and a new behavior that is considered correct and preferred for use by
new projects. Every policy has documentation detailing the motivation for the change, and the
old and new behaviors
Setting Policies
Projects may configure the setting of each policy to request old or new behavior. When
CMake encounters user code that may be affected by a particular policy it checks to see
whether the project has set the policy. If the policy has been set (to OLD or NEW) then
CMake follows the behavior specified. If the policy has not been set then the old behavior is
used, but a warning is issued telling the project author to set the policy.
There are a couple ways to set the behavior of a policy. The quickest way is to set all policies
to a version corresponding to the release version of CMake for which the project was written.
Setting the policy version requests the new behavior for all policies introduced in the
corresponding version of CMake or earlier. Policies introduced in later versions are marked as
not set in order to produce proper warning messages. The policy version is set using the
cmake_policy command's VERSION signature. For example, the code
cmake_policy (VERSION 2.6)
will request the new behavior for all policies introduced in CMake 2.6 or earlier. The
cmake_minimum_required command will also set the policy version, which is convenient
for use at the top of projects. A project should typically begin with the lines52. Writing CMakeLists Files
cmake_minimum_required (VERSION 2.6)
project (MyProject)
# ...code using CMake 2.6 policies
Of course one should replace "2.6" with whatever version of CMake you are currently writing
to. You can also set each policy individually if you wish. This is sometimes helpful for project
authors who want to incrementally convert their projects to use the new behavior, or silence
warnings about dependence on old behavior. The cmake_policy command's SET option
may be used to explicitly request old or new behavior for a particular policy.
For example, CMake 2.6 introduced policy cMP0002, which requires all logical target names
to be globally unique (duplicate target names previously worked in some cases by accident
but were not diagnosed). Projects using duplicate target names and working accidentally will
receive warnings referencing the policy. The warnings may be silenced by the code
cmake_policy (SET CMP0002 OLD)
which explicitly tells CMake to use the old behavior for the policy (silently accept duplicate
target names). Another option is to use the code
cmake_policy (SET CMP0002 NEW)
to explicitly tell CMake to use new behavior and produce an error when a duplicate target is
created. Once this is added to the project it will not build until the author removes any
duplicate target names.
When a new version of CMake is released that introduces new policies it will still build old
projects, because by default they do not request NEW behavior for any of the new policies.
When starting a new project one should always specify the most recent release of CMake to
be supported as the policy version level. This will make sure that the project is written to
work using policies from that version of CMake and not using any old behavior. If no policy
version is set CMake will warn and assume a policy version of 2.4, This allows existing
projects that do not specify cmake_minimum_required to build as they would have with
CMake 2.4.
The Policy Stack
Policy settings are scoped using a stack. A new level of the stack is pushed when entering a
new subdirectory of the project (with add_subdirectory) and popped when leaving it.
Therefore setting a policy in one directory of a project will not affect parent or sibling
directories, but will affect subdirectories.Policies 53
This is useful when a project contains subprojects maintained separately but built inside the
tree. The top-level CMakeLists file in a project may write
cmake_policy (VERSION 2.6)
project (MyProject)
add_subdirectory (OtherProject)
# ... code requiring new behavior as of CMake 2.6
while the OtherProject/CMakeLists.txt file contains
cmake_policy (VERSION 2.4)
project (OtherProject)
# ... code that builds with CMake 2.4
This allows a project to be updated to CMake 2.6 while subprojects, modules, and included
files continue to build with CMake 2.4 until their maintainers update them.
User code may use the cmake_policy command to push and pop its own stack levels as long
as every push is paired with a pop. This is useful to temporarily request different behavior for
a small section of code. For example, policy CMP0003 removes extra link directories that used
to be included when new behavior is used. While incrementally updating a project it may be
difficult to build a particular target with the new behavior but all other targets are okay. The
code
cmake_policy (PUSH)
cmake policy (SET CMP0003 OLD) # use old-style link for now
add_executable (myexe ...)
cmake policy (POP)
will silence the warning and use the old behavior for that target. You can get a list of policies
and help on specific policies by running cmake from the command line as follows
cmake --help-command cmake_policy
cmake --help-policies
cmake --help-policy CMP0003
Updating a Project For a New Version of CMake
When a CMake release introduces new policies it may generate warnings for some existing
projects. These warnings indicate that changes to the project may need to be made to deal
correctly with the new policies. While old releases of the project can continue to build with54 Writing CMakeLists Files
the warnings the project development tree should be updated to take the new policies into
account. There are two approaches to updating a tree: one-shot and incremental. Which one is
easier depends on the size of the project and what new policies produce warnings.
The One-Shot Approach
The simplest approach to updating a project for a new version of CMake is simply to change
the policy version set at the top of the project, try building with the new CMake version, and
fix problems. For example, to update a project to build with CMake 2.8 one might write
cmake_minimum_required (VERSION 2.8)
at the beginning of the top-level CMakeLists file. This tells CMake to use the new behavior
for every policy introduced in CMake 2.8 and below. When building this project with CMake
2.8 no warnings will be produced about policies because it knows of no policies introduced in
later versions. However, if the project was depending on the old behavior of a policy it may
not build since CMake now uses the new behavior without warning. It is up to the project
author who added the policy version line to fix these issues.
The Incremental Approach
Another approach to updating a project for a new version of CMake is to deal with each
warning one-by-one. One advantage of this approach is that the project will continue to build
throughout the process, so the changes can be made incrementally.
When CMake encounters a situation where it needs to know whether to use the old or new
behavior for a policy, it checks whether the project has set the policy. If the policy is set
CMake silently uses the corresponding behavior. If the policy is not set, CMake uses the old
behavior but warns that the policy is not set.
In many cases the warning message will point at the exact line of code in the CMakeLists files
that caused the warning. In some cases the situation cannot be diagnosed until CMake is
generating the native build system rules for the project, so the warning will not include
explicit context information. In these cases CMake will try to provide some information about
where code may need to be changed. The documentation for these "generation-time" policies
should indicate the point in the project code at which the policy should be set to take effect.
In order to incrementally update a project one warning should be addressed at a time. Several
cases may occur as described below.
Silence a Warning When the Code is Correct
Many policy warnings may be produced simply because the project has not set the policy
even though the project may work correctly with the new behavior (there is no way for
CMake to know the difference). For a warning about some policy CMP one may check
whether this is the case by addingPolicies 55,
cmake_policy (SET CMP NEW)
to the top of the project and trying to build it. If the project builds correctly with the new
behavior one may move on to the next policy warning. If the project does not build correctly
one of the other cases may apply.
Silence a Warning Without Updating the Code
One may suppress all instances of a warning CMP by adding
cmake policy (SET CMP OLD)
at the top of a project. However, we encourage project authors to update their code to work
with the new behavior for all policies. This is especially important because versions of CMake
in the (distant) future may remove support for the old behavior and produce an error for
projects requesting it (which tells the user to get an older CMake to build the project).
Silence a Warning by Updating Code
When a project does not work correctly with the NEW behavior for a policy its code needs to
be updated. In order to deal with a warning for some policy CMP one may add
cmake_policy (SET CMP WEW)
at the top of the project and then fix the code to work with the NEW behavior.
If many instances of the warning occur fixing all of them simultaneously may be too difficult.
Instead a developer may fix one at a time. This may be done using the PUSH/POP signatures
of the cmake_policy command:
emake_policy (PUSH)
emake policy (SET CMP NEW)
# ... code updated for new policy behavior ...
cmake_policy (POP)
This will request the new behavior for a small region of code that has been fixed. Other
instances of the policy warning may still appear and must be fixed separately.
Updating the Project Policy Version
After addressing all policy warnings and getting the project to build cleanly with the new
CMake version one step remains. The policy version set at the top of the project should now
be updated to match the new CMake version, just as in the one-shot approach above. For56 Writing CMakeLists Files
example, after updating a project to build cleanly with CMake 2.8 one may update the top of
the project with the line
cmake_minimum_required (VERSION 2.8)
This will set all policies introduced in CMake 2.8 or below to use the new behavior. Then one
may sweep through the rest of the code and remove all the calls to the cmake_policy
command used to request the new behavior incrementally. The end result should look the
same as the one-shot approach above but could be attained step-by-step.
Supporting Multiple CMake Versions
Some projects might want to support a few releases of CMake simultaneously. The goal is to
build with an older version but also work with newer versions without warnings. In order to
support both CMake 2.4 and 2.6, one may write code like
emake _minimum_required (VERSION 2.4)
if (COMMAND cmake_policy)
# policy settings
cmake_policy (SET CMP0003 NEW)
endif (COMMAND cmake_policy)
This will set the policies when buitding with CMake 2.6 and just ignore them for CMake 2.4.
In order to support both CMake 2.6 and some policies of CMake 2.8, one may write code like
cmake_minimum_required (VERSION 2.6)
if (POLICY CMP1234)
# policies not known to CMake 2.6 ...
cmake_policy (SET CMP1234 NEW)
endif (POLICY CMP1234)
This will set the policies when building with CMake 2.8 and just ignore them for CMake 2.6.
If it is known that the project builds with both CMake 2.6 and CMake 2.8's new policies one
may write
cmake minimum required (VERSION 2.6)
if (NOT ${CMAKE VERSION} VERSION_LESS 2.8)
cmake_ policy (VERSION 2.8)
endif ()Linking Libraries ST
4.8 Linking Libraries
In CMake 2.6 and later a new approach to generating link lines for targets has been
implemented. Consider these libraries:
/path/to/Libfoo.a
/path/to/libfoo.so
Previously if someone wrote
target_link_libraries (myexe /path/to/libfoo.a)
CMake would generate this code to link it:
. -L/path/to -W1,-Bstatic -lfoo -W1,-Bdynamic ...
This worked most of the time, but some platforms (such as Mac OS X) do not support the -
Bstatic or equivalent flag. This made it impossible to link to the static version of a library
without creating a symlink in another directory and using that one instead. Now CMake will
generate this code:
/path/to/libfoo.a ...
This guarantees that the correct library is chosen. However there are some caveats to keep in
mind. In the past a project could write this (incorrect) code, and it would work by accident:
add_executable (myexe myexe.c)
target_link libraries (myexe /path/to/libA.so B)
where "8" is meant to link "/path/to/1libB.so". This code is incorrect because it asks
CMake to link to B but does not provide the proper linker search path for it. It used to work by
accident because the -L/path/to would get added as part of the implementation of linking
to A. The correct code would be either
link_directories (/path/to)
add_executable (myexe myexe.c)
target_link libraries (myexe /path/to/libA.so B)58. Writing CMakeLists Files
or even better
add_executable (myexe myexe.c)
target_link libraries (myexe /path/to/1libA.so /path/to/1ibB.so)
Linking to System Libraries
System libraries on UNIX-like systems are typically provided in /usr/1ib or /1ib. These
directories are considered implicit linker search paths because linkers automatically search
these locations, even without a flag like -L/usr/1ib. Consider the code
find_library (M_LIB m)
target _link libraries (myexe ${M_LIB})
Typically the find_library command would find the math library /usr/1lib/1ibm.so,
but some platforms provide multiple versions of libraries correesponding to different
architectures. For example, on an IRIX machine one might find the libraries
/asr/lib/libm.so {ELF 032)
/usr/1ib32/libm.so (ELF n32)
/usr/1ib64/libm.so (ELF 64)
On a Solaris machine one might find
/usr/1ib/libm.so (sparcv8 architecture)
/asr/lib/sparcv9/libm.so (sparcvS architecture)
Unfortunately, £ind_library may not know about all of the architecture-specific system
search paths used by the linker. In fact, when it finds /usr/1ib/1ibm.so, it may be finding
a library with the incorrect architecture. If the link computation were to produce the line
/usr/lib/libm.so .,.
the linker might complain if /usr/1ib/1ibm.so does not match the architecture it wants.
One solution to this problem is for the link computation to recognize that the library is in a
system directory and ask the linker to search for the library. It could produce the link line
-im .Shared Libraries and Loadable Modules 59
and the linker would search through its architecture-specific implicit link directories to find
the correct library. Unfortunately, this solution suffers from the original problem of
distinguishing between static and shared versions. In order to ask the linker to find a static
system library with the correct architecture it must produce the link line
. “W1,-Bstatic -Im ... -Wl,-Bshared ...
Since not all platforms support such flags CMake compromises. Libraries that are not in
implicit system locations are linked by passing the full library path to the linker. Libraries that
are in implicit system locations (such as /usr/1ib) are linked by passing the -1 option ifa
flag like -Bstatic is available, and by passing the full library path to the linker otherwise.
Specifying Optimized or Debug Libraries with a Target
On Windows platforms it is often required to link debug libraries with debug libraries, and
optimized libraries with optimized libraries. CMake helps satisfy this requirement with the
target_link libraries command, which accepts an optional flag that is debug or
optimized. So, if a library is preceded with either debug or optimized, then that library will
only be linked in with the like configuration type. For example:
add_executable (foo foo.c)
target_link libraries (foo debug libdebug optimized libopt}
In this case foo will be linked against libdebug if a debug build was selected, or against libopt
if an optimized build was selected.
4.9 Shared Libraries and Loadable Modules
Shared fibraries and loadable modules are very powerful tools for software developers. They
can be used to create extension modules or plugins for off-the-shelf software, and can be used
to decrease the compile/fink/run cycles for C and C++ programs. However, despite years of
use, the cross platform creation of shared libraries and modules remains a black art
understood by only a few developers. CMake has the ability to aid developers in the creation
of shared libraries and modules. CMake knows the correct tools and flags to use in order to
produce the shared libraries for most modern operating systems that support them.
Unfortunately, CMake cannot do all the work, and developers must sometimes alter source
code and understand the basic concepts and common pitfalls associated with shared libraries
before they can be used effectively. This section will describe many of the issues required to
take advantage of shared libraries and loadable modules.
A shared library should be thought of more like an executable than a static library, and on
most systems actually requires executable permissions to be set on the shared library file. This60, Writing CMakeLists Files
means that shared libraries can link to other shared libraries when they are created in the same
way as an executable. Unlike a static library where the atomic unit is the object file, for shared
libraries, the entire library is the atomic unit. This can cause some unexpected linker errors
when converting from static to shared libraries. If an object file is part of a static library, but
the executable linking to the library does not use any of the symbols in that object file, then
the file is simply excluded from the final linked executable. With shared libraries, all the
object files that make up the library and all of the dependencies that they require come as one
unit. For example, suppose you had a library with an object file defining the function
DisplayOnxWindow() which required the X11 library. If you linked an executable to that
library, but did not call the DisplayOnXWindow () function, the static library version would
not require X11, but the shared library version would require the X11 library. This is because
a shared library has to be taken as one unit, and a static library is only an archive of object
files from which linkers can choose which objects are needed. This means that static linked
executables can be smaller, as they only contain the object code actually used.
Another difference between shared and static libraries is library order. With static libraries the
order on the link line can make a difference. This is because most linkers only use the
symbols that are needed in a single pass over all the given libraries. So, the library order
should go from the library that uses the most other libraries to the library that uses no other
libraries. CMake will preserve and remember the order of libraries and library dependencies
of a project. This means that each library in a project should use the
target_link_libraries command to specify all of the libraries that it directly depends
on. The libraries will be linked with each other for shared builds, but not static builds.
However, the link information is used in static builds when executables are linked. An
executable that only links library libA will get libA plus libB and libC as long as JibA’s
dependency on libB and libC was properly specified using target_link libraries
{44bA 1ibB 1ibC).
At this point, one might wonder why shared libraries would be preferred over static libraries.
There are several reasons. First, shared libraries can decrease the compile/link/run cycle time.
This is because the linker does not have to do as much work when linking to shared libraries
because there are fewer decisions to be made about which object files to keep. Also, often
times, the executable does not even need to be re-linked after the shared fibrary is rebuilt. So,
developers can work on a library compiling and linking only the small part of the program
that js currently being developed, and then re-run the executable after each build of the shared
library. Also, if a library is used by many different executables on a system, then there only
needs to be one copy of the library on disk, and often in memory too.
In addition to the concept of a software library, shared libraries can also be used on many
systems as run time loadable modules. This means that a program can at run time, load and
execute object code that was not part of the original software. This allows developers to create
software that is both open and closed. (For more information see Object Oriented Software
Construction by Bertrand Meyer.) Closed software is software that cannot be modified. It has
been through a testing cycle and can be certified to perform specific tasks with regressionShared Libraries and Loadable Modules 61
tests, However, a seemingly opposite goal is sought after by developers of object oriented
software. This is the concept of Open software that can be extended by future developers.
This can be done via inheritance and polymorphism with object systems. Shared libraries that
can be loaded at run time, allow for these seemingly opposing goals to be achieved in the
same software package. Many common applications support the idea of plugins. The most
common of these applications is the web browser. Internet Explorer uses plugins to support
video over the web and 3D visualization. In addition to plugins, loadable factories can be used
to replace C++ objects at run time, as is done in VTK.
Once it is decided that shared libraries or loadable modules are the right choice for a
particular project, there are a few issues that developers need to be aware of. The first
question that must be answered is which symbols are exported by the shared library? This
may sound like a simple question, but the answer is different from platform to platform. On
many, but not all UNIX systems, the default behavior is to export all the symbols much like a
static library. However, on Windows systems, developers must explicitly tell the linker and
compiler which symbols are to be exported and imported from shared libraries. This is often a
big problem for UNIX developers moving to Windows. There are two ways to tell the
compiler/linker which symbols to export/import on Windows. The most common approach is
to decorate the code with a Microsoft™ C/C++ language extension. An alternative is to create
an extra file called a .def file. This file is a simple ASCII file containing the names of all the
symbols to be exported from a library.
The Microsoft™ extension uses the __declspec directive. Ifa symbol has _declspec (
dllexport ) in front of it, it will be exported, and ifithas _declspec( dllimport ) it
will be imported. Since the same file may be shared during the creation and use of a library, it
must be both exported and imported in the same source file. This can only be done with the
preprocessor. The developer can create a macro called LIBRARY_EXPORT that is defined to
dilexport when building the library and dilimport when using the library. CMake helps
this process by automatically defining ${LIBNAME} EXPORTS when building a DLL
(dynamic link library, a.k.a. a shared library) on Windows.
The following code snippet is from the VTK library vtkCommon, and is inchided by all files
in the vtkCommon library:
#if defined (WIN32)
#if defined (vtkCommon_EXPORTS
#define VIK COMMON EXPORT __declspec( dllexport
else
#define VIK_COMMON_EXPORT __declspec( dllimport
fendif
else
#define VTK_COMMON_EXPORT
#endif82 Writing CMakeLists Files
The example checks for Windows and checks the vtkCommon_EXPORTS macro provided by
CMake. So, on UNIX VTx_COMMON_EXPORT is defined to nothing, and on Windows during
the building of vtkCommon.dll it is defined as _declspec(dllexport), and when the file
is being used by another file, it is defined to __declspec(dllimport).
The second approach requires a def file to specify the symbols to be exported. This file could
be created by hand, but for a large and changing C++ library that could be time consuming
and error prone. CMake’s custom commands can be used to run a pre-link program that will
create a def file from the compiled object files automatically. In the following example, a
Perl script called makedef .p1 is used, the script runs the DUMPBIN program on the .obj files
and extracts all of the exportable symbols and writes a .def file with the correct exports for ali
‘the symbols in the library mylib.
----CMakeLists.txt-----
emake minimum required (VERSION 2.6)
project (myexe)
set (SOURCES mylib.cxx mylib2.cxx)
# create a list of all the object files
string (REGEX REPLACE "\\.cxx" ".obj" OBJECTS "$(SOURCES}")
# create a shared library with the .def file
add_library (mylib SHARED ${SOURCES}
${CMAKE_CURRENT_BINARY_DIR}/mylib.def
)
# set the .def file as generated
set_source files properties (
$(CMAKE_CURRENT_BINARY_DIR}/mylib.def
PROPERTIES GENERATED 1
)
# create an executable
add_executable (myexe myexe.cxx)
# link the executable to the dll
target_link libraries (myexe mylib)
#convert to windows slashes
set (OUTDIR
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
)Shared Libraries and Loadable Modules 63
string (REGEX REPLACE "/" "\\\\" OUTDIR ${OUTDIR})
# create a custom pre link command that runs
# a perl script to create a .def file using dumpbin
add_custom_command (
TARGET mylib PRE_LINK
COMMAND perl
ARGS ${CMAKE_CURRENT_SOURCE_DIR}/makedef.pl
${CMAKE_CURRENT_BINARY DIR}\\mylib.def mylib
S{OUTDIR} ${OBJECTS}
COMMENT "Create .def file"
)
---myexe .cxx----
#include
#include "mylib.h"
int main()
{
std
std
out << myTen() << "\;
out << myEight() << "\n
---mylib.cxx--
int myTen()
{
return 10;
=-mylib2.cxx---
int myEight ()
{
return 8;64 Writing CMakeLists Files
There is a significant difference between Windows and most UNIX systems with respect to
the requirements of symbols. DLLs on Windows are required to be fully resolved, this means
that they must link every symbol at creation. UNIX systems allow shared libraries to get
symbols ftom the executable or other shared libraries at run time. On UNIX systems that
support this feature, CMake will compile with the flags that allow executable symbols to be
used by shared libraries. This small difference can cause large problems, A common, but hard
to track down bug with DLLs happens with C++ template classes and static members. Two
DLLs can end up with separate copies of what is supposed to be a single global static member
of a class. There are also problems with the approach taken on most UNIX systems. The start
up time for large applications with many symbols can be long since much of the linking is
deferred to run time.
Another common pitfall occurs with C++ global objects. These objects require that
constructors must be called before they can be used. The main that links or loads C++ shared
libraries MUST be linked with the C++ compiler, or globals like cout: may not be initialized
before they are used, causing strange crashes at start up time.
Since executables that link to shared libraries must be able to find the libraries at run time,
special environment variables and linker flags musi be used. There are tools that can be used
to show which libraries an executable is actually using. On many UNIX systems there is a
tool called Lad (otool -L on Mac OS X) that shows which libraries are used by an
executable. Qn Windows, a program called depends can be used to find the same type of
information. On many UNIX systems there are also environment variables like
LO_LIBRARY_PATH that tell the program where to find the libraries at run time, Where
supported CMake will add run time library path information into the linked executables, so
that LD_LIBRARY_PATH is not required. This feature can be turned off by setting the cache
entry CMAKE_SKIP_RPATH to false. This may be desirable for installed software that should
not be looking in the build tree for shared libraries. On Windows there is only one PATH
environment variable that is used for both DLLs and finding executables,
4.10 Shared Library Versioning
When an executable is linked to a shared library, it is important that the copy of the shared
library loaded at runtime matches that expected by the executable. On some UNIX systems, a
shared library has an associated "soname” intended to solve this problem. When an executable
links against the library, its soname is copied into the executable. At runtime, the dynamic
linker uses this name from the executable to search for the library,
Consider a hypothetical shared library "foo" providing a few C functions that implement some
functionality. The interface to foo is called an Application Programming Interface (API). It
the implementation of these C functions changes in a new version of foo, but the API remains
the same, then executables linked against foo will still run correctly. When the API changes,Shared Library Versioning 65
old executables will no longer run with a new copy of foo, so a new API version number must
be associated with foo.
This can be implemented by creating the original version of foo with a soname and file name
such as libfoo.so.1. A symbolic link such as libfoo.so -> libfoo.so.1 will allow standard
linkers to work with the library and create executables. The new version of foo can be called
libfoo.so.2 and the symbolic link updated so that new executables use the new library. When
an old executable runs, the dynamic linker will look for libfoo.so.1, find the old copy of the
library, and run correctly. When a new executable runs, the dynamic linker will look for
libfoo.so.2 and correctly load the new version.
This scheme can be expanded to handle the case of changes to foo that do not modify the API.
We introduce a second set of version numbers that is totally independent of the first. This new
set corresponds to the software version providing foo. For example, some larger project may
have introduced the existence of library foo starting in version 3.4. In this case, the file name
for foo might be libfoo.so.3.4, but the soname would still be libfoo.so.1 because the API for
foo is still on its first version. A symbolic link from libfoo.so.1 -> libfoo.so.3.4 will allow
executables linked against the library to run. When a bug is fixed in the software without
changing the API to foo, then the new library file name might be libfoo.so.3.5, and the
symbolic link can be updated to allow existing executables to run.
CMake supports this soname-based version number encoding on platforms supporting soname
natively. A target property for the shared library named "VERSION" specifies the version
number used to create the file name for the library. This version should correspond to that of
the software package providing foo. On Windows the VERSION property is used to set the
binary image number, using major.minor format. Another target property named
"SOVERSION" specifies the version number used to create the soname for the library. This
version should correspond to the API version number for foo. These target properties are
ignored on platforms where CMake does not support this scheme.
The following CMake code configures the version numbers of the shared library foo:
set_target_properties (foo PROPERTIES VERSION 1.2 SOVERSION 4)
This results in the following library and symbolic links:
libfoo.so.1.2
libfoo.so.4 -> libfoo.so.1.2
libfoo.so -> libfoo.so.4
If only one of the two properties is specified, the other defaults to its value automatically. For
example, the code66 Writing CMakeLists Files
set_target_properties (foo PROPERTIES VERSION 1.2)
results in the following shared library and symbolic link:
libfoo.so.1.2
libfoo.se -> libfoo.so.1.2
CMake makes no attempt to enforce sensible version numbers. It is up to the programmer to
utilize this feature in a productive manner.
4.11 Installing Files
Software is typically installed into a directory separate from the source and build trees. This
allows it to be distributed in a clean form and isolates users from the details of the build
process. CMake provides the install command to specify how a project is to be installed.
This command is invoked by a project in the CMakeLists file and tells CMake how ta
generate installation scripts. The scripts are executed at install time to perform the actual
installation of files. For Makefile generators (UNIX, NMake, Borland, MinGW, etc.), the user
simply runs "make install" (or “nmake install”) and the make tool will invoke
CMake's installation madule. With GUI based systems (Visual Studio, Xcode, etc.) the user
simply builds the target called INSTALL,
Each call to the instal1 command defines some installation rules. Within one CMakeLists
file (source directory) these rules will be evaluated in the order in which the corresponding
commands are invoked. The order across multiple directories is not specified.
The install command has several signatures designed for common installation use cases. A
particular invocation of the command specifies the signature as the first argument. The
signatures are TARGETS, FILES, PROGRAMS, DIRECTORY, SCRIP, and CODE.
install (TARGETS ...)
Install the binary files corresponding to targets built inside the project.
install (FILES .,.)
General-purpose file installation. It is typically used for installation of header files,
documentation, and data files required by your sofware.
install (PROGRAMS ...)
Installs executable files not built by the project, such as shell scripts. It is identical to
install (FILES) except that the default permissions of the installed file include
the executable bit.Installing Files &7
install (DIRECTORY ...)
Install an entire directory tree. This may be used for installing directories with
resources such as icons and images.
install (SCRIPT ...)
Specify a user-provided CMake script file to be executed during installation.
Typically this is used to define pre-install or post-install actions for other rules.
install (CODE ...)
Specify user-provided CMake code to be executed during the installation. This is
similar to install (SCRIPT) but the code is provided inline in the call as a string.
The TARGETS, FILES, PROGRAMS, DIRECTORY signatures are all meant to create install rules
for files. The targets, files, or directories to be installed are listed immediately after the
signature name argument. Additional details can be specified using keyword arguments
followed by corresponding values. Keyword arguments provided by most of the signatures are
as follows.
DESTINATION
Specifies the location in which the installation rule will place files. This argument
must be followed by a directory path indicating the location. If the directory is
specified as a full path it will be evaluated at install time as an absolute path. If the
directory is specified as a relative path it will be evaluated at install time relative to
the installation prefix. The prefix may be set by the user through the cache variable
CMAKE_INSTALL_PREFIX. A platform-specific default is provided by CMake:
“/usr/locai” on UNIX and “/Program Files/”
on Windows, where SystemDrive is something like “C:” and ProjectName is the
name given to the top-most PROJECT command.
PERMISSIONS
Specifies file permissions to be set on the installed files. This option is needed only
to override the default permissions selected by a particular INSTALL command
signature. Valid permissions are OWNER_READ, OWNER_WRITE, OWNER_EXECUTE,
GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, WORLD_READ, WORLD_WRITE,
WORLD_EXECUTE, SETUID, and SETGID. Some platforms do not support all of these
permissions, on such platforms those permission names are ignored.
CONFIGURATIONS
Specifies a list of build configurations for which an installation rule applies (Debug,
Release, etc.). For Makefile generators the build configuration is specified by the
CMAKE_BUILD_TYPE cache variable. For Visual Studio and Xcode generators the
configuration is selected when the INSTALL target is built. An installation rule will68 Writing CMakeLists Files
be evaluated only if the current install configuration matches an entry in the list
provided to this argument. Configuration name comparison is case-insensitive.
COMPONENT
Specifies the installation component for which the installation rule applies. Some
projects divide their installations into multiple components for separate packaging.
For example, a project may define a “Runt ime” component that contains the files
needed to run a tool, a “Development” component containing the files needed to
build extensions to the tool, and a “Documentation” component containing the
manual pages and other help files. The project may then package each component
separately for distribution by installing only one component at a time. By default all
components are installed. Component-specific installation is an advanced feature
intended for use by package maintainers. It requires manual invocation of the
installation scripts with an argument defining the COMPONENT variable to name the
desired component. Note that component names are not defined by CMake. Each
project may define its own set of components.
OPTIONAL
Specifies that it is not an error if the input file to be installed does nat exist. If the
input file exists it will be installed as requested. If it does not exist it will be silently
not installed.
Projects typically install some of the library and executable files created during their build
process. The install command provides the TARGETS signature for this purpose:
install (TARGETS targets...
[ [ARCHIVE | LIBRARY | RUNTIME | FRAMEWORK | BUNDLE |
PRIVATE_HEADER| PUBLIC_HEADER | RESOURCE ]
(DESTINATION ]
{PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT ]
(OPTIONAL]
[EXPORT ]
{NAMELINK ONLY |NAMELINK SKIP]
J [..-])
The TARGETS keyword is immediately followed by a list of the targets created using
add_executable or add_library to be installed. One or more files corresponding to each
target will be installed.
Files installed with this signature may be divided into three categories: ARCHIVE, LIBRARY,
and RUNTIME. These categories are designed to group target files by typical installationInstalling Files 69
destination. The corresponding keyword arguments are optional, but if present specify that
other arguments following them apply only to target files of that type. Target files are
categorized as follows:
executables - RUNTIME
Created by add_executable (.exe on Windows, no extension on UNIX)
Joadabie modules - LIBRARY
Created by add_library with the MODULE option (.dIl on Windows, .so on UNIX)
shared libraries - LIBRARY
Created by add_library with the SHARED option on UNIX-like platforms (.so on
most UNIX, .dylib on Mac)
dynamic-link libraries - RUNTIME
Created by add_library with the SHARED option on Windows platforms (-dll)
import libraries - ARCHIVE
Linkable file created by a dynamic-link library that exports symbols (lib on most
Windows, .dll.a on Cygwin and MinGW).
static libraries - ARCHIVE
Created by add_library with the STATIC option (.lib on Windows, .a on UNIX,
Cygwin, and MinGW)
Consider a project that defines an executable myExecutable that links to a shared library
mySharedLib. It also provides a static library myStaticLib and a plugin module to the
executable called myPlugin that also links to the shared library. The executable, static
library, and plugin file may be installed individually using the commands
install (TARGETS myExecutable DESTINATION bin)
install (TARGETS myStaticLib DESTINATION lib/myproject)
install (TARGETS myPlugin DESTINATION lib)
The executable wil] not be able to run from the installed location until the shared library to
which it links is also installed. Installation of the library requires a bit more care in order to
support all platforms. It must be installed to a location searched by the dynamic linker on each
platform. On UNIX-like platforms the library is typically installed to 1ib,while on Windows
it should be placed next to the executable in bin. An additional challenge is that the import
library associated with the shared library on Windows should be treated like the static library
and installed to 1ib/myproject. In other words we have three different kinds of files
created with a single target name that must be installed to three different destinations!70 Writing CMakeLists Files
Fortunately this problem can be solved using the category keyword arguments. The shared
library may be installed using the command
install (TARGETS mySharedLib
RUNTIME DESTINATION bin
LIBRARY DESTINATION 1ib
ARCHIVE DESTINATION lib/myproject)
This tells CMake that the RUNTIME file (dll) should be installed to bin, the LIBRARY file
(so) should be installed to lib, and the ARCHIVE (lib) file should be installed to
lib/myproject. On UNIX the LIBRARY file will be installed and on Windows the RUNTIME
and ARCHIVE files will be installed.
If the above sample project is to be packaged into separate runtime and development
components we must assign the appropriate component to each target file installed. The
exeentable, shared library, and plugin are required in order to run the application, so they
belong in a Runtime component. Meanwhile the import library (corresponding to the shared
library on Windows) and the static library are only required to develop extensions to the
application, and therefore belong in a Development component.
Component assignments may be specified by adding the COMPONENT argument to each of the
commands above. We may also combine all of the installation rules into a single command
invocation. This single command is equivalent to all of the above commands with
components added. The files generated by each target are installed using the rule for their
category.
install (TARGETS myExecutable mySharedLip myStaticLib myPlugin
RUNTIME DESTINATION bin COMPONENT Runtime
LIBRARY DESTINATION lib COMPONENT Runtime
ARCHIVE DESTINATION lib/myproject COMPONENT Development)
Either NAMELINK_ONLY or NAMELINK_SKIP may be specified as a LIBRARY option. On some
platforms a vessioned shared library has a symbolic link such as
lib.so -> lib.so.1
where lib.so.1 is the soname of the library and lib,so is a "namelink"
that helps linkers to find the library when given -1. The NAMELINK_ONLY option
causes installation of only the namelink when a library target is installed. The
NAMELINK_SKIP option causes installation of library files other than the namelink when a
library target is installed. When neither option is given both portions are installed. OnInstalling Files 71
platforms where versioned shared libraries do not have namelinks, or when a library is not
versioned, the NAMELINK_SKIP option installs the library and the NAMELINK_ONLY option
installs nothing. See the VERSION and SOVERSION target properties for details on creating
versioned shared libraries.
Projects may install files other than those that are created with add_executable or
add_library, such as header files or documentation, General-purpose installation of files is
specified using the FILES signature:
install (FILES files... DESTINATION
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT ]
(RENAME ] [OPTIONAL])
The FILES keyword is immediately followed by a list of files to be installed. Relative paths
are evaluated with respect to the current source directory. Files will be installed to the given
DESTINATION directory. For example, the command
install (FILES my-api.h ${CMAKE_CURRENT_BINARY_DIR}/my-config.h
DESTINATION include}
Installs the file my-api.h from the source tree and the file my-config.h from the build tree
into the include directory under the instailation prefix. By default installed files are given
permissions OWNER_WRITE, OWNER_READ, GROUP_READ, and WORLD_READ, but this may be
overridden by specifying the PERMISSIONS option. Consider the case in which we want to
instal] a global configuration file on a UNIX system that is readable only by its owner (such
as root), We may accomplish this with the command
install (FILES my-rc DESTINATION /etc
PERMISSIONS OWNER_WRITE OWNER_READ)
which installs the file my-rc with owner read/write permission into the absolute path /etc.
The RENAME argument specifies a name for an installed file that may be different from the
original file. Renaming is allowed only when a single file is installed by the command. For
example, the command
install(FILES version.h DESTINATION include RENAME my-version.h)72 Writing CMakeLists Files
will install the file version.h from the source directory to include/my-version.h under
the installation prefix.
Projects may also install helper programs such as shell scripts or python scripts that are not
actually compiled as targets. These may be installed with the FILES signature using the
PERMISSIONS option to add execute permission. However this case is common enough to
justify a simpler interface. CMake provides the PROGRAMS signature for this purpose:
install (PROGRAMS files... DESTINATION
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT ]
[RENAME ] [OPTIONAL])
The PROGRAMS keyword is immediately followed by a list of scripts to be installed. This
command is identical to the FILES signature except that the default permissions additionally
include OWNER_EXECUTE, GROUP_EXECUTE, and WORLD_EXECUTE. For example, we may
install a python utility script with the command
install (PROGRAMS my-util.py DESTINATION bin)
which installs my-util.py to the bin directory under the installation prefix and gives it
owner, group, and world read and execute permission plus owner write.
Projects may also provide a whole directory full of resource files such as icons or html
documentation. An entire directory may be installed using the DIRECTORY signature:
install (DIRECTORY dirs... DESTINATION
[FILE_PERMISSIONS permissions...]
[DIRECTORY _PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT ]
[[PATTERN | REGEX ]
[EXCLUDE] [PERMISSIONS permissions...]] [...1)
The DIRECTORY keyword is immediately followed by a list of directories to be installed.
Relative paths are evaluated with respect to the current source directory. Each named
directory is installed to the destination directory. The last component of each input directoryInstalling Files 73
name is appended to the destination directory as that directory is copied. For example, the
command
install (DIRECTORY data/icons DESTINATION share/myproject)
will install the data/icons directory from the source tree into share/myproject/icons
under the installation prefix. A trailing slash will leave the last component empty and install
the contents of the input directory to the destination. The command
install (DIRECTORY doc/html/ DESTINATION doc/myproject)
installs the contents of doc/htm1 from the source directory into doc/myproject under the
installation prefix. If no input directory names are given, as in
install (DIRECTORY DESTINATION share/myproject/user)
the destination directory will be created but nothing will be installed into it.
Files installed by the DIRECTORY signature are given the same default permissions as the
FILES signature. Directories installed by the DIRECTORY signature are given the same default
permissions as the PROGRAMS signature. The FILE_PERMISSIONS and
DIRECTORY_PERMISSIONS options may be used to override these defaults. Consider the case
in which a directory full of example shell scripts is to be installed into a directory that is both
owner and group writable. We may use the command
install (DIRECTORY data/scripts DESTINATION share/myproject
FILE_PERMISSIONS
OWNER_READ OWNER_EXECUTE OWNER_WRITE
GROUP_READ GROUP_EXECUTE
WORLD _READ WORLD_EXECUTE
DIRECTORY_PERMISSIONS
OWNER READ OWNER_EXECUTE OWNER_WRITE
GROUP_READ GROUP_EXECUTE GROUP_WRITE
WORLD_READ WORLD_EXECUTE)
which installs the directory data/scripts into share/myproject/scripts and sets the
desired permissions. In some cases a fully prepared input directory created by the project may
have the desired permissions already set. The USE_SOURCE_PERMISSIONS option tells
CMake to use the file and directory permissions from the input directory during installation. If74 Writing CMakeLists Files
in the previous example the input directory were to have already been prepared with correct
permissions the following command may have been used instead.
install (DIRECTORY data/scripts DESTINATION share/myproject
USE_SOURCE_PERMISS IONS)
If the input directory to be installed is under source management, such as CVS, there may be
extra subdirectories in the input that we do not wish to install. There may also be specific files
which should not be installed, or be installed with different permissions, while most files get
the defaults. The PATTERN and REGEX options may be used for this purpose. A PATTERN
option is followed first by a globbing pattern and then by an EXCLUDE or PERMISSIONS
option. A REGEX option is followed first by a regular expression and then by EXCLUDE or
PERMISSIONS. The EXCLUDE option skips installation of those files or directories matching
the preceding pattern or expression, while the PERMISSIONS option assigns specific
permissions to them.
Each input file and directory is tested against the pattern or regular expression as a full path
with forward slashes. A pattern will match only complete file or directory names occurring at
the end of the full path while a regular expression may match any portion. For example, the
pattern “foo*” will match “.../foo.txt” but not “,../myfoo.txt” or “.../foo/bar.txt”
but the regular expression “£00” will match all of them.
Returning to the above example of installing an icons directory, consider the case in which the
input directory is managed by CVS and also contains some extra text files that we do not want
to install. The command
install (DIRECTORY data/icons DESTINATION share/myproject
PATTERN “CVS” EXCLUDE
PATTERN “*.txt” EXCLUDE)
installs the icons directory while ignoring any CVS directory or text file contained. The
equivalent command using the REGEX option is
install (DIRECTORY data/icons DESTINATION share/myproject
REGEX “/CVS$” EXCLUDE
REGEX “/(*/]*.txt$” EXCLUDE)
which uses ‘/’ and ‘$” to constrain the match in the same way as the patterns. Consider a
similar case in which the input directory contains shell scripts and text files that we wish to
install with different permissions than the other files. The commandInstalling Files 75
install (DIRECTORY data/other/ DESTINATION share/myproject
PATTERN “CVS” EXCLUDE
PATTERN “*.txt”
PERMISSIONS OWNER_READ OWNER_WRITE
PATTERN “*.sh”
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
will install the contents of data/other from the source directory to share/myproject.
while ignoring CVS directories and giving specific permissions to . txt and . sh files.
Project installations may need to perform tasks other than just placing files in the installation
tree. Third-party packages may provide their own mechanisms to register new plugins which
must be invoked during project installation. The SCRIPT signature is provided for this
purpose:
install (SCRIPT )
The ScR1Pr keyword is immediately followed by the name of a CMake script. CMake will
execute the script during installation. If the file name given is a relative path it will be
evaluated with respect to the current source directory. A simple use case is printing a message
during installation. We first write a message .cmake file containing the code
message (“Installing My Project”)
and then reference this script using the command
install (SCRIPT message.cmake)
Custom installation scripts are not executed during the main CMakeLists file processing.
‘They are executed during the installation process itself. Variables and macros defined in the
code containing the install (SCRIPT) call will not be accessible from the script. However
there are a few variables defined during the script execution which may be used to get
information about the installation. The variable CMAKE_INSTALL_PREFTX is set to the actual
installation prefix. This may be different from the corresponding cache variable value because
the installation scripts may be executed by a packaging tool that uses a different prefix. An
environment variable ENV{DESTDIR} may be set by the user or packaging tool. Its value is
prepended to the installation prefix and to absolute installation paths to determine the location
to which files are installed. In order to reference an instal! location on disk the custom script
may use SENV{DESTDIR}${CMAKE_INSTALL_PREFIX} as the top portion of the path. The
variable CMAKE_INSTALL_CONFIG_NAME is set to the name of the build configuration76 Writing CMakeLists Files
currently being installed (Debug, Release, etc.). During component-specific installation the
variable CMAKE_INSTALL_COMPONENT is set to the name of the current component.
Custom installation scripts, as simple as the message above, may be more easily created with
the script code placed inline in the call to the INSTALL command. The CODE signature is
provided for this purpose:
install (CODE “”)
The CoDE keyword is immediately followed by a string containing the code to place in the
installation script. An install-time message may be created using the command
install (CODE “MESSAGE (\"Installing My Project\”)”)
which has the same effect as the message. cmake script but contains the code inline.
Installing Prerequisite Shared Libraries
Executables are frequently built using shared libraries as building blocks. When you install
such an executable, you must also install its prerequisite shared libraries, called
“prerequisites” because the executable requires their presence in order to load and run
properly. The three main sources for shared libraries are the operating system itself, the build
products of your own project and third party libraries belonging to an external project. The
ones from the operating system may be relied upon to be present without installing anything:
they are on the base platform on which your executable runs. The build products in your own
project presumably have add_library build rules in the CMakeLists files, and so it should be
straightforward to create CMake install rules for them. It is the third party libraries that
frequently become a high maintenance item when there are more than a handful of them or
when the set of them fluctuates from version to version of the third party project. Libraries
may be added, code may be reorganized, and the third party shared libraries themselves may
actually have additional prerequisites that are not obvious at first glance.
CMake provides two modules to make it easier to deal with required shared libraries. The first
module, GetPrerequisites.cmake, provides the get_precequisites function to analyze and
classify the prerequisite shared libraries upon which an executable depends. Given an
executable file as input, it will produce a list of the shared libraries required to run that
executable, including any prerequisites of the discovered shared libraries themselves. It uses
native tools on the various underlying platforms to perform this analysis: dumpbin
(Windows), otool (Mac) and Idd (Linux). The second module, BundleUtilities.cmake,
provides the fixup_bundle function to copy and fixup prerequisite shared libraries using
well-defined locations relative to the executable. For Mac bundle applications, it embeds the
libraries inside the bundle, fixing them up with install name _tool to make a self-Installing Files 77
contained unit. On Windows, it copies the libraries into the same directory with the
executable since executables will search in their own directories for their required DLLs.
The fixup_bundle function helps you create relocatable install trees. Mac users appreciate
self-contained bundle applications: you can drag them anywhere, double click them and they
still work. They do not rely on anything being installed in a certain location other than the
operating system itself. Similarly Windows users without administrative privileges appreciate
a relocatable install tree where an executable and all of its required DLLs are installed in the
same directory and it works no matter where you install it. You can even move things around
after installing them and is will still work.
To use fixup_bundle, first install one of your executable targets. Then, configure a CMake
script that can be called at install time. Inside the configured CMake script, simply include
BundleUtilities and call the £ixup_bundle function with appropriate arguments.
In CMakcLists.txt:
install (TARGETS myExecutable DESTINATION bin)
# To install, for example, MSVC runtime libraries:
include (InstallRequiredSystemLibraries)
# To install other/non-system 3rd party required libraries:
configure file (
${CMAKE_CURRENT_SOURCE_DIR}/FixBundle.cmake.in
${CMAKE_CURRENT BINARY _DIR}/FixBundle.cmake
@ONLY
)
install (SCRIPT ${CMAKE CURRENT _BINARY_DIR}/FixBundle.cmake)
In FixBundle.cmake.i
include (BundleUtilities)
# Set bundle to the full path name of the executable already
# existing in the install tree:
set (bundle
“${CMAKE_INSTALL_PREFIX}/myExecutable@CMAKE EXECUTABLE _SUFFIX@”)
# Set other_libs to a list of full path names to additional
# libraries that cannot be reached by dependency analysis.
# (Dynamically loaded Plugins, for example.)78 Writing CMakeLists Files
set (other_libs ‘*”)
# Set dirs to a list of directories where prerequisite libraries
# may be found:
set (dirs “@LIBRARY_OUTPUT_PATH@”)
fixup_bundle (“${bundle}” “${other_libs}” “S{dirs}”)
You are responsible for verifying that you have permission to copy and distribute the
prerequisite shared libraries for your executable. Some libraries may have restrictive software
licenses that prohibit making copies a la £ixup_bundle.
Exporting and Importing Targets
Make 2.6 introduced support for exporting targets from one CMake-based project and
importing them into another. The main feature allowing this functionality is the notion of an
IMPORTED target. Here we present imported targets and then show how CMake files may be
generated by a project to export its targets for use by other projects.
Importing Targets
Imported targets are used to convert files outside of the project on disk into logical targets
inside a CMake project. They are created using the IMPORTED option to the
add_executable and add_library commands. No build files are generated for imported
targets. They are used simply for convenient, flexible reference to outside executables and
libraries. Consider the following example which creates and uses an IMPORTED executable
target:
add_executable (generator IMPORTED) #1
set_property (TARGET generator PROPERTY
IMPORTED_LOCATION "/path/to/some_generator") # 2
add_custom_command (OUTPUT generated.c
COMMAND generator generated.c) #3
add_executable (myexe srcl.c src2.c generated.c)
Line #1 creates a new CMake target called generator. Line #2 tells CMake the location of
the target on disk to import. Line #3 references the target in a custom command. Once CMake
is run the generated build system will contain a command line such as
/path/to/some_generator /project/binary/dix/generated.cInstalling Files 79
in the rule to generate the source file. In a similar manner libraries from other projects may be
used through IMPORTED targets:
add_library (foo IMPORTED)
set_property (TARGET foo PROPERTY
IMPORTED_LOCATION "/path/to/libfoo.a")
add_executable (myexe srcl.c src2.c)
target_link_libraries (myexe foo)
On Windows a .dil and its lib import library may be imported together:
add_library (bar IMPORTED)
set_property (TARGET bar PROPERTY
IMPORTED_LOCATION "c:/path/to/bar.dll")
set property (TARGET bar PROPERTY
IMPORTED IMPLIB "c:/path/to/bar.1ib")
add_executable (myexe srcl.c src2.c)
target_link libraries (myexe bar)
A library with multiple configurations may be imported with a single target:
add_library (f00 IMPORTED)
set_property (TARGET foo PROPERTY
IMPORTED _LOCATION_RELEASE "c:/path/to/foo.1ib")
set_property (TARGET foo PROPERTY
IMPORTED_LOCATION DEBUG "c:/path/to/foo_d.1ib")
add_executable (myexe srcl.c src2.c)
target_link libraries (myexe foo)
The generated build system will link myexe to f00.1ib when it is built in the release
configuration and ¢£00_d.1ib when built in the debug configuration.
Exporting Targets
Imported targets on their own are useful, but they still require the project that imports them to
know the locations of the target files on disk. The real power of imported targets is when the
project providing the target files also provides a file to help import them.
The install(TARGETS) and install (EXPORT) commands work together to install both a
target and a CMake file to help import it. For example, the code
add_executable (generator generator.c)80. Writing CMakeLists Files
install (TARGETS generator DESTINATION lib/myproj/generators
EXPORT myproj-targets)
install (EXPORT myproj-targets DESTINATION 1ib/myproj)
will install the two files
/lib/myproj/generators/generator
/lib/myproj/myproj-targets.cmake
The first is the regular executable named generator. The second file, myproj-
targets.cmake, is a CMake file designed to make it easy to import generator. This file
contains code such as
get_filename_ component (_self "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component (PREFIX "${_self}/../.." ABSOLUTE)
add_executable (generator IMPORTED)
set property (TARGET generator PROPERTY
IMPORTED _LOCATION "${PREFIX}/1ib/myproj/generators/generator™)
(note that $ {PREFIX} is computed relative to the file location). An outside project may now
use generator as follows:
include (${PREFIX}/1ib/myproj/myproj-targets.cmake) # 1
add_custom_command (OUTPUT generated.c
COMMAND generator generated.c) # 2
add_executable (myexe srcl.c src2.c generated.c)
Line #1 loads the target import script (see section 5.7 to make this automatic). The script may
import any number of targets. Their locations are computed relative to the script location so
the install tree may be easily moved. Line #2 references the generator executable in a custom
command. The resulting build system will run the executable from its installed location.
Libraries may also be exported and imported:
add_library (foo STATIC fool.c)
install (TARGETS foo DESTINATION lib EXPORTS myproj-targets)
install (EXPORT myproj-targets DESTINATION lib/mypro})
This installs the library and an import file referencing it, Outside projects may simply writeInstalling Files 81
include (${PREFIX} /1ib/myproj/myproj-targets .cmake)
add_executable (myexe srcl.c)
target_link libraries (myexe foo)
and the executable will be linked to the library £00 exported and installed by the original
project.
Any number of target installations may be associated with the same export name. The export
names are considered global so any directory may contribute a target installation. Only one
call tothe install (EXPORT) command is needed to install an import file that references all
targets. Both of the examples above may be combined into a single export file, even if they
are in different subdirectories of the project as shown in the code below.
# A/CMakeLists.txt
add_executable (generator yenerator.c)
install (TARGETS generator DESTINATION lib/myproj/generators
EXPORT myproj-targets)
# B/CMakeLists.txt
add_library (foo STATIC fool.c)
install (TARGETS foo DESTINATION lib EXPORTS myproj~targets)
# Top CMakeLists.txt
add_subdirectory (A)
add subdirectory (B)
install (EXPORT myproj-targets DESTINATION lib/myproj)
Typically projects are built and installed before being used by an outside project. However in
some cases it is desirable to export targets directly from a build tree. The targets may then be
used by an outside project that references the build tree with no installation involved. The
export command is used to generate a file exporting targets from a project build tree. For
example, the code
add_executable (generator generator.c)
export (TARGETS generator FILE myproj-exports.cmake)
will create a file in the project build tree called myproj-exports ,.cmake that contains the
tequired code to import the target. This file may be loaded by an outside project that is aware
of the project build tree in order to use the executable to generate a source file. An example
application of this feature is for building a generator executable on a host platform when cross
compiling. The project containing the generator executable may be built on the host platform
and then the project that is being cross-compiled for another platform may load it,82 Writing CMakeLists Files
4.12 Advanced Commands
There are a few commands that can be very useful but are not typically used in writing
CMakeLists files. This section will discuss a few of these commands and when they are
useful. First consider the add_dependencies command which creates a dependency
between two targets. CMake automatically creates dependencies between targets when it can
determine them. For example, CMake will automatically create a dependency for an
executable target that depends on a library target. The add_dependencies command is
typically used to specify inter target dependencies between targets where at least one of the
targets is a custom target (see section 6.4 for more information on custom targets).
The include_regular_expression command also relates to dependencies. This
command controls the regular expression that is used for tracing source code dependencies.
By default CMake will trace all the dependencies for a source file including system include
files such as stdio.h. If you specify a regular expression with the
include_regular_expression command that regular expression will be used to limit
what include files are processed. For example; if your software project’s include files all
started with the prefix foo (e.g. fooMain.c fooStruct.h ete) then you could specify a
regular expression of *£00.*$ to limit the dependency checking to just the files of your
project.
Occasionally you might want to get a listing of all the source files that another source file
depends on. This is useful when you have a program that uses pieces of a large library but you
are not sure what pieces it is using. The output_required_files command will take a
source file and produce a list of all the other source files it depends on, You could then use
this list to produce a reduced version of the library that only contains the necessary files for
your program.
Some tools such as Rational Purify on the Sun platform are run by inserting an extra
command before the final link step. So, instead of
CC f00.0 -o foo
The link step would be
purify CC foo.0 -o foo
It is possible to do this with CMake. To run an extra program in front of the link line change
the rule variables CMAKE_CXX_LINK_EXECUTABLE, and CMAKE_C_LINK_EXECUTABLE. Rule
variables are described in chapter 11. The values for these variables are contained in the file
Modules/CMakeDefaultMakeRuleVariables.cmake, and they are sometimes redefinedAdvanced Commands 83
in Modules/Platform/*.cmake. Make sure it is set after the PROJECT command in the
CMakeLists file. Here is a small example of using purify to link a program called foo:
project (£00)
set (CMAKE_CXX_LINK_EXECUTABLE
“purify ${CMAKE_CXX_LINK EXECUTABLE}")
add_executable (£00 f00.cxx)
Of course, for a generic CMakeLists file you should have some if checks for the correct
platform. This will only work for the Makefile generators because the rule variables are not
used by the IDE generators, Another option would be to use $(PURIFY) instead of plain
purify. This would pass through CMake into the Makefile and be a make variable. The
variable could be defined on the command line like this: make PURIFY=purify. If not
specified then it would just use the regular rule for linking a C++ executable as PURIFY
would be expanded by make to nothing.Chapter 5
System Inspection
This chapter will describe how you can use CMake to inspect the environment of the system
on which the software is being built. This is a critical factor in creating cross-platform
applications or libraries. It covers how to find and use system and user installed header files
and libraries. It also covers some of the more advanced features of CMake including the
try_compile and try_run commands. These commands are extremely powerful tools for
determining the capabilities of the system and compiler that is hosting your software. This
chapter also describes how to generate configured files and how to cross compile with
CMake. Finally, the steps required to enable a project for the £ind_package command are
covered, explaining how to create a Config.cmake file and other required files.
5.1 Using Header Files and Libraries
Many C and C++ programs depend on external libraries. However, when it comes to the
practical aspects of compiling and linking a project, taking advantage of existing libraries can
be difficult for both developers and users. Problems usually show up as soon as the software
is built on a system other than that on which it was developed. Assumptions regarding where
libraries and header files are located become obvious when they are not installed in the same
place on the new computer and the build system is unable to find them. CMake has many
features to aid developers in the integration of external software libraries into a project.
The CMake commands that are most relevant to this type of integration are the find_file,
find_library, find_path, find_program, and find_package commands. For most C
and C++ libraries, a combination of find library and find_path will be enough to
compile and fink with an installed library, find_library can be used to locate, or allow a86 System Inspection
user to locate a library, and find_path can be used to find the path to a representative
include file from the project. For example, if you wanted to link to the tiff library, you could
use the following commands in your CMakeLists.txt file:
# find libtiff, looking in some standard places
find_library (TIFF_LIBRARY
NAMES tiff tiff2
PATHS /usr/local/lib /usr/lib
)
# find tiff.h looking in some standard places
find_path (TIFF_INCLUDES tiff.h
/ust/local/include
/usr/include
)
include_directories (${TIFF_INCLUDES})
add_executable (mytiff mytiff.c )
target_link libraries (myprogram ${TIFF_LIBRARY})
The first command used is find_library which in this case will look for a library with the
name tiff or tiff2. The find_library command only requires the library’s base name
without any platform specific prefixes or suffixes, such as lib and .dll. The appropriate
prefixes and suffixes for the system running CMake will be added to the library name
automatically when CMake attempts to find it. All the FIND_* commands will look in the
PATH environment variable. In addition, the commands allow the specification of additional
search paths as arguments listed after the PATHS marker argument. As well as supporting
standard paths, windows registry entries and environment variables can be used to construct
search paths. The syntax for registry entries is the following:
(HKEY_CURRENT_USER\\Software\\Kitware\\Path;Build1]
Because software can be installed in many different places, it is impossible for CMake to find
the library every time, but most standard installations should be covered. The find_*
commands automatically create a cache variable so that users can override or specify the
location from the CMake GUI. This way if CMake is unable to locate the files it is looking for
users will still have an opportunity to specify them. If CMake does not find a file, the value is
set to VAR-NOTFOUND. This value tells CMake that it should continue looking each time
CMake’s configure step is run. Note that in if statements, values of VAR-NOTFOUND will
evaluate as false.System Properties 87,
The next command used is find_pata. This is a general purpose command that, in this
example, is used to locate a header file from the library. Header files and libraries are often
installed in different locations, and both locations are required to compile and fink programs
that use them. find_path is similar to f£ind_library, although it only supports one name.
It supports a list of search paths.
The next part of the CMakeLists file uses the variables created by the find_* commands.
The variables can be used without checking for valid values as CMake will print an error
message notifying the user if any of the required variables have not been set. The user can
then set the cache values and reconfigure until the message goes away. Optionally, a
CMakeLists file could use the if command to use alternative libraries or options to build the
project without the library if it cannot be found.
From the above example you should be able to see how using the £ind_* commands can help
your software to compile on a wide variety of systems. It is worth noting that the find_*
commands search for a match starting with the first argument and first path. So when listing
paths and library names you should list your preferred paths and names first. If there are
multiple versions of a library, and you would prefer tiff over tiff2, make sure you list them in
that order.
5.2 System Properties
Although it is a common practice in C and C++ code to add platform-specific code inside
preprocessor ifdef directives, for maximum portability this should be avoided. Software
should not be tuned to specific platforms with ifdefs, but rather to a canonical system
consisting of a set of features. Coding to specific systems makes the software less portable,
because systems and the features they support change with time, and even from system to
system. A feature that may not have worked on a platform in the past may be a required
feature for the platform in the future. The following code fragments illustrate the difference
between coding to a canonical system and a specific system:
// coding to a feature
#ifdef HAS _FOOBAR_CALL
foobar ();
felse
my foobar () ;
#endif
// coding to specific platforms
#if defined(SUN) && defined(HPUX) && !defined(GNUC)
foobar ();
#else
myfoobar ();88 System Inspection
#endif
The problem with the second approach is that the code will have to be modified for each new
platform on which the software is compiled. For example, a future version of SUN may no
longer have the foobar call. Using the HAS_FOOBAR_CALL approach, the software will work
as Jong as HAS_FOOBAR_CALL is defined correctly, and this is where CMake can help. CMake
can be used to define HAS_FOOBAR_CALL correctly and automatically by making use of the
try_compile and try run commands, These commands can be used to compile and run
small test programs during the CMake configure step. The test programs will be sent to the
compiler that will be used to build the project, and if errors occur the feature can be disabled.
These commands require that you write a small C or C++ program to test the feature. For
example, to test if the foobar call is provided on the system, try compiling a simple program
that uses foobar. First write the simple test program (testNeedFoobar.c in this example) and
then add the CMake calls to the CMakeLists file to try compiling that code. If the compilation
works then HAS_FOOBAR_CALL will be set to true.
--- testNeedFoobar.c -----
#include
main ()
{
foobar ();
--- testNeedFoobar,.cmake --~-
try_compile (HAS FOOBAR_CALL
${CMAKE_BINARY_DIR}
${PROJECT_SOURCE_DIR}/testNeedFoobar.c
)
Now that HAS_FOOBAR_CALL is set correctly in CMake you can use it in your source code
through either the add_definitions command or by configuring a header file. We
recommend configuring a header file as that file can be used by other projects that depend on
your library. This is discussed further in section 5.6.
Sometimes, just compiling a test program is not enough. In some cases, you may actually
want to compile and run a program to get its output. A good example of this is testing the byte
order of a machine. The following example shows how you can write a small program that
CMake will compile and then run to determine the byte order of a machine.System Properties 89
---- TestByteOrder.c ------
int main () {
/* Are we most significant byte first or last */
union
{
long 1;
char c{sizeof (long) ];
dou
ul =1;
exit (u.c[sizeof (long) - 1]
----- TestByteOrder .cmake-
try_run (RUN_RESULT_VAR
COMPILE_RESULT_VAR
${CMAKE_BINARY_DIR}
${PROJECT_SOURCE_DIR}/Modules/TestByteOrder.c
OUTPUT_VARIABLE OUTPUT
}
The return result of the run will go into RUN_RESULT_VAR and the result of the compile will
go into COMPILE _RESULT_VAR, and any output from the run will go into ovTpuT. You can
use these variables to report debug information to the users of your project.
For small test programs the FILE command with the WRITE option can be used to create the
source file from the CMakeLists file. The following example tests the C compiler to verify
that it can be run.
file (WRITE
${CMAKE_BINARY_ DIR}/CMakeTmp/testCCompiler.c
"int main() {return 0;}"
)
try_compile (CMAKE_C_COMPILER_WORKS
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}/CMakeTmp/testCCompiler.c
OUTPUT_VARIABLE OUTPUT
)90 System Inspection
There are several predefined try-run and try-compile macros in the CMake/Modules
directory, some of which are listed below. These macros allow some common checks to be
performed without having to create a source file for each test. For detailed documentation or
to see how these macros work look at the implementation files for them in the
CMake/Modules directory of your CMake installation. Many of these macros will look at the
current value of the CMAKE_REQUIRED_FLAGS and CMAKE_REQUIRED_LIBRARIES variables
to add additional compile flags or link libraries to the test.
CheckFunctionExists.cmake
Checks to see if a C function is on a system. This macro takes two arguments, the
first is the name of the function to check for. The second is the variable to store the
result into. This macro does use CMAKE_REQUIRED_FLAGS and
CMAKE_REQUIRED_LIBRARIES if they are set.
CheckIncludeFile.cmake:
Checks for an include file on a system. This macro takes two arguments. The first is
the include file to look for and the second is the variable to store the result into.
Additional CFlags can be passed in as a third argument or by setting
CMAKE_REQUIRED_FLAGS.
CheckIncludeFileCXX.cmake
Check for an include file in a C++ program. This macro takes two arguments. The
first is the include file to look for and the second is the variable to store the result
into. Additional CFlags can be passed in as a third argument.
CheckIncludeFiles.cmake
Check for a group of include files. This macro takes two arguments. The first is the
include files to look for and the second is the variable to store the result into. This
macro does use CMAKE_REQUIRED_FLAGS if it is set. This macro is useful when a
header file you are interested in checking for is dependent on including another
header file first.
CheckLibraryExists.cmake
Check to see ifa library exists. This macro takes four arguments; the first is the name
of the library to check for. The second is the name of a function that should be in that
library. The third argument is the location of where the library should be found. The
fourth argument is a variable to store the result into. This macro uses
CMAKE_REQUIRED_FLAGS and CMAKE_REQUIRED_LIBRARIES if they are set.
CheckSymbolExists.emake
Check to see if a symbol is defined in a header file. This macro takes three
arguments. The first argument is the symbol to took for. The second argument is a
list of header files to try including. The third argument is where the result is stored.System Properties 94
This macro uses CMAKE_REQUIRED_FLAGS and CMAKE_REQUIRED_ LIBRARIES if
they are set.
CheckTypeSize.cmake
Determines the size in bytes of a variable type. This macro takes two arguments. The
first argument is the type to evaluate. The second argument is where the result is
stored. Both CMAKE REQUIRED_FLAGS and CMAKE_REQUIRED_LIBRARIES are
used if they are set.
CheckVariableExists.cmake
Checks to see if a global variable exists. This macro takes two arguments. The first
argument is the variable to look for. The second argument is the variable to store the
result in. This macro will prototype the named variable and then try to use it. If the
test program compiles then the variable exists. This will only work for C variables.
This macro uses CMAKE_REQUIRED_FLAGS and CMAKE_REQUIRED_LIBRARIES if
they are set. ‘
Consider the following example that shows a variety of these modules being used to compute
properties of the platform. At the beginning of the example four modules are loaded from
CMake. The remainder of the example uses the macros defined in those modules to test for
header files, libraries, symbols, and type sizes respectively.
# Include all the necessary files for macros
include (CheckIncludeFiles)
include (CheckLibraryExists)
include (CheckSymbolExists)
include (CheckTypeSize)
# Check for header files
set (INCLUDES "")
CHECK_INCLUDE_FILES ("${INCLUDES};winsock.h" HAVE_WINSOCK_H)
if (HAVE_WINSOCK_H)
set (INCLUDES ${INCLUDES} winsock.h)
endif (HAVE_WINSOCK_H)
CHECK_INCLUDE_FILES ("${INCLUDES};io.
if (HAVE_IO_H)
set (INCLUDES ${INCLUDES} io.h)
endif (HAVE_IO_H)
" HAVE_IO_H)
# Check for all needed libraries
set (LIBS "")
CHECK_LIBRARY_EXISTS ("dl;${LIBS}" dlopen "" HAVE_LIBDL)92 System Inspection
if (HAVE_LIBDL)
set (LIBS ${LIBS} dl)
endif (HAVE_LIBDL)
CHECK_LIBRARY_EXISTS ("ucb;${LIBS}" gethostname "" HAVE _LIBUCB)
if (HAVE_LIBUCB)
set (LIBS ${LIBS} ucb)
"endif (HAVE_LIBUCB)
# Add the libraries we found to the libraries to use when
# looking for symbols with the CHECK_SYMBOL_EXISTS macro
set (CMAKE REQUIRED LIBRARIES ${LIBS})
# Check for some functions that are used
CHECK_SYMBOL_EXISTS (socket "${INCLUDES}" HAVE_SOCKET)
CHECK_SYMBOL_EXISTS (poll "S$ {INCLUDES}" HAVE_POLL)
# Various type sizes
CHECK TYPE SIZE (int SIZEOF_INT)
CHECK_TYPE_SIZE (size_t SIZEOF_SI2E_T)
For more advanced try_compile and try_run operations, it may be desirable to pass flags
to the compiler, or to CMake. Both commands support the optional arguments CMAKE_FLAGS
and COMPILE DEFINITIONS. CMAKE_FLAGS can be used to pass -DVAR: TYPE=VALUE flags
to CMake. The value of COMPILE_DEFINITIONS is passed directly to the compiler command
line.
5.3. Finding Packages
Many software projects provide tools and libraries meant as building blocks for other projects
and applications. CMake projects that depend on outside packages locate their dependencies
using the find_package command. A typical invocation is of the form
find_package ( [version])
where “” is the name of the package to be found, and “[version]” is an optional
version request (of the form major|.minor.{patch}]). See Appendix C — Listfile
Commands for the full command documentation. The command’s notion of a package is
distinct from that of CPack, which is meant for creating source and binary distributions and
installers.Built-in Find Modules 93
The command operates in two modes: Module mode and Config mode. In Module mode the
command searches for a find-module: a file named "Find.cmake". It looks
first in the CMAKE_MODULE_PATH and then in the CMake installation. If a find-module is
found, it is loaded to search for individual components of the package. Find-modules contain
package-specific knowledge of the libraries and other files they expect to find, and internally
use commands like find_1ibrary to locate them. CMake provides find-modules for many
common packages; see Appendix D — Selected Modules. Find-modules are tedious and
difficult to write and maintain because they need very specific knowledge of every version of
the package to be found.
The Config mode of find_package provides a powerful alternative through cooperation
with the package to be found. It enters this mode after failing to locate a find-module or when
explicitly requested by the caller. In Config mode the command searches for a package
configuration file: a file named “Config.cmake” or “-
config.cmake” that is provided by the package to be found. Given the name of a package,
the find_package command knows how to search deep inside installation prefixes for
locations like
/1ib//-config.cmake
(see documentation of find_package in Appendix C — Listfile Commands for a complete
list of locations). CMake creates a cache entry called “_DIR” to store the location
found or allow the user to set it. Since a package configuration file comes with an installation
of its package, it knows exactly where to find everything provided by the installation. Once
the find_package command locates the file it provides the locations of package components.
without any additional searching.
The “[version]” option asks find_package to locate a particular version of the package.
In Module mode, the command passes the request on to the find-module. In Config mode the
command looks next to each candidate package configuration file fora package version
file: a file named “ConfigVersion.cmake” or “-config-
.cmake”. The version file is loaded to test whether the package version is an
acceptable match for the version requested (see documentation of find_package for the
version file API specification). If the version file claims compatibility the configuration file is
accepted, otherwise it is ignored. This approach allows each project to define its own rules for
version compatibility.
5.4 Built-in Find Modules
CMake has many predefined modules that can be found in the Modules subdirectory of
CMake. The modules can find many common software packages. See Appendix D ~ Selected
Modules for a detailed list.94 System Inspection
Each Find.cmake module defines a set of variables that will allow a project to use the
software package once it is found. Those variables all start with the name of the software
being found . With CMake we have tried to establish a convention for naming these
variables, but you should read the comments at the top of the module for a more definitive
answer. The following variables are used by convention when needed:
_INCLUDE_DIRS
Where to find the package’s header files, typically .h, etc.
_LIBRARIES.
The libraries to link against to use . These include full paths.
_DEFINITIONS
Preprocessor definitions to use when compiling code that uses .
_EXECUTABLE
Where to find the tool that is part of the package.
__EXECUTABLE
Where to find the tool that comes with .
_ROOT_DIR
Where to find the base directory of the installation of . This is useful for large
packages where you want to reference many files relative to a common base (or root)
directory.
_VERSION_
Version of the package was found if true. Authors of find modules should
make sure at most one of these is ever true. For example TCL_VERSION_84
__FOUND
If false, then the optional part of package is not available.
_FOUND
Set to false, or undefined, if we haven't found or don't want to use .
Not all of the variables are present in each of the Findxx.cmake files. However, the
_FOUND should exist under most circumstances. If is a library, then
_LIBRARIES should also be defined, and _INCLUDE_D1R should usually be
defined.How to Pass Parameters to a Compilation? 95
Modules can be included in a project either with the include command or the
find_package command.
f£ind_package (OpenGL)
is equivalent to
include (${CMAKE_ROOT} /Modules/FindOpenGL.cmake)
and
include (FindOpenGL)
If the project converts over to CMake for its build system, then the find_package will still
work if the package provides a Config.cmake file. How to create a CMake package is
described in section 5.7.
5.5 How to Pass Parameters to a Compilation?
Once you have determined all features of the system in which you are interested, it is time to
configure the software based on what has been found. There are two common ways to pass
this information to the compiler: on the compile line, and using a preconfigured header. The
first way is to pass definitions on the compile line. A preprocessor definition can be passed to
the compiler from a CMakeLists file with the add_definitions command. For example, a
common practice in C code is to have the ability to selectively compile in/out debug
statements,
#ifdef DEBUG_BUILD
printf ("the value of v is %d", v);
#endif
A CMake variable could be used to turn on or off debug builds using the OPTION command:
option (DEBUG_BUILD
"Build with extra debug print messages.")
if (DEBUG_BUILD)
add_definitions (-DDEBUG_BUILD)
endif (DEBUG_BUILD)