<div dir="ltr"><span style="font-size:12.800000190734863px">I realise I wasn't very clear in my previous explanation. Hopefully this paints a better picture;</span><div style="font-size:12.800000190734863px"><br></div><div style="font-size:12.800000190734863px">- We have 40 or so developers spread across Visual Studio 2015 (MSBuild - Windows), Xcode (macOS) and Make/Clang (Linux). 80% use Windows. </div><div style="font-size:12.800000190734863px">- We have a core set of libs in use by a number of projects (~30 static libs and ~10 different projects), but the projects mix and match which libs they use - merging the static libs (beyond a few of them) isn't something we want to do.</div><div style="font-size:12.800000190734863px">- I have recently been revising our CMake structure and have boiled it down to a fairly simple "add_library(x), target_link_libraries(x, default_compile_settings, dependencies)" which means compile settings, include directories and macros propagate through the libs nicely.</div><div style="font-size:12.800000190734863px">- We sometimes want to build and use certain libs as shared libs instead of static libs.</div><div style="font-size:12.800000190734863px"><br></div><div style="font-size:12.800000190734863px">With regards to the COMPILE_DEPENDS feature that I have mocked up and started testing with our team;</div><div style="font-size:12.800000190734863px"><br></div><div style="font-size:12.800000190734863px">- If and only if COMPILE_DEPENDS is set for a STATIC library, then when building the target dependencies for that library, it uses the list of provided targets instead of those that would have been inferred from previous calls to "target_link_libraries" or "add_dependencies".</div><div style="font-size:12.800000190734863px"><br></div><div style="font-size:12.800000190734863px">The reality is, the libs which are being built statically can nearly all build in parallel with only one or two "real" dependencies. I understand that our case is rather specific, but having implemented "COMPILE_DEPENDS" and written ~10 lines of CMake in our project (hard coding the one or two actual build order dependencies and disabling the rest), our compile graph looks much nicer and saves a significant amount of time building on a single machine (see <a href="https://www.johnwordsworth.com/temp/cmake_compile_depends.jpg" target="_blank">https://www.johnwordsworth.<wbr>com/temp/cmake_compile_<wbr>depends.jpg</a>). We see similar savings on macOS using Xcode but have not tested on Linux yet. When we allow Incredibuild to distribute building of compilation units across 15-20 agents, the proportional build time drops more dramatically between the two (the same project goes from ~2.6mins -> ~1.6mins).</div><div style="font-size:12.800000190734863px"><br></div><div style="font-size:12.800000190734863px">I understand that just "hard overriding" the target dependencies is a bit messy, but I'd also be happy to explore other ways I could add a similar feature to CMake if there is a potentially better way to do this. What I am ideally looking for in a solution is that I can continue to propagate include directories / compile settings / preprocessor macros through the chain of libs and that it improves building static libs in parallel across all our build systems (MSVC / XCode / make). Ideally, I wouldn't have to restructure my CMake project too much either - as the draft I have for our new structure feels super clean now and refactoring it just to remove build order dependencies would be shame. If there are any alternative ideas for how to implement this, I'd love to discuss. I'm no CMake expert, but maybe if we could use "target_link_libraries" with OBJECT libraries to grab compile settings, or perhaps I could look into a mechanism for not adding build order dependencies on VS2015/Xcode if there is no need too?</div><div style="font-size:12.800000190734863px"><br></div><div style="font-size:12.800000190734863px">Thanks again for the feedback and discussion so far.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jan 4, 2018 at 12:16 PM, Eric Noulard <span dir="ltr"><<a href="mailto:eric.noulard@gmail.com" target="_blank">eric.noulard@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote"><span class="">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="m_3309051407182410551gmail-">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></span><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><span class=""><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="m_3309051407182410551gmail-"><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></span><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/" target="_blank">https://blogs.msdn.microsoft.<wbr>com/vcblog/2017/05/10/cmake-<wbr>support-in-visual-studio-<wbr>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" target="_blank">https://cmake.org/cmake/help/<wbr>v3.10/release/3.10.html</a><br></div><span class=""><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="m_3309051407182410551gmail-"><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></span><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" target="_blank">https://github.com/frerich/<wbr>clcache</a>, but as you guessed I did never used that.</div><span class="HOEnZb"><font color="#888888"><div><br></div>-- <br><div class="m_3309051407182410551gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Eric<br></div></div></div></div></div>
</font></span></div></div>
</blockquote></div><br></div>