[CMake] ADD_SUBDIRECTORY() with a higher level directory

Michael Hertling mhertling at online.de
Sat Nov 5 23:10:37 EDT 2011


On 11/04/2011 02:20 PM, Daniel Dekkers wrote:
> Hi Michael, 
> 
> Thanks for the reply.
> 
> Maybe, we are trying to achieve too many goals at once.
> 
> In our case, what we really want most of all is to show all the examples and
> the lib as independent projects inside a main project (a solution in Visual
> Studio, preferably a workspace in Xcode (but not yet covered by CMake)) in
> the IDE. So we can do a single build and check for failures, in the library
> or the examples. All the sources should be visible and the library project
> should be built first so it can be linked to the examples.
> 
> If I understand you correctly, the easiest way that could be achieved, is
> from a top-level CMakeLists.txt directly in library, so you don't have any
> "reversed-hierarchy" ADD_SUBDIRECTORY() problems. It would just recurse into
> library/src and after that into library/examples, creating PROJECT()'s as it
> goes.
> 
> For distribution of the lib, where people might not want to build all the
> examples, you could introduce a BUILD_EXAMPLES option that is default OFF in
> the CMake GUI... it will then just build the lib.
> 
> So far so good.
> 
> It starts to become more difficult if you want to use the CMakeLists.txt in
> library/examples (and deeper) directly as entry points for the build. But
> maybe, we should just try not to want that.

This is exactly what I would recommend. Let's assume that you want
library/examples/example0/CMakeLists.txt as an entry point for the
configuration. How do you ensure that the library is built before?
A possible approach is

IF(NOT TARGET <library>)
    ADD_SUBDIRECTORY(path/to/library bindir)
ENDIF()

but what is the path/to/library? Without the top-level CMakeLists.txt,
you can't refer to ${CMAKE_SOURCE_DIR}/src, so you would need to say
../../src. Now, imagine that example0 or the library is once moved
within the overall project's source tree; you'd need to adapt *any*
of these ADD_SUBDIRECTORY() commands. That's a typical consequence
of unnecessarily tightly coupled parts of a project, in this case
due to a required backward-inclusion of library/src/CMakeLists.txt.

Is the possibility of a subordinate CMakeLists.txt file as entry point
for the configuration really of such an importance for you? Unless you
have a compelling reason, I'd advise that you configure the project as
usual, i.e. in a top-down manner with exactly one ADD_SUBDIRECTORY()
command for each CMakeLists.txt file, except for the top-level one.
Then, choose a target as entry point for *building*, and as the case
may be, exclude parts of the project from the configuration by use of
options, keeping an eye on the other parts' interdependencies. In this
way, the project will always be configured completely and consistently
with dependencies resolved, but without any fragile constructs in the
CMakeLists.txt files. IMO, this is much more preferrable than setting
up the latters in order to serve as entry points for a configuration.

> What we will need/have later on though, is developers writing their own
> projects, outside the library realm. But I guess, that will need a
> find_package() solution. And.. if they want library as source, they can
> still just ADD_SUBDIRECTORY(path/to/library) themselves in their own
> CMakeLists.txt.
> 
> What keeps mindbugging (is that a word?) me is an awkwardness between
> library as a "bundle" and the hierarchy as a source tree.
> 
> Maybe you would want this:
> 
> librarybundle <- representing the bundle (lib and examples)
> + library <- representing the lib
>   + src <- sources of the lib
> + examples <- representing the examples
>   + example0 <- representing example0
>     + src <- representing sources of example0 
>   + example1 <- representing example1
>     + src <- representing sources of example1
> 
> and not...
> 
> library
> + src
> + examples
>   + example0
>     + src
>   + example1
>     + src
> 
> This gives you some more space (three CMake levels: librarybundle,
> librarybundle/library and librarybundle/library/src) but I don't think
> libraries follow this structure?...

Every project's code base should be organized in the way that suits the
needs best, whatever the needs may be. ;-) E.g., my personal liking for
the general directory hierarchy of a project xyz - library or not - is

xyz
  xyz
  examples
  utilities
  ...

i.e., the project's main part is organized as a sibling of typical
supplementary parts like examples and utilities, and perhaps, one
likes to centralize the tests in another sibling xyz/tests, too.
This approach makes it easier to cope with a growing complexity;
e.g., you do not need to worry where to put the examples if the
main part is about to be split in, say, xyz-{core,gui,net,...}.
In other words: Separate the main part(s) of a project from its
supplementary parts and make the code base reflect this clearly.
Again, that's just my personal taste, and others certainly vary.

Regards,

Michael

PS: Please don't drop the ML.

> -----Oorspronkelijk bericht-----
> Van: cmake-bounces at cmake.org [mailto:cmake-bounces at cmake.org] Namens Michael
> Hertling
> Verzonden: vrijdag 4 november 2011 1:03
> Aan: cmake at cmake.org
> Onderwerp: Re: [CMake] ADD_SUBDIRECTORY() with a higher level directory
> 
> On 11/03/2011 09:10 PM, Daniel Dekkers wrote:
>> Hi,
>>
>> We are creating a directory structure for distribution of an 
>> open-source library with examples included.
>> It looks something like this:
>>
>> + library <- the root directory
>>   CMakeLists.txt <- create context for building (only) the library
>>   + src <- contains the sources of the library
>>     CMakeLists.txt <- actually add sources for (only) the library
>>   + examples
>>     CMakeLists.txt <- create context for building all the examples 
>> (and the library, once)
>>     + example0
>>       CMakeLists.txt <- create context for building example0 (and the
>> library)
>>       + src
>>         CMakeLists.txt <- add sources for example0
>>       + rsrc
>>     + example1
>>       CMakeLists.txt <- create context for building example1 (and the
>> library)
>>       + src
>>         CMakeLists.txt <- add sources for example1 
>>       + rsrc
>>     + ...
>>
>> The CMakeLists.txt in library, library/examples and 
>> library/examples/example0 and library/examples/example1 should all be 
>> possible entry points for a build. Maybe you want to build only the 
>> library, maybe you want to build the whole example suite, or maybe an 
>> individual example.
>>
>> Of course, the CMakeLists.txt in examples (or example0 and example1) 
>> depends on the actual library, so, from that level, we would like to 
>> call
>> ADD_SUBDIRECTORY() to the *higher level* library directory... which is 
>> unacceptable for ADD_SUBDIRECTORY() (and probably conflicts with the 
>> whole CMake structure).
>>
>> If we would move examples "up" the hierarchy there wouldn't be a 
>> problem, but that doesn't give a nice distribution package.
>>
>> Any hints on a proper way to do this?
>>
>> Kind Regards,
>>
>> Daniel Dekkers
> 
> IMO, you should set up your overall project roughly as usual, i.e.:
> 
> library/CMakeLists.txt:
> ADD_SUBDIRECTORY(src)
> ADD_SUBDIRECTORY(examples)
> 
> library/examples/CMakeLists.txt:
> SET_DIRECTORY_PROPERTIES(PROPERTIES EXCLUDE_FROM_ALL TRUE)
> ADD_SUBDIRECTORY(example0)
> ADD_SUBDIRECTORY(example1)
> ...
> ADD_CUSTOM_TARGET(examples)
> ADD_DEPENDENCIES(examples example0 example1 ...)
> 
> library/examples/example0/CMakeLists.txt:
> TARGET_LINK_LIBRARIES(<example0> <library>)
> 
> In this way, you will have all dependencies set up correctly, and the
> examples are not built on behalf of "make" or "make all". In order to build
> them, you might trigger the "examples" target or any individual "example<i>"
> target, or you can jump into a target's directory under- neath
> CMAKE_BINARY_DIR and issue "make" from within there. However, you don't have
> an automatic target anymore to build everything, so you would need to
> provide one on your own, e.g.:
> 
> library/CMakeLists.txt:
> ADD_CUSTOM_TARGET(world)
> ADD_DEPENDENCIES(world <library> examples)
> 
> If you want to exclude unwanted parts of your project already from the
> configuration, you can use appropriate OPTION() commands and surround the
> ADD_SUBDIRECTORY() commands by IF(<option>)...ENDIF(). Note that you will
> have to handle the dependencies of your project's parts by yourself in this
> case, i.e. you can't disable ADD_SUBDIRECTORY(src) while enabling
> ADD_SUBDIRECTORY(examples) in library/CMakeLists.txt.
> 
> 'hope that helps.
> 
> Regards,
> 
> Michael
> 
> PS: Please don't hijack foreign threads.


More information about the CMake mailing list