3

I'm trying to set up an SDL project with Visual Studio 2019 using this article:

https://www.wikihow.com/Set-Up-SDL-with-Visual-Studio

but the compiler is throwing me the errors 'one or more multiply defined symbols found' and
'_main already defined in main.obj'.

main.obj is a file in the debug folder of my project but when I try deleting it or the entire debug folder, VS recreates it when I run the project.

I've read that c++ can't have more than one main function but I can't open the main.obj file and I don't really want to delete the one in main.cpp

Here's the code I'm running and thanks for your help!

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

int main(int argc, char* argv[])
{
    SDL_Init(SDL_INIT_VIDEO);

    SDL_Window* window = SDL_CreateWindow
    ("An SDL2 window", // window's title
        10, 25, // coordinates on the screen, in pixels, of the window's upper left corner
        640, 480, // window's length and height in pixels  
        SDL_WINDOW_OPENGL);

    SDL_Delay(3000); // window lasts 3 seconds
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}
LordPotato
  • 53
  • 8
  • 2
    [By default SDL sets up a `main` for you](https://stackoverflow.com/questions/11976084/why-sdl-defines-main-macro). It should also call your `main` from it. Not sure what went wrong here, so I'm going to shut up and leave this to the SDL gurus. – user4581301 Jul 02 '19 at 23:03
  • Are you including your main.cpp in some other file? – mfnx Jul 02 '19 at 23:25
  • @MFnx , not that I know of, main.cpp was the only file I wrote, everything else was created by visual studio or SDL. – LordPotato Jul 02 '19 at 23:27
  • @LordPotato Are you sure SDL.h is in your include directories? Have you tried #include ? – mfnx Jul 02 '19 at 23:32
  • @MFnx Yes, my additional include directories has'C:\SDL\SDL2-2.0.9\include;%(AdditionalIncludeDirectories)' and that file has SDL.h in it. I also tried #include , that doesn't change anything – LordPotato Jul 02 '19 at 23:36
  • 2
    @LordPotato try to add #define SDL_MAIN_HANDLED before the #include and rebuild from scratch (clean your build if necessary) – mfnx Jul 02 '19 at 23:36
  • @MFnx adding #define SDL_MAIN_HANDLED before the include gives me a different error (so win?) The error is: 'function int main(int,char*[]) already has a body' – LordPotato Jul 02 '19 at 23:39
  • @LordPotato SDL injects its main function which is probably the cause of your problem. Maybe you could create a class with your SDL stuff in it using the pimpl idiom, and include SDL only in the cpp file of that class. That is, no SDL stuff in the header, only in the source file. You can than safely include the header of that class in your main function, and there'll be only one definition for your int main(...) in your main.obj – mfnx Jul 02 '19 at 23:49
  • If you use pimpl, you won't need to #define SDL_MAIN_HANDLED If you're not sure about how to do this, I'll write an example in an answer tomorrow. You maybe even don't need the pimpl idiom. Just make sure you don't include SDL.h in the header. – mfnx Jul 02 '19 at 23:57

2 Answers2

1

Glad to know it works now. Maybe you had a messy file structure with your previous SDL installation. Anyways, I think it might be interesting to show how the SDL dependency can be removed from your main.cpp file, to avoid such problems in the future.

First, let's consider the example in your question. The example is not very useful in practice, but I'll show a better version after.

The main idea is hiding everything that has to do with SDL from your main.cpp and headers.

1. Simple Example

// MySDL.h - NO SDL STUFF
class MySDL
{
public:
    MySDL() = default; // or whatever you need
    void runtest() const; // here we'll run the 3sec window
};

Now, we can put all our SDL stuff in the cpp file:

// MySDL.cpp
#include "MySDL.h"
#include "SDL.h" // HERE WE INCLUDE SDL

void MySDL::runtest()
{
    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_Window* window = SDL_CreateWindow("yee haw", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_SHOWN);

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);

    SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);

    SDL_RenderClear(renderer);
    SDL_RenderPresent(renderer);

    SDL_Delay(3000);
}

No SDL included in main.cpp, we just include our SDL interface MySDL.h.

// Now you can use your SDL interface like this
int main(int, char* [])
{
    MySDL sdl;
    sdl.runtest();

    return 0;
}

2. Better Version

However, you would typically want something more sofisticated than a window which disappears in 3 seconds. Therefore, you might want to store class members which depends on SDL. But then, you would have to #include "SDL.h" in your MySDL.h header file, which would give you the same problems as described in your question and comments. To remove this dependency, we can use the pimpl idiom.

The header file now includes a pointer to our SDL implementation. This SDL implementation will be defined in the cpp file in order to remove the SDL dependency.

// MySDL.h
class MySDL
{
public:
    MySDL() = default; // or whatever you need
    ~MySDL();

    void doSmthWithYourWindow(/*args*/);

private:
    // pointer to our SDLImplementation (defined in cpp file)
    class SDLImplementation;
    std::unique_ptr<SDLImplementation> _sdl;
};

In our cpp file, we define the SDLImplementation, and MySDL has access to that implementation through the _sdl pointer.

// MySDL.cpp
#include "MySDL.h"
#include "SDL.h"

// here we can store class members which depend on SDL
struct MySDL::SDLImplementation
{
    SDLImplementation()
    {
        SDL_Init(SDL_INIT_EVERYTHING);
        _window = SDL_CreateWindow("yee haw", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_SHOWN);
        _renderer = SDL_CreateRenderer(_window, -1, 0);
        SDL_SetRenderDrawColor(_renderer, 0, 255, 0, 255);

        SDL_RenderClear(_renderer);
        SDL_RenderPresent(_renderer);
    }

    // functionality of your SDL implementation
    void turnWindowUpsideDown() { /* _window->turnUpsideDown(); */ }

    // members depending on SDL
    SDL_Window* _window;
    SDL_Renderer* _renderer;
};

MySDL::~MySDL() = default;

void MySDL::doSmthWithYourWindow(/*args*/)
{
    // here we have access to our SDL implementation
    _sdl->turnWindowUpsideDown();
}

Just like before, we only include our MySDL.h interface in the main.cpp file.

int main(int, char* [])
{
    MySDL sdl;
    sdl.doSmthWithYourWindow();
    return 0;
}
mfnx
  • 2,894
  • 1
  • 12
  • 28
0

So I ended up deleting SDL and completely restarting with a different tutorial linked here:

https://www.youtube.com/watch?v=QQzAHcojEKg

Not really sure what the difference was but it worked. Anyways, thanks for your help and I'll put the new code here.

#include "SDL.h"

int main(int argc, char* argv[])
{
    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_Window* window = SDL_CreateWindow("yee haw", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_SHOWN);

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);

    SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);

    SDL_RenderClear(renderer);
    SDL_RenderPresent(renderer);

    SDL_Delay(3000);

    return 0;
}
LordPotato
  • 53
  • 8