[CMake] How do you handle recursive dependencies in CMake

Sven Baars s.baars at rug.nl
Tue Jun 28 05:26:47 EDT 2016


Hey all,

Since I did not receive a reply to my previous mail, I decided to write
a minimal example explaining my problem, where I kept al the names as I
used in my previous mails. I hope that after seeing my example, someone
can explain me what I am doing wrong here. I included a script that
reproduces the problem.

Cheers,
Sven

On 06/10/2016 01:34 PM, Sven Baars wrote:
> 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/20160628/b2ce5753/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: cmake-example.tar.gz
Type: application/gzip
Size: 2096 bytes
Desc: not available
URL: <http://public.kitware.com/pipermail/cmake/attachments/20160628/b2ce5753/attachment-0001.bin>


More information about the CMake mailing list