[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