Mastering Cmake PDF
Mastering Cmake PDF
”)
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)