[CMake] How do you handle recursive dependencies in CMake

Sven Baars s.baars at rug.nl
Tue Jun 28 09:07:19 EDT 2016


Hey Cfyz,

After reading your post to the list, it does indeed seem like we have
the same problem. I also wrote a lot of homebrew code you mentioned at
the end of the post, but it indeed always seems to always break
something for some user of the code, even though it seems to work for
everyone else. Hence my question if there is some "right" way of doing
this with CMake, without all of the code I wrote to work around the problem.

In the mean time I'll have a look at the code you wrote, but it seems
very similar to something I already had, which broke for some users.

Sven

On 06/28/2016 02:35 PM, Cfyz wrote:
> Hello.
>
> I've posted a message a few days ago on a very similar subject. Didn't
> know there was a discussion already.
>
> The main problem in my opinion is that CMake target exporting system
> does not handle transitive dependencies at all. CMake handles them
> correctly at the build step, but not at the export. As I've noted in
> my message there is a small hint on that being a conscious decision:
> documentation about target_link_libraries and relevant target
> properties advises not to include paths to dependencies into the
> target interface as it would hard-code dependencies' locations.
> Personally I do not agree with that as I see neither any way around
> specifying paths to dependencies not any substantial harm in that.
> Maybe I am missing something but as far as I've found there was not
> discussion about this matter before.
>
> With that there are some ways to make transitive dependencies work.
> Though you'll have to forsake most of CMake's export machinery.
> Probably the easiest way is to make each library export it's full
> interface in the Foo_INCLUDE_DIRS / Foo_LIBRARIES variables. By
> writing the AConfig.cmake by hand you can figure out and export the
> full path to the A. Therefore AConfig.cmake will essentially be:
>
>   get_filename_component(A_CONFIG_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
>   find_library(A_LIB "A" HINTS ${A_CONFIG_DIR}/../../../lib)
>   set(A_INCLUDE_DIRS ${A_CONFIG_DIR}/../../../include)
>   set(A_LIBRARIES ${A_LIB})
>   set(A_FOUND TRUE)
>
> From here on, every other library which care about its dependencies
> will have to export its interface in a similar way. However, since
> BConfig.cmake cannot find A by itself, it will need some help from the
> project configuration step. B project will need to gather its
> interface and do a configure_file() fixing B's interface dependencies
> in it:
>
>   find_package(A)
>   list(APPEND B_INTERFACE_INCLUDE_DIRS ${A_INCLUDE_DIRS})
>   list(APPEND B_INTERFACE_LIBRARIES ${A_LIBRARIES}) # here comes the
> full path to A library
>   ...
>   configure_file(BConfig.cmake.in <http://BConfig.cmake.in>
> ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/BConfig.cmake @ONLY)
>
> Where BConfig.cmake.in <http://BConfig.cmake.in> may look like:
>
>   get_filename_component(B_CONFIG_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
>   find_library(B_LIB "B" HINTS ${B_CONFIG_DIR}/../../../lib)
>   set(B_INCLUDE_DIRS ${B_CONFIG_DIR}/../../../include
> @B_INTERFACE_INCLUDE_DIRS@)
>   set(B_LIBRARIES ${B_LIB} @B_INTERFACE_LIBRARIES@)
>   set(B_FOUND TRUE)
>
> Now find_package(B) will export B_INCLUDE_DIRS / B_LIBRARIES which
> will list full paths to everything necessary to build against it.
>
> At my company we usually use static libraries so that it's rarely a
> problem but with dynamic libraries (.so) this approach will not be
> enough to run the app. Searching for dynamic libraries is not exactly
> the build system responsibility, though and greatly depends on the
> platform and the way you distribute the resulting application. If
> anything it always possible to make another transitive Foo_RPATHS
> property.
>
> This 'simple' approach does not work with libraries that export
> 'imported targets' only (if I recall correctly, the Qt find module
> exports Qt::XYZ targets but not Qt_LIBRARIES) so that there is no
> interface variables to merge. In this case one would need to iterate
> over imported targets and merge their INTERFACE_xxx properties in a
> similar way.
>
> I believe this to be an oversight. Everything should be fine if there
> was an option to resolve and export transitive dependencies along the
> targets in CMake export() command. Probably this may be fixed by an
> external helper script (similar to CMakePackageConfigHelpers module)
> providing some function that takes a list of targets, analyzes them
> and writes a config file complete with targets and their dependencies.
>
> On 28 June 2016 at 13:35, Sven Baars <s.baars at rug.nl
> <mailto:s.baars at rug.nl>> wrote:
>
>     Hey Ray,
>
>     Project A is used by many projects, and so is project B. So
>     ExternalProject is not the right solution. I just want to be able
>     to fix
>     project B in such a way that people, including myself, can easily
>     use it
>     without knowledge of where project A is located. The packages will all
>     be used mostly on supercomputers, where users never have rights to
>     install anything, and even if they install them as a module, it is
>     still
>     in a non-standard path. As you can see from the example, this
>     works fine
>     for project B which depends on A, but not for project C which
>     depends on
>     B. Even if you set the PATH correctly.
>
>     Sven
>
>     On 06/28/2016 12:25 PM, Raymond Wan wrote:
>     > Hi Sven,
>     >
>     >
>     > On Tue, Jun 28, 2016 at 6:03 PM, Sven Baars <s.baars at rug.nl
>     <mailto:s.baars at rug.nl>> wrote:
>     >> The packages I use are installed in a non-standard path,
>     because I don't
>     >> have access to the system directories on most systems I work
>     on, but are
>     >> used by many other libraries. They are also all separate
>     packages, not
>     >> packages in the same source tree. I did not see my attachment
>     on the
>     >> mailing list archive, so instead I just put it on Github. It can be
>     >> found here:
>     >>
>     >> https://github.com/Sbte/cmake-example
>     >>
>     >> I hope the example shows my workflow, and also what doesn't
>     work for me.
>     >
>     > Hmmmm, in that case, I should probably remain quiet as this is not
>     > quite something I've had to do.
>     >
>     > Maybe the only advice I can give is, if you plan to distribute your
>     > work to others, what are your expectations in terms of where do you
>     > think users should install these dependencies.
>     >
>     > For example, if it's a system-level directory, then maybe you can
>     > consider a FIND_PACKAGE solution which has a list of default
>     paths to
>     > search.  When you're developing on your own computer, you just
>     change
>     > the default path to include paths in your home directory.
>     >
>     > There is also the ExternalProject () directive which you could
>     > consider
>     [https://cmake.org/cmake/help/v3.3/module/ExternalProject.html]
>     > .  This would retrieve the dependencies from outside sources (i.e.,
>     > repositories) and build them.  This would keep everything within the
>     > same build/ path and I haven't done that (and didn't mention it
>     > before) because all of my packages are within the same source tree.
>     >
>     > So, still not quite your situation, though.
>     >
>     > I hope this helps!  Perhaps others can chime in and help you with
>     > exactly what you're stuck with...
>     >
>     > Ray
>
>     --
>
>     Powered by www.kitware.com <http://www.kitware.com>
>
>     Please keep messages on-topic and check the CMake FAQ at:
>     http://www.cmake.org/Wiki/CMake_FAQ
>
>     Kitware offers various services to support the CMake community.
>     For more information on each offering, please visit:
>
>     CMake Support: http://cmake.org/cmake/help/support.html
>     CMake Consulting: http://cmake.org/cmake/help/consulting.html
>     CMake Training Courses: http://cmake.org/cmake/help/training.html
>
>     Visit other Kitware open-source projects at
>     http://www.kitware.com/opensource/opensource.html
>
>     Follow this link to subscribe/unsubscribe:
>     http://public.kitware.com/mailman/listinfo/cmake
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/cmake/attachments/20160628/b8304e4e/attachment-0001.html>


More information about the CMake mailing list