<div dir="ltr"><div class="gmail_default" style="font-family:tahoma,sans-serif">Hi Michael, thanks for reply!</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">Essentially <b>I don't want to artificially couple app executable and tool shared library</b><br>by defining repo project with both targets.</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">I have three main motivations:</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">1) I want to be able to load into an IDE (for example CLion, Visual Studio, Qt Creator)<br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">only one target that at the time (plus its dependencies).<br>That way IDE will not have to process code that I'm not interested at the moment,<br>so I could get very fast code navigation, finding usages, code completion, etc.</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">

<span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">For example if I would want to work on util static library in CLion,</span><br style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">I would just load //repo/util/CMakeLists.txt and everything would work great.</span><br style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"><span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">However, if I would want to work only on app executable,<br>I would be forced to load tool shared library, </span><span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">because I would point to //repo/CMakeLists.txt.</span><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">2) I also want to be able to selectively check out code from repository,<br>so I won't be forced to download code that I don't need at the moment.</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">For example if I would want to work on tool shared library,<br>

<span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">I don't want to be forced to check out //repo/app from the repository.<br></span>

<span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">I think that checking out //repo/util and //repo/tool should work just fine<br></span>(plus or minus //repo/CMakeLists.txt).</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">3) I want to be able to analyse source code (including CMake source code)<br>form just part of the repo and be able to have complete knowledge of that part (local reasoning).<br><br>For example, if I need to analyse code defining tool shared library,<br>I have to know that there is another place in the CMake source code (in this case //repo/CMakeLists.txt),<br>which will add sub-directories with targets satisfying dependencies of tool target (in this case add_subdirectory(util)).<br><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">The point is project repo is a global entity, with which every shared target needs to synchronize with.<br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">I know that I presented simple example, but think about repo with large number of projects.<br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">I as a developer need to manually make sure that this global list is defined correctly - it's not something enforced
<span style="font-size:small;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">automatically</span>.</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">It would be much better if each project defining a target with dependencies <br>would add sub-directories satisfying its dependencies - no global synchronization point needed.</div><div class="gmail_default" style="font-family:tahoma,sans-serif">Unfortunately this is not currently possible, since calling add_subdirectory() twice is an error.<br><br>To me this situation is very similar to how header files work in C++.</div><div class="gmail_default" style="font-family:tahoma,sans-serif">It is not a good idea to write a header file, which requires another header file included before it.</div><div class="gmail_default" style="font-family:tahoma,sans-serif">Header files should be stand-alone and I think that similar rule should apply for CMake projects.</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">I hope my arguments makes sense to you and my motivation is clear.</div><div class="gmail_default" style="font-family:tahoma,sans-serif"><br></div><div class="gmail_default" style="font-family:tahoma,sans-serif">Thank you, Mateusz Zych</div></div><div class="gmail_extra"><br><div class="gmail_quote">2018-08-13 18:37 GMT+02:00 Michael Ellery <span dir="ltr"><<a href="mailto:mellery451@gmail.com" target="_blank">mellery451@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">it’s not clear to me why you are trying to do this multiple project thing…I mean why not just?:<br>
<br>
project(myrepo)<br>
add_subdirectory(util)<br>
add_subdirectory(tool)<br>
add_subdirectory(app)<br>
<br>
and then if you only want to build util for instance:<br>
<br>
cd build && cmake .. && cmake --build . --target=util<br>
<br>
is there some other reason using the targets generated by the project doesn’t work for you?<br>
<br>
-Mike<br>
<div><div class="h5"><br>
> On Aug 12, 2018, at 5:45 AM, Mateusz Zych <<a href="mailto:mte.zych@gmail.com">mte.zych@gmail.com</a>> wrote:<br>
> <br>
> Hi, I'm trying to understand what's the recommended way of<br>
> implementing CMake build system in the following repository:<br>
> <br>
> repo<br>
> |<br>
> |___ util<br>
> |    |___ include<br>
> |    |    |___ util<br>
> |    |         |___ util.h<br>
> |    |<br>
> |    |___ source<br>
> |    |    |___ util.cpp<br>
> |    |<br>
> |    |___ CMakeLists.txt<br>
> |<br>
> |___ tool<br>
> |    |___ include<br>
> |    |    |___ tool<br>
> |    |         |___ tool.h<br>
> |    |<br>
> |    |___ source<br>
> |    |    |___ tool.cpp<br>
> |    |<br>
> |    |___ CMakeLists.txt<br>
> |<br>
> |___ app<br>
>      |___ app.cpp<br>
>      |<br>
>      |___ CMakeLists.txt<br>
> <br>
> Essentially this repo contains static library util, shared library tool and executable app.<br>
> <br>
> Both executable app and shared library tool depend on static library util,<br>
> but they don't depend on each other.<br>
> This can be represented by dependency graph like so:<br>
> <br>
> app   tool<br>
>  |    |<br>
>  |    |<br>
>  V    V<br>
>   util<br>
> <br>
> The reason why static library util is placed in the root of repo,<br>
> is the fact that it's shared by both executable app and shared library tool.<br>
> <br>
> Writing //repo/util/CMakeLists.txt is very easy:<br>
> <br>
> cmake_minimum_required(VERSION 3.11)<br>
> <br>
> project(util)<br>
> <br>
> add_library(util STATIC)<br>
> target_sources(util PRIVATE include/util/util.h<br>
>                                   source/util.cpp)<br>
> target_include_directories(<wbr>util PUBLIC include)<br>
> <br>
> However, implementing //repo/tool/CMakeLists.txt<br>
> <br>
> cmake_minimum_required(VERSION 3.11)<br>
> <br>
> # no project definition<br>
> <br>
> add_library(tool SHARED)<br>
> target_sources(tool PRIVATE include/tool/tool.h<br>
>                                   source/tool.cpp)<br>
> target_include_directories(<wbr>tool PUBLIC include)<br>
> target_link_libraries(tool PRIVATE util)<br>
> <br>
> and //repo/app/CMakeLists.txt is more challenging.<br>
> <br>
> cmake_minimum_required (VERSION 3.11)<br>
> <br>
> # no project definition<br>
> <br>
> add_executable(app)<br>
> target_sources(app PRIVATE app.cpp)<br>
> target_link_libraries(app PRIVATE util)<br>
> <br>
> I understand CMake project as a set of targets, which are standalone (can be built by themselves).<br>
> Source: <a href="https://stackoverflow.com/questions/26878379/in-cmake-what-is-a-project" rel="noreferrer" target="_blank">https://stackoverflow.com/<wbr>questions/26878379/in-cmake-<wbr>what-is-a-project</a><br>
> <br>
> This meas that I can define project util consisting of one target (static library util),<br>
</div></div>> because target util doesn't have any dependencies, meaning it's standalone.<br>
<span class="">> Unfortunately defining project tool and project app is problematic,<br>
> because executable app and shared library tool do depend on static library util.<br>
> <br>
> I found two solutions to this issue, but neither seems "correct" to me:<br>
> <br>
> 1. Create //repo/CMakeLists.txt and define project repo which will add util, tool and app as sub-directories.<br>
> <br>
> cmake_minimum_required(VERSION 3.11)<br>
> <br>
> project(repo)<br>
> add_subdirectory(util)<br>
> add_subdirectory(tool)<br>
> add_subdirectory(app)<br>
> <br>
> This is the cleanest solution, but it has a serious drawback of not defining project app and project tool,<br>
> which could be built independently from each other.<br>
> <br>
> I thought that I will be able to mitigate this issue by<br>
> defining multiple projects in //repo/CMakeLists.txt each with its own separate set of targets.<br>
> <br>
> cmake_minimum_required(VERSION 3.11)<br>
> <br>
> project(tool)<br>
> add_subdirectory(util)<br>
> add_subdirectory(tool)<br>
> <br>
> project(app)<br>
> add_subdirectory(util)<br>
> add_subdirectory(app)<br>
> <br>
> project(repo)<br>
> add_subdirectory(util)<br>
> add_subdirectory(tool)<br>
> add_subdirectory(app)<br>
> <br>
</span>> This is not possible, since one CMakeLists.txt can define only single project and<br>
<div><div class="h5">> calling add_subdirectory() twice on the same directory is an error.<br>
> I believe these constraints arise from the fact that<br>
> CMake projects are not providing any scoping / grouping mechanism for targets.<br>
> Source: <a href="https://cmake.org/pipermail/cmake/2009-June/030188.html" rel="noreferrer" target="_blank">https://cmake.org/pipermail/<wbr>cmake/2009-June/030188.html</a><br>
> <br>
> It is possible to create W/A mitigating this issue,<br>
> by using if(), elseif() and else() commands in //repo/CMakeLists.txt,<br>
> but this solution looks to me like an awful hack.<br>
> <br>
> cmake_minimum_required(VERSION 3.11)<br>
> <br>
> if(TOOL)<br>
>       project(tool)<br>
>       add_subdirectory(util)<br>
>       add_subdirectory(tool)<br>
> elseif(APP)<br>
>       project(app)<br>
>       add_subdirectory(util)<br>
>       add_subdirectory(app)<br>
> else()<br>
>       project(repo)<br>
>       add_subdirectory(util)<br>
>       add_subdirectory(tool)<br>
>       add_subdirectory(app)<br>
> endif()<br>
> <br>
> Making matters worse this approach requires global handling of sub-directories in a project,<br>
> meaning that knowledge of the whole dependency graph is required to add sub-directories in correct order.<br>
> This breaks down the most desirable properties of modern CMake - modularity and isolation of targets.<br>
> <br>
> 2. Define project as a self-containing set of targets by adding sub-directories were they are required.<br>
> <br>
> In this approach //repo/tool/CMakeLists.txt would add upper directory util<br>
> by defining not only source directory, but also binary directory.<br>
> <br>
> cmake_minimum_required(VERSION 3.11)<br>
> <br>
> project(tool)<br>
> add_subdirectory(../util util)<br>
> <br>
> add_library(tool SHARED)<br>
> target_sources(tool PRIVATE include/tool/tool.h<br>
>                                   source/tool.cpp)<br>
> target_include_directories(<wbr>tool PUBLIC include)<br>
> target_link_libraries(tool PRIVATE util)<br>
> <br>
> Using the exact same technique //repo/app/CMakeLists.txt would also add upper directory util.<br>
> <br>
> cmake_minimum_required (VERSION 3.11)<br>
> <br>
> project(app)<br>
> add_subdirectory(../util util)<br>
> <br>
> add_executable(app)<br>
> target_sources(app PRIVATE app.cpp)<br>
> target_link_libraries(app PRIVATE util)<br>
> <br>
> This approach allows each project to be stand-alone,<br>
> because all sub-directories required by targets directly defined by that project are added directly in place.<br>
> <br>
> This is huge advantage compared to the first solution,<br>
> because project is responsible only for adding sub-directories,<br>
> which are required by direct dependencies of targets defined directly in that project.<br>
> <br>
> All sub-directories required for satisfying project's indirect dependencies<br>
> will be added automatically by projects defining targets,<br>
> which are direct dependencies of targets defined directly in that project.<br>
> <br>
> For example, if target util would depend on target foo,<br>
> then in project util sub-directory foo would be added to satisfy that dependency.<br>
> <br>
> cmake_minimum_required(VERSION 3.11)<br>
> <br>
> project(util)<br>
> add_subdirectory(../foo foo)<br>
> <br>
> add_library(util STATIC)<br>
> target_sources(util PRIVATE include/util/util.h<br>
>                                   source/util.cpp)<br>
> target_include_directories(<wbr>util PUBLIC include)<br>
> target_link_libraries(util PRIVATE foo)<br>
> <br>
> So in case of app project util sub-directory would be added first,<br>
> then foo sub-directory would be added by the util project.<br>
> Effectively adding sub-directory will create a cascade of add_subdirectory() commands,<br>
> meaning that sub-directories would be added transitively.<br>
> <br>
> This approach doesn't require knowledge of the whole dependency graph - just direct dependencies are needed to be known.<br>
> Now targets can be modular and isolated, which is what modern CMake is all about.<br>
> <br>
> <br>
> Unfortunately this approach has major flaw - it doesn't allow sharing libraries between targets.<br>
> It's a trap giving false illusion, that knowledge of whole dependency graph is not required.<br>
> <br>
> Consider adding repo project in //repo/CMakeLists.txt.<br>
> <br>
> cmake_minimum_required(VERSION 3.11)<br>
> <br>
> project(repo)<br>
> add_subdirectory(tool)<br>
> add_subdirectory(app)<br>
> <br>
> This will immediately fail,<br>
> because directory util will be added twice - first time by project tool and second time by project app.<br>
> Essentially in this approach projects cannot share libraries,<br>
> because it is required to  control globally how sub-directories are added to make sure that they are added exactly once.<br>
> <br>
> Considering that both solutions feels like complete failures,<br>
> what is recommended way of implementing CMake build system in described repository?<br>
> <br>
> Am I missing something or CMake legitimately lacks mechanisms for handling this case properly?<br>
> Honestly it's hard to believe that CMake would lack support for this case,<br>
> considering this is such a widely used and flexible build system.<br>
> <br>
> I would really appreciate help with solving this issue. :-)<br>
> Thank you, Mateusz Zych<br>
</div></div>> --<br>
> <br>
> Powered by <a href="http://www.kitware.com" rel="noreferrer" target="_blank">www.kitware.com</a><br>
> <br>
> Please keep messages on-topic and check the CMake FAQ at: <a href="http://www.cmake.org/Wiki/CMake_FAQ" rel="noreferrer" target="_blank">http://www.cmake.org/Wiki/<wbr>CMake_FAQ</a><br>
> <br>
> Kitware offers various services to support the CMake community. For more information on each offering, please visit:<br>
> <br>
> CMake Support: <a href="http://cmake.org/cmake/help/support.html" rel="noreferrer" target="_blank">http://cmake.org/cmake/help/<wbr>support.html</a><br>
> CMake Consulting: <a href="http://cmake.org/cmake/help/consulting.html" rel="noreferrer" target="_blank">http://cmake.org/cmake/help/<wbr>consulting.html</a><br>
> CMake Training Courses: <a href="http://cmake.org/cmake/help/training.html" rel="noreferrer" target="_blank">http://cmake.org/cmake/help/<wbr>training.html</a><br>
> <br>
> Visit other Kitware open-source projects at <a href="http://www.kitware.com/opensource/opensource.html" rel="noreferrer" target="_blank">http://www.kitware.com/<wbr>opensource/opensource.html</a><br>
> <br>
> Follow this link to subscribe/unsubscribe:<br>
> <a href="https://cmake.org/mailman/listinfo/cmake" rel="noreferrer" target="_blank">https://cmake.org/mailman/<wbr>listinfo/cmake</a><br>
<br>
</blockquote></div><br></div>