Modular build system for repository with libraries shared between multiple targets.

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Modular build system for repository with libraries shared between multiple targets.

Mateusz Zych
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).
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 d
epend 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 utiltool 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)

T
his 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.


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
Reply | Threaded
Open this post in threaded view
|

Re: Modular build system for repository with libraries shared between multiple targets.

Michael Ellery
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 <[hidden email]> 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

--

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 (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Modular build system for repository with libraries shared between multiple targets.

Mateusz Zych
Hi Michael, thanks for reply!

Essentially I don't want to artificially couple app executable and tool shared library
by defining repo project with both targets.

I have three main motivations:


1) I want to be able to load into an IDE (for example CLion, Visual Studio, Qt Creator)
only one target that at the time (plus its dependencies).
That way IDE will not have to process code that I'm not interested at the moment,
so I could get very fast code navigation, finding usages, code completion, etc.

For example if I would want to work on util static library in CLion,
I would just load //repo/util/CMakeLists.txt and everything would work great.
However, if I would want to work only on app executable,
I would be forced to load tool shared library, 
because I would point to //repo/CMakeLists.txt.


2) I also want to be able to selectively check out code from repository,
so I won't be forced to download code that I don't need at the moment.

For example if I would want to work on tool shared library,
I don't want to be forced to check out //repo/app from the repository.
I think that checking out //repo/util and //repo/tool should work just fine
(plus or minus //repo/CMakeLists.txt).


3) I want to be able to analyse source code (including CMake source code)
form just part of the repo and be able to have complete knowledge of that part (local reasoning).

For example, if I need to analyse code defining tool shared library,
I have to know that there is another place in the CMake source code (in this case //repo/CMakeLists.txt),
which will add sub-directories with targets satisfying dependencies of tool target (in this case add_subdirectory(util)).

The point is project repo is a global entity, with which every shared target needs to synchronize with.
I know that I presented simple example, but think about repo with large number of projects.
I as a developer need to manually make sure that this global list is defined correctly - it's not something enforced automatically.

It would be much better if each project defining a target with dependencies
would add sub-directories satisfying its dependencies - no global synchronization point needed.
Unfortunately this is not currently possible, since calling add_subdirectory() twice is an error.

To me this situation is very similar to how header files work in C++.
It is not a good idea to write a header file, which requires another header file included before it.
Header files should be stand-alone and I think that similar rule should apply for CMake projects.


I hope my arguments makes sense to you and my motivation is clear.

Thank you, Mateusz Zych

2018-08-13 18:37 GMT+02:00 Michael Ellery <[hidden email]>:
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 <[hidden email]> 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



--

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