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.
Related
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.
I don't really understand the why behind this, but I think I've figured out the what.
My brother is working on a homework project and they're using Visual Studio. He was having issues getting his project to compile. The project in question consisted of:
main.cpp
classes.h
class_functions.cpp
general_functions.cpp
They had the following import structure:
main.cpp
#include "classes.h"
#include "class_functions.cpp"
#include "general_functions.cpp"
class_functions.cpp
#include "classes.h"
general_functions.cpp
#include "classes.h"
He kept getting link errors when trying to compile, even though g++ would compile it just fine. So I tried via Visual Studio command prompt and cl. This compiled just fine, so I tried msbuild which (obviously?) failed. I went into the vxproj file, because hey, what is it telling cl that I'm not?
In the proj file it was including classes.h, general_functions.cpp and class_functions.cpp, as well as main.cpp. When I removed general and class functions, msbuild ran just fine. Put either of them back and boom. classes.h contains
#ifndef myclasses
#define myclasses
/* Code here */
#endif
And the other .cpp files contain similar directives.
I finally figured out how to eliminate the problem - eliminate
#include "general_functions.cpp"
#include "class_functions.cpp"
from the code base, and now Visual Studio compiles this just fine.
The question is why? What is the justification or possible benefits from doing this?
the difference between .cpp and .h files is that the .h files are usually included with the #include directive while .cpp files are included in the linking process.
The #include instruction will insert a copy of the included file in the code you are compiling, so by including the .cpp files you will compile a single source file that contains all your .cpp files. It's very bad practice but still could work.
But if you are then adding the .cpp files also in the linking step then you are adding those files a second time creating probably duplicate definitions of your functions, e.g. linker error. I think that's probably the main error (without the linker error codes I'm just guessing).
I have a Qt project using precompiled headers (not sure if that's relevant) in VS2012 and it compiles and works fine. But when I try to compile the same project in QtCreator it shows errors. First of all - both projects correspond to each other and were previously correctly configured (they compiled and worked just fine). After latest changes to the code, however, something went wrong.
Errors:
pch.h:34: error:C2084: function 'void handleExceptionByShowingMessage(std::exception &)' already has a body
main.cpp:16: error:C3861: 'handleExceptionByShowingMessage': identifier not found
These go on for 30+ lines with another function defined in pch.h (inline too) and a few more cpp files. But all errors are analogical.
From pch.h:
inline void handleExceptionByShowingMessage(std::exception &e)
{
QMessageBox msgBox;
msgBox.setText(QString::fromUtf16((ushort*)e.what()));
msgBox.setStandardButtons(QMessageBox::Discard);
msgBox.setIcon(QMessageBox::Warning);
int ret = msgBox.exec();
}
I don't paste function calls from cpp files because it's just a regular use. All cpp files include pch.h correctly (first line of code) and as I said - the exactly same code and file structure works in VS2012 (whose compiler, I believe, QtCreator actually uses...).
If you need more code/information please let me know.
Update:
Yes, all headers have #pragma once. Interesting notice though - when I moved these two function definitions to a dummy header file and included it in the pch.h, the project compiled fine.
#pragma once only prevents the file containing the directive from being included several times. You precompiled header file, pch.h, gets included when the precompiled headers are loaded, and a second time when you files are compiled. The #pragma directive sees them as separate files so it won't work in this context.
The pch.h file (or stdafx.h) is an optimization and ideally should not contain source code but only #includes to other header files. That way, including it several times won't be an issue.
Another solution would be using an include guard (#ifndef PCH #define PCH #endif), which will prevent the file to be included several times.
you may try static inline if the code is in header.
I do not know why inline does not imply static but i also stumbled about this a time ago.
I am having issues compiling the decNumber http://speleotrove.com/decimal/, source is here http://download.icu-project.org/files/decNumber/decNumber-icu-368.zip (includes examples etc. that need to be deleted)
Has anyone compiled this successfully? Your comments will be much appreciated!!
The compiler issues an error as a result of the following directives:
#if !defined(QUAD)
#error decBasic.c must be included after decCommon.c
#endif
(This is a small section of code from decCommon.c and decBasic.c is another source file)
The author of the code states in comments that these 2 source files are shared. There are no corresponding .h files.
I am on Windows 7 64 bit, compiling with Visual Studio 2010 32 bit.
Thank you in advance for your help.
decBasic.c and decCommon.c are #included at the BOTTOM of the specific implementation files (such as decDouble.c). So - you shouldn't compile decBasic.c or decCommon.c, but treat them like header files.
If you look at the MAKE file included, you can see what the compilation targets are: decBasic and decCommon are missing.
If you are using Visual Studio, you can add decBasic.c and decCommon.c as headers, so they appear in the project but will not be compiled.
decNumber is not in a compilable state in its original form as it requires some source code modifications to include standard integer types.
QDecimal library handles this issue by using slightly modified version of decNumber.
Please see QDecimal project for details:
http://code.google.com/p/qdecimal/
http://code.google.com/p/qdecimal/source/browse/doc/INSTALL.txt
When compiling with Visual Studio 2010 do not include decBasic.c and decCommmon.c to the project. These files are include-only and should not be compiled separately. In my case I am using decDouble module only and my project is setup as follows:
Header Files
decContext.h
decDouble.h
decDPD.h
decnumberlocal.h
decQuad.h
Source Files
decContext.c
decDouble.c
decQuad.c
Additionally files decBasic.c and decCommon.c are in the same directory where decQuad.c is located.
So,
I've got this code I'm trying to update. It was written for visual studio 6, and I'm trying to get it to compile in visual studio 2010.
In stdafx.h, it includes afx.h and afxwin.h and a few other things necessary for the program to work. Notably, there's usage of CString in other header files.
At the top of the includes in stdafx.h, I added in a #pragma message, to verify that it was being compiled first. There's one at the top of the header file which throws the error, as well. I can see from the compiler output that stdafx.h was being compiled first, so that's good.
However, there was the error. (CString wasn't being recognized as a type.) So, I decided to make sure that it got through all of the includes. So, I put another #pragma message after #include and that message is not printed.
Does that mean is not actually being included?
Your explanation is a little hard to follow, but I think you're running into the differences between normal compilation and pre-compiled headers.
With pre-compiled headers, the compiler processes the first file normally (the new project wizard sets up stdafx.cpp for this). After processing the include file (typically stdafx.h) set in project options for pre-compilation control, the compiler saves its state to a .pch file.
For every other file, the compiler skims over the file without any processing, just looking for the include file. Then it reads the .pch file, loads the saved state, and continues parsing and compiling normally.
One consequence of this design is that any lines above #include "stdafx.h" in stdafx.cpp become part of the state and are seen by all other files. And lines above #include "stdafx.h" in other files are simply ignored.
Passing my comment to an answer.
CString in VS 6 times was a class and it changed afterwards to be a template. Maybe it has something to due with that?
The problem had to do with using
typedef with CString. Post VS 6,
that's not possible. I just changed
references by hand, and it compiles
now.
The problem had to do with using typedef with CString. Post VS 6, that's not possible. I just changed references by hand, and it compiles now.