CMake 2.6 Notes: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
Line 9: Line 9:
=Packages=
=Packages=


This section documents creation and use of packages that help projects locate each other.
Please see our tutorial on [[CMake/Tutorials/Packaging|Packaging]].
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.
 
'''Note:''' If your project does not already have a <code><prefix>/lib/Foo*/</code> directory you may prefer to put the package file in <code><prefix>/lib/cmake/Foo*/</code> to keep the <code>lib</code> directory clean.  However, CMake 2.6.2 and lower do not search there.  CMake 2.6.3 and above do.
 
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 myproj-config.cmake DESTINATION lib/myproj)
 
where <code>myproj-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:
 
{| border=1
! CMake 2.6.2 and Above !! CMake 2.6.0 and 2.6.1
|-valign="top"
|<pre>
PACKAGE_FIND_NAME          = the <package> name
PACKAGE_FIND_VERSION      = full requested version string
PACKAGE_FIND_VERSION_MAJOR = major version if requested, else 0
PACKAGE_FIND_VERSION_MINOR = minor version if requested, else 0
PACKAGE_FIND_VERSION_PATCH = patch version if requested, else 0
PACKAGE_FIND_VERSION_TWEAK = tweak version if requested, else 0
PACKAGE_FIND_VERSION_COUNT = number of version components, 0 to 4
</pre>
||<pre>
PACKAGE_FIND_NAME          = the <package> name
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
</pre>
|}
 
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            = full provided version string
  PACKAGE_VERSION_EXACT      = true if version is exact match
  PACKAGE_VERSION_COMPATIBLE = true if version is compatible
  PACKAGE_VERSION_UNSUITABLE = true if unsuitable as any version (CMake >= 2.6.3)
 
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:
 
{| border=1
! CMake 2.6.2 and Above !! CMake 2.6.0 and 2.6.1
|-valign="top"
|<pre>
<package>_VERSION      = full provided version string
<package>_VERSION_MAJOR = major version if provided, else 0
<package>_VERSION_MINOR = minor version if provided, else 0
<package>_VERSION_PATCH = patch version if provided, else 0
<package>_VERSION_TWEAK = tweak version if provided, else 0
<package>_VERSION_COUNT = number of version components, 0 to 4
</pre>
||<pre>
<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
</pre>
|}
 
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=

Revision as of 20:15, 20 January 2011

This page documents some of the changes and new features available in CMake 2.6.

Exporting and Importing Targets

Please see our tutorial on Exporting and Importing Targets.

Packages

Please see our tutorial on Packaging.

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 COMPILE_DEFINITIONS 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 add_definitions command is called with flags like "-DX" the definitions are extracted and added to the current directory's COMPILE_DEFINITIONS property. When a new subdirectory is created with add_subdirectory 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 set_property command will actually set the property and replace any existing value. The command provides the APPEND 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 "-DD -DDV=4" when building src1.c.

Definitions may also be added on a per-configuration basis using the COMPILE_DEFINITIONS_<CONFIG> property. For example, the code

 set_property(
   TARGET mylib
   PROPERTY COMPILE_DEFINITIONS_DEBUG MYLIB_DEBUG_MODE
   )

will build sources in mylib with -DMYLIB_DEBUG_MODE only when compiling in a Debug 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 -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 side-effects that affect compatibility with existing projects (documented in the next two subsections).

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 "B" is meant to link "/path/to/libB.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

  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 "-L/path/to" paths for all libraries linked with full paths even though the linker will not need those paths to find the main libraries. See policy CMP0003 for details.

Linking to System Libraries

System libraries on UNIX-like systems are typically provided in /usr/lib or /lib. These directories are considered implicit linker search paths because linkers automatically search these locations even without a flag like -L/usr/lib. 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/lib/libm.so

Some platforms provide multiple versions of libraries corresponding 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)

Unfortunately find_library may not know about all the architecture-specific system search paths used by the linker. In fact when it finds /usr/lib/libm.so it may be finding a library of incorrect architecture. If the link computation were to produce the line

 ... /usr/lib/libm.so ...

the linker might complain if /usr/lib/libm.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

 ... -lm ...

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:

 /usr/lib/libm.a
 /usr/lib/libm.so

In order to ask the linker to find the static system library of the correct architecture it must produce the link line

 ... -Wl,-Bstatic -lm ... -Wl,-Bshared ...

This solution directly contradicts the original motivation to give the linker paths to libraries instead of -l options: not all platforms have an option like -Bstatic. Fortunately the platforms that do not provide such flags also tend to not have architecture-specific implicit link directories.

The solution used by CMake is:

  • Libraries not in implicit system locations are linked by passing the file path to the linker
  • Libraries in implicit system locations are linked by
    • passing the -l option if a flag like -Bstatic is available
    • passing the file path to the linker otherwise

Users can override this behavior by using the IMPORTED targets feature:

 add_library(math STATIC IMPORTED)
 set_property(TARGET math PROPERTY IMPORTED_LOCATION /usr/lib/libm.a)
 add_executable(foo foo.c)
 target_link_libraries(foo math) # will link using full path

CMake Policy Mechanism

CMake 2.6 introduces a new mechanism for backwards compatibility support. See CMake Policies for more information.