LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 10-07-2005, 11:56 AM   #1
jamesjoy
LQ Newbie
 
Registered: Aug 2005
Location: Louth, Ireland
Distribution: FC 4
Posts: 27

Rep: Reputation: 15
Compiling Multiple Files, g++ error. Please Help


I ve started trying to do a small amount of game programming in Linux using the allegro libaries. I m using g++ and trying to compile a program which contains 4 different source files setup.cpp input.cp main.cpp etc.

The command i ve tried is
g++ screen.cpp main.cpp -o v1 `allegro-config --libs`
and various variations of it and i keep getting this same error:

/tmp/cconwWAE.o(.bss+0x94): multiple definition of `scores'
/tmp/ccOaDbDs.o(.bss+0x94): first defined here
/tmp/cconwWAE.o(.bss+0x9c): multiple definition of `gameover'
/tmp/ccOaDbDs.o(.bss+0x9c): first defined here
/tmp/cconwWAE.o(.bss+0xa0): multiple definition of `bullets'
/tmp/ccOaDbDs.o(.bss+0xa0): first defined here
/tmp/cconwWAE.o(.bss+0xc0): multiple definition of `mybullets'
/tmp/ccOaDbDs.o(.bss+0xc0): first defined here
/tmp/cconwWAE.o(.bss+0x148): multiple definition of `tanks'
/tmp/ccOaDbDs.o(.bss+0x148): first defined here
/tmp/cconwWAE.o(.bss+0x160): multiple definition of `mytanks'
/tmp/ccOaDbDs.o(.bss+0x160): first defined here
collect2: ld returned 1 exit status

At the start of my header file i ve placed
#ifndef tank_h
#define tank_h

and then at the end

#endif tank_h

but it doesnt work Please help bin at this for ages and have had no luck

Thanks
 
Old 10-07-2005, 12:06 PM   #2
Dark_Helmet
Senior Member
 
Registered: Jan 2003
Posts: 2,786

Rep: Reputation: 374Reputation: 374Reputation: 374Reputation: 374
Ok, first, you need all the .cpp files listed on the command line:
Code:
g++ -o v1 screen.cpp main.cpp setup.cpp input.cpp `allegro-config --libs`
Second, are there any other flags needed for allegro? Some packages have two different sets of compiler flags. One for creating object code, the other for linking. An example is GTK version 1. It needs:
Code:
gcc -o program_name some_file.c `gtk-config --cflags` `gtk-config --libs`
Third, for the errors you report, are you declaring fundtions or variables of the same name anywhere inside your code? You shouldn't be. If the allegro libraries contain definitions with those names, then you should avoid using them and come up with something else. If your compile command is correct, then you don't need to worry about prototyping the allegro functions or anything along those lines. The library should take care of all that for you.

EDIT:
To be of much more help (like to test on my end), the code would be useful.

Last edited by Dark_Helmet; 10-07-2005 at 12:08 PM.
 
Old 10-07-2005, 01:08 PM   #3
deiussum
Member
 
Registered: Aug 2003
Location: Santa Clara, CA
Distribution: Slackware
Posts: 895

Rep: Reputation: 32
It kind of looks to me like there are global variables defined in one of your .h files somewhere. You should declare it extern in the .h file and then pick 1 and only 1 .cpp file to create an instance of it in. For example:

Code:
// h1.h

extern int someglobal;
Code:
// h1.cpp
#include "h1.h"

int someglobal = 0;
Code:
//h2.cpp
#include "h1.h"

int somefunc()
{
     someglobal = 10;
}
Basically, your linker is complaining because you have definitions of those variables in more than one object module so they conflict.

Last edited by deiussum; 10-12-2005 at 09:44 AM.
 
Old 10-07-2005, 07:16 PM   #4
jamesjoy
LQ Newbie
 
Registered: Aug 2005
Location: Louth, Ireland
Distribution: FC 4
Posts: 27

Original Poster
Rep: Reputation: 15
1st reply:
I d love to post the source so you could have a look but its 4 cpp files and 3 or 4 bitmaps so not sure how id manage that!!
Not totaly sure if other allegro commands exist for compiling multiple files havent found anything in my googling on the subject and there is nothing in any of the books i ve bin using.

2nd reply
I dont quite understand what you are suggesting but is it that i have defined some of the varibles more than once in different areas of the code? What puzzles me though is that if I copy all the source code into one huge file(main.cpp) and one header it compiles fine! Which would suggest that the problem seems to lie with the command i m using to compile. Do you reckon i should try changing all my variables to extern int somevar rather than the traditional int somevar that i have been using?

Thanks very much for your reply
 
Old 10-07-2005, 07:51 PM   #5
Dark_Helmet
Senior Member
 
Registered: Jan 2003
Posts: 2,786

Rep: Reputation: 374Reputation: 374Reputation: 374Reputation: 374
Ok, it sounds like deiussum was closer to the mark.

Question: Do you declare any variable in any of your header files? I don't mean data type definitons (like classes, structs, enums, etc.), but any instantiations of those data types do count (whether they are directly after the definition or later in the header). If you're not sure, then you can post the headers.

If the answer is "yes" there are two follow-up questions:

1. Is the header that declares the variable #include'd by more than one cpp file?
2. Do your header files contain anything like this:
Code:
#ifndef HEADER_FILENAME_H
#define HEADER_FILENAME_H

/* data type definitions, etc. */

#endif
If the answer to #1 is "yes" and the answer to #2 is "no" then that's bad. Each time the header file is included by a cpp file, the compiler tries to create another variable of the same name. That's illegal. I'm also one of "those people" that strongly suggests you do not use global variable. In 99% of the cases, you can just pass variables by reference. There's no need to declare them globally.

If you need to use globals, then you should use deiussum's method: preface the variable declaration with "extern" in the header file, and then put another declaration (without extern) in the global scope (outside the main function) of main.cpp.

Last edited by Dark_Helmet; 10-07-2005 at 07:53 PM.
 
Old 10-08-2005, 04:23 AM   #6
jamesjoy
LQ Newbie
 
Registered: Aug 2005
Location: Louth, Ireland
Distribution: FC 4
Posts: 27

Original Poster
Rep: Reputation: 15
I think the answer to the first question is yes but here It is any way!
Q1. Yes i declare the header file at the start of every source code file
Q2. Thats the puzzling part i ve had that line in all the time but appears not to make any difference.

Just for your info the compiler complains about every variable from SPRITE mytanks down to BITMAP *back

Code:
#ifndef _TANKWAR_H
#define _TANKWAR_H

#include <stdlib.h>
#include "allegro.h"

#define MODE GFX_AUTODETECT_WINDOWED
#define WIDTH 640
#define HEIGHT 480
#define MAXSPEED 4
#define BULLETSPEED 10
#define TILEW 32
#define TILEH 32
#define TILES 39
#define COLS 10
#define MAP_ACROSS 31
#define MAP_DOWN 33
#define MAPW MAP_ACROSS * TILEW
#define MAPH MAP_DOWN * TILEH
#define SCROLLW 310
#define SCROLLH 375

#define TAN makecol(255,242,169) 
#define BURST makecol(255,189,73)
#define BLACK makecol(0,0,0)
#define WHITE makecol(255,255,255)
#define GRAY makecol(128,128,128)
#define GREEN makecol(0,255,20)

typedef struct SPRITE
{
	int dir, alive;

	int x, y;
	int width, height;
	int xspeed, yspeed;
	int xdelay, ydelay;
	int xcount, ycount;
	int surframe, maxframe, animdir;
	int framecount, framedelay; 
}SPRITE;

SPRITE mytanks[2];
SPRITE *tanks[2];
SPRITE mybullets[2];
SPRITE *bullets[2];

int gameover;
int scores[2];
int scrollx[2], scrolly[2];
int startx[2], starty[2];
int tilex, tiley, n;
int radarx, radary;

BITMAP *tank_bmp[2][8];
BITMAP *bullet_bmp;
BITMAP *explode_bmp;

extern int map[];

BITMAP *buffer;

BITMAP *tiles;

BITMAP *scroll;

BITMAP * back;

void drawtank(int num);
void erasetank(int num);
void movetank(int num);
void explode(int num, int x, int y);
void movebullet(int num);
void drawbullet(int num);
void fireweapon(int num);
void forward(int num);
void backward(int num);
void turnleft(int num);
void turnright(int num);
void getinput();
void setuptanks();
void setupscreen();
int inside(int, int, int, int, int, int);
BITMAP *grabframe(BITMAP *, int, int, int, int, int, int);

#endif
Do you think trying to use a makefile of some sort might help solve the problem?

Thanks again James
 
Old 10-08-2005, 11:03 AM   #7
deiussum
Member
 
Registered: Aug 2003
Location: Santa Clara, CA
Distribution: Slackware
Posts: 895

Rep: Reputation: 32
A Makefile will not help. You need extern in front of all those global variables you have in the header. I'll use a simple example to try and explain what is happening.

Code:
// blah.h
#ifndef __BLAH_H__
#define __BLAH_H__

int aglobal;

void DoSomething();
#endif
Code:
// blah1.cpp
#include "blah.h"

int main()
{
    void DoSomething();
}
Code:
//blah2.cpp
#include "blah.h"

void DoSomething()
{
   aglobal = 10; 
}
Now, when you compile all that, the compiler essentially makes a separate object file for each unit of compilation. (Each .cpp file in this case) When you give g++ all the .cpp files and have it link right away, it does this all behind your back, but it is important to understand it. For the sake of demonstration, we will do this one step at a time like so:

Code:
g++ -c -o blah1.o blah1.cpp
g++ -c -o blah2.o blah2.cpp
Now you have two .o files that you want to link into an executable with something like:

Code:
g++ -o blah blah1.o blah2.o
It is at this stage you are getting your error. Why? Because BOTH blah1.o and blah2.o have THEIR OWN COPY of aglobal. The linker cannot sees this and so it lets you know.

Why does putting extern in front solve this? By putting extern in front, you tell the compiler that there exists a global variable of this name, but it may or may not be physically located in this compilation unit. So in this way, the compiler knows about the existence of the variable, but it won't physically put it in this compilation unit unless you instantiate it somewhere else.

It is the same reason you only put the function prototype in the header as well. If you put the full function in the header, you end up with two objects that both contain object code for that function, and the linker finds duplicates.

Last edited by deiussum; 10-08-2005 at 11:05 AM.
 
Old 10-12-2005, 05:39 AM   #8
jamesjoy
LQ Newbie
 
Registered: Aug 2005
Location: Louth, Ireland
Distribution: FC 4
Posts: 27

Original Poster
Rep: Reputation: 15
Sorry bout the late reply. Long weekend! Any way i totally understand what your saying about the variables and the need for extern thing. But when i tried it i got more errors. Basically now its complaing that

undefined refernece to (list of all the variables that are used later in the program which i declare with extern int)

It seems now like the compiler isn't able to find or use the variables anymore.

I thin k there most be something allegro specific that i m leaving out. So i dont what i m going to do but i ll just have to search for a an allegro specific forum somewhere and see if I can get any more luck out there.

One last question could it possibly be anything to do with my version on g++ would a reinstall of g++ maybe help.
Is there any C++ editor besides Kdev that i could use that might do all the command line stuff for me

Thanks again for all the help.

James
 
Old 10-12-2005, 07:02 AM   #9
Wim Sturkenboom
Senior Member
 
Registered: Jan 2005
Location: Roodepoort, South Africa
Distribution: Ubuntu 12.04, Antix19.3
Posts: 3,794

Rep: Reputation: 282Reputation: 282Reputation: 282
Simple example
file1.c:
Code:
int myscore;

int main()
{
  return 0;
}
file2.c:
Code:
extern int myscore;

int myfunc()
{
// do something

  return 0;
}
If you want to do a similar thing using a header file
myinclude.h:
Code:
#ifdef _MYMAIN_
int myscore;
#else
extern int myscore;
#endif
file1.c:
Code:
#define _MYMAIN_
#include "myinclude.h"

.....
.....
file2.c:
Code:
#include "myinclude.h"

.....
.....
If you compile file1.c, _MYMAIN_ is defined and the variable is declared the normal way.
If you compile file2.c, _MYMAIN_ is not defined so the variable is now declared as external (so no new copy will be made).

You have to fit the idea in your source yourself.

Last edited by Wim Sturkenboom; 10-12-2005 at 07:21 AM.
 
Old 10-12-2005, 09:43 AM   #10
deiussum
Member
 
Registered: Aug 2003
Location: Santa Clara, CA
Distribution: Slackware
Posts: 895

Rep: Reputation: 32
Quote:
Originally posted by jamesjoy


It seems now like the compiler isn't able to find or use the variables anymore.

It sounds like you are missing the part where you create a NON-EXTERN copy of those variables in ONE AND ONLY ONE .cpp file.

I'll bold that part of my example above in post #3...

Last edited by deiussum; 10-12-2005 at 09:45 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Compiling on multiple machines at once kenneho Programming 3 10-12-2005 02:27 AM
Multiple Machines Compiling RemusX2 Linux - General 2 07-06-2005 04:44 AM
compiling on multiple computers Peluso Linux - Software 3 08-30-2004 12:26 PM
Error when compiling 2.4.26(can't find the include files) iZvi Slackware 2 05-25-2004 05:27 AM
Help I need help tarring multiple files in multiple directories VisionZ Linux - Newbie 28 03-25-2004 05:25 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:43 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration