Re: Avoid full recompilation
I'm not sure if I this is your case, but to avoid full recompiling, I use this schema :
In file "A.h" :
class A
{
public :
A();
virtual ~A();
....
};
In file "B.h" :
class A;
class B
{
A* m_PrivateA; ( or a PIMPL pointer )
public :
B();
virtual ~B();
};
and in file "B.cpp" :
#include "A.h"
#include "B.h"
B::B{}
{
m_PrivateA = new A;
}
B::~B{}
{
delete m_PrivateA;
}
This is a simple approach, I use much more a PIMPL mechanism, like Qt does, so I don't need to worry about resource leaks ( aka forgetting to delete the private class members )
Obviously, this schema will recompile B.cpp every time you change "A.h", but if you derive B class like this ( file "C.h" )
#include "B.h"
class C : public class B
{
public :
C() : B() {};
....
}
In file "C.cpp" :
#include "B.h"
If you change "A.h", "C.cpp" doesn't have to recompile ( if you don't need to include "A.h", of course... )
Re: Avoid full recompilation
If you only use pointers or references to a class (or struct), or if the class is just used as a function return value, then you do not need the class's full declaration.
A forward declaration is then enough: you may remove the #include and add a line of "class X;" instead.
(The compiler will tell you if you were wrong.)
After removal of the #include, you won't have the compile dependency any more.
(Side note: if class B contains an object of class A (not just a pointer or reference to it), or if it inherits from class A then you always need the full declaration and it is not possible to avoid the compile dependency.)
HTH
Re: Avoid full recompilation
Hi,
Thanks,
Will try and tell you if it is going well.
Re: Avoid full recompilation
Hi,
Just one question: I'm looking "qstring.h" and "qstring.cpp" from Qt sources. Why they use "#include" statments into cpp file? What is the diference on including a header on the h file or in the cpp file? I knew that the include statment must be on the header files only.
Thanks,
Re: Avoid full recompilation
Quote:
Originally Posted by
^NyAw^
What is the diference on including a header on the h file or in the cpp file?
Basically, (re)compilation time. If you include "A.h" file on "B.h" file, every time you change "A.h" ALL the files depending on it ( B.h, B.cpp and others ) MUST be recompiled.
But if you include only in B.cpp, all files depending on B.h MUST not be recompiled.
Quote:
I knew that the include statment must be on the header files only.
No, it must be only if absolutely necessary ( avoid it if possible ) !!. As a good practice, You usually have to put the declaration of classe's interface in h files and the implementation in cpp files.
And if you can do "tricks" like the ones I've said before, you will save time and dependencies between files.
Re: Avoid full recompilation
And if you could not strip out more #include statements, then you might want to resort to a hacky approach called unity builds. We use this in our company for a project with several thousand source/header files.
Re: Avoid full recompilation
I've never heard about Unity Builds but, wow !! It's a great ( and simple ) idea !! ;)
I'm dealing with a very big project with more than 300 modules and a complete build from scratch takes about 20 minutes on my machine.
I'll try that aproach and give you the results, but I'm sure will improve compilation speed.
Re: Avoid full recompilation
I think that the improvement of build times is only partially due to i/o issues. I would guess that the bigger save stems from the fact that stuff like STL (string, vector, ...) has to be compiled only once, templates only instanciated once...
Basically with something like UB the code base to be compiled is way smaller.
Re: Avoid full recompilation
Quote:
Originally Posted by
caduel
I think that the improvement of build times is only partially due to i/o issues. I would guess that the bigger save stems from the fact that stuff like STL (string, vector, ...) has to be compiled only once, templates only instanciated once...
Basically with something like UB the code base to be compiled is way smaller.
Actually you can avoid the whole recompilation using header guards / #pragma once already. So the real improvement of unity builds really is the file i/o operations.
Re: Avoid full recompilation
no.
If two different translation units (i.e. .cpp files) both include vector then the templates will be (included, i.e.) read twice, instanciated twice, and also compiled twice.
Include guards or #pragma once do not help here, as we are talking about separate translation units.
Re: Avoid full recompilation
Quote:
Originally Posted by
caduel
no.
If two different translation units (i.e. .cpp files) both include vector then the templates will be (included, i.e.) read twice, instanciated twice, and also compiled twice.
Include guards or #pragma once do not help here, as we are talking about separate translation units.
Hmmm... iirc I thought that header guards prevented exactly that behaviour? Of course, all the files will certainly be opened again (=> read twice) but they should not be compiled twice (because, for example, the preprocessor got told by a header guard to not include the following stuff any further).
BTW, if you want to use unity builds with incredibuild, I suggest creating 5-6 unity files. That's what we did at work and we managed to reduce a full recompile from 45 minutes to 6 minutes (of which ~50% is spent with linking).
Re: Avoid full recompilation
the compiler compiles file a.cpp and b.cpp separately.
A header x.hpp will not be included twice in a.cpp or b.cpp - that is prevented by the guards.
The header will, however, be included (and read, parsed, compiled) in both a.cpp and b.cpp if included there. The compiler is invoked twice after all: for each file separately. Therefore it can not know anymore whatever it did in a.cpp once working on b.cpp, so it has to do the work again. And that work (including io) can be quit a bit to do, esp. if templates and template metaprogramming (like in Boost) is used a lot. (C++ unlike C headers contain nontrivial stuff...)
Re: Avoid full recompilation
I don't understand how UB could be faster for large projects.
I imagine those projects for which it works must be very tightly connected indeed. A well-designed piece of software should have as little interdependency as possible, so when a change is made in one or two files only (especially if they're implementation files), there's no need to recompile the entire project. Only those files and their reverse dependencies.
Of course there are some files that are used in a large portion of the project. But they should be the exception rather than the rule. Is this not true?
Re: Avoid full recompilation
This morning I've tested to compile my "framework" with Unit Builds. It has 3 parts ( without taking in consideration specific business logic code ) :
- App launcher ( main executable, thats loads business logic as plugins )
- Admin business logic ( 2 lightweigth plugins )
- Main "Core" shared Library ( by now, 93 cpp files => Passed to a single UB )
The test has been very unsatisfactory to me. Compile time is the same : no gain ( some seconds but not a REAL gain ), and if i touch ANY module, forces to recompile ALL modules => 3 minutes in my library.
So IMO if you are careful with #including in .h files, only when you make major changes you will have a complete recompilation. And in your usual work if you're careful the traditional approach is better...
I'm using other "hacking" to avoid full recompiling and I can contain compile time to acceptable ranges :
- XX_p.h files & private implementations => also makes interface look better , improves library stability & version maintenance / compatibility is simpler.
- "class XX" in .h files, using references or pointers as parameters / return values and including XX.h in Cpp files.
So, that's my opinion : if you need to use UB, perhaps you haven't been too much careful creating your code...
Re: Avoid full recompilation
@caduel: Yeah, correct. It's interesting how ones memory about some things fades when it is rarely required. :-)
@Michiel and jpujolf:
Very good guess. That large project I am working is not very well designed. So in this company's tradition a hack was used to solve the issues other hacks created. I am glad I am not working there for much longer anymore ;-)
Basically there are 4 or 5 files which are included about everywhere, and which get changed just about ... everytime some other little tweak is needed (very, very bad design).