[cmake-developers] Tools for handling cross project dependencies

Egor Pugin egor.pugin at gmail.com
Tue Oct 3 05:45:41 EDT 2017


I see now.
>From my POV if you link opencv to your target, opencv implicitly
provides all necessary deps not you. I.e. opencv -> tiff, tiff ->
zlib. This is usual CMake workflow, isn't it?
But you are managing these deps manually, so have to choose an order.


On 3 October 2017 at 01:20, Raffi Enficiaud
<raffi.enficiaud at mines-paris.org> wrote:
> Le 02.10.17 à 18:06, Egor Pugin a écrit :
>>
>> Sorry, maybe I did not understand you correctly, but why do you need
>> some order of 'add_subdirectory'?
>
>
> I am not sure to understand why you are asking this, please let me know if I
> am off-topic :)
>
> I have say libOpenCV, libTIFF and libZ. libTIFF depends on libZ, libOpenCV
> depends on libTIFF and libZ.
>
> libTIFF and libZ are doing some magic, say they compile from source or if
> those libraries are available from the OS, they just include the system
> libraries as imported targets.
>
> In a project, I would like to link to libOpenCV, I know it depends on
> libTIFF and libZ, but I do not know if there is any dependencies between
> those libTIFF and libZ.
>
> I know that I should do an add_subdirectory(libOpenCV) and before that, do
> an add_subdirectory of libTIFF and libZ. Depending on the orders of the
> add_subdirectory, I would be able to compile or not libTIFF and subsequently
> libOpenCV.
>
> This should work:
>
> """""
> add_subdirectory(libZ)
> add_subdirectory(libTIFF)
> add_subdirectory(libOpenCV)
> """""
>
> and this should not work
> """""
> add_subdirectory(libTIFF)
> add_subdirectory(libZ)
> add_subdirectory(libOpenCV)
> """""
>
> (because the declaration of the libTIFF targets make implicit reference to
> headers and shared/static library of libZ.)
>
> So in a "superproject" (the one that is making the 3 calls to
> add_subdirectory above), there is an implicit orchestration/ordering of the
> add_subdirectory commands, and I would somehow like to encode this within
> CMake and without any other tool.
>
> Of course, in this very naive and simplified example, it is easy to address,
> but this does not scale up efficiently. Somehow, there is a need to encode
> the graph of dependencies, and to inject that graph into CMake.
>
> This is what I suggest to do: discuss about the interest and the "protocol"
> for encoding such a graph, and what type of information which should carry
> in the graph (nodes and arrows).
>
>> Cppan knows from config (yaml) files what deps must be included and
>> just adds them one by one. If they're already in the tree, include
>> guard prevents second use.
>
>
> Right, but there is also an explicit order in your YAML files, isn't it? I
> have to say I have not look very deeply.
>
>> One rule is not to have cyclic deps.
>
>
> Yes, the dependencies should form a Directed Acyclic Graph, otherwise we
> have troubles. This can be checked also very easily.
>
>
>>> In summary (correct me if I am wrong) what this does is (in some pseudo
>>> code):
>>
>>
>> Correct pseudo code for cppan:
>> ---
>> if (TARGET t1)
>>   return
>>
>> include(d1) # include file has i. guard
>> include(d2) # cannot use add_subdirectory directly
>> ...
>>
>> declare t1
>> target_deps t1 d1 d2 ...
>> ---
>
>
> Also in a more complicated settings, you can certainly have the targets
> defined by
> d1/d2 sourced by another CMakeLists.txt (say libZ used for target t1=OpenCV
> and target
> t2=libYAML, those being on different CMakeLists.txt).
>
> You address this by adding an include guard.
> As a matter of facts, include guards are inducing a topological sort on the
> order
> of the targets declaration (roughly speaking "include guards=an
> implementation of topological sort").
>
> Having access to the dependency graph is however providing a richer
> information and ease
> of maintenance, and I am pretty sure this can find many different use cases
> (outside of mine of course).
>
> For example:
>
> * being agnostic to the overall directory layout: in your example you only
> care about the
>   targets d1/d2 being declared, not the file/location of their declaration
> (while the include
>   directive enforces some directory layout)
> * detect cyclic dependencies
> * easy filtering of include or add_subdirectory calls, based on the
> selection of specific
>   targets (only the direct and indirect parents of the selected target are
> included in the project,
>   which is easy to do if we have access to the dependency graph)
> * generated installation package dependency declaration (the debian packages
> extract the
>   direct dependencies from this graph)
> * etc...
>
> I hope I clarified better the problems I am trying to address,
>
> Best,
> Raffi
>
>
>> On 2 October 2017 at 16:10, Raffi Enficiaud
>> <raffi.enficiaud at mines-paris.org> wrote:
>>>
>>> Le 27.09.17 à 19:10, Egor Pugin a écrit :
>>>>>
>>>>>
>>>>> The idea is to include several "packages" (one package ~ one project in
>>>>> Boost) and make those available to the build, exactly as for a regular
>>>>> CMakeLists.txt that adds several directories or subprojects through a
>>>>> sequence of calls to "add_directories".
>>>>> However, the difference here is that "packages" have
>>>>> inter-dependencies,
>>>>> and the order of the "add_directories" should honor those dependencies.
>>>>
>>>>
>>>>
>>>> I solved the issue of including several dirs (via 'add_directories')
>>>> using guards 'if (TARGET name); return(); endif()' in my pkg manager.
>>>> See boost libraries there: https://cppan.org/search?q=boost
>>>> Each library can be included to project separately with autoincluding
>>>> required deps for it.
>>>
>>>
>>>
>>> Hi,
>>>
>>> Thank you for your answer. What you did with CPAN is wonderful, but I
>>> think
>>> this much more than what my humble scripts are trying to address.
>>>
>>> Also the guard mechanism does not really address the issue of ordering
>>> the
>>> add_directories in some topological order. In particular, you guard
>>> because
>>> you do not want to declare several times the same target, but it does not
>>> tell when to include any other dependencies your target may have.
>>>
>>> In summary (correct me if I am wrong) what this does is (in some pseudo
>>> code):
>>>
>>> ---------
>>> if(target1, target2 ... already defined)
>>>   return
>>>
>>> declare target1, target2 ...
>>> target_dependencies target1, target1.1, target1.2 ...
>>> target_dependencies target2, target2.1, target2.2 ...
>>> ---------
>>>
>>> but it does not tell when to declare target1.1, target1.2 ... and this
>>> knowledge should be encoded somewhere else in your scripts.
>>>
>>> Best,
>>> Raffi
>>>
>>>
>>>
>>> --
>>>
>>> Powered by 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-developers
>>
>>
>>
>>
>
>
> --
>
> Powered by 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-developers



-- 
Egor Pugin


More information about the cmake-developers mailing list