I have a Visual Studio 2017 C++ project which uses precompiled headers (stdafx.h).
My (simplified) file structure is as follows:
header1.hpp
header2.hpp
stdafx.h -> includes header1.hpp
code1.cpp -> includes stdafx.h
code2.cpp -> includes stdafx.h and header2.hpp
To avoid any ambiguity, by saying includes header1.hpp, I mean there is a line #include <header1.hpp> in the file.
After I modify stdafx.h, all three files stdafx.h, code1.cpp and code2.cpp are recompiled (as expected).
After I modify code1.cpp, only code1.cpp is recompiled (as expected).
After I modify header2.cpp, all three files stdafx.h, code1.cpp and code2.cpp are recompiled (not expected!).
I would have expected item 3 to compile only code2.cpp, and not everything else.
A possible reason for this behavior would be that the build manager can't inspect and follow #include directives, so it simply recompiles everything if any header file is modified.
Since my project is quite large, recompiling all the files like code1.cpp takes up a significant amount of time. I purposely did not include header2.hpp from stdafx.h because I know I would modify header2.hpp often and only code2.cpp needs to use it. (header2.hpp is a template library that has functions only code2.cpp needs.)
Is this behavior expected, and what can I do to get Visual Studio to recognize that the other files need not be recompiled?
Turns out I had disabled precompiled headers a year ago (but left stdafx.h and stdafx.cpp in the project), and when I wanted to use them again I forgot to turn on the /Yc and Yu options.
No errors were given, and Visual Studio had been compiling stdafx.cpp like a regular .cpp file.
Also, I had the wrong idea of how precompiled headers worked. I thought stdafx.h gets compiled by itself (then dumped into those .cpp files that #include "stdafx.h" via some intermediate representation), but actually the file that gets compiled is stdafx.cpp (and while compiling produces the .pch file). (As per this question.)
After turning on the precompiled header options, when I modify header2.cpp, only code2.cpp gets recompiled, as I would like.
Also, compilation times are now significantly faster.
Related
When I am making changes to my code, the external files are compiled multiple times. I am using math library glm, and Visual Studio seem to be compiling exactly same glm/vec3.hpp file multiple times. I have included glm header multiple time, and it seems that it doesn't use previously compiled code, but recompiles it again.
For example, in my math.h I have included.
#ifndef MATH_HH
#define MATH_HH
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
...
And when I am compiling after changes to code, I see that Visual Studio compiles glm/vec3.hpp multiples times. Basically it compiles it each time that it compiles one of my edited files.
For example, the Visual Studio output looks like this:
1>C:\test\external\glm\glm\detail\type_vec3.hpp(50,1): warning C4201: nonstandard extension used: nameless struct/union
...
10>own_file.cc
11>C:\test\external\glm\glm\detail\type_vec3.hpp(50,1): warning C4201: nonstandard extension used: nameless struct/union
...
Is there a way to prevent this? Or do I need to compile them each time some cpp file uses them? Or am I just confused of Visual Studio's style warnings?
Basically it compiles it each time that it compiles one of my edited files.
That's how C++ works. It compiles source files. Including a header file is just taking the text in that file and dumping it into your source file. Therefore, if you include a header file in 3 source files, the text of that header will be compiled 3 times.
There are precompiled headers (a compiler-specific tool), and the C++20 modules feature, that can avoid this. But outside of those, there's nothing you can do.
I have a header file called gui.h where I keep all my gui stuff. Because of this I often change its contents. The problem is: every time I do this I get a runtime error usually related to memory. However, when I recompile all the project, everything works properly. The error occurs always after changing the .h file contents and it's always fixed by recompilation. Why is this happening? Is there any way I can fix it or I'll have to recompile entire project after every gui change?
EDIT:
I'm using Visual Studio IDE, normal project, not CMake
The files
gui.h
globals.h
Game.cpp
gui.cpp
Includes
gui.cpp has #include "gui.h"
globals.h has #include "gui.h"
Game.cpp has #include "globals.h"
The story
I make a change in gui.h
I hit F5
I see globals.h getting recompiled
I see gui.cpp getting recompiled
I see "Generating code" message in Build log
The project runs
I immediately get a runtime error related to memory (access violation)
The solution:
Recompile all the files that require gui.h to work manually (in this case Game.cpp)
The problem:
Why isn't Game.cpp recompiled automatically?
You haven't specified what tool you use to build your program. What is probably happening is that the tool you're using doesn't realize that a change to that particular h file requires anyone including it (directly or indirectly) needs to be recompiled.
For instance, if you're using "make", your Makefile may have a line that looks like this:
foo.o: foo.cpp foo.h
But it really would need to be:
foo.o: foo.cpp foo.h gui.h
In other words -- foo.o requires not only the corresponding .cpp and .h file, but also this huge gui.h file.
Any .cpp that directly or indirection includes gui.h probably needs recompiling when gui.h changes. That is:
#include "gui.h"
-or-
#include "foo.h"
and foo.h has an include of gui.h.
Since the content of the header file is pasted into the source files that include it by the compiler preprocessor, whenever you change the header, the program will remain the same, since it has been compiled from a source file that contained the content of the old header file.
I suggest that you could try to set incremental compilation.
Project->Properties->Configuration Properties->C/C++-Code Generation->Enable Minimal Regbuild: Yes(/Gm)
Project->Properties->Configuration Properties->C/C++->General->Debugging Information Format: Program Database (/Zi)
Project->Properties->Configuration Properties->Linker->General->Enable incremental linking: select "Yes"
Tools->Options->Projects and Solutions->Build and Run->On Run, when projects are out of date: select "Prompt to generate"
Tools->Options->Projects and Solutions->Build and Run->Check Only build startup projects and dependencies on Run
Tools->Options->Projects and Solutions->Build and Run->MSBuild project build output verbosity: select "Minimal"
I am a bit confused about when to use /Yc (create PCH) as opposed to /Yu (use PCH.) For a project that has never used precompiled headers in the past, naturally, the PCH file will not exist initially. Am I supposed to fire off a initial build with /Yc, have it create the PCH file and then change the setting to /Yu for all subsequent builds?
That can't possibly be it, right?
Try this: Create a header to contain all the headers to pre-compile eg: stdafx.h (this MUST be the 1st include in all .cpp files). File to generate the PCH: stdafx.cpp which only includes stdafx.h and compile this with /Yc. All other .cpp files include stdafx.h at the start and compile with /Yu. MSVC is clever enough to do the /Yc file 1st.
I understand what precompiled headers are doing with "#include "StdAfx.h" and yes, I know I can turn them off. But that's not my question.
If you're using precompiled headers, Visual C++ requires every cpp file to #include "StdAfx.h", even the files that aren't using any of the headers in StdAfx.h. If you forget to include StdAfx.h on one file, it's an error. But why? The obvious approach would be just "If you include StdAfx.h then that file will use it, but if you forget to include it, then those header files will simply not be included." I don't understand why VC++ would require you to include StdAfx.h when it's not needed. Seems like it would have been easier for them to treat it like a normal header file.
Is there any good reason why this is required?
Just a addition to the Marks answer. In fact, you do not have to manually include stdafx.h in the all project source files. You may use project option Forced Include Files:
That way stdafx.h will be automatically included in all your sources.
Your project default is "use precompiled headers". You can set individual files to "not use precompiled headers" if you desire.
In fact, stdafx.cpp itself has a different option from the project defaults:
What this configuration is saying is "start compiling this file (stdafx.cpp), stop when you finish compiling the statement that includes stdafx.h" and save the precompiled information as as .pch file." Visual studio is also smart enough to compile this file first so it is available for use.
The project defaults are:
What this configuration is saying is "For each compiled file, start with the precompiled data in the specified .pch and start compiling new information after the point stdafx.h is included." That's important and why stdafx.h should be included as the first line of the file. It will still work if you put it later in the file, but anything before the #include is ignored because that data won't be in the .pch. Absence of the #include means VS will scan the whole file looking for the pre-compiled starting location and not find it...generating an error.
If you have a file that you don't want to use pre-compiled information, you can select the file and override it. Example:
Visual Studio won't use the precompiled information and won't look for a header to include.
When you select the file, right-click properties, go to the "C/C++ \ Precompiled Headers" section and set "Precompiled Header" to "Not using Precompiled Headers", be sure that the Configuration (top left) is applicable to the current selected build.
It doesn't always automatically select the "active" configuration; so you could be setting the option for a non-active configuration so you will continue to experience the error ;)
I am working on a project that has a vendor-provided API. I've made a class that uses that API in my project and I've included the vendors header file in my stdafx.h file. Things would not compile.
I then put the #include directly into my class' header file and now things compile (And yes, my class includes stdafx.h so that isn't the reason.
Do any of you have any guesses as to why it wouldn't compile the first time around? This isn't a project-stopper by far but I'd prefer if I could keep all vendor API files in stdafx.h where they belong.
EDIT: Problem solved, I'd created a cyclic dependency by forgetting to #ifndef a header file and then including them in the wrong order. I feel like an idiot.
stdafx.h is mainly used in the VS generated projects as the 'container' of headers to be precompiled.
When you added a new #include to stdafx.h it didn't get included because your project is probably configured to use precompiled headers, and when you add something to stdafx.h you need to regenerate the .pch file that contains the precompiled information.
One way to do that is to have a .cpp file in your project that does nothing but #include "stdafx.h". Maybe call it `precompile.cpp". Then go to the project settings for that one .cpp file and change the following setting (for all configurations):
"C/C++ | Precompiled Headers | Precompiled Header" setting
and select "Create /Yc".
That will set up the build so that when precompile.cpp needs to be built (because the stdafx.h header it includes has changed), it'll rebuild the .pch file that everything else uses.
EDIT: Wait - I don't think I read the question right. May still be helpful, though.
Another name for stdafx.h is a 'Precompiled header'
There aren't really any 'vendor specifics' in stdafx.h, what it does is it precompiles headers so that the compiler doesn't have to re-compile them every time you build the project.
It's only really helpful if you have a huge project (or a small one that includes tonnes of headers).
I use visual studio 2010 as well, generally it's not worth the fuss - I just disable it (which would solve your class inclusion issue also - make your own header, stick the vendor's in there).