[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