Difference between revisions of "CMake/Policies"

From KitwarePublic
Jump to navigationJump to search
(Replace content with link to new CMake community wiki)
 
(10 intermediate revisions by 2 users not shown)
Line 1: Line 1:
The CMake Policy mechanism provides backwards compatibility as a
+
{{CMake/Template/Moved}}
first-class feature.
 
  
This page provides information intended for use by project developers to help update their projects to deal with new policies.
+
This page has moved [https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/Policies here].
 
 
=Motivation=
 
 
 
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.
 
 
 
==Fixing an Interface Breaks Work-Arounds==
 
 
 
Consider the <code>add_definitions</code> command:
 
 
 
  add_definitions(-DFOO)
 
 
 
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
 
supported.
 
 
 
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.
 
 
 
==Changing an Implementation Breaks Projects Building Accidentally==
 
 
 
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
 
 
 
  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)
 
 
 
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
 
 
 
=Solution=
 
 
 
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)
 
  project(MyProject)
 
  # ...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.
 
 
 
Policy CMP0000 has been introduced to require all projects to specify a policy version in their top-level CMakeLists.txt file.  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 <code>cmake_minimum_required</code> to build as they would have with CMake 2.4.
 
 
 
==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
 
policy.
 
 
 
For example, CMake 2.6 introduces policy <code>CMP0002</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 CMP0002 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 CMP0002 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)
 
  project(MyProject)
 
  add_subdirectory(OtherProject)
 
  # ... code requiring new behavior as of CMake 2.6 ...
 
 
 
while the <code>OtherProject/CMakeLists.txt</code> file contains
 
 
 
  cmake_policy(VERSION 2.4)
 
  project(OtherProject)
 
  # ... 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>CMP0003</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(PUSH)
 
  cmake_policy(SET CMP0003 OLD) # use old-style link directories for now
 
  add_executable(myexe ...)
 
  cmake_policy(POP)
 
 
 
will silence the warning and use the OLD behavior for that target.
 
 
 
==Interaction with Previous Compatibility Mechanisms==
 
 
 
CMake 2.4 and below dealt with backwards compatibility by providing
 
the <code>CMAKE_BACKWARDS_COMPATIBILITY</code> variable as a cache
 
entry.  The variable could be set by the user when building a project
 
to tell CMake to try to support an older version.  This allowed users
 
to build older projects but only if they knew how to set the variable.
 
In some cases CMake could generate an error about old behavior and
 
tell the user to set the variable but in other cases it would silently
 
fail or produce errors not mentioning the variable.
 
 
 
The main problem with the <code>CMAKE_BACKWARDS_COMPATIBILITY</code>
 
was that it did not distinguish between a user trying to build someone
 
else's project and that project's author.  Only project authors should
 
be required to do anything that changes how their project builds with
 
new CMake versions.  The CMake Policy mechanism addresses this issue.
 
 
 
The CMake Policy mechanism was introduced in version CMake 2.6.  For
 
maximum compatibility CMake does not try to retroactively convert
 
behavior changes introduced in versions 2.4 or lower into policies.
 
Instead policy <code>CMP0001</code> decides whether or not to support
 
2.4-style compatibility.  It's OLD behavior is to present
 
<code>CMAKE_BACKWARDS_COMPATIBILITY</code> and check for settings
 
lower than 2.4.  It's NEW behavior is to not add
 
<code>CMAKE_BACKWARDS_COMPATIBILITY</code> and not check its value
 
therefore removing all compatibility with versions lower than 2.4.
 
 
 
Since all policies are introduced in CMake version 2.6 or later it
 
does not make sense to allow a policy version lower than 2.4 to be
 
set.  Therefore the <code>cmake_policy</code> command's VERSION
 
argument may not be lower than 2.4.  Similarly,
 
<code>cmake_minimum_required</code> will never set the policy version
 
lower than 2.4 no matter what version is specified.  This allows
 
existing projects to automatically build with the old-style
 
compatibility rules.
 
 
 
=Updating a Project for a new CMake Version=
 
 
 
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
 
with 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.
 
 
 
==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.6 one might write
 
 
 
  cmake_minimum_required(VERSION 2.6)
 
 
 
at the beginning of the top-level <code>CMakeLists.txt</code> file.
 
This tells CMake to use the NEW behavior for every policy introduced
 
in CMake 2.6 and below.  When building this project with CMake 2.6 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.
 
 
 
==Incremental Approach==
 
 
 
Another approach to updating a project for a new version of CMake is
 
to deal with each warning one-by-one.  An 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 <code>CMakeLists.txt</code> files that produces 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.
 
 
 
===Silence a Warning When 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 <code>CMP<''NNNN''></code> one may check
 
whether this is the case by adding
 
 
 
  cmake_policy(SET CMP<''NNNN''> 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 Code===
 
 
 
One may suppress all instances of a warning
 
<code>CMP<''NNNN''></code> by adding
 
 
 
  cmake_policy(SET CMP<''NNNN''> 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 <code>CMP<''NNNN''></code> one may add
 
 
 
  cmake_policy(SET CMP<''NNNN''> NEW)
 
 
 
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
 
<code>cmake_policy</code> command:
 
 
 
  cmake_policy(PUSH)
 
  cmake_policy(SET CMP<''NNNN''> NEW)
 
  # ... code updated for new policy behavior ...
 
  cmake_policy(POP)
 
 
 
This will request 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.  For
 
example, after updating a project to build cleanly with CMake 2.6 one
 
may update the top of the project with the line
 
 
 
  cmake_minimum_required(VERSION 2.6)
 
 
 
or
 
 
 
  cmake_policy(VERSION 2.6)
 
 
 
This will set all policies introduced in CMake 2.6 or below to use NEW
 
behavior.  Then one may sweep through the rest of the code and remove
 
all the calls to the <code>cmake_policy</code> command used to request
 
NEW behavior incrementally.  The end result should look the same as
 
the one-shot approach above but could be attained step-by-step.
 

Latest revision as of 11:40, 30 April 2018


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

This page has moved here.