views:

222

answers:

4

I am getting linker errors that suggest I am not using #ifndef and #define.

1>TGALoader.obj : error LNK2005: "struct TGA tga" (?tga@@3UTGA@@A) already defined in main.obj 1>TGALoader.obj : error LNK2005: "struct TGAHeader tgaheader" (?tgaheader@@3UTGAHeader@@A) already defined in main.obj 1>TGALoader.obj : error LNK2005: "unsigned char * uTGAcompare" (?uTGAcompare@@3PAEA) already defined in main.obj 1>TGALoader.obj : error LNK2005: "unsigned char * cTGAcompare" (?cTGAcompare@@3PAEA) already defined in main.obj 1>LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library

I have included a header file Texture.h and tga.h from the nehe opengl tutorials into my project. I have

#ifndef TGAISCOOL
#define TGAISCOOL
#endif

in my tga.h file. If I include this more than once, I get the errors from the linker that I pasted above. The first two are from texture.h though the situation is the same.

Any ideas on what is wrong?

+3  A: 

There's no reason to conclude that #ifndef isn't working properly. What the error message is saying is that you have items with the same name defined in multiple translation units (.obj files). The link process is therefore failing.

As for how to fix it, we need to see more code.

Andrew Medico
I am curious on how to handle this request. I have many many lines of codes to paste. What exactly do I need to include? Is there a place I can put my entire solution zipped?
bobber205
@bobber205: http://gist.github.com/ is an easy way to share things, but also you should try to cut down to a minimal reproducible test case. In other words, get rid of anything that you can while still demonstrating the failure.
ephemient
+4  A: 

The problem is you are putting definitions in your header file instead of declarations.

Include guards only work for multiple includes of a single translation unit (i.e a source file). If you compile multiple translation units, each one will see the contents of your header file.

So, instead of putting this definition in your header file:

struct TGA tga;

You want to put this declaration in your header file:

/* whatever.h */
extern struct TGA tga;

And then add the definition in a source file:

/* whatever.c */
#include "whatever.h"

struct TGA ta;

The rule of thumb is that definitions go in source files and declarations go in header files.

R Samuel Klatchko
Static/inline definitions are fine in header files; it's having externally-visible ones in multiple translation units where problems arise.
ephemient
@ephemient - I definitely concede the point on inline definitions. But while static definitions technically work fine in header files, I think they are such horrible style they are not worth mentioning.
R Samuel Klatchko
I meant "fine" as in "works", not as in "good taste" ;-)
ephemient
And I meant "rule of thumb" as in "a principle with broad application that is not intended to be strictly accurate."
R Samuel Klatchko
I've tried this but gotten nowhere. :(Just more compiler errors which makes me sad. Oddly I've never encountered his problem before. IF Ifndef doesn't work like I expect, how am I supposed to have a struct defined in a .h file?
bobber205
@bobber205 - update the question with both the new version of your code and the compilation errors you are getting.
R Samuel Klatchko
+3  A: 

You're not doing anything wrong. The problem is with the Tga.h file you got from NeHe. This header file defines four objects which means that if you include the file in different translation units the symbols for these will appear multiple times and that is what the linker is complaining about.

The solution is to move the definitions of these objects into the Tga.cpp file.

The lines in Tga.h that previously had the definitions should now read

extern TGAHeader tgaheader;
extern TGA tga;

extern GLubyte uTGAcompare[12];
extern GLubyte cTGAcompare[12];

with the original versions of these lines now in Tga.cpp

Troubadour
A: 

Change your Tga.H like this:

#ifndef Tga_H
#define Tga_H
#include "Texture.h"



struct TGAHeader
{
    GLubyte Header[12];                                 // TGA File Header
} ;


struct TGA
{
    GLubyte     header[6];                              // First 6 Useful Bytes From The Header
    GLuint      bytesPerPixel;                          // Holds Number Of Bytes Per Pixel Used In The TGA File
    GLuint      imageSize;                              // Used To Store The Image Size When Setting Aside Ram
    GLuint      temp;                                   // Temporary Variable
    GLuint      type;   
    GLuint      Height;                                 //Height of Image
    GLuint      Width;                                  //Width ofImage
    GLuint      Bpp;                                    // Bits Per Pixel
} ;


extern  TGAHeader tgaheader;                                    // TGA header
extern  TGA tga;                                                // TGA image data



extern GLubyte uTGAcompare[12]; // Uncompressed TGA Header
extern GLubyte cTGAcompare[12]; // Compressed TGA Header
bool LoadTGA(Texture * , char * );
bool LoadUncompressedTGA(Texture *, char *, FILE *);    // Load an Uncompressed file
bool LoadCompressedTGA(Texture *, char *, FILE *);      // Load a Compressed file

#endif

Add the following lines in your TGALoader.cpp file on top:

TGAHeader tgaheader;
TGA tga;
GLubyte uTGAcompare[12] = {0,0,2, 0,0,0,0,0,0,0,0,0};
GLubyte cTGAcompare[12] = {0,0,10,0,0,0,0,0,0,0,0,0};
Nitesh Bhatia