Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Multiple source files and headers

Credits go to CGamesPlay and Dustin Dettmer for helping out!
This thread is locked; no one can reply to it. rss feed Print
Multiple source files and headers
moon_rabbits
Member #8,469
March 2007
avatar

I have two .cpp files and one .h file in my current project, here's the source:

main.cpp

1/***********************
2 * Basic Map Editor *
3 * Kelly Crawford *
4 * 2 April 2007 *
5 ***********************/
6 
7#include <allegro.h>
8extern "C" {
9 #include <agup.h>
10}
11#include "dialog.h"
12 
13 
14 
15int main()
16{
17 // initialize allegro
18 allegro_init();
19 set_color_depth(16);
20 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
21 install_keyboard();
22 install_mouse();
23
24 agup_init(abeos_theme); // initialize agup
25
26 do_dialog(the_dialog, -1); // start dialog
27 agup_shutdown(); // release dialog
28 return 0;
29}
30END_OF_MAIN()

menu.cpp

1/**********************
2 * Main Menu Source *
3 * Kelly Crawford *
4 * 4 April 2007 *
5 **********************/
6
7#include <allegro.h>
8extern "C"{
9 #include <agup.h>
10}
11#include "dialog.h"
12 
13int NewMap()
14{
15 the_dialog[2].flags = D_GOTFOCUS;
16}

dialog.h

1 
2#ifndef DIALOG_INF_H
3#define DIALOG_INF_H
4 
5int NewMap();
6 
7MENU file_child[] =
8{
9 /* (text) (proc) (child) (flags) (dp) */
10 { "&New", NewMap, NULL, 0, NULL },
11 { "&Load", NULL, NULL, 0, NULL },
12 { "&Save", NULL, NULL, 0, NULL },
13 { "", NULL, NULL, 0, NULL },
14 { "&Quit", NULL, NULL, 0, NULL }
15};
16 
17MENU edit_child[] =
18{
19 /* (text) (proc) (child) (flags) (dp) */
20 { "&Resize", NULL, NULL, 0, NULL },
21 { "&Tileset", NULL, NULL, 0, NULL },
22 { "&Name", NULL, NULL, 0, NULL }
23};
24 
25MENU about_child[] =
26{
27 /* (text) (proc) (child) (flags) (dp) */
28 { "&About", NULL, NULL, 0, NULL },
29 { "&Help", NULL, NULL, 0, NULL }
30};
31 
32MENU main_menu[] =
33{
34 /* (text) (proc) (child) (flags) (dp) */
35 { "&File", NULL, file_child, 0, NULL },
36 { "&Edit", NULL, edit_child, 0, NULL },
37 { "&About", NULL, about_child, 0, NULL }
38};
39 
40DIALOG the_dialog[] =
41{
42 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
43
44 { d_agup_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
45
46 { d_agup_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, main_menu, NULL, NULL },
47
48 { d_agup_box_proc, 50, 50, 200, 200, 0, 0, 0, D_HIDDEN, 0, 0, NULL, NULL, NULL },
49
50 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
51};
52 
53#endif

It SHOULD compile right, right? Except I'm getting errors that say all of the menus and the_dialog are being declared multiple times. Shouldn't the lines:

#ifndef DIALOG_INF_H
#define DIALOG_INF_H

prevent this?

Dustin Dettmer
Member #3,935
October 2003
avatar

Quote:

all of the menus and the_dialog are being declared multiple times.

They have to be declared in a .cpp file. Include guards can guard against some things, but not this.

moon_rabbits
Member #8,469
March 2007
avatar

How do I do that, though?

Now I have:

dialog.h

#ifndef DIALOG_INF_H
#define DIALOG_INF_H

int NewMap();

MENU file_child[5];
MENU edit_child[3];
MENU about_child[2];
MENU main_menu[3];

DIALOG the_dialog[4];

#endif

and the dialog.cpp file:

1/************************
2 * Dialog and Menu Src *
3 * Kelly Crawford *
4 * 4 April 2007 *
5 ************************/
6 
7#include "dialog.h"
8 
9file_child[] =
10{
11 /* (text) (proc) (child) (flags) (dp) */
12 { "&New", NewMap, NULL, 0, NULL },
13 { "&Load", NULL, NULL, 0, NULL },
14 { "&Save", NULL, NULL, 0, NULL },
15 { "", NULL, NULL, 0, NULL },
16 { "&Quit", NULL, NULL, 0, NULL }
17};
18 
19edit_child[] =
20{
21 /* (text) (proc) (child) (flags) (dp) */
22 { "&Resize", NULL, NULL, 0, NULL },
23 { "&Tileset", NULL, NULL, 0, NULL },
24 { "&Name", NULL, NULL, 0, NULL }
25};
26 
27about_child[] =
28{
29 /* (text) (proc) (child) (flags) (dp) */
30 { "&About", NULL, NULL, 0, NULL },
31 { "&Help", NULL, NULL, 0, NULL }
32};
33 
34main_menu[] =
35{
36 /* (text) (proc) (child) (flags) (dp) */
37 { "&File", NULL, file_child, 0, NULL },
38 { "&Edit", NULL, edit_child, 0, NULL },
39 { "&About", NULL, about_child, 0, NULL }
40};
41 
42the_dialog[] =
43{
44 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
45
46 { d_agup_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
47
48 { d_agup_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, main_menu, NULL, NULL },
49
50 { d_agup_box_proc, 50, 50, 200, 200, 0, 0, 0, D_HIDDEN, 0, 0, NULL, NULL, NULL },
51
52 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
53};

The other two .cpp files (menu.cpp and main.cpp) are unmodified, but I still get the same errors.

Dustin Dettmer
Member #3,935
October 2003
avatar

Add the word 'extern' to the variable definitions in your header files.

extern MENU file_child[5];
extern MENU edit_child[3];
// etc ...

Kibiz0r
Member #6,203
September 2005
avatar

Doesn't that also mean adding the type identifier to the .cpp file?

MENU file_child[5] = ...
MENU edit_child[3] = ...
//etc ...

LennyLen
Member #5,313
December 2004
avatar

Quote:

extern MENU file_child[5]; // incorrect
extern MENU edit_child[3]; // incorrect

extern MENU file_child[]; // correct
extern MENU edit_child[]; // correct

Quote:

Doesn't that also mean adding the type identifier to the .cpp file?

MENU file_child[5] = ...
MENU edit_child[3] = ...
//etc ...

The declaration is made in one of the .cpp files, and all the others include the .h file that has the extern definitions.

Kitty Cat
Member #2,815
October 2002
avatar

LennyLen said:

Quote:

extern MENU file_child[5]; // incorrect
extern MENU edit_child[3]; // incorrect

extern MENU file_child[]; // correct
extern MENU edit_child[]; // correct

The former is perfectly correct (as is the latter). Putting the values like that even helps the compiler, in some situations.

That said, you generally don't put the size of the array in MENU or DIALOG arrays, since they're NULL terminated anyway, it makes increasing or decreasing the size easier, and the benefits aren't too useful when dealing with them. There's nothing wrong with it of course, it's just not something I see done.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

LennyLen
Member #5,313
December 2004
avatar

Quote:

The former is perfectly correct (as is the latter). Putting the values like that even helps the compiler, in some situations.

Oh? I thought it counted as a multiple declaration if more than one file includes that header?

Kitty Cat
Member #2,815
October 2002
avatar

Not as long as it's declared extern. Putting in the array size just lets the compiler know how big the array is (without it, things like sizeof(file_child) won't work).

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

CGamesPlay
Member #2,559
July 2002
avatar

I wrote about this about a week ago... Read up!

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

moon_rabbits
Member #8,469
March 2007
avatar

I'm still a little bit confused, as I've never used extern before. I get it, but it's still not working.

main.cpp has remained unchanged.

dialog.h is:

1/*************************
2 * Dialog + Menu Header *
3 * Kelly Crawford *
4 * 4 April 2007 *
5 *************************/
6
7#ifndef DIALOG_INF_H
8#define DIALOG_INF_H
9 
10#include <allegro.h>
11 
12extern int NewMap();
13 
14extern DIALOG the_dialog[];
15 
16extern MENU main_menu[];
17extern MENU file_child[];
18extern MENU edit_child[];
19extern MENU about_child[];
20 
21#endif

and dialog.cpp is:

1/************************
2 * Dialog and Menu Src *
3 * Kelly Crawford *
4 * 4 April 2007 *
5 ************************/
6 
7#include <allegro.h>
8extern "C" {
9 #include <agup.h>
10}
11 
12#include "dialog.h"
13 
14// menu information
15 
16MENU main_menu[] =
17{
18 /* (text) (proc) (child) (flags) (dp) */
19 { "&File", NULL, file_child, 0, NULL },
20 { "&Edit", NULL, edit_child, 0, NULL },
21 { "&About", NULL, about_child, 0, NULL }
22};
23//-----------------------------------------------------------------------
24 
25MENU file_child[] =
26{
27 /* (text) (proc) (child) (flags) (dp) */
28 { "&New", NewMap, NULL, 0, NULL },
29 { "&Load", NULL, NULL, 0, NULL },
30 { "&Save", NULL, NULL, 0, NULL },
31 { "", NULL, NULL, 0, NULL },
32 { "&Quit", NULL, NULL, 0, NULL }
33};
34//-----------------------------------------------------------------------
35 
36MENU edit_child[] =
37{
38 /* (text) (proc) (child) (flags) (dp) */
39 { "&Resize", NULL, NULL, 0, NULL },
40 { "&Tileset", NULL, NULL, 0, NULL },
41 { "&Name", NULL, NULL, 0, NULL }
42};
43//-----------------------------------------------------------------------
44 
45MENU about_child[] =
46{
47 /* (text) (proc) (child) (flags) (dp) */
48 { "&About", NULL, NULL, 0, NULL },
49 { "&Help", NULL, NULL, 0, NULL }
50};
51 
52//-----------------------------------------------------------------------
53//-----------------------------------------------------------------------
54// Dialog information
55 
56DIALOG the_dialog[] =
57{
58 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
59
60 { d_agup_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
61
62 { d_agup_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, main_menu, NULL, NULL },
63
64 { d_agup_box_proc, 50, 50, 200, 200, 0, 0, 0, D_HIDDEN, 0, 0, NULL, NULL, NULL },
65
66 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
67};

And yet I am still getting multiple definition errors.

Also, should I include allegro.h and agup.h in all the .cpp files, or just in the dialog.h, since dialog.h is included in all the .cpp files, doesn't that mean allegro is too? Or would it be better form to just include it in all the files it's used in, even if it was already included by dialog.h?

Dustin Dettmer
Member #3,935
October 2003
avatar

You can include allegro.h and agup.h in as many or as few places as you would like, thats the beauty of headers.

Kelly said:

I am still getting multiple definition errors.

I can't see offhand what else is wrong, here are a few comments on stuff though:

extern int NewMap();

Its not really important, but extern is assumed for all function definitions. If you wanted to sound smart in front of C geeks you'd want to drop the explicit usage of the word here.

You also never implement the NewMap function in dialog.cpp, is there reason for this?

Also IIRC your MENU lists should end with a NULL instance, like the dialog does. Aka:

MENU main_menu[] =
{
   /*   (text)     (proc)   (child)         (flags)    (dp) */
      { "&File",    NULL,    file_child,     0,         NULL },
      { "&Edit",    NULL,    edit_child,     0,         NULL },
      { "&About",   NULL,    about_child,    0,         NULL },
      { NULL }
};

However, I can't see any multiple definition errors in your code. Could you paste your exact compiler command and the resulting errors. Its important that all this information is copied and pasted exactly (in all its jargony glory).

moon_rabbits
Member #8,469
March 2007
avatar

NewMap() was never implemented because I was going to write the function, but I got all these multiple definition errors and haven't gotten around to it yet. I removed the declaration from my source code for now just for less clutter while we work this out.

So once again, here is all the source + errors:

dialog.h:

1/*************************
2 * Dialog + Menu Header *
3 * Kelly Crawford *
4 * 4 April 2007 *
5 *************************/
6
7#ifndef DIALOG_INF_H
8#define DIALOG_INF_H
9 
10#include <allegro.h>
11 
12extern DIALOG the_dialog[];
13 
14extern MENU main_menu[];
15extern MENU file_child[];
16extern MENU edit_child[];
17extern MENU about_child[];
18 
19#endif

main.cpp:

1/***********************
2 * Basic Map Editor *
3 * Kelly Crawford *
4 * 2 April 2007 *
5 ***********************/
6 
7#include <allegro.h>
8extern "C" {
9 #include <agup.h>
10}
11#include "dialog.h"
12 
13int main()
14{
15 // initialize allegro
16 allegro_init();
17 set_color_depth(16);
18 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
19 install_keyboard();
20 install_mouse();
21
22 agup_init(abeos_theme); // initialize agup
23
24 do_dialog(the_dialog, -1); // start dialog
25 agup_shutdown(); // release dialog
26 return 0;
27}
28END_OF_MAIN()

dialog.cpp:

1/************************
2 * Dialog and Menu Src *
3 * Kelly Crawford *
4 * 4 April 2007 *
5 ************************/
6 
7#include <allegro.h>
8extern "C" {
9 #include <agup.h>
10}
11 
12#include "dialog.h"
13 
14// menu information
15 
16MENU main_menu[] =
17{
18 /* (text) (proc) (child) (flags) (dp) */
19 { "&File", NULL, file_child, 0, NULL },
20 { "&Edit", NULL, edit_child, 0, NULL },
21 { "&About", NULL, about_child, 0, NULL }
22};
23//-----------------------------------------------------------------------
24 
25MENU file_child[] =
26{
27 /* (text) (proc) (child) (flags) (dp) */
28 { "&New", NULL, NULL, 0, NULL },
29 { "&Load", NULL, NULL, 0, NULL },
30 { "&Save", NULL, NULL, 0, NULL },
31 { "", NULL, NULL, 0, NULL },
32 { "&Quit", NULL, NULL, 0, NULL }
33};
34//-----------------------------------------------------------------------
35 
36MENU edit_child[] =
37{
38 /* (text) (proc) (child) (flags) (dp) */
39 { "&Resize", NULL, NULL, 0, NULL },
40 { "&Tileset", NULL, NULL, 0, NULL },
41 { "&Name", NULL, NULL, 0, NULL }
42};
43//-----------------------------------------------------------------------
44 
45MENU about_child[] =
46{
47 /* (text) (proc) (child) (flags) (dp) */
48 { "&About", NULL, NULL, 0, NULL },
49 { "&Help", NULL, NULL, 0, NULL }
50};
51 
52//-----------------------------------------------------------------------
53//-----------------------------------------------------------------------
54// Dialog information
55 
56DIALOG the_dialog[] =
57{
58 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
59
60 { d_agup_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
61
62 { d_agup_menu_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, main_menu, NULL, NULL },
63
64 { d_agup_box_proc, 50, 50, 200, 200, 0, 0, 0, D_HIDDEN, 0, 0, NULL, NULL, NULL },
65
66 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
67};

And the errors:

Quote:

multiple definition of `main_menu'
first defined here
multiple definition of `file_child'
first defined here
multiple definition of `edit_child'
first defined here
multiple definition of `about_child'
first defined here
multiple definition of `the_dialog'
first defined here
ld returned 1 exit status
[Build Error] [guistuff.exe] Error 1

Usually, when I double click an error in Dev-Cpp, it highlights the line where the error occurs. Unfortunately it is not taking me to the first definitions.

Dustin Dettmer
Member #3,935
October 2003
avatar

Quote:

Unfortunately it is not taking me to the first definitions.

Yes this is because it does not know where they are. Did you do a full recompile?

Also, the compile command itself would be helpful, you can get it by going to the "Compile Log" tab and selecting everything in that textbox.

**
To do a full recompile click this button:

591742

You can also hit control + F11.
** edited in later

moon_rabbits
Member #8,469
March 2007
avatar

:-[ I can't believe I didn't rebuild the project. It works now.

Thanks for the help~

Peter Wang
Member #23
April 2000

Quote:

Its not really important, but extern is assumed for all function definitions.

assumed for function declarations

Quote:

If you wanted to sound smart in front of C geeks you'd want to drop the explicit usage of the word here.

::)

Dustin Dettmer
Member #3,935
October 2003
avatar

Quote:

declarations

Ah right, I always mix up those two words:P

Go to: