Frameworks/Epics/CMake target usage requirements: Difference between revisions
No edit summary |
No edit summary |
||
Line 21: | Line 21: | ||
* Link directories | * Link directories | ||
* Preprocessor definitions | * Preprocessor definitions | ||
* Compiler flags | * Compiler flags (eg, if -msoft-float is used by a dependency then it should be used by dependents?) | ||
* Linker flags | * Linker flags | ||
Revision as of 23:17, 5 May 2012
This page collects ideas and requirements for a CMake which is fully target orientated, rather than directory orientated and propagates usage requirements, towards convention driven usage of propagated properties.
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).
- Possibly 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 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?)
- 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 'porcelain' API for the consumer is a new cmake command like:
target_use_package(Foo Bar)
where Foo is a target created in the local CMakeLists file, and Bar is one of:
- A package containing imported targets and variables with the appropriate naming conventions for variables for use with each property (eg for linking, include directories, flags etc).
- An imported target
- A prefix for variables with the appropriate naming conventions for variables for use with each property (eg for linking, include directories, flags etc).
The 'plumbing' API would be the populated variables themselves, for example, the Bar_LIBRARIES Bar_INCLUDE_DIRECTORIES variables and others. Consumers could choose to forego the porcelain API where needed and use the plumbing API instead.
The implementation of the target_use_package command would take the following steps:
- find the Bar package if not already found this allows consumers to find the package with their own arguments to find_package and then call target_use_package)
Notes:
In the case where Bar is a package which has no components, or in which we do not specify components, there is no need to use find_package.
target_use_package(Foo Bar)
If Bar is not defined, it is assumed to be a package, and is searched for. After that, if Bar_LIBRARIES contains imported targets, they and their appropriate properties are used when building Foo. Otherwise, the variables with the appropriate naming conventions (eg Bar_LIBRARIES Bar_INCLUDE_DIRS) are used.
In the case where we want to customize how we find the package:
find_package(Bar PATHS ...) target_use_package(Foo Bar) # Checks Bar_FOUND and does not attempt to find it again.
In the case of using a package with components, it would work like this:
find_package(Bar REQUIRED Bat) target_use_package(Foo ${Bar_Bat_LIBRARIES})
If Bar_Bat_LIBRARIES is an imported target, the appropriate properties from it are used when building Foo. Otherwise, the variables with the appropriate naming conventions (eg Bar_Bat_LIBRARIES Bar_Bat_INCLUDE_DIRS) are used.
The publishing phase
Inside of Find modules or Config modules, the variables would be set and populated. The variables would all contain an ExactCase prefix, and whatever other information is appropriate. That is, some information would be encoded in the name of variables (eg, there might be Bar_INCLUDE_DIRS_<CONFIG> defined here), and some information would be encoded in generator expressions (eg, Bar_INCLUDE_DIRS might contain several entries of the form $<CONFIG?Debug:/foo/bar>). The generator expressions form would be most convenient for consumers and should be preferred, but the decision may also be influenced by existing convention (eg in the case of CMAKE_CXX_FLAGS_DEBUG).
For creators of Find modules, the responsibility would be on the Find module author to ensure adherence to the correct naming conventions, as appropriate. 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>" )
There will likely be a need for a porcelain API for these properties too, such as
target_include_directories(Foo "/internal/dependency" CONFIGURATION Debug "/internal/dependency" PUBLIC "/includes/you/need/to/use/foo" CONFIGURATION Debug "/foo/debugstuff" CONFIGURATION Release "/foo/releasestuff" )
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