Skip to main content
gamedev.net
🔒 Locked 🎲 GameMaker

Solving recursive inclusion problems

Started by Roots 6 replies 1.5k views
Original Post
Roots
Roots
I'm sure someone has had this problem before. Here's the thing. boot.h includes global.h global.h includes data.h data.h includes map.h map.h includes pause.h pause.h includes global.h ... BUT HEY!!! When pause.h includes global.h it gets to this line in global.h : #ifndef __GLOBAL_HEADER__ (then define __GLOBAL_HEADER__ and include the file) BUT, since we defined __GLOBAL_HEADER__ in the very beginning of the global.h (when we first included it from boot.h), this file doesn't get included, AND it also didn't get to it's data definitions (because it first started including files), sh*t is on it's way ******************************* We've been trying to find a good fix for this problem and I'm wondering if anyone has any suggestions. Here's a list of our inclusion paths. (source -> dest, means that source #includes dest)

audio.h -> utils.h
boot.h -> video.h, audio.h, global.h, utils.h, map.h, (maybe quit.h)
data.h -> video.h, audio.h, global.h, utils.h, boot.h, map.h, battle.h, menu.h
global.h -> data.h, utils.h (it may be possible to get rid of data.h)
map.h -> video.h, audio.h, global.h, pause.h, quit.h, battle.h, menu.h, scene.h
pause.h -> video.h, audio.h, global.h
quit.h -> video.h, audio.h, global.h, boot.h
scene.h -> video.h, audio.h, global.h, pause.h
utils.h -> {nothing}
video.h -> utils.h 
Well at least that's the core inclusion tree. There's also more stuff in the video engine and map_editor but there doesn't seem to be a problem there yet. To get an idea of what our inclusion tree looks like, one of my staff members made this quick image: And I proposed cleaning it up like this: And then put forward class declarations for all the game mode classes (boot, battle, map, etc) in global.h Then I think everything will be ok...? I'm not sure though. The biggest problem here is with data.h, which handles are C++<=>Lua data handling. All of our config settings and game data are stored in Lua so for the game settings to initialize global.h needs to call a function in data.h to initialize it's members, and data.h needs to include global.h so that it knows the class definition and can set those members. Is there a better way around this? Any help would be greatly appreciated, thanks! [smile]
JohnBolton
JohnBolton
If you have this situation:
*** a.h ***#include "b.h"class a{    b    m_b;};*** b.h ***#include "a.h"class b{    a    m_a;};
Keep in mind that circular dependencies like this frequently (but not always) indicate a poor design. The way to fix it is like this:
*** a.h ***class b;class a{    b *  m_b; // Now created by the constructor or passed as a parameter to the constructor};*** b.h ***#include "a.h"class b{    a    m_a;};
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Roots
Roots
Ok thanks. That's actually what we are implementing right now I was just wondering if there was another, possibly more convenient way of doing it is all. [smile]
oliii
oliii
Just for info, "#pragma once " includes files only once (VC6). But it's VC6 only. And It's more than saving typing.

Usually, when adding a new h/cpp combo, you should be able to compile the .cpp file with only including his corresponding h file (with no other code or other includes in it). If it doesn't build, then you have header dependency problems. the CPP would look like..

/*------------------------------------------------------------------File: Vector.cppStarted: 11/03/2003 10:15:35  $Header: $$Revision: $$Locker: $$Date: $  Author: Oliii------------------------------------------------------------------Module: Description: ------------------------------------------------------------------$History: $------------------------------------------------------------------*/#include "core/core.h"#include "Maths/Vector.h"


"core.h" is a file that has to be included everywhere in the code. COntains pre-processor definitition and trivial typedefs. The problem is, if you include it into headers, then everytime a compilation is run, the header has to be pulled out, and core would be processed many many times per compiled file. SO including it instead in the cpp should speed up the compilation.

Also, by using forward declarations whereever possible, you also reduce the compilation time. It's good to keep the number of headers included into other headers to a minimum.

Along the same lines, doing this

#ifdef __INC_MATHS_VECTOR_H__
#include "Maths/Vector.h"
#endif //__INC_MATHS_VECTOR_H__

should speed up the compilation, since the file Vector.h won't have to be opened. That's in escence what "#pragma once" does. Saves the opening and parsing of the file again and again.

I haven't found a way to wrap that into a macro yet though... would be something like

#define INCLUDE(A) "#ifndef INC_"#A"\n"\\  "#define  INC_"#A"\n"\\  "#include \""#A".h\"\n"\\  "#endif\n"  printf(INCLUDE(Maths/Vector));


but it's obvously not working, and I don't think that could be done with ANSI C++ (can't put preprocessor keywords inside a preprocess macro, can't stringify "Maths/Vector" into "MATHS_VECTOR"....).

Anyway, after that, you should be able to put the includes in any order you like. Quite handy, so you can organise them by include names, engine/game files or platform specific.
Everything is better with Metal.
Zahlman
Zahlman
Quote:
Original post by oliii
I haven't found a way to wrap that into a macro yet though... would be something like

*** Source Snippet Removed ***

but it's obvously not working, and I don't think that could be done with ANSI C++ (can't put preprocessor keywords inside a preprocess macro, can't stringify "Maths/Vector" into "MATHS_VECTOR"....).


Eww, using the C preprocessor to generate a string, and then write C code to output that as a file? Ugh. Use a proper scripting language to generate files from a template:

import osdef make_files(name):  os.makedirs(os.path.split(name)[0])  cpp = file(name + ".cpp", "w")  cpp.write('#include "%s.h"\n\n' % name)  cpp.close()  h = file(name + ".h", "w")  symbol = name.replace("/", "_").upper()  h.write("""#ifndef %s_H#define %s_H#endif""" % (symbol, symbol))  h.close()if __name__ == "__main__":  import sys  make_files(sys.argv[1])  # If you like, add a system() call here to launch your favourite text  # editor with the files in question. After all, you already imported os ;)
cozman
cozman
As far as auto-generating source shells with include guards: makecpp.py is a little thing I wrote that takes care of this for me.

Usage:
python makecpp.py ClassName [RootNamespace subNS1 subNS2...]


Feel free to use/modify it for your own needs, public domain. (A PM if you decide to use/modify it wouldn't hurt)
oliii
oliii
Quote:
Original post by Zahlman
Eww, using the C preprocessor to generate a string, and then write C code to output that as a file? Ugh. Use a proper scripting language to generate files from a template:

*** Source Snippet Removed ***


I already have a macro to write me header guards on H files. That's what I mean, there is nothing that would make the one time inclusion automatic in C/C++ using preprocessor. #pragma once will do it, but is C++ only. something like #include_once "blablabla.h" would be nice.
Everything is better with Metal.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.