CMake 2.6 Notes: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
(Replace content with link to new CMake community wiki)
 
(23 intermediate revisions by 4 users not shown)
Line 1: Line 1:
__TOC__
{{CMake/Template/Moved}}


This page documents some of the changes and new features available in CMake 2.6.
This page has moved [https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/notes/2.6 here].
 
=Exporting and Importing Targets=
 
CMake 2.6 introduces support for exporting targets from one project and importing them into another.
The main feature allowing this functionality is the notion of an <code>IMPORTED</code> 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 targtes are used to convert files outside the project on disk into logical targets inside a CMake project.
They are created using the <code>IMPORTED</code> option to <code>add_executable</code> and <code>add_library</code> commands.
No build files are generated for imported targets.
They are useful 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
 
  set(GENERATED_SRC ${CMAKE_CURRENT_BINARY_DIR}/generated.c)
  add_custom_command(
    OUTPUT ${GENERATED_SRC}
    COMMAND generator ${GENERATED_SRC}                                                  # 3
    )
 
  add_executable(myexe src1.c src2.c ${GENERATED_SRC})
 
Line #1 creates a new CMake target called "<code>generator</code>".
Line #2 tells CMake the location of the file on disk to import.
Line #3 references the target in a custom command.  The generated build system will contain a command line such as
 
  /path/to/some_generator /project/binary/dir/generated.c
 
in the rule to generate the source file.
 
Libraries may also be used through imported targets:
 
  add_library(foo IMPORTED)
  set_property(TARGET foo PROPERTY IMPORTED_LOCATION /path/to/libfoo.a)
  add_executable(myexe src1.c src2.c)
  target_link_libraries(myexe foo)
 
The generated build system will contain a command line such as
 
  ... -o myexe /path/to/libfoo.a ...
 
in the rule to link <code>myexe</code>.
On Windows a .dll 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.lib)
  add_executable(myexe src1.c src2.c)
  target_link_libraries(myexe bar)
 
The generated build system will contain a command line such as
 
  ... -o myexe.exe c:/path/to/bar.lib ...
 
in the rule to link <code>myexe</code>.
A library with multiple configurations may be imported with a single target:
 
  add_library(foo IMPORTED)
  set_property(TARGET foo PROPERTY IMPORTED_LOCATION_RELEASE c:/path/to/foo.lib)
  set_property(TARGET foo PROPERTY IMPORTED_LOCATION_DEBUG  c:/path/to/foo_d.lib)
  add_executable(myexe src1.c src2.c)
  target_link_libraries(myexe foo)
 
The generated build system will link <code>myexe</code> to <code>foo.lib</code> when it is built in the release configuration and <code>foo_d.lib</code> when built in the debug configuration.
 
==Exporting Targets==
 
Imported targets on their own are useful, but they still require the project that imports targets to know the locations of the target files on disk.
The real power of this feature is when the project providing the target files also provides a file to help import them.
 
===Exporting from and Installation Tree===
 
The <code>install(TARGETS)</code> and <code>install(EXPORT)</code> commands work together to install a target and a file to help import it.
For example, the code
 
  add_executable(generator generator.c)
  install(TARGETS generator DESTINATION lib/myproj/generators EXPORT myproj-targets)
  install(EXPORT myproj-targets DESTINATION lib/myproj)
 
installs the files
 
  <prefix>/lib/myproj/generators/generator
  <prefix>/lib/myproj/myproj-targets.cmake
 
The <code>myproj-targets.cmake</code> file contains code such as
 
  add_executable(generator IMPORTED)
  set_property(
    TARGET generator
    PROPERTY IMPORTED_LOCATION ${PREFIX}/lib/myproj/generators/generator
    )
 
(in practice the <code>${PREFIX}</code> is computed relative to the file location automatically).
An outside project may now contain code such as
 
  include(${PREFIX}/lib/myproj/myproj-targets.cmake)          # 1
  set(GENERATED_SRC ${CMAKE_CURRENT_BINARY_DIR}/generated.c)
  add_custom_command(
    OUTPUT ${GENERATED_SRC}
    COMMAND generator ${GENERATED_SRC}                        # 2
    )
  add_executable(myexe src1.c src2.c ${GENERATED_SRC})
 
Line #1 loads the target import script.  The script may import any number of targets.  Their locations are computed relative to the script location so the install tree may be moved around.
The importing project need only find the import script (see the packaging section of this document for how this might be done).
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 foo1.c)
  install(TARGETS foo DESTINATION lib EXPORTS myproj-targets)
  install(EXPORT myproj-targets DESTINATION lib/myproj)
 
This installs the library and an import file referencing it.  Outside projects may simply write
 
  include(${PREFIX}/lib/myproj/myproj-targets.cmake)
  add_executable(myexe src1.c)
  target_link_libraries(myexe foo)
 
and the executable will be linked to the library <code>foo</code> 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 to the <code>install(EXPORT)</code> command is needed to install an import file that references all targets.
Both of the examples above may be combined into a single export, even if they are in different subdirectories of the project:
 
  # A/CMakeLists.txt
  add_executable(generator generator.c)
  install(TARGETS generator DESTINATION lib/myproj/generators EXPORT myproj-targets)
 
  # B/CMakeLists.txt
  add_library(foo STATIC foo1.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)
 
===Exporting from a Build Tree===
 
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 <code>export</code> 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 <code>myproj-exports.cmake</code> that contains code such as
 
  add_executable(generator IMPORTED)
  set_property(TARGET generator PROPERTY IMPORTED_LOCATION "/path/to/build/tree/generator")
 
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.
 
=Packages=
 
This section documents creation and use of packages that help projects locate each other.
These features are distinct from CPack which is meant for creating source and binary distributions and installers.
 
The <code>find_package</code> command has been enhanced with features to help find packages without the use of "find" modules (FindXXX.cmake files).
Projects that are aware of CMake may provide a "package configuration file" inside their installation trees.
Naming the file correctly and installing it in a suitable location will allow the <code>find_package</code> command to find it easily.
 
==Package Configuration Files==
 
Consider a project "Foo" that installs the following files:
 
  <prefix>/include/foo-1.2/foo.h
  <prefix>/lib/foo-1.2/libfoo.a
 
It may also provide a CMake package configuration file
 
  <prefix>/lib/foo-1.2/foo-config.cmake
 
with content such as
 
  # ...
  # (compute PREFIX relative to file location)
  # ...
  set(foo_INCLUDE_DIRS ${PREFIX}/include/foo-1.2)
  set(foo_LIBRARY ${PREFIX}/lib/foo-1.2/libfoo.a)
 
If another project wishes to use Foo it need only to locate the <code>foo-config.cmake</code> file and load it to get all the information it needs about package content locations.
Since the package configuration file is provided by the package installation it already knows all the file locations.
 
The <code>find_package</code> command may be used to search for the configuration file:
 
  find_package(Foo)
 
This command (assuming no <code>FindFoo.cmake</code> module exists) constructs a set of installation prefixes and searches under each prefix in several locations.
Given the name "Foo", it looks for a file called "<code>FooConfig.cmake</code>" or "<code>foo-config.cmake</code>".
The full set of locations is specified in the <code>find_package</code> command documentation, but one place it looks is
 
  <prefix>/lib/Foo*/
 
where "<code>Foo*</code>" is a case-insensitive globbing expression.
In our example the globbing expression will match "<code><prefix>/lib/foo-1.2</code>" and the configuration file will be found.
 
Once found, a package configuration file is immediately loaded.  It contains all the information the project needs to use the package.
 
===Packaging and Exporting===
 
Package configuration files may also work in conjunction with the target exporting/importing feature discussed above.
For example, a project might write
 
  add_library(mylib STATIC mylib.c mylib.h)
  install(FILES mylib.h DESTINATION include/myproj)
  install(TARGETS mylib DESTINATION lib/myproj EXPORT mylib-targets)
  install(EXPORT mylib-targets DESTINATION lib/myproj)
  install(FILES mylib-config.cmake DESTINATION lib/myproj)
 
where <code>mylib-config.cmake</code> contains something like
 
  get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
  include(${SELF_DIR}/mylib-targets.cmake)
  get_filename_component(myproj_INCLUDE_DIRS "${SELF_DIR}/../../include/myproj" ABSOLUTE)
 
After the project is built and installed, an outside project may use it by writing
 
  find_package(myproj REQUIRED)
  include_directories(${myproj_INCLUDE_DIRS})
  add_executable(myexe myexe.c)
  target_link_libraries(myexe mylib)
 
==Package Version Files==
 
The <code>find_package</code> command offers a version request argument.  One might write
 
  find_package(Foo 1.2)
  find_package(Bar 4.2 EXACT)
 
in order to get a version of package <code>Foo</code> that is compatible with version 1.2 and exactly package <code>Bar</code> version 4.2.
CMake does not attempt to define any convention for the compatibility or exactness of version numbers for a package.
It also does not try to map the version number to a directory or file name.
Instead packages must provide "version" files next to their package configuration files.
This allows maximum flexibility for project authors and package maintainers.
 
A package version file is placed next to the package configuration file.
Its name matches that of the configuration file but has either "<code>-version</code>" or "<code>Version</code>" appended to the name before the "<code>.cmake</code>" extension.
For example, the files
 
  <prefix>/lib/foo-1.3/foo-config.cmake
  <prefix>/lib/foo-1.3/foo-config-version.cmake
 
and
 
  <prefix>/lib/bar-4.2/BarConfig.cmake
  <prefix>/lib/bar-4.2/BarConfigVersion.cmake
 
are each pairs of package configuration files and corresponding version files.
When the <code>find_package</code> command finds a candidate package configuration file it looks next to it for a version file.
The version file is loaded to test whether the package version is an acceptable match for the version requested.
If the version file claims compatibility the configuration file is accepted.  Otherwise it is ignored.
 
When the <code>find_package</code> command loads a version file it first sets the following variables:
 
  PACKAGE_FIND_NAME          = the <package> name given as the first argument of find_package
  PACKAGE_FIND_VERSION      = full requested version string
  PACKAGE_FIND_VERSION_MAJOR = requested major version, if any
  PACKAGE_FIND_VERSION_MINOR = requested minor version, if any
  PACKAGE_FIND_VERSION_PATCH = requested patch version, if any
 
The version file must use these variables to check whether it is compatible or an exact match for the requested version.
It sets the following variables with results:
 
  PACKAGE_VERSION            = package version (major[.minor[.patch]])
  PACKAGE_VERSION_EXACT      = true if version is exact match
  PACKAGE_VERSION_COMPATIBLE = true if version is compatible
 
For example, <code>foo-config-version.cmake</code> might contain
 
  set(PACKAGE_VERSION 1.3)
  if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 1)
    set(PACKAGE_VERSION_COMPATIBLE 1) # compatible with any version 1.x
    if("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 3)
      set(PACKAGE_VERSION_EXACT 1)    # exact match for version 1.3
    endif("${PACKAGE_FIND_VERSION_MINOR}" EQUAL 3)
  endif("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL 1)
 
if it is compatible with all "<code>1.x</code>" versions of Foo and exactly matches version "<code>1.3</code>".
Note that the input variable names all start in "<code>PACKAGE_FIND_</code>" and the output variable names all start in "<code>PACKAGE_</code>".
The names are fixed and do not vary with the package name.
 
Version files are loaded in a nested scope so they are free to set any variables they wish as part of their computation.
The <code>find_package</code> command wipes out the scope when the version file has completed and it has checked the output variables.
When the version file claims to be an acceptable match for the requested version the <code>find_package</code> command sets the following variables for use by the project:
 
  <package>_VERSION      = package version (major[.minor[.patch]])
  <package>_VERSION_MAJOR = major from major[.minor[.patch]], if any
  <package>_VERSION_MINOR = minor from major[.minor[.patch]], if any
  <package>_VERSION_PATCH = patch from major[.minor[.patch]], if any
 
The variables report the version of the package that was actually found.
The "<code><package></code>" part of their name matches the argument given to the <code>find_package</code> command.
 
=Preprocessor Definitions=
 
Preprocessor definitions may now be added to builds with much finer granularity than in previous versions of CMake.  There is a new property called <code>COMPILE_DEFINITIONS</code> that is defined directories, targets, and source files.  For example, the code
 
  add_library(mylib src1.c src2.c)
  add_executable(myexe main1.c)
 
  set_property(
    DIRECTORY
    PROPERTY COMPILE_DEFINITIONS A AV=1
    )
  set_property(
    TARGET mylib
    PROPERTY COMPILE_DEFINITIONS B BV=2
    )
  set_property(
    SOURCE src1.c
    PROPERTY COMPILE_DEFINITIONS C CV=3
    )
 
will build the source files with these definitions:
 
  src1.c:  -DA -DAV=1 -DB -DBV=2 -DC -DCV=3
  src2.c:  -DA -DAV=1 -DB -DBV=2
  main2.c:  -DA -DAV=1
 
When the <code>add_definitions</code> command is called with flags like "<code>-DX</code>" the definitions are extracted and added to the current directory's <code>COMPILE_DEFINITIONS</code> property.  When a new subdirectory is created with <code>add_subdirectory</code> the current state of the directory-level property is used to initialize the same property in the subdirectory.
 
Note in the above example that the <code>set_property</code> command will actually '''set''' the property and replace any existing value.  The command provides the <code>APPEND</code> option to help add more definitions without removing existing ones.  For example, the code
 
  set_property(
    SOURCE src1.c
    APPEND PROPERTY COMPILE_DEFINITIONS D DV=4
    )
 
will add the definitions "<code>-DD -DDV=4</code>" when building <code>src1.c</code>.
 
Definitions may also be added on a per-configuration basis using the <code>COMPILE_DEFINITIONS_<CONFIG></code> property.  For example, the code
 
  set_property(
    TARGET mylib
    PROPERTY COMPILE_DEFINITIONS_DEBUG MYLIB_DEBUG_MODE
    )
 
will build sources in mylib with <code>-DMYLIB_DEBUG_MODE</code> only when compiling in a <code>Debug</code> configuration.
 
=Link Line Generation=
 
CMake 2.6 implements a new approach to generating link lines for targets.
 
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 -Wl,-Bstatic -lfoo -Wl,-Bdynamic ...
 
This worked most of the time, but some platforms (such as OS X) do not
support the <code>-Bstatic</code> 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 side-effects.
 
==Missing Linker Search Directories==
 
Projects used to be able to write this (wrong) code and it would work by accident:
 
  add_executable(myexe myexe.c)
  target_link_libraries(myexe /path/to/libA.so B)
 
where "<code>B</code>" is meant to link "<code>/path/to/libB.so</code>".  This code is incorrect
because it asks CMake to link to <code>B</code> but does not provide the proper
linker search path for it.  It used to work by accident because the
<code>-L/path/to</code> would get added as part of the implementation of linking to
A.  The correct code would be
 
  link_directories(/path/to)
  add_executable(myexe myexe.c)
  target_link_libraries(myexe /path/to/libA.so B)
 
or even better
 
  add_executable(myexe myexe.c)
  target_link_libraries(myexe /path/to/libA.so /path/to/libB.so)
 
In order to support projects that have this bug, we've added a
compatibility feature that adds the "<code>-L/path/to</code>" paths for all libraries
linked with full paths even though the linker will not need those paths
to find the main libraries.  The compatibility mode is enabled when a
link line contains a non-full-path library (like <code>B</code>) and either
<code>CMAKE_BACKWARDS_COMPATIBILITY</code> is set to 2.4 or lower or
<code>CMAKE_LINK_OLD_PATHS</code> is set to true.
 
If you are trying to build a project and run into this problem, a quick-fix is to run
 
  cmake -DCMAKE_LINK_OLD_PATHS:BOOL=ON .
 
in the top of the build tree.
 
==Linking to System Libraries==
 
System libraries on UNIX-like systems are typically provided in <code>/usr/lib</code> or <code>/lib</code>.  These directories are considered implicit linker search paths because linkers automatically search these locations even without a flag like <code>-L/usr/lib</code>.  Consider the code
 
  find_library(M_LIB m)
  target_link_libraries(myexe ${M_LIB})
 
Typically the <code>find_library</code> command would find the math library
 
  /usr/lib/libm.so
 
In CMake 2.4 the link line generation would split off the link directory <code>/usr/lib</code> and the library <code>libm.so</code> and produce the
 
  ... -lm ...
 
Note that the <code>-L/usr/lib</code> option is left out because it is an implicit linker search path.  The linker would see <code>-lm</code> and search for the math library.  Typically the linker would find /usr/lib/libm.so too.  However some platforms provide multiple versions of libraries correesponding to different architectures.  For example, on an IRIX machine one might find the libraries
 
  /usr/lib/libm.so        (ELF o32)
  /usr/lib32/libm.so      (ELF n32)
  /usr/lib64/libm.so      (ELF 64)
 
On a Solaris machine one might find
 
  /usr/lib/libm.so          (sparcv8 architecture)
  /usr/lib/sparcv9/libm.so  (sparcv9 architecture)
 
When the linker sees <code>-lm</code> it in fact searches the system path corresponding to the current architecture.  Internally it might use <code>-L/usr/lib/sparcv9</code> instead of <code>-L/usr/lib</code>.
 
In CMake 2.6 most libraries are given to the linker using their full path.  The code
 
  target_link_libraries(myexe /my/special/dir/libm.so)
 
generates the link line
 
  ... /my/special/dir/libm.so ...
 
Unfortunately if this were done also for <code>/usr/lib/libm.so</code> the linker might complain if <code>/usr/lib/libm.so</code> does not match the architecture it wants.
 
The problem is created because <code>find_library</code> may not know about all the architecture-specific system search paths used by the linker.  In fact when it finds <code>/usr/lib/libm.so</code> it may be finding a library of incorrect architecture.  The solution is for the link computation to recognize that when it is given a library in a system search path that it should ask the linker to find the correct version of the library at link time.  Consider the original example:
 
  find_library(M_LIB m)
  target_link_libraries(myexe ${M_LIB})
 
If <code>find_library</code> finds the library in a directory that is not an implicit link directory the full path will be linked as usual.
If <code>find_library</code> finds <code>/usr/lib/libm.so</code> the link computation will realize that this might be a system library and produces the link line
 
  ... -lm ...
 
and the linker will locate the correct version of the library.  This solution suffers from the original problem of distinguishing between static and shared versions:
 
  /usr/lib/libm.a
  /usr/lib/libm.so
 
When asked to link <code>/usr/lib/libm.a</code> the link computation will produce
 
  ... -Wl,-Bstatic -lm ... -Wl,-Bshared ...
 
On platforms that do not have flags such as <code>-Bstatic</code> the link computation will never convert a full path to a <code>-l</code> option.

Latest revision as of 15:41, 30 April 2018


The CMake community Wiki has moved to the Kitware GitLab Instance.

This page has moved here.