|
allegro.h desperation: multiple definitions |
Paul Wilhelm
Member #10,731
February 2009
|
Good evening Allegro community! To introduce myself first: my Name is Paul (19 at this time) and I'm from Germany. Nevertheless, I am definately not a C expert yet. Unfortunately I have some serious problems with my header files. Since every module ("main.c", "video.c", "logic.c", ...) accesses functions of the Allegro library, I have to include "allegro.h" in every single header file of all the modules. But when I compile, I get a huge amount of "multiple definition" errors. What is the right way of using header files? Believe me, for the last two days I tried everything possible to get the whole thing to work, but I just couldn't make it. I really hope, someone here can help me. Thanks! Greetings from Germany, ______________________________________________ |
OnlineCop
Member #7,919
October 2006
|
If you're reusing global variables in more than a single .C file, your compiler will complain. If you have a global that you will use in multiple places, pick one of the files to be its "official declaration" file. Everywhere else, define those variables as "extern". main.c: int MAP_WIDTH; int MAP_HEIGHT; video.c: extern int MAP_WIDTH; extern int MAP_HEIGHT; logic.c: // same as in video.c: extern int MAP_WIDTH; extern int MAP_HEIGHT; That sounds like one of your bigger problems. If you use header files, MAKE SURE that you put in header guards. At the top of those header files, you want to use the preprocessor "#ifndef" checks: main.h: #ifndef MAIN_H #define MAIN_H // Everything found within your main.h file as normal here... #endif Now, it doesn't matter WHICH source files are trying to include that header file... when it gets compiled and linked, it will only include it once.
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Quote: If you have a global that you will use in multiple places, pick one of the files to be its "official declaration" file. Everywhere else, define those variables as "extern". main.c: int MAP_WIDTH; video.c: extern int MAP_WIDTH; logic.c: // same as in video.c: No, that's not correct. If you need to access data from outside the source file, you need to include the header that declares it, and in that header is where it should be declared as extern. Then, define that data in exactly one source file. The header makes it available for reference, the source file gives it a place to be stored. When the multiple object files consisting of the project are linked together there will only be one actual definition then. global_data.h // #ifndef global_data_H #define global_data_H #include "Settings_struct.h" extern Settings settings; // declare other globally accessible data as extern here #endif // global_data_H // global_data.c // Settings settings; // main.c // #include "global_data.h" /// In main... LoadSettings(&settings , "config_file.txt"); //
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
LennyLen
Member #5,313
December 2004
|
Quote: No, that's not correct. If you need to access data from outside the source file, you need to include the header that declares it, and in that header is where it should be declared as extern. Then, define that data in exactly one source file. The header makes it available for reference, the source file gives it a place to be stored. When the multiple object files consisting of the project are linked together there will only be one actual definition then. Both ways are equally correct.
|
Thomas Fjellstrom
Member #476
June 2000
|
Quote: Both ways are equally correct. Both ways look identical to the compiler. -- |
LennyLen
Member #5,313
December 2004
|
Quote: Both ways look identical to the compiler. Yea, I should have extended that a bit: Both ways are equally correct in that to the comiler they're the same so the only real difference is in programming style. I do it a similar way to Edgar. I have a "globals.h" file that contains all the extern declarations. I put the non-extern declarations in main.c and include globals.h in any other .c file that needs access to any of the globals. Header guards prohibit multiple declarations. EDIT: N.b. I sometimes use declaration when I mean definition, and vice versa.
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Well, I guess that method would work, but it's not good practice to do that manually. The extern declaration belongs in a header because it gives you the interface. When the preprocessor runs, the effect would be the same but it's bound to give you problems trying to remember to manually add every external symbol to every file you want to access them in. Putting them into a header also eliminates unnecessary code replication as well. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
LennyLen
Member #5,313
December 2004
|
Quote: Well, I guess that method would work Just for clarification, I assume that by "that method" you mean what OnlineCop described, since the way that I mentioned does put the extern declarations in a header file.
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
I suppose I should have been more explicit then. Yes, adding an extern declaration to each source file manually will work, but it is better practice to do that by including a header containing the extern declarations instead. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Johan Halmén
Member #1,550
September 2001
|
If one of the multiple definitions is BITMAP, remember to do this. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest. |
Paul Wilhelm
Member #10,731
February 2009
|
Thanks for your quick replies and the clarifications on the whole extern / global declarations topic. But that doesn't seem to be my problem, I am sorry if I didn't express myself good enough. GCC complains about the multiple inclusion of allegro.h. Let me give you an example, which describes exactly my problem: main.c: #include "main.h" int main(void) { return 0; } main.h: #ifndef MAIN_H_INCLUDED #define MAIN_H_INCLUDED #include <allegro.h> int abc = KEY_UP; #endif init.c: #include "init.h" void foo() { } init.h: #ifndef INIT_H_INCLUDED #define INIT_H_INCLUDED #include <allegro.h> BITMAP *noob; void foo(); #endif I am compiling this with gcc -std=gnu99 -Wall -O2 `allegro-config --libs` main.c init.c -o main and I get a huge list of multiple definition errors: /tmp/ccU6qa1p.o: In function `bmp_read24': init.c:(.text+0x0): multiple definition of `bmp_read24' /tmp/cctySkfU.o:main.c:(.text+0x0): first defined here /tmp/ccU6qa1p.o: In function `bmp_write24': init.c:(.text+0x20): multiple definition of `bmp_write24' /tmp/cctySkfU.o:main.c:(.text+0x20): first defined here
Like I said in my first post, both modules make use of the Allegro library. Greetings, ______________________________________________ |
Edgar Reynaldo
Major Reynaldo
May 2007
|
There is one problem in your main.h header. It defines an int named abc instead of declaring it. If more than one source module includes main.h, then each will have defined their own 'int abc'. Then when they are linked together it will give you a redefinition error for it. Similarly, your init.h header does the same thing with your 'BITMAP* noob' variable definition. The redefinition errors you are getting don't seem related though. Try moving the `allegro-config --libs` option to the end of the compilation command. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Paul Wilhelm
Member #10,731
February 2009
|
That is the thing. I am now actually only compiling these two exact files, which both don't include each others header files. I am aware of the problem you just described, when other modules include the same definitions. I moved the allegro-config option to the end of the command, like you said, but it doesn't seem to matter. I really don't know what to do... ______________________________________________ |
LennyLen
Member #5,313
December 2004
|
Your code is fine, as I was able to build it with no errors (except for the missing END_OF_MAIN() which I needed since I'm on Windows). Try comiling the sources individually and link the object files with the allegro library. EDIT: I jumped to the command line, and the following worked for me: gcc -o main.exe main.c init.c -lalleg -Wall -O2 -std=gnu99 If you replace -lalleg with `allegro-config --libs`, does it work?
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
Well, those are linking errors, not compilation errors, so perhaps `allegro-config --libs` is not giving you the correct output somehow. Start from the beginning - post which OS and OS version you are compiling on, as well as which version of Allegro you are using. Post the output of `allegro-config --libs` by itself as well. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Paul Wilhelm
Member #10,731
February 2009
|
Allegro Version: 4.2.2 I am using Ubuntu 8.10 (intrepid). If I replace the allegro-config parameter by -lalleg, I get even more error output. EDIT: WOOT! I experimented, and it works when I leave out the -std=gnu99. Any explanations? Thank you all for your help so far. :-) ______________________________________________ |
Thomas Fjellstrom
Member #476
June 2000
|
Quote: Any explanations? IIRC C99 changes how "extern inline" (or something like that) works. -- |
LennyLen
Member #5,313
December 2004
|
Quote: IIRC C99 changes how "extern inline" (or something like that) works. So why did it compile without a problem for me with that option? Some difference in the Windows and Linux builds of Allegro?
|
Paul Wilhelm
Member #10,731
February 2009
|
LennyLen: Which GCC version are you using? Mine is 4.3.2. I just read that gcc does not implement C99 completely yet. However, I'm using the C89 standard now. Now I can't do cool stuff like for (int a = 0; ...) anymore, but I can live with that. Thanks so far! ______________________________________________ |
LennyLen
Member #5,313
December 2004
|
Quote:
Mine is 4.3.2. I just read that gcc does not implement C99 completely yet. I'm using GCC 3.4.5, which is the current Windows version. MinGW is getting a little bit behind - even the WIP branch is only GCC 4.3.0.
|
OnlineCop
Member #7,919
October 2006
|
LennyLen said: I'm using GCC 3.4.5, which is the current Windows version... Are you sure? My mingw version shows: gcc (GCC) 4.3.0 20080305 (alpha-testing) mingw-20080502 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. g++ (GCC) 4.3.0 20080305 (alpha-testing) mingw-20080502 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
gnolam
Member #2,030
March 2002
|
Quote: gcc (GCC) 4.3.0 20080305 (alpha-testing) mingw-20080502 Emphasis added. -- |
|