• Advertisement
Sign in to follow this  

Accessing Full Source

This topic is 2263 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I work on quite a few fairly large programs (nothing huge, but about 30 different files and 20 different classes.) Well I use all these classes throughout the entire program, among other variables and things like that which need to be accessed from everywhere. I have a habit right now of the format below, which sucks. Basically it works perfectly but every time I change ANY header file, the entire program needs to be recompiled. What is the 'proper' way to go about this? I was thinking that just have every single source include all class headers which wouldn't need to recompile the whole program, but it's ugly.


// Class Source...
#include "ClassHeader.h"

// Class Header...
#include "Program.h"

// Program Header
// Include all Windows SDK's
// Include all class headers

Share this post


Link to post
Share on other sites
Advertisement
Precompiled headers will save you compile time.

One other thing I always do is add the oldschool headerguards and include the class definition header file as the last one in the CPP with the implementation. This way you can't have any cross includes or dependencies going wrong if you keep yourself to this rule. All other includes before the header containing the definition of the implementation in the CPP file.

Share this post


Link to post
Share on other sites
Include only the headers you need in source files.
Avoid including headers in headers as far as possible; use forward declarations and techniques such as the pimpl idiom.
For stable headers, consider using a precompiled header.

You certainly don't want to be including every header in every source file (for precisely the reason you've discovered -- it results in worst-case incremental build times).

Share this post


Link to post
Share on other sites
In addition to the other suggestions I'd suggest using the #pragma once directive, it is almost universally accepted now by most compilers and unless you do any funky pre-processor tricks it can speed up compile times considerably.

Given your example though, I try to stick to a standard layout:


// .h
#pragma once

#include <Core/Types.h> // Basically uint32_t, intptr_t, NULL, etc.

// ONLY includes which are absolutely required. I.e. if I "contain" a Vector3fv, I need to include it here.
// Otherwise, always reference them via pointer or reference.

// Optional: global forward references.
class GlobalIcky;

// Optional: other namespace forward references.
namespace other
{
class otheritem;
}

//
namespace whatever
{
// Same namespace forward references.
}


// ----------- In the cpp
#include <myheader.h>
#include <Math/Vector3.h>
....etc


Now, assume you are in code which uses Vector3fv a lot. A habit many folks have, which is bad, is to go into a core header and include it from there, DON'T do that. Not only does this slow compiles down it also drives coworkers who have had to clean up such messes, insane. Instead, consider making a "namespace" include such as:


// In subsystem named header. I.e. if the namespace is Go, this would be Go.h. Example from my game object system.
#pragma once

#include <Core/Types.h>
#include <Math/Vector3.h>

....


Then in subsystem related headers, include this centralized header instead of the types header. It is not "as" good as managing each header individually but at least it doesn't spread throughout the entire source code. And, in this case, pragma once can greatly decrease compile times if you start including things such as std or boost which can be compile time hogs. Of course, if another subsystem includes this subsystem, make sure to make another subsystem header to include the other subsystem instead of directly including it. I.e. if Go depends on Core/Types and Ai depends on Go, make an Ai.h which includes "Go.h" instead of including types and make sure all your subsystem headers include Ai.h instead of parts of Go. This is a maintenance item, if you refactor Go so it has minimal includes at a later time, it will likely break any dependent libraries either way, but in this way mostly the dependencies are going to be things like <map> no longer being included in Go.h instead of in some random header somewhere.

This is simply suggestion based on my experience. I don't keep the headers perfectly clean at all times during heavy development and this sort of minimal discipline helps later when I go back and clean things up. At each point though, you can compile the files in the subsystem, make sure that works then move to dependencies one by one. Of note, this came about as I tend to structure my projects as very small individual static libraries. So my unit test is over 100 projects in VC and XCode because it includes each item individually, while my real code (game/experiment/whatever at the time) simply embeds all the individual items into a larger library. This has become habit since I started using CMake/Premake and other build generators instead of IDE project management.

It is all part of project architecture. I spent a lot of time with CMake (hate the language, love the tool) in order to make my desire work with the ability to pick and choose which bits to pull in and which to ignore. But it goes hand in hand with making sure your include files are fairly clean and you include as little as absolutely possible.

Share this post


Link to post
Share on other sites

In addition to the other suggestions I'd suggest using the #pragma once directive, it is almost universally accepted now by most compilers and unless you do any funky pre-processor tricks it can speed up compile times considerably.

Most modern compilers perform the same optimisation for header files with inclusion guards - you aren't in general going to see much of a performance difference between the two.

Share this post


Link to post
Share on other sites
among other variables and things like that which need to be accessed from everywhere[/quote]

You should take a look at the "extern" keyword then.

Share this post


Link to post
Share on other sites

[quote name='AllEightUp' timestamp='1323558312' post='4892653']
In addition to the other suggestions I'd suggest using the #pragma once directive, it is almost universally accepted now by most compilers and unless you do any funky pre-processor tricks it can speed up compile times considerably.

Most modern compilers perform the same optimisation for header files with inclusion guards - you aren't in general going to see much of a performance difference between the two.
[/quote]

Not to say this is incorrect but I have found that those optimizations are not as good as using the pragma. Very often I find noticeable speed increases by using the pragma, especially when a file in question includes boost. Unfortunately I don't have a specific way to make an example of this, I just found it by accident in a couple places where bog standard include guards on a header left the file compiling 2-3 times longer than when the guards were replaced with the pragma. The same behavior was noted on GCC, Clang and VC, though in different files most often. Take this with a grain of salt, never did figure out the problem just noted it was never a problem with the pragma and switched to it exclusively.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement