Search code examples
c++sdl

Error: one or more multiply defined symbols found


I am setting up my first proper SDL project and c++ project, but I am getting errors. The last error says one or more multiply defined symbols found. Along with that error, I am getting a bunch of errors, one of them is:

Severity    Code    Description Project File    Line    Suppression State
Error   LNK2005 "public: bool __thiscall Game::init(void)" (?init@Game@@QAE_NXZ) already defined in 
game.obj    learnSDL    C:\Users\myself\source\repos\learn\learn\main.obj

All of the other errors I am getting are in the same format as well, but they are for different attributes in Game class.

game.h:

#pragma once

#include <iostream>
#include "SDL.h"

class Game
{
public:

    bool init();
    bool constructWindow
    (
        const char* windowName,
        uint16_t xWindowPos,
        uint16_t yWindowPos,
        uint16_t windowWidth,
        uint16_t windowHeight,
        bool fullScreen = false
    );

    void render();
    void update();
    SDL_Window* getWindow();
    bool handleEvents();

protected:


private:
    SDL_Window* window = nullptr;
    SDL_Renderer* renderer = nullptr;
    SDL_Event event;
    bool quit = true;

};

game.cpp:

#include "game.h"

bool Game::init()
{
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
        return true;
    else
        std::cout << "Could not initialise SDL" << '\n' << "Error: " << SDL_GetError() << std::endl;
}

bool Game::constructWindow(const char* windowName, uint16_t xWindowPos, uint16_t yWindowPos
    , uint16_t windowWidth, uint16_t windowHeight, bool fullScreen)
{
    window = SDL_CreateWindow(windowName, xWindowPos, yWindowPos, windowWidth, windowHeight, fullScreen);
    if (!window)
        std::cout << "Could not create window" << '\n' << "Error: " << SDL_GetError() << std::endl;

    return window;
}

void Game::render()
{
    renderer = SDL_CreateRenderer(window, -1, 0);
    if (!renderer)
        std::cout << "Failed to create a renderer" << '\n' << "Error: " << SDL_GetError() << std::endl;
}

void Game::update()
{
    SDL_RenderPresent(renderer);
}

SDL_Window* Game::getWindow()
{
    return window;
}

bool Game::handleEvents()
{
    while (SDL_PollEvent(&event))
        if (event.type == SDL_QUIT)
            quit = true;
    return quit;
}

I am not sure is main is related to the problem, but here it is anyways:

#include "game.cpp"

int main(int argc, char* argv[])
{
    Game app;
    if (app.init())
        if (app.constructWindow("3D Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1200, 600))
            while (!app.handleEvents())
            {
                app.render();
                app.update();
            }

    SDL_DestroyWindow(app.getWindow());
    SDL_Quit();

}

Solution

  • I am not sure is main is related to the problem

    Oh, yes, it is! :-)

    By including game.cpp into main.cpp, you define all the things in game.cpp twice, once in the main object file and once in the game object file. Object files aren't necessary for an implementation but they're common enough to use as an explanation. In any case, the fact your error message mentions game.obj indicates your environment does use them.

    Including a file really just substitutes the #include line with the contents of the file, explaining why both object files end up having the same definitions.

    Then, when you link the two object files together, voila, symbols defined twice.

    You should generally never include cpp files into other cpp files since they tend to define things that you would rather not have multiple copies of. Instead you should include header files, which tend to just declare things.

    This is an important distinction that I explain to students as follows. A declaration is just declaring that something exists, without actually creating it. You can do that as many times as you want. A definition, on the other hand, brings it into existence, and you really only want to do that once.

    The one-definition rule is what you should investigate if you want to understand this more than my greatly simplified explanation provides for.