Ah, yep, there's circular includes in there. For example:
rgl includes application
application includes audio
audio includes rgl
rgl includes application ... and so on.
Here's a simplified example:
// aaa.h
#ifndef AAA_H
#define AAA_H
#include "bbb.h"
class AAA
{
BBB *b;
};
#endif
// bbb.h
#ifndef BBB_H
#define BBB_H
#include "aaa.h"
class BBB
{
AAA *a;
};
#endif
// main.cpp
#include "aaa.h"
int main()
{
return 0;
}
Here's what the preprocessor will do. First, it replaces the #include in main.cpp with the contents of aaa.h:
// main.cpp
#ifndef AAA_H
#define AAA_H
#include "bbb.h"
class AAA
{
BBB *b;
};
#endif
int main()
{
return 0;
}
Then it will replace the #include "bbb.h" with the contents of bbb.h:
// main.cpp
#ifndef AAA_H
#define AAA_H
#ifndef BBB_H
#define BBB_H
#include "aaa.h"
class BBB
{
AAA *a;
};
#endif
class AAA
{
BBB *b;
};
#endif
int main()
{
return 0;
}
That added another #include "aaa.h", so it has to replace that too:
// main.cpp
#ifndef AAA_H
#define AAA_H
#ifndef BBB_H
#define BBB_H
#ifndef AAA_H
#define AAA_H
#include "bbb.h"
class AAA
{
BBB *b;
};
#endif
class BBB
{
AAA *a;
};
#endif
class AAA
{
BBB *b;
};
#endif
int main()
{
return 0;
}
Now this is where it gets stuck. It can't replace the new #include "bbb.h" because that code is disabled by the include guards.
From the top, it checks if AAA_H isn't defined. It isn't, so it defines it.
Then it checks if BBB_H isn't defined. It isn't, so it defines it.
Then it checks if AAA_H isn't defined. But at this point it is (from above), so the entire contents of the third #ifdef block are removed.
// main.cpp
#ifndef AAA_H
#define AAA_H
#ifndef BBB_H
#define BBB_H
#ifndef AAA_H
//#define AAA_H
//
//#include "bbb.h"
//
//class AAA
//{
// BBB *b;
//};
//
#endif
class BBB
{
AAA *a;
};
#endif
class AAA
{
BBB *b;
};
#endif
int main()
{
return 0;
}
Now that the preprocessor has completed, the compiler works its way down the code. The first thing it sees (that isn't a # command) is class BBB, which contains an AAA. But AAA hasn't been declared yet, so the compiler gives an error and stops.
Generally, the headers shouldn't have dependencies on things that include them. So if rgl.hpp includes application.hpp, then it's risky for anything in application.hpp to rely on rgl.hpp. Same for audio.hpp, it shouldn't rely on application.hpp, and so on.
One fix for some of these things is to predeclare the types. So aaa.h doesn't really need to include bbb.h if instead it added the line:
class BBB;
That's enough to warn the compiler "hey, don't panic at this BBB thing, I'll fill in the details later". But that only works for pointers or references. You can't have a BBB object without all the details already specified. So this is fine:
class BBB;
BBB *b;
but this is invalid:
class BBB;
BBB b;
because it can't make a BBB without knowing the class contents, but pointers don't care.
Mostly it comes down to reorganising the headers to make sure dependencies don't loop back on themselves. It's rather tricky at times, this is one side of C++ I don't like compared to other languages.
Hmm, that got a bit long. My holidays ended today, so my brain has kicked back into teaching mode.