Boost logo

Boost :

Subject: Re: [boost] [cmake] Minimum viable cmakeification for Boost
From: Thomas Heller (thom.heller_at_[hidden])
Date: 2017-06-21 08:01:45


On 06/20/2017 11:56 PM, Niall Douglas via Boost wrote:
>> I'll ask again: do you have any reference to those statements? The
>> official cmake docs seem to disagree about this specific case.
>
> The cmake docs are updated on a git pull request basis by volunteers as
> and when someone feels they need to be updated. They are, in general,
> woefully out of date. And as I mentioned here before, Stephen never
> finished the cmake3 documentation effort he began due to changes in
> personal circumstance (returning home to Ireland).

To be honest, and forgive my skepticism, I find this to be not a good
sign of something that is to suppose to dominate the industry:
 - There is no real documentation available on the "best practices" you
   advertise, they are told based on anecdotes
 - Kitware is indeed a company who offers support and consulting and
   claims to maintain CMake.

Not saying that you (or Stephen Kelly) don't know what you are talking
about...

>
>> Why should the root cmake be responsible for configuring a specific sub
>> module. This is asking for cluttering everything into one single entity
>> in a (almost) totally unrelated place. Why not keep it local to where it
>> should be used.
>
<snip>
>
> In the cmake I mocked up we are separating concerns: "how to build this
> library" from "how to configure this library". It is like the intended
> difference between the SConstruct and SConscript files in scons: one
> file says what needs to be built and how they relate declaratively, the
> other file sets flags, optimisation, settings according to the target
> system etc imperatively.

I can see that and certainly see the benefit of it. I think there is a
great chance to further drive the modularization with that approach. I
guess the consensus would be (each of those file local to the module
being built):
 - CMakeLists.txt: Describe targets declaratively
 - Dependencies.cmake: Describe dependencies (PUBLIC, PRIVATE,
   INTERFACE)
 - Install.cmake: Define the install logic
 - Setup.cmake: Define Options etc. and eventually call
   add_subdirectory to have the CMakeLists.txt being processed

This would seperate concerns, the root CMakeLists.txt would then include
the corresponding Setup.cmake and Install.cmake files. This would be how
the authors envision that the module should be built.
Third parties can either follow that approach or derive their own logic.
The advantage of the advise to have everything clobbered in the root
CMakeLists.txt would be:
 - it is scalable (Library authors don't need to ask for permission to
   have some options etc. added inside the root)
 - the information would be local to the package being built, that is
   every user can directly observe which different build options are
   available
 - Each package can be used standalone or within the super project. The
   imperative logic is split, and can be reused on a by need basis
   without copy&pasting from one large, central CMakeLists.txt

Does this sound like a suitable approach?

>
> In exactly the same way as with scons, the non-root CMakeLists are the
> declarative structure describing a build graph. The rootmost CMakeLists
> are the imperative commands transforming some subset of that build graph
> into a build according to local conditions.
>
> That's the way you ought to be ideally speaking writing your cmake3. I
> don't know what else I can explain here. As Peter mentioned, this is 101
> elementary build system theory here. It's nothing cmake specific, though
> because of how variable scopes usually begin with CMakeLists.txt, it
> does strongly encourage the imperative logic to go into the rootmost
> layer rather than somewhere more logically placed. But it is what it is.

Interesting that you bring this up ... If you are so much in favor of a
declarative build system, we already have multiple. For example plain
old make or Boost.Build. With that being said, wouldn't it be more
viable to improve Boost.Build with:
  - Better Documentation
  - More examples
  - Tight integration with CMake:
     * Have Boost.Build generate XXXConfig.cmake and XXXTargets.cmake
       files
     * Have a CMake module that drives b2
This would make everyone happy, wouldn't it? People who prefer
declarative builds can stick to Boost.Build. Boost.Build would stop
being "asocial" to CMake based projects.

>
>> One concrete example: I have networking layer which supports different
>> transports, say tcp, libfabric, MPI and infiniband verbs. The user of my
>> library doesn't really care about which one is used, so ideally, I would
>> give him a compiled version of my library with the internal settings I
>> believe are best for him. In that case, my network layer module would be
>> configured with one of those options. Naturally, I would think, those
>> options are defined within this very sub project. The root project
>> really doesn't care, nor do I want that this implementation detail leaks
>> into the users CMakeLists.txt.
>>
>> Would you consider that bad practice to begin with? How would you solve
>> this?
>
> It depends on if you ever expect unknown third parties to want to do
> custom builds of your codebase. If you don't, your approach is fine, and
> it's easier. If you do, then you need to separate the declarative stuff
> from the imperative stuff. Then unknown third parties can reuse your
> declarative stuff, and skip or ignore your imperative stuff as they are
> doing a custom build.
>
>> There are tons of other use cases very similar to that. Having
>> everything clobbering up in the root Cmakelists.txt doesn't sound
>> appealing to me.
>
> You obviously don't place ALL your imperative logic in the very rootmost
> CMakeLists. There are natural root points where build config markedly
> changes when you go up a directory level. That's where you locate the
> imperative logic. If higher level cmake wants to ignore your imperative
> logic, it skips over the directory with the CMakeLists with the
> imperative logic and adds the subdirectories of the inner directories
> directly, thus bringing in only the declarative parts only. So you
> "reach in" two directory levels to skip the imperative logic.
>
> Does this make more sense now?

Thanks for the explanations. It does indeed make more sense now. I hope
I could summarize it correctly and provide a nice consensus.

>
> Niall
>


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk