Sign in to follow this  
Shining_Saber

Linker errors when function is moved

Recommended Posts

Hi. I've had the functions for my main menu and actual ingame engine of my game in the same C++ source for a while, and I decided to move it, as it would help unload resources that the engine didn't need. So I did the #ifndef thing on all of my header files, and moved my engine function, plus all of its variables. Then I made a header included in both files, where "tells" the main menu about the engine function (via int engine( int argc, char* args[] ); ). So I try to compile, and get 26 errors like this. Error 3 error LNK2005: "public: __thiscall Timer::Timer(void)" (??0Timer@@QAE@XZ) already defined in main.obj engine.obj Metroid Walrus Error 18 error LNK2005: "public: int __thiscall Tile::get_type(void)" (?get_type@Tile@@QAEHXZ) already defined in main.obj engine.obj Metroid Walrus Error 26 error LNK2005: "class Timer fpstimer" (?fpstimer@@3VTimer@@A) already defined in main.obj engine.obj Metroid Walrus Error 28 fatal error LNK1169: one or more multiply defined symbols found C:\Users\Shawn\Documents\Visual Studio 2008\Projects\Metroid Walrus\Debug\Metroid Walrus.exe Metroid Walrus Error 27 error LNK2005: "class Timer metanim" (?metanim@@3VTimer@@A) already defined in main.obj engine.obj Metroid Walrus What could the problem be? Especially that last one, since metanim (the last error) doesn't EXIST in engine.obj. Thanks in advance, I know I'm a noob at multiple source files. :P EDIT : By the way, feel free to request the source if you really need it to tell the problem, but I'll have to send you it via a link in PM, since 'alot of H files. (10)

Share this post


Link to post
Share on other sites
Quote:
Original post by Hodgman
Is Timer::Timer defined in a header file? If so can you move it into a source file OR make it inline?


Yes, its defined in a header file, I'll try to just move it to each of the source files to see if it works.
And what is "making it inline"?
EDIT : I'll have to find out what that inline thing is. I can't move it, since there's classes in other header files dependent on this one. It seems that every single header file I have is giving errors, though..
EDIT2: Also, I moved metanim to the menus source file, and its still giving the same error.

Share this post


Link to post
Share on other sites
#includeing a header is pretty much the same as copy/pasting it into your source files - so if you've defined a function or variable in a header, then when you include that header in more than one source file, then each source is going to have it's own copy of it!
This (as you have found out) gives the linker a headache.

There is a special keyword - inline - which tells the compiler "this function is so small that you can pretend that it's not really a function, if you like". Usually this is used for optimisation, (as it basically allows the compiler to just copy&paste the body of the function into the place where you call it from instead of actually performing a function call) but it also has the side effect of allowing you to tell the linker to get over the fact that the function is going to be defined in multiple source files.

[EDIT]
Here's an example header with 3 classes, Foo, Bar and Baz.

#ifndef STUFF
#define STUFF

class Foo
{
public:
Foo()
{
DoStuff();
}
};


class Bar
{
public:
Bar();
};
inline Bar::Bar()
{
DoStuff();
}


class Baz
{
public:
Baz();
};
Baz::Baz()
{
DoStuff();
}

#endif


Foo is ok because by writing functions inside the class definition like that, the compiler automatically makes them inline.

Bar is ok because we've specifically told that function to be inline.

Baz is *not* ok, because the function is not inline and it is defined in the header - so if you include (which == copy&paste, remember) this header into more than one source file, the linker will end up complaining about Baz::Baz being defined multiple times.
The solution to this is just to put all function definitions into source files (inlining is not really recommended).


Solving your linker problems for global variables is a little different - you need to use the extern keyword in the header to say "this variable exists, but i'm not defining it", and then define it as usual in one of the source files.


So to solve this:
//in the header:
class Baz
{
public:
Baz();
};

extern Baz myVariable;//"a Baz exists somewhere called myVariable"

//in *one* of the CPP files:
#include "baz.h"

Baz myVariable;//The actual variable lives in this source file

Baz::Baz()
{
DoStuff();
}

Share this post


Link to post
Share on other sites
I've started adding that to commands and stuff, I think its working, too, the errors are going down. Thanks alot, seriously :)
EDIT : Yeah, I tried everything, my source still gives errors, but that helped bring down the number of errors. I guess I'll rewrite the source from scratch keeping your ideas in mind. :)

[Edited by - Shining_Saber on August 18, 2008 12:05:13 AM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this