Search code examples
c++sdl

main already defined in main.obj


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;
}

Solution

  • 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;
    }