it’s not clear to me why you are trying to do this multiple project thing…I mean why not just?:
project(myrepo) add_subdirectory(util) add_subdirectory(tool) add_subdirectory(app) and then if you only want to build util for instance: cd build && cmake .. && cmake --build . --target=util is there some other reason using the targets generated by the project doesn’t work for you? -Mike > On Aug 12, 2018, at 5:45 AM, Mateusz Zych <[email protected]> wrote: > > Hi, I'm trying to understand what's the recommended way of > implementing CMake build system in the following repository: > > repo > | > |___ util > | |___ include > | | |___ util > | | |___ util.h > | | > | |___ source > | | |___ util.cpp > | | > | |___ CMakeLists.txt > | > |___ tool > | |___ include > | | |___ tool > | | |___ tool.h > | | > | |___ source > | | |___ tool.cpp > | | > | |___ CMakeLists.txt > | > |___ app > |___ app.cpp > | > |___ CMakeLists.txt > > Essentially this repo contains static library util, shared library tool and > executable app. > > Both executable app and shared library tool depend on static library util, > but they don't depend on each other. > This can be represented by dependency graph like so: > > app tool > | | > | | > V V > util > > The reason why static library util is placed in the root of repo, > is the fact that it's shared by both executable app and shared library tool. > > Writing //repo/util/CMakeLists.txt is very easy: > > cmake_minimum_required(VERSION 3.11) > > project(util) > > add_library(util STATIC) > target_sources(util PRIVATE include/util/util.h > source/util.cpp) > target_include_directories(util PUBLIC include) > > However, implementing //repo/tool/CMakeLists.txt > > cmake_minimum_required(VERSION 3.11) > > # no project definition > > add_library(tool SHARED) > target_sources(tool PRIVATE include/tool/tool.h > source/tool.cpp) > target_include_directories(tool PUBLIC include) > target_link_libraries(tool PRIVATE util) > > and //repo/app/CMakeLists.txt is more challenging. > > cmake_minimum_required (VERSION 3.11) > > # no project definition > > add_executable(app) > target_sources(app PRIVATE app.cpp) > target_link_libraries(app PRIVATE util) > > I understand CMake project as a set of targets, which are standalone (can be > built by themselves). > Source: > https://stackoverflow.com/questions/26878379/in-cmake-what-is-a-project > > This meas that I can define project util consisting of one target (static > library util), > because target util doesn't have any dependencies, meaning it's standalone. > Unfortunately defining project tool and project app is problematic, > because executable app and shared library tool do depend on static library > util. > > I found two solutions to this issue, but neither seems "correct" to me: > > 1. Create //repo/CMakeLists.txt and define project repo which will add util, > tool and app as sub-directories. > > cmake_minimum_required(VERSION 3.11) > > project(repo) > add_subdirectory(util) > add_subdirectory(tool) > add_subdirectory(app) > > This is the cleanest solution, but it has a serious drawback of not defining > project app and project tool, > which could be built independently from each other. > > I thought that I will be able to mitigate this issue by > defining multiple projects in //repo/CMakeLists.txt each with its own > separate set of targets. > > cmake_minimum_required(VERSION 3.11) > > project(tool) > add_subdirectory(util) > add_subdirectory(tool) > > project(app) > add_subdirectory(util) > add_subdirectory(app) > > project(repo) > add_subdirectory(util) > add_subdirectory(tool) > add_subdirectory(app) > > This is not possible, since one CMakeLists.txt can define only single project > and > calling add_subdirectory() twice on the same directory is an error. > I believe these constraints arise from the fact that > CMake projects are not providing any scoping / grouping mechanism for targets. > Source: https://cmake.org/pipermail/cmake/2009-June/030188.html > > It is possible to create W/A mitigating this issue, > by using if(), elseif() and else() commands in //repo/CMakeLists.txt, > but this solution looks to me like an awful hack. > > cmake_minimum_required(VERSION 3.11) > > if(TOOL) > project(tool) > add_subdirectory(util) > add_subdirectory(tool) > elseif(APP) > project(app) > add_subdirectory(util) > add_subdirectory(app) > else() > project(repo) > add_subdirectory(util) > add_subdirectory(tool) > add_subdirectory(app) > endif() > > Making matters worse this approach requires global handling of > sub-directories in a project, > meaning that knowledge of the whole dependency graph is required to add > sub-directories in correct order. > This breaks down the most desirable properties of modern CMake - modularity > and isolation of targets. > > 2. Define project as a self-containing set of targets by adding > sub-directories were they are required. > > In this approach //repo/tool/CMakeLists.txt would add upper directory util > by defining not only source directory, but also binary directory. > > cmake_minimum_required(VERSION 3.11) > > project(tool) > add_subdirectory(../util util) > > add_library(tool SHARED) > target_sources(tool PRIVATE include/tool/tool.h > source/tool.cpp) > target_include_directories(tool PUBLIC include) > target_link_libraries(tool PRIVATE util) > > Using the exact same technique //repo/app/CMakeLists.txt would also add upper > directory util. > > cmake_minimum_required (VERSION 3.11) > > project(app) > add_subdirectory(../util util) > > add_executable(app) > target_sources(app PRIVATE app.cpp) > target_link_libraries(app PRIVATE util) > > This approach allows each project to be stand-alone, > because all sub-directories required by targets directly defined by that > project are added directly in place. > > This is huge advantage compared to the first solution, > because project is responsible only for adding sub-directories, > which are required by direct dependencies of targets defined directly in that > project. > > All sub-directories required for satisfying project's indirect dependencies > will be added automatically by projects defining targets, > which are direct dependencies of targets defined directly in that project. > > For example, if target util would depend on target foo, > then in project util sub-directory foo would be added to satisfy that > dependency. > > cmake_minimum_required(VERSION 3.11) > > project(util) > add_subdirectory(../foo foo) > > add_library(util STATIC) > target_sources(util PRIVATE include/util/util.h > source/util.cpp) > target_include_directories(util PUBLIC include) > target_link_libraries(util PRIVATE foo) > > So in case of app project util sub-directory would be added first, > then foo sub-directory would be added by the util project. > Effectively adding sub-directory will create a cascade of add_subdirectory() > commands, > meaning that sub-directories would be added transitively. > > This approach doesn't require knowledge of the whole dependency graph - just > direct dependencies are needed to be known. > Now targets can be modular and isolated, which is what modern CMake is all > about. > > > Unfortunately this approach has major flaw - it doesn't allow sharing > libraries between targets. > It's a trap giving false illusion, that knowledge of whole dependency graph > is not required. > > Consider adding repo project in //repo/CMakeLists.txt. > > cmake_minimum_required(VERSION 3.11) > > project(repo) > add_subdirectory(tool) > add_subdirectory(app) > > This will immediately fail, > because directory util will be added twice - first time by project tool and > second time by project app. > Essentially in this approach projects cannot share libraries, > because it is required to control globally how sub-directories are added to > make sure that they are added exactly once. > > Considering that both solutions feels like complete failures, > what is recommended way of implementing CMake build system in described > repository? > > Am I missing something or CMake legitimately lacks mechanisms for handling > this case properly? > Honestly it's hard to believe that CMake would lack support for this case, > considering this is such a widely used and flexible build system. > > I would really appreciate help with solving this issue. :-) > Thank you, Mateusz Zych > -- > > 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: > https://cmake.org/mailman/listinfo/cmake
signature.asc
Description: Message signed with OpenPGP
-- 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: https://cmake.org/mailman/listinfo/cmake
