CMake targets with detailed dependencies
来源:互联网 发布:淘宝淘口令有危险吗 编辑:程序博客网 时间:2024/06/05 18:11
转自: https://crascit.com/2015/02/02/cmake-target-dependencies/
If only software build systems would do what we intuitively expect! I’m sure many of you have your own horror stories of having to unravel convoluted scripts, project settings, compiler bugs, etc. in order to get code to build, despite the project requirements seeming to be relatively simple. If you work with cross-platform software, this is probably a pain point you are particularly familiar with. This article demonstrates some more recent features of CMake which greatly reduce that pain.
Specifying target dependencies
If you are using CMake to control your builds, then versions 2.8.11 and later have added some very useful features which make specifying dependencies between build targets much simpler and more robust. Instead of carrying around compiler flags, linker options, header search paths, etc. in CMake variables, you can now attach that information directly to the targets themselves and let CMake add them as needed for anything that links to that target. This greatly simplifies projects, especially those with a large number of target dependencies spread across multiple directories.
The most relevant commands that have been added or extended to support these features are the following:
- target_compile_definitions
- target_compile_options
- target_include_directories
- target_link_libraries
These commands all follow a similar pattern:
target_XXX_YYY(targetName
[PUBLIC ...]
[PRIVATE ...]
[INTERFACE ...]
)
Things specified as PUBLIC
will apply to both targetName
and anything that links to it. PRIVATE
specifies things that only apply to targetName
, meaning anything that links to it doesn’t need to know about it. INTERFACE
applies only to targets that link to targetName
but which are not needed by targetName
itself.
A concrete example best demonstrates how these commands and keywords are used. Let’s say we have a project with some libraries which make use of an external package, Boost:
- Static library
foo
will use Boost features internally when theuseBoost
pre-processor symbol is defined, but does not expose anything related to Boost in its interface. When enabled, Boost libraries need to be linked in for any target usingfoo
. - Shared library
bar
always uses parts of Boost which only require its headers but do not require Boost libraries to be linked in. - Library
gumby
does not use Boost in any way, but it usesfoo
internally and it also uses parts ofbar
in its own public interface.
We can define these libraries as follows:
# Let CMake find Boost for us.
# Details omitted for brevity.
find_package(Boost ...)
# Basic definition of library targets
add_library(foo STATIC foo.cpp)
add_library(bar SHARED bar.cpp)
add_library(gumby gumby.cpp)
# Dependency details for the libraries
target_compile_definitions(foo
PRIVATE useBoost=true
)
target_link_libraries(foo
INTERFACE ${Boost_LIBRARIES}
)
target_include_directories(bar
PUBLIC ${Boost_INCLUDE_DIRS}
)
target_link_libraries(gumby
PRIVATE foo
PUBLIC bar
)
Now if we have other targets which need to link against these libraries, even if those targets are in different directories, it is trivial to do so and CMake will take care of the dependencies for us.
add_executable(appA appA.cpp)
target_link_libraries(appA foo)
add_executable(appB appB.cpp)
target_link_libraries(appB gumby)
In the above, we only explicitly link appA
against the static library foo
. The dependencies we set up for foo
, however, will ensure that appA
is also linked against the Boost libraries.
For appB
, we only specified that it should link against gumby
, but CMake will also do the following for us automatically:
- Add
bar
to the linked in libraries becausebar
is aPUBLIC
dependency ofgumby
. - Add the Boost header search paths when compiling
appB.cpp
because they are aPUBLIC
dependency ofbar
. - Add Boost libraries to those linked in because
foo
is a dependency ofgumby
. Even though this is aPRIVATE
dependency, CMake still honours the requirement that anything linking tofoo
must also link to the Boost libraries.
Real world example: Qt
The above example was fairly contrived to show how the CMake commands are used. In practice, targets may be defined in different directories or come from entirely separate third-party projects. A particularly powerful example of how the above CMake features can be exploited to very good effect is the way they are used with recent Qt versions. Qt has a number of different modules, each one requiring its own header search paths, libraries to be linked and pre-processing symbols to be defined, with a lot of this information varying from platform to platform. In the past, these things all had to be specified via CMake variables and they were awkward to use for multiple targets which used different Qt modules. Using the new target dependency commands, it is now just a simple matter of linking to the required Qt modules and CMake takes care of the rest. For example:
# List the Qt modules required by any target
find_package(QtNetwork REQUIRED)
find_package(QtGui REQUIRED)
# Create some executable targets
add_executable(consoleApp ...)
add_executable(openGLApp WIN32 ...)
# Make each executable depend only on the
# Qt modules they need
target_link_libraries(consoleApp
Qt5::Network
)
target_link_libraries(openGLApp
Qt5::Network
Qt5::Gui
)
Those two target_link_libraries
commands hide a great deal of dependency information that we mere mortals do not need to know about. We just want our targets to be able to use those Qt modules and not have to care about the details. Behind the scenes, these commands will add header search paths, compiler flags and other Qt libraries and system libraries required by the Qt module(s) that we did actually specify. In the case of openGLApp
, it even handles adding a special static library (qtmain
) which is only required for Windows GUI Qt applications. Furthermore, the above shows how two different targets can use different sets of Qt modules. Those developers who have worked with Qt prior to CMake 2.8.11 will appreciate just how much simpler this is compared to before!
For the interested reader, a more complete description of using CMake with Qt5 is now maintained as part of Qt itself.
- CMake targets with detailed dependencies
- CMake/Tutorials/Exporting and Importing Targets
- JVM detailed test case with code
- Multiple Render Targets in OpenGL with Cg
- Targets
- CMake Error install TARGETS given unknownn argument "INCLUDES"
- Compile TensorFlow with CMake
- ShaderSimpler(9) : Deferred shading with Multiple Render Targets
- Adding Jar Files With Dependencies And Modules
- Mysql install failed with dependencies error
- Build with CMake in Eclipse
- LINK_LIBRARIES: Targets may link only to libraries. CMake is dropping the item.
- Targets may link only to libraries. CMake is dropping the item.
- CMake Error: TARGETS given no LIBRARY DESTINATION for shared library target
- CMake错误: Imported targets not available for * version, Could NOT find *, ... 解决
- Dependencies
- CMake with Eclipse:UNIX Makefile Generator
- Using OpenCV with gcc and CMake
- java排序之 --- 快速排序
- ThinkPHP3.2设置404跳转页面
- tomcat配置Https
- 逆流而上读书笔记1
- Jedis操作Redis--String类型
- CMake targets with detailed dependencies
- 对fork()函数的一点理解
- 第二次迭代总结
- 【SpringMVC】控制器
- Boost.Asio技术文档
- python3 学习杂记(及首篇博客)
- Linux内核学习笔记——进程管理
- string的查找和替换
- 装箱拆箱