[CMake] How do you handle recursive dependencies in CMake

Chuck Atkins chuck.atkins at kitware.com
Wed Jun 8 12:07:22 EDT 2016


If the projects are each providing their own Config.cmake file then you
probably will want to use those instead of Find modules.  Instead of using
the Foo_Bar_LIBRARIES variable though, try using the actual imported
targets from the config files.  Those should have the appropriate
dependency information. If you're not sure what they are you should be able
to dig through the provided Config.cmake and Targets.cmake files for FooBar
and see which targets are created bu "add_library(FooBar::Foo ...
IMPORTED)".

- Chuck

On Wed, Jun 8, 2016 at 11:31 AM, Sven Baars <s.baars at rug.nl> wrote:

> In my case all projects provide their own FooBarConfig.cmake, but not a
> FindFooBar.cmake. For this reason I wanted to use those, because I thought
> it saves me the effort of writing a lot of FindFooBar.cmake files, and it
> also seemed like the right way to do it, because it provides things like
> FooBar_LIBRARIES, which is what I need. The reason I said that I create my
> own FooBarConfig.cmake, is because I want to use CMake properly in my own
> project, so I also want to provide a FoorBarConfig.cmake file for my users.
> So even if the projects I use don't do everything properly, I still want to
> do it properly myself. The problem in this case is that I'm not sure what
> the proper way is. If the FoorBarConfig.cmake file is not enough to handle
> the dependencies I encounter, should I provide a FindFooBar.cmake file or
> something, instead of just the FooBarConfig.cmake? And meanwhile also write
> a FindFooBar.cmake file for all my dependencies?
>
> Another reason why this seems odd to me, is because if N different
> projects use FooBar, then also possibly N different versions of
> FindFooBar.cmake are created by all the different projects (I have actually
> already seen this a lot). That is the case, because the FindFooBar.cmake
> file is not provided by the FooBar project, unlike the FooBarConfig.cmake.
>
> Cheers,
> Sven
>
>
> On 06/08/2016 03:11 PM, Chuck Atkins wrote:
>
> The FooBarConfig.cmake is something that should be generated by FooBar's
> build.   The reason you don't get absolute paths for the "libraries" from a
> package config file is that they're not actually libraries but imported
> targets.  The imported target let's you treat "foo" as though it were a
> library built by your project.  It then has the appropriate target
> properties set on it ti define the full path to it's library, etc.  That
> being said, if you're manually creating the FooBarConfig.cmake that's not
> really the right approach.  If the FooBar buil;d doesn't actually generate
> it's own FooBarConfig.cmake file then you'll want to create you're own
> FindFooBar.cmake.  A bare bones find module that creates an imported target
> would look something like this:
>
> if(NOT FooBar_FOUND AND NOT TARGET FooBar::FooBar)
>   find_path(FooBar_INCLUDE_DIR FooBar.h)
>   find_library(FooBar_LIBRARY FooBar)
>
>   include(FindPackageHandleStandardArgs)
>   find_package_handle_standard_args(FooBar
>     FOUND_VAR FooBar_FOUND
>     REQUIRED_VARS FooBar_INCLUDE_DIR FooBar_LIBRARY
>   )
> endif()
>
> if(FooBar_FOUND AND NOT TARGET FooBar::FooBar)
>   add_library(FooBar::FooBar UNKNOWN IMPORTED)
>   set_target_properties(FooBar::FooBar PROPERTIES
>     IMPORTED_LOCATION ${FooBar_LIBRARY}
>     INTERFACE_INCLUDE_DIRECTORIES ${FooBar_INCLUDE_DIR}
>   )
> endif()
>
> Then in your project you can use:
>
> find_package(FooBar)
> add_library(MyLib supercoolfiles.cxx)
> target_libkLibraries(MyLib FooBar::FooBar)
>
> Where this starts to get really helpful in your situation is if you have
> an imported target for A, B, and C, then you can create the appropriate
> dependencies.  Say, for example, you have a FindA.cmake that follows the
> pattern above and generates an A::A target.  Then in your FindB.cmake you
> can have:
>
> if(NOT B_FOUND AND NOT TARGET B::B)
>   find_path(B_INCLUDE_DIR B.h)
>   find_library(B_LIBRARY B)
>
>   include(FindPackageHandleStandardArgs)
>   find_package_handle_standard_args(B
>     FOUND_VAR B_FOUND
>     REQUIRED_VARS B_INCLUDE_DIR B_LIBRARY
>   )
>
>
>
>
> *  find_package(A QUIET)   if(A_FOUND)     set(B_Extra_Deps A::A)
> endif()*
> endif()
>
> if(B_FOUND AND NOT TARGET B::B)
>   add_library(B::B UNKNOWN IMPORTED)
>   set_target_properties(B::B PROPERTIES
>     IMPORTED_LOCATION ${B_LIBRARY}
>     INTERFACE_INCLUDE_DIRECTORIES ${B_INCLUDE_DIR}
>   )
>
>
>
>
> *  if(B_Extra_Deps)     set_target_properties(B::B PROPERTIES
> INTERFACE_LINK_LIBRARIES ${B_Extra_Deps}     )   endif()*
> endif()
>
> and similarly for FindC.cmake.  Since A::A, B::B, and C::C are actual
> proper CMake targets and not just library files then they carry with them
> associated target dependency information.  In CMake vernacular we refer
> this as "target usage requirements" since the target caries with it all the
> necessary information for something to actually use it, whether that's just
> extra link libraries or also extra include directories and compile
> definitions needed.  The Package::Target naming convention is the idea
> that each package has it's own namespace where you may define multiple
> targets.
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/cmake/attachments/20160608/ee080477/attachment.html>


More information about the CMake mailing list