Build time: Visual Studio 2015-2017 build very slow [closed]
Asked Answered
S

1

6

For my small (5-6000 lines of code) C++ program I have used both VS 2015 and 2017 and my build times are around 2 minutes on first build. This is obviously incredibly slow but I'm not sure why. In tools->options->projects and solutions->build and run - I've already set the "maximum number of parallel project builds" to 8 but no change occurred.

Are there any other settings or general rules which can be applied to reduce build times?

Scutage answered 12/11, 2017 at 15:8 Comment(9)
Check that your code is not one big lump of mutual dependency. If a small change necessitates the rebuild of the entire app, your build times will be atrocious.Lurlenelurline
Also header only template libraries can get time consuming. You might try using precompiled header files. But there's no way to give you good advice in general, it totally depends on your source code and project structure.Pythagorean
But wouldn't setting the number of parallel builds to 8 make things at least a little faster?Scutage
@Scutage That depends on what can actually be built in parallel.Pythagorean
There can be many reasons for a slow build. Perhaps you are including headers you don't need. Perhaps you are specifying dependencies in your build system that are not true. Perhaps you are auto-generating source files on every build that you don't need to regenerate. There can be many reasons*...Deportee
@Pythagorean Okay, well that's what I wanted to try and narrow down. I've never anything bigger than a 500 line program before so I'm trying to narrow down who's at fault, me or VS. In case there was a known issue with VS building that needed to be setup or somethingScutage
Why is this on hold? It's absolutely NOT unclear (Build process is slow), it shows effort (parallel compiling) and a target what to achieve (should be faster). Of course it is pretty broad and thus requires a pretty general (and potentially extensive) answer, but why not? I do not understand the question requirements interpretation and votes made by many users anymore these days :(Allerie
I reworded this a little bit (has to be reviewed). IMO it would be a waste to close this.Allerie
Ya, I know I would really like to be able to reference this answer in the futureScutage
A
16

Compiling takes time... it's a complicated process, especially in large solutions with many files and projects. But there are some things, which can reduce compile times on Visual Studio.

Use good hardware.

An SSD with sufficient empty space, good multi core processor and sufficient RAM is always a good fundament for quicker compiling.

Use Precompiled Headers

Precompiled headers can speed up the build process a lot. They are a bit complicated to set up if they have not been automatically created during project creation, but it's definitely worth the effort in many cases. Here's how to switch them on:

You'll need two files in your project, for example called pch.h and pch.cpp. enter image description here

pch.h contains all defines and headers you want to commonly use in your project., e.g.

#ifdef _WIN32
#   define _WIN32_WINNT                 0x0502    
#   define WIN32_LEAN_AND_MEAN
#   define VC_EXTRALEAN
#   define NOMINMAX
#endif
#include <windows.h>  

#define OIS_DYNAMIC_LIB
#include "OgreVector3.h"

#include <string>
#include <vector>
etc. pp.

pch.cpp contains only one line:

#include "pch.h"

It has a special purpose (see below).

Now add a #include "pch.h" to EVERY cpp in your project, at the VERY TOP position of your cpp files. This is mandatory for precompiled headers.

The next thing is to enable the precompiled headers in your project. Open your project properties, and enter for all configurations and all platforms, that they should "use" the precompiled headers:

enter image description here

This tells the project that you want to use your pch.h as the precompiled headers.

The last step is to change the file properties of your pch.cpp to "create" (that's the special purpose): enter image description here

This means that the pch.cpp will from now on create the binary precompiled header file Visual Studio needs.

Split Projects and maintain a good project hierarchy.

Generally it is not a good idea to place everything in one large project and call each file from each file, neither compile-time-wise nor design-wise. You should split your solution into static libraries of a certain "level".

The lowest level could e.g. be a basic network library, IO library, wrappers, std improvements, convenience helpers etc.

The medium levels could be e.g. a specialized Thread library (which makes use of the lower levels like network, IO and so on)

The highest level would be your application.

Higher levels can access lower levels (preferrably the level directly below), but lower levels can never access higher levels (except via interfaces, if necessary). This ensures that - while you are working on your application - only the application will have to be rebuilt, and not the whole project.

Avoid unneccessary Header-Only-Classes.

Of course you NEED header-only classes, e.g. STL. And also templates are only possible in header-only-classes. But if you're writing a non-template class, it should be classically split into cpp and header to improve the compile times. Also, only short methods (e.g. trivial getters and setters) should be implemented in the header.

Avoid unneccessary includes, use forward-declarations instead

Let's say you have a class in a lower level header:

#include "my_template_lib_which_takes_ages_to_compile.h"

namespace LowLevel {
  class MySuperHelper {
    my_template<int> m_bla;
  public:
    MySuperHelper();
    virtual ~MySuperHelper();
    void doSomething();
  };
}

And you want to store a reference or (smart) pointer of this class in a higher level class header:

#include "lowlevel.h"

namespace MediumLevel {
  class MyMediumClass {
    std::unique_ptr<LowLevel::MySuperHelper> m_helperRef;
  public:
    MyMediumClass(); //constructor initializes the smart pointer in cpp
    virtual ~MyMediumClass();
    void work(); // works with the smart pointer in cpp
  };
}

then of course this is valid code, but it's potentially slow to compile. MySuperHelper uses the slow compiling template lib to instantiate his member and thus includes its header. If you now include lowlevel.h, you will include the slow template lib as well. And if a higher class includes your medium class header, it will include the medium level header, the low level header and the template header... and so on.

You can avoid that with forward-declarations.

namespace LowLevel {
  class MySuperHelper;
}

namespace MyMediumLevel {
  class MyMediumClass {
    std::unique_ptr<LowLevel::MySuperHelper> m_helperRef;
  public:
    MyMediumClass(); //constructor initializes the smart pointer in cpp
    virtual ~MyMediumClass();
    void work(); // works with the smart pointer in cpp
  };
}

No need to include the whole header! Since m_helperRef is not a whole instantiated class object but only a smart pointer, and that smart pointer is only used in the CPP, the header doesn't need to know what MySuperHelper exactly is, it just needs a forward declaration. Only the CPP - which instantiates and works with MySuperHelper directly - needs to know exactly what it is and thus has to #include "lowlevel.h" This can speed up compiling a lot. A library/engine, which does this pretty good, is Ogre; if you #include <ogre.h>, you will only include a list of forward declarations, which is quick to compile. If you want to work with Ogre's classes, you then include the specific header in the CPP.

Use multicore parallel compiling

Like I said, compiling is a pretty complicated process, and I have to confess that I'm not very good in the secrets on how to improve parallel compiling (may be someone else can help). Compiling is in many cases a sequencial process of dependencies. Nevertheless, some cases can be compiled in parallel without deeper knowledge, and Visual Studio has some options to do so.

Under Tools/Options/Build and Run you can enter the maximum number of projects to build concurrently. enter image description here

But these are only projects to build in parallel. The projects itself still will be compiled sequentially. But this can also be changed in the project settings of the projects itself (you will have to do this for every project)

enter image description here

Nevertheless, don't expect any wonders from parallel compiling. There are still a lot of cases which have to be handled sequencially.

Analyze your header inclusion

You can switch on "Show includes", which will give you a list of the included header files in the build output: enter image description here (Of course this feature should be switched on only temporarily, because it slows down the build process extremely - which is the opposite of what you want ;)) After the build you can then analyze the output and perhaps find some unneccessary headers you can remove. AFAIK there are also some tools, which can do that automatically for you, but haven't tried out myself yet. Here's a post which states that ReSharper C++ provides a functionality to remove unused headers (also this I haven't tried yet)

Disable virus scanners for build folders

During a build a large amount of files will be created. If the virus scanner accesses these files during build, this can cause a major slowdown. Exclude at least the temporary build folders from virus scanner access.

Allerie answered 12/11, 2017 at 17:45 Comment(2)
Wow, fantastic answer. Thank you very much for your insights and effort. I think you covered pretty much every reason for slow build times and this should get more upvotes. In the end, setting the /MP option to utilize more cores really did the trick (cutting a minute from build time) and did what I was attempting to do with the "maximum number of parallel project builds" option (which I now realize has nothing to do with utilizing more cores).Scutage
Thanks, glad I could help :) Well indeed "maximum number of parallel project builds" does utilize more cores - but only if you have many projects in your solution. /MP is more powerful.Allerie

© 2022 - 2024 — McMap. All rights reserved.