Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting imported targets through `find_package`?

Tags:

cmake

The CMake manual of Qt 5 uses find_package and says:

Imported targets are created for each Qt module. Imported target names should be preferred instead of using a variable like Qt5<Module>_LIBRARIES in CMake commands such as target_link_libraries.

Is it special for Qt or does find_package generate imported targets for all libraries? The documentation of find_package in CMake 3.0 says:

When the package is found package-specific information is provided through variables and Imported Targets documented by the package itself.

And the manual for cmake-packages says:

The result of using find_package is either a set of IMPORTED targets, or a set of variables corresponding to build-relevant information.

But I did not see another FindXXX.cmake-script where the documentation says that a imported target is created.

like image 821
JojOatXGME Avatar asked Mar 05 '16 15:03

JojOatXGME


2 Answers

find_package is a two-headed beast these days:

CMake provides direct support for two forms of packages, Config-file Packages and Find-module Packages

Source

Now, what does that actually mean?

Find-module packages are the ones you are probably most familiar with. They execute a script of CMake code (such as this one) that does a bunch of calls to functions like find_library and find_path to figure out where to locate a library.

The big advantage of this approach is that it is extremely generic. As long as there is something on the filesystem, we can find it. The big downside is that it often provides little more information than the physical location of that something. That is, the result of a find-module operation is typically just a bunch of filesystem paths. This means that modelling stuff like transitive dependencies or multiple build configurations is rather difficult.

This becomes especially painful if the thing you are trying to find has itself been built with CMake. In that case, you already have a bunch of stuff modeled in your build scripts, which you now need to painstakingly reconstruct for the find script, so that it becomes available to downstream projects.

This is where config-file packages shine. Unlike find-modules, the result of running the script is not just a bunch of paths, but it instead creates fully functional CMake targets. To the dependent project it looks like the dependencies have been built as part of that same project.

This allows to transport much more information in a very convenient way. The obvious downside is that config-file scripts are much more complex than find-scripts. Hence you do not want to write them yourself, but have CMake generate them for you. Or rather have the dependency provide a config-file as part of its deployment which you can then simply load with a find_package call. And that is exactly what Qt5 does.

This also means, if your own project is a library, consider generating a config file as part of the build process. It's not the most straightforward feature of CMake, but the results are pretty powerful.

Here is a quick comparison of how the two approaches typically look like in CMake code:

Find-module style

find_package(foo)
target_link_libraries(bar ${FOO_LIBRARIES})
target_include_directories(bar ${FOO_INCLUDE_DIR})
# [...] potentially lots of other stuff that has to be set manually

Config-file style

find_package(foo)
target_link_libraries(bar foo)
# magic!

tl;dr: Always prefer config-file packages if the dependency provides them. If not, use a find-script instead.

like image 82
ComicSansMS Avatar answered Nov 17 '22 22:11

ComicSansMS


Actually there is no "magic" with results of find_package: this command just searches appropriate FindXXX.cmake script and executes it.

If Find script sets XXX_LIBRARY variable, then caller can use this variable.

If Find script creates imported targets, then caller can use these targets.

If Find script neither sets XXX_LIBRARY variable nor creates imported targets ... well, then usage of the script is somehow different.

Documentation for find_package describes usual usage of Find scripts. But in any case you need to consult documentation about concrete script (this documentation is normally contained in the script itself).

like image 5
Tsyvarev Avatar answered Nov 17 '22 22:11

Tsyvarev