Where should find_package be called in CMakeLists.txt?
Asked Answered
D

2

7

Including external libraries in a cmake project is usually performed using find_package().

But in a large multi-application / multi-library project, it is typical for some 3rd-party and/or system libraries to be used by multiple applications and libraries.

Where should find_package() for these common libraries be called?

  1. In the CMakeLists.txt file for each executable/library that needs them?
  2. Or, once in a top-level CMakeLists.txt file?

The first options seems to be a more modular approach, but the associated find_package() scripts are executed for each library/executable that uses them. This can slow down the configuration step.

The second option is more efficient, but looks a bit too much like a global variable to me.

Dispassion answered 12/7, 2018 at 6:10 Comment(2)
I think it should go in the top-level CMakeLists.txt, and then they should be used with something like target_link_libraries(my_exe PUBLIC Boost::system)Spermic
Sounds like "opinion-base" question for me. Second and futher invocations of find_package for the same package usually takes a little time, because it does not search again but reuses cached results from the first invocation. So in case of per-directory invocation of find_package perfomance needn't neccessary to be a problem. (But, as usual with performance, one should measure it before draw the conclusions.)Cetus
M
2

I would distinguish between subprojects/-directories that might be standalone packages on their own (or already are) and those that exclusively reflect the source code structure.

  • In the first case, find_package should clearly be in the subdirectory CMakeLists.txt to allow for extracting the subdirectory for a standalone build or distribution. Inefficiency of the configuration step should not be a concern here, as the configuration of a build is not performed that often.

  • In the second case, I would prefer find_package calls in the toplevel CMakeLists.txt. If you don't use the variables set by these calls to populate global variables but use target_link_libraries instead (as suggested in the comments), this should be clean enough. Sometimes though, found packages do not export proper targets to link against, but rather define some include path variables and the like. Then, it should be easy to define your own INTERFACE library that encapsulate these flags/paths as usage requirements and propagate them transitively when linked via target_link_libraries again.

Maggot answered 12/7, 2018 at 7:22 Comment(3)
It doesn't seem to work for me... When I do a find_package in the top level CMakeLists.txt it gets found, but the target then appears unknown in subdir/CMakeLists.txt.Vienna
@CarloWood And have you made sure that find_package is invoked before you add_subdirectory subdir/CMakeLists.txt?Maggot
I figured it out: a find_package must appear in every CMakeLists.txt that explicitly uses the target. Aka, if foo/CMakeLists.txt uses bar::bar then foo/CMakeLists.txt must do a find_package(bar). There is no way to do it elsewhere. With 'uses' I mean you type it out. If it gets linked in as a dependency of something else then there is no need for the find_package.Vienna
I
0

Invoke find_package in the CMakeFiles.txt file in which the package is referenced. References might include

Following similar principles such as Include What You Use and Keep scopes small, you should aim to ensure that software items are:

  • Cohesive: the package is used in that CMakeLists.txt file, so finding the package belongs there too. This brings modularity and makes it easier to relocate or reuse the file, and to see more easily what packages it uses.
  • Uncoupled: distant CMakeLists.txt files don't depend on one another in ways which might be surprising or puzzling. This makes it easier to change one CMakeLists.txt without breaking functionality in another.

Note that while this approach is more robust, scalable and maintainable, it's at least as verbose and onerous to follow. If you prefer to list packages in the root CMakeLists.txt instead, then at least be consistent and find them all there together.

Ire answered 2/10, 2024 at 13:11 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.