Difference between revisions of "CMake/Policies"

From KitwarePublic
Jump to navigationJump to search
(Replace content with link to new CMake community wiki)
(22 intermediate revisions by 3 users not shown)
Line 1: Line 1:
The CMake Policy mechanism provides backwards compatibility as a
first-class feature.
This page has moved [https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Policies here].
CMake is an evolving project.  The developers strive to support
existing projects as much as possible as changes are made.
Unfortunately there are some cases where it is not possible to fix
bugs and preserve backwards compatibility at the same time.  We give
some examples here.
==Interface of ADD_DEFINITIONS==
Consider the <code>add_definitions</code> command:
When originally introduced the command was intended only to add simple
definitions.  Its implementation was simply to pass its arguments on
to the compiler's command line.  Since CMake supports configured
header files using the <code>configure_file</code> command it is not
necessary to pass complicated definitions on compile command lines.
However, some project authors tried to do so anyway with code like
  add_definitions("-DFOO=\"some string\"")
but found that it did not work.  The string
  -DFOO="some string"
would appear on the command line and the compiler would receive a
definition equivalent to
  #define FOO some string
Some authors proceeded to work around the problem by adding escape
sequences manually:
  add_definitions("-DFOO=\"\\\"some string\\\"\"")
The escape sequences work for some native build tools (such as Unix
Makefiles) but not others.  The proper way to deal with this issue was
to fix the implementation in CMake to actually produce the correct
escape sequences for each native build tool automatically.
Unfortunately introducing the fix would break existing projects that
add their own escape sequences because the escapes themselves would be
escaped.  In order to support such projects no fix was introduced for
years.  This allowed many more projects to continue to suffer from the
problem and add their own work-arounds which must now also be
This problem with <code>add_definitions</code> is an example of a
class of problems: how are we to fix an interface without breaking
work-arounds for the very problem being fixed?  The policy mechanism
is a solution to this problem.
==Magic Link Directories==
When using CMake 2.4 or below projects may write this (wrong) code and it works 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.  The correct code would be
  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)
CMake 2.4 implemented the link to library A partly by adding
<code>-L/path/to</code> to the linker command line.  This allowed
library B to be found even though no linker search path was provided
for it.  CMake 2.6 implements linking to library A by passing
<code>/path/to/libA.so</code> directly to the linker as a path.  This
leaves out the <code>-L/path/to</code> which may prevent library B
from being found.
While the code above leading to this problem is technically wrong it
worked with a previous CMake release and needs to be supported.
Therefore CMake 2.6 has support for passing the directories containing
libraries whose full paths are known as linker search paths even
though they are not needed for correct user code.  Full compatibility
would require us to support this behavior by default forever.  That
would allow new projects to be written with the same bug.
This problem is an example of a class of problems: how are we to fix
an implementation without breaking projects depending on undocumented
details of the original implementation?  The policy mechanism is a
solution to this problem.
=Design Goals=
The design goals for the CMake Policy mechanism were as follows:
# '''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
# '''Correctness of new interfaces or bugs fixed in old ones should not be inhibited by compatibility requirements'''
#* Any reduction in correctness of the latest interface is not fair to new projects
# '''Every change to CMake that may require changes to project code 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
# '''We must be able to eventually remove code implementing compatibility with ancient CMake versions'''
#* Such removal is necessary to keep the code clean and allow internal refactoring
#* After such removal attempts to build projects written for ancient versions must fail with an informative message
We've introduced the notion of a '''policy''' for dealing with changes
in CMake behavior.  Each policy has
* A name of the form '''<code>CMP_''NNNN''</code>''' where ''NNNN'' is an integer identifier
* '''OLD''' behavior that preserves compatibility with earlier versions of CMake
* '''NEW''' behavior that is considered correct and preferred for use by new projects
* Documentation detailing the motivation for the change and the OLD and NEW behaviors
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 produced telling the project author
to set the policy.
==Setting Policies by CMake Version==
In most cases a project release should simply set a ''policy version'' corresponding to the release version of
CMake for which the project is written.  Setting the policy version
requests 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 <code>cmake_policy</code>
command's <code>VERSION</code> signature.  For example, the code
  cmake_policy(VERSION 2.6)
will request NEW behavior for all policies introduced in CMake 2.6 or
earlier.  The <code>cmake_minimum_required</code> command will also
set the policy version which is convenient for use at the top of
projects.  A project should typically begin with the lines
  cmake_minimum_required(VERSION 2.6)
  # ...code using CMake 2.6 policies
Of course one should replace "<code>2.6</code>" with a higher version
as necessary.
When a new version of CMake is released that introduces new policies
it will still build old projects because 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.
==Setting Policies Individually==
Each policy may be set individually to help project authors
incrementally convert their projects to use new behavior or silence
warnings about dependence on old behavior.  The
<code>cmake_policy</code> command's <code>SET</code> signature may be
used to explicitly request OLD or NEW behavior for a particular
For example, CMake 2.6 introduces policy <code>CMP_0002</code> 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 CMP_0002 OLD)
which explicitly tells CMake to use OLD behavior for the policy
(silently accept duplicate target names).  Another option is to use
the code
  cmake_policy(SET CMP_0002 NEW)
to explicitly tell CMake to use NEW behavior (produce an error when a
duplicate target is created).  Once this is added to the project it
will not build until the author removes the duplicate targets.
==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
<code>add_subdirectory</code>) 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.
This is useful when a project contains subprojects maintained
separately but built inside the tree.  The top-level
<code>CMakeLists.txt</code> file in a project may write
  cmake_policy(VERSION 2.6)
  # ... code requiring new behavior as of CMake 2.6 ...
while the <code>OtherProject/CMakeLists.txt</code> file contains
  cmake_policy(VERSION 2.4)
  # ... code that buidls with CMake 2.4 ...
This allows the main project to be updated to CMake 2.6 while the
subproject continues to build with CMake 2.4 until its maintainers
update it.
User code may use the <code>cmake_policy</code> command to PUSH and
POP its own stack levels as long as every PUSH must be paired with a
POP.  This is useful to temporarily request different behavior for a
small section of code.  For example, policy <code>CMP_0003</code>
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(SET CMP_0003 OLD) # use old-style link directories for now
  add_executable(myexe ...)
will silence the warning and use the OLD behavior for that target.

Latest revision as of 10:40, 30 April 2018

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

This page has moved here.