<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">2018-01-04 10:48 GMT+01:00 Craig Scott <span dir="ltr"><<a href="mailto:craig.scott@crascit.com" target="_blank">craig.scott@crascit.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote"><span class="gmail-">On Thu, Jan 4, 2018 at 8:27 AM, John Wordsworth <span dir="ltr"><<a href="mailto:john@johnwordsworth.com" target="_blank">john@johnwordsworth.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div>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 (<a href="https://cmake.org/Bug/view.php?id=13799" target="_blank">https://cmake.org/Bug/view.ph<wbr>p?id=13799</a>). 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.</div><br><div>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).</div></div></blockquote></span></div></div></div></blockquote><div><br></div><div>You said you tested with Incredibuild but with what kind of configuration?</div><div>AFAIK Incredibuild takes its power from distributing the build? So does your CMake test uses something that distribute the build too ?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="gmail-"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><br></div><div>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.</div></div></blockquote><div><br></div></span><div>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 <a href="https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/" target="_blank">this article</a> helpful).</div><div><br></div><div>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<a href="https://gitlab.kitware.com/cmake/cmake/merge_requests/430" target="_blank"> introduced in CMake 3.9.0</a> 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.</div></div></div></div></blockquote><div><br></div><div>I fully agree with Craig here. We use CMake + Ninja and we get really efficient parallel build (on 10+ cores machines).</div><div>This is on Linux though but it seems MS is putting effort to get CMake + ninja build work with Visual Studio:</div><div><a href="https://blogs.msdn.microsoft.com/vcblog/2017/05/10/cmake-support-in-visual-studio-whats-new-in-2017-15-3-update/">https://blogs.msdn.microsoft.com/vcblog/2017/05/10/cmake-support-in-visual-studio-whats-new-in-2017-15-3-update/</a><br></div><div><br></div><div>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</div><div>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 </div><div>poor performance link time. Namelly if you have many unit tests linking to too many static libs because of overspecified deps.</div><div><br></div><div>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.</div><div><br></div><div>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.</div><div>Note that with CMake 3.10 you can now see difference between PUBLIC, PRIVATE and INTERFACE deps:</div><div><a href="https://cmake.org/cmake/help/v3.10/release/3.10.html">https://cmake.org/cmake/help/v3.10/release/3.10.html</a><br></div><div> </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>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.</div><span class="gmail-"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><br></div><div>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.</div></div></blockquote><div><br></div></span><div>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).</div><div><br></div><div>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.</div></div></div></div></blockquote><div><br></div><div>+1 again.</div><div><br></div><div>ccache boost our build. It can be more than 10x faster (depends on cache hit).</div><div>You can even share (on a local network) the ccache directory between developers and the CI and get very high hit rate (> 80%).</div></div><div class="gmail_extra"><br></div><div class="gmail_extra">Now I'm not working on windows nor with Visual Studio and AFAIK ccache does not work with MSVC.</div><div class="gmail_extra">There seem to be alternative, <a href="https://github.com/frerich/clcache">https://github.com/frerich/clcache</a>, but as you guessed I did never used that.</div><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Eric<br></div></div></div></div></div>
</div></div>