Jump to content

Frameworks/Epics/CMake target usage requirements

From KDE Community Wiki

This page collects ideas and requirements for a CMake which is fully target orientated, rather than directory orientated. Additionally the targets propagate usage requirements to simplify the use of well-defined targets.

By 'fully target orientated', the intention is to be able to connect targets in a build system to other targets in that same build system and to imported targets.

Several feature requests related to this also mention the requirement to set these properties on a per-source-file basis. This wiki page ignores the source-file level requirement and defers it to future work.

There are several dimensions to this:

  • CMake needs to be able to set all necessary properties to configure the build.
  • CMake needs to be able to set properties differently based on debug and release configurations
  • Transitive behaviour - dependants should be easily informed of what properties they should use.
  • CMake needs to be able to set properties differently based on whether downstreams should use its contents or not (public versus private).
  • Different values based on whether linking statically or dynamically
  • Possibly different values based on the language being used.
  • Different values based on whether it is used from its build location (ie, targets created in the same buildsystem) or installed location (eg the include directories of a library).
  • The public/installed include directories must be relocatable. This may present several challenges.
  • CMake may need update some properties based on the value of some other properties. For example, if the WIN32_EXECUTABLE property is true, we may need to link in a static library, as we do on windows with qtmain. https://codereview.qt-project.org/#change,26577

There is also a possibility that the host and target platforms (when cross compiling) should be dimensions of this feature (or possibly the generator being used). It's not clear how that could work however without turning the possibilities for Generator-expressions entirely unmaintainable. For more see http://thread.gmane.org/gmane.comp.programming.tools.cmake.user/42060/focus=42095. For now, that's not a topic for this page.

The properties that should be covered by this mechanism are:

  • Link libraries
  • Include directories
  • Link directories
  • Preprocessor definitions
  • Compiler flags (eg, if -msoft-float is used by a dependency then it should be used by dependents, or -std=C++11?) Note that the raw flags should not be stored as a target property as they vary among compilers. Instead abstracted properties on the target should be made available, such as POSITION_INDEPENDENT_CODE or STD_CXX11.
  • Linker flags

There are several aspects to this

  • The implementation - the upstream developer needs to be able to mark properties for the values in each required dimension (The usage requirements).
  • The publisher - Imported targets need to be able to define their usage requirements . Exported target generator needs to be able to generate them.
  • The consumer - Developer needs to be able to easily read and act upon the usage requirements of dependencies.

In the case of using targets from the same buildsystem, the publisher phase is not executed, and the consumer phase simply uses the same properties set in the implementation phase.

The consuming phase

The target API for the consumer is a new cmake command like:

target_use_targets(Foo TARGETS Bar Bat Blub)

where Foo is a target created in the local CMakeLists file, and Bar, Bat and Blub are one of:

  • A target created in this buildsystem, or
  • An imported target

The publishing phase

All required information would need to be encoded in properties on the targets, probably in generator expressions (eg, The INCLUDE_DIRECTORIES_PUBLIC of the Bar target might contain several entries of the form $<CONFIG?Debug:/foo/bar>).

For creators of Find modules, the responsibility would be on the Find module author to ensure correctly creating imported targets and populating the correct properties on them.

For Config files, exported targets should be used, which will generate properties on the imported targets based on the values of properties set during the implementation phase.

The implementation phase

For authors of libraries which create CMake Config files, there needs to be API to populate each property on particular targets. The properties are then used when targets are exported with the install(... EXPORT ...) signature.

Plumbing API:

The plumbing API and implementation detail for this will be based on target properties, not directory level properties. The properties will have well-defined names, preferably without containing any of the dimensions in their name (eg, language, config, shared/ststic etc), though it will likely be necessary to include in the name whether it is a internal requirement or a usage requirement (eg public versus private) and make use of generator expressions to deal with those dimensions. The implementor will be able to for example:

set_property(TARGET Foo
  APPEND PROPERTY INCLUDE_DIRECTORIES
  "/internal/dependency"
  "$<CONFIG?Debug:/internal/foo/debugstuff>"
)
set_property(TARGET Foo
  APPEND PROPERTY INCLUDE_DIRECTORIES_PUBLIC
  "/includes/you/need/to/use/foo"
  "$<CONFIG?Debug:/foo/debugstuff>"
  "$<CONFIG?Release:/foo/releasestuff>"
)

A more complete syntax for the generator expressions is described here, and would look like this:

set(FOO_INCLUDE_DIRS
  $<$<CONFIG:Debug>:${FOO_INCLUDE_DIRS_DEBUG}>
  $<$<CONFIG:Release>:${FOO_INCLUDE_DIRS_RELEASE}>
  )

Current state

Property Directory-level API Target-level API Notes
Link Libraries link_libraries command target_link_libraries command Already possible to differentiate between public and private linking, and debug/optimized. However, it might be worth porting this to generator expressions too for consistency and to allow differentiation based on other configurations.
Include directories include_directories set target property INCLUDE_DIRECTORIES

Needs to get support for generator expressions, and possibly needs a way to differentiate public/private

Preprocessor defintions add_defnitions command set target property COMPILE_DEFINITIONS and COMPILE_DEFINITIONS_<CONFIG> No way of specifying language (needed?). May need to get support for generator expressions, and needs a way to differentiate public/private
Compile options set(CMAKE_CXX_FLAGS) string with language and configuration specified set COMPILE_FLAGS target property with no language or configuration specified No way of specifying language (needed?). Needs to get support for generator expressions for configuration, and needs a way to differentiate public/private. Rebase the COMPILE_OPTIONS branch to master and finish it so that we can deal with ';' separated lists instead of spaces.

Links

http://thread.gmane.org/gmane.comp.programming.tools.cmake.user/39090/focus=39114

http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/2145

http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/2574

http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/3119

http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/3083

http://thread.gmane.org/gmane.comp.kde.devel.buildsystem/7165/

http://lists.qt-project.org/pipermail/development/2011-November/000258.html

http://www.cmake.org/pipermail/cmake/2007-June/014386.html

http://lists.qt-project.org/pipermail/development/2011-November/000251.html

http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/3119/focus=3315

http://thread.gmane.org/gmane.comp.programming.tools.cmake.user/37340