-1

I'm trying to get used to Visual Studio's c++ environment and I'm having an issue with a set of functions which I wish to define into their own .h and .cpp files.

Within my project, there is a file containing some common variables and definitions called "common.h".

So far I have a simple main.cpp and I'm trying to break apart these functions to clean up my project a bit.

The .h file looks like this so far:

#pragma once

#include "common.h"

void SDLInitGameData();
void SDLCleanUp();

The .cpp to the .h above has the definitions listed in the header as well as some helper functions that I wanted to keep "private" to those functions.

Within my main.cpp I have this so far:

#include <iostream>

#include "common.h"
#include "SDLInitialize.h"

int main()
{
    SDLInitGameData();
    system("pause");
    SDLCleanUp();
    return 0;
}

void ReportError(const char* ccpErrorMessage, const TInitializationError xReturnStatus)
{
    cerr << ccpErrorMessage << ": ";

    if (xReturnStatus == SDL_TTF_INIT_ERROR_CODE)
    {
        cerr << TTF_GetError();
    }
    else if (xReturnStatus == SDL_INITFRAMEFRATE_ERROR_CODE)
    {
        cerr << "Unable to initialize FPSManager Object.";
    }
    else
    {
        cerr << SDL_GetError();
    }

    cerr << "\n";

    SDLCleanUp();
    exit(xReturnStatus);
}

My common.h looks like this so far:

#pragma once

#include "SDL.h"
#include "SDL_ttf.h"
#include "SDL2_gfxPrimitives.h"
#include "SDL2_framerate.h"

#include <stdint.h>

#ifdef _WIN32
#include "Windows.h"
#endif

//Program will not compile without this
#ifdef main
#undef main
#endif /* main */

#define SCRN_TITLE "Title"
#define SCRN_WIDTH 640
#define SCRN_HEIGHT 480

#define FPS_CAP 30

struct TGameData
{
    static SDL_Window* Window;
    static SDL_Renderer* Renderer;
    static FPSmanager* Manager;
} gxGameData;

SDL_Window* TGameData::Window = nullptr;
SDL_Renderer* TGameData::Renderer = nullptr;
FPSmanager* TGameData::Manager = nullptr;

enum TInitializationError
{
    SDL_INIT_ERROR_CODE = 1,
    SDL_CREATEWINDOW_ERROR_CODE,
    SDL_CREATERENDERER_ERROR_CODE,
    SDL_INITFRAMEFRATE_ERROR_CODE,
    SDL_TTF_INIT_ERROR_CODE
};

void ReportError(const char* ccpErrorMessage, const TInitializationError xReturnStatus);

I am getting a handful of LNK2005. From my research, this is a "One Definition Rule" issue. When I would do code like this in a makefile, I would have had a rule to compile the SDLInitialize.h/cpp file and link it with main. That doesn't appear to work in Visual Studio.

Any ideas what I'm doing wrong?

Zulukas
  • 1,180
  • 1
  • 15
  • 35
  • Not directly related to the question, but `#undef main` shouldn't be needed, unless you are doing something weird elsewhere in the code or in the project settings. – dxiv Aug 26 '16 at 02:36
  • It's a weird case, but apparently SDLmain.lib has a main function within it. If you don't have it, the linker will gripe. Undef it and it'll compile just fine. – Zulukas Aug 26 '16 at 03:24
  • 1
    That's unusual and not the best practice. Anyway, I looked up `SDLmain` by curiosity, and that's not how you are supposed to do it. Per [their FAQ](http://wiki.libsdl.org/FAQWindows#I_get_.22Undefined_reference_to_.27SDL_main.27.22_...), your `main` *must* have the prototype `int main(int argc, char *argv[])` i.e. not just `int main()`. – dxiv Aug 26 '16 at 04:02

1 Answers1

1

In your common.h:

SDL_Window* TGameData::Window = nullptr;
SDL_Renderer* TGameData::Renderer = nullptr;
FPSmanager* TGameData::Manager = nullptr;

Every translation unit that includes this header file is going to define these variables in the global scope, hence the duplicate definitions at link time.

Instead, you need to declare all of these as extern, and then define them in one of the translation units.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Thank you, that did it exactly. Sometimes those linker errors are a bit cryptic rather than just saying what it is that they're trying to say. :) – Zulukas Aug 26 '16 at 03:25