c++compiler-errorslnk2005

What is causing the "error LNK2005: already defined in .obj" s errors in my code?


I would like to know what is causing a double definition linker error in my code. It confuses me because there doesn't seem to be any reason for it. I don't think I'm #includeing any .h files in places that would cause this, as my file's #includes are linearly structured.

To be clear, I am not asking what the errors mean, I am asking what, in my code, is causing it. I have already researched on this site (and others) as to what it means, and can't find an answer relevant to what could be causing it in my code.

Btw I am using Visual Studio 2017

Here are the errors:

1>ObjectHandler.cpp

1>Main.cpp

1>Generating Code...

1>ObjectHandler.obj : error LNK2005: "void __cdecl pixelsInit(void)" (?
pixelsInit@@YAXXZ) already defined in Main.obj

1>ObjectHandler.obj : error LNK2005: "void __cdecl pixelsUpdate(void)" (?
pixelsUpdate@@YAXXZ) already defined in Main.obj

1>ObjectHandler.obj : error LNK2005: "void __cdecl spritesInit(void)" (?
spritesInit@@YAXXZ) already defined in Main.obj

1>ObjectHandler.obj : error LNK2005: "void __cdecl spritesUpdate(void)" (?
spritesUpdate@@YAXXZ) already defined in Main.obj

1>ObjectHandler.obj : error LNK2005: "class std::vector<struct pixel,class 
std::allocator<struct pixel> > pixels" (?pixels@@3V?$vector@Upixel@@V?
$allocator@Upixel@@@std@@@std@@A) already defined in Main.obj

1>ObjectHandler.obj : error LNK2005: "class std::map<class 
std::basic_string<char,struct std::char_traits<char>,class 
std::allocator<char> >,struct sprite,struct std::less<class 
std::basic_string<char,struct std::char_traits<char>,class 
std::allocator<char> > >,class std::allocator<struct std::pair<class 
std::basic_string<char,struct std::char_traits<char>,class 
std::allocator<char> > const ,struct sprite> > > sprites" (?sprites@@3V?
$map@V?$basic_string@DU?$char_traits@D@std@@V?
$allocator@D@2@@std@@Usprite@@U?$less@V?$basic_string@DU?
$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?
$basic_string@DU?$char_traits@D@std@@V?
$allocator@D@2@@std@@Usprite@@@std@@@2@@std@@A) already defined in Main.obj

1>fatal error LNK1169: one or more multiply defined symbols found

Here is my code structure:

SimpleTypes.h:

#pragma once

struct loc {

    int x;
    int y;
    int d;
    int s;

};

struct color {

    _int8 r;
    _int8 g;
    _int8 b;
    _int8 a;

};

ComplexTypes.h:

#pragma once
#include "SimpleTypes.h"
#include <string>

struct pixel {

    loc pos;

    color col;

};

struct sprite {

    std::string name;

    std::string file;

    loc pos;

};

ObjectHandler.cpp:

#include "ComplexTypes.h"
#include <string>
#include <map>
#include <vector>

std::vector<pixel> pixels;
std::map<std::string, sprite> sprites;

void pixelsInit(){};

void spritesInit(){};

void pixelsUpdate(){};

void spritesUpdate(){};

Main.cpp

#include "ObjectHandler.cpp"

int main() {

    pixelsInit();
    spritesInit();

    while (true) {

        pixelsUpdate();
        spritesUpdate();

    };

    return 0;
}

Solution

  • In your project you are compiling ObjectHandler.cpp as an independent translation unit. And at the same time you also including ObjectHandler.cpp into Main.cpp where it gets compiled again as part of Main.cpp.

    Thus, everything defined in ObjectHandler.cpp gets defined twice in your program. Hence the errors.

    The question is: why are you including ObjectHandler.cpp into Main.cpp? What did you try to achieve by that?

    And if you, for some unorthodox reason, really want/have to include ObjectHandler.cpp into Main.cpp and compile it as part of Main.cpp, then stop compiling ObjectHandler.cpp as an independent translation unit at the same time.

    Meanwhile, a more traditional approach in this case would be to write a proper ObjectHandler.h file for your ObjectHandler.cpp. Something like

    #pragma once
    #include "ComplexTypes.h"
    #include <string>
    #include <map>
    #include <vector>
    
    extern std::vector<pixel> pixels;
    extern std::map<std::string, sprite> sprites;
    
    void pixelsInit();
    void spritesInit();
    void pixelsUpdate();
    void spritesUpdate();
    

    and include it into Main.cpp instead.

    Your ObjectHandler.cpp might look as follows

    #include "ObjectHandler.h"
    
    std::vector<pixel> pixels;
    std::map<std::string, sprite> sprites;
    
    void pixelsInit(){}
    void spritesInit(){}
    void pixelsUpdate(){}
    void spritesUpdate(){}
    

    Note the important detail: the .h file contains declarations only (functions have no bodies and objects are declared with extern), while .cpp file contains definitions (functions have bodies and objects are declared without extern)