[CMake] How do you handle recursive dependencies in CMake

Sven Baars s.baars at rug.nl
Fri Jun 10 07:34:15 EDT 2016


Hey Chuck,

In ATargets.cmake it says

add_library(a SHARED IMPORTED)

and in BTargets.cmake it says

add_library(b SHARED IMPORTED)

However, if I build C it will say

/usr/bin/ld: cannot find -la

when I do

    find_package(B)
    target_link_libraries(c b)
    add_executable(main main.cpp)
    target_link_libraries(main c)

This, I think, because the 'b' target depends on 'a' but doesn't know
where 'a' is located, because this is not described in BTargets.cmake.

Sven

On 06/08/2016 06:07 PM, Chuck Atkins wrote:
> 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
> <mailto: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/20160610/66c1a1ae/attachment-0001.html>


More information about the CMake mailing list