[cmake-developers] Optionally disabling static lib dependencies with COMPILE_DEPENDS

Eric Noulard eric.noulard at gmail.com
Thu Jan 4 06:16:43 EST 2018


2018-01-04 10:48 GMT+01:00 Craig Scott <craig.scott at crascit.com>:

>
>
> On Thu, Jan 4, 2018 at 8:27 AM, John Wordsworth <john at johnwordsworth.com>
> wrote:
>
>> I have recently been reviewing ways to improve build times for our
>> project, which is comprised of a number of static libraries. I stumbled
>> across this post on the CMake tracker from 2012/13 (
>> https://cmake.org/Bug/view.php?id=13799). It suggests adding a
>> COMPILE_DEPENDS target property to to explicitly set dependencies for
>> STATIC libraries instead of always using all linked libraries as
>> build-order dependencies.
>>
>> Having done a draft implementation in a local CMake repository it has
>> shaved off  20% of our 120s build time. I expect the savings to be much
>> more dramatic when I test with Incredibuild (approximately 50% based on
>> tests done previously from just deleting dependencies manually in Visual
>> Studio).
>>
>
You said you tested with Incredibuild but with what kind of configuration?
AFAIK Incredibuild takes its power from distributing the build? So does
your CMake test uses something that distribute the build too ?


>
>> I don’t really want to refactor our code to use “OBJECT” libraries as the
>> inability to link with other targets means that propagating compile options
>> / include directories etc down the chain of linked libs becomes painful.
>> This method allows me to switch between static and shared libs using a
>> config option and none of my CMake scripts need to change.
>>
>
> There's a couple more choices here. If your project consists of lots of
> small (static) libraries, consider whether you can combine some of them to
> result in a smaller number of larger libraries. This isn't always a gain,
> but in terms of ability to compile sources in parallel, it will often lead
> to more efficient builds. You just need to be careful you don't end up with
> so many objects being combined into one library that you start to hit max
> open file limits during linking/archiving (something I've hit on multiple
> platforms lately, so it's not just a hypothetical example). Use of
> target_sources() can be quite helpful if you want to try out this path (you
> may find this article
> <https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/>
> helpful).
>
> Another choice is to go in the opposite direction and take advantage of
> the optimisation made for the Ninja generator (if that's a choice open to
> you) that was introduced in CMake 3.9.0
> <https://gitlab.kitware.com/cmake/cmake/merge_requests/430> where if no
> custom commands exist on a target A, then compilation steps of another
> target B linking to A are allowed to proceed without waiting for A's link
> step to complete. Only B's link step will depend on A's link step. In your
> project, if you have custom commands, see if you can split up that target
> into just those sources that need the results of the custom command and
> another target that doesn't. The latter will then be able to compile
> earlier, so fewer sources have to wait for earlier linking steps. This
> might be hard to do, it really depends on how your project is structured.
>

I fully agree with Craig here. We use CMake + Ninja and we get really
efficient parallel build (on 10+ cores machines).
This is on Linux though but it seems MS is putting effort to get CMake +
ninja build work with Visual Studio:
https://blogs.msdn.microsoft.com/vcblog/2017/05/10/cmake-support-in-visual-studio-whats-new-in-2017-15-3-update/

Another way to improve your build may be to review your dependency graph
carefully. You can use cmake --grahviz options to dump the graph and see
whether you can cut
some dependencies due to transitivity of dependency. I have seen many
projects with "overspecified deps". I think this impair build time when
using a lot of static libs because in that case you may get
poor performance link time. Namelly if you have many unit tests linking to
too many static libs because of overspecified deps.

That said you did not specify whether if the 120s build time is only for
the library or if this is a "global" build time which includes linking
somes executables and possible unit tests programs.

Note that even if this is not the case having a "big-picture" look at the
dependency build graph generated by CMake may be insightful.
Note that with CMake 3.10 you can now see difference between PUBLIC,
PRIVATE and INTERFACE deps:
https://cmake.org/cmake/help/v3.10/release/3.10.html



>
> Both of the above choices allow you to retain the automatic propagation of
> compile options, include directories, etc. and to switch between
> shared/static easily, but the latter is specific to the Ninja generator and
> may not be an acceptable change for you.
>
>
>>
>> Anyway, I was wondering whether there was any interest in me pushing my
>> solution back to Git / submitting a Pull request so that it might be merged
>> in at some point. If there is - any advice on any gotchas I might watch for
>> instead of just adding some fairly simple code to
>> cmComputeTargetDepends.cxx would be gratefully received - especially as
>> this is my first time poking around in CMake code.
>>
>
> The existing behaviour is conservative and any change would have to also
> be conservative, meaning that it must not introduce any possibility of
> breaking existing projects. If I'm understanding your proposed feature
> correctly, it sounds like you want to relax the build-order dependencies by
> default when a COMPILE_DEPENDS target property is defined. Basically, if
> COMPILE_DEPENDS is defined, you are taking over responsibility for the
> build-order dependencies. This would be something I'd usually discourage
> projects from doing because such manual dependencies would be a prime
> candidate for not being kept up to date as a project evolves, leading to
> subtle, hard-to-trace build errors. Some judicious project restructuring
> can normally give a pretty efficient parallel build without having to
> resort to such measures, so I'm wary of adding a feature like this (though
> I can understand the desire for it).
>
> In my experience, you can get some considerable speedups using tools like
> ccache (and its equivalents for other platforms/compilers). These obviously
> only help for subsequent builds of things that have been built previously,
> but for everyday development where you switch between branches or for CI
> servers doing lots of similar builds, the savings can be impressively big.
>

+1 again.

ccache boost our build. It can be more than 10x faster (depends on cache
hit).
You can even share (on a local network) the ccache directory between
developers and the CI and get very high hit rate (> 80%).

Now I'm not working on windows nor with Visual Studio and AFAIK ccache does
not work with MSVC.
There seem to be alternative, https://github.com/frerich/clcache, but as
you guessed I did never used that.

-- 
Eric
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://cmake.org/pipermail/cmake-developers/attachments/20180104/48b1a770/attachment-0001.html>


More information about the cmake-developers mailing list