SDL problem :: entry point must be defined

Hi guys,

I'm having problems setting up SDL on my IDE, I am using MSVC 2017 x86

I downloaded the pre compiled zip from https://www.libsdl.org/download-2.0.php under development libraries / windows / visual c++

the error I am getting is LNK1561 entry point must be defined, I added the SDL header files to my project by adding them under existing files to the project, I then copied and pasted them into the directory of my project which contains the source and header files.

I have not added the .lib file yet, but this should still compile fine as I have not called any SDL functions.

I followed this - https://stackoverflow.com/questions/18672303/sdl2-lnk1561-entry-point-must-be-defined

but to no avail

thanks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include "SDL.h"
#include "escapi.h"


using namespace std;

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

	int dev = setupESCAPI();
	cout << dev << endl;
	

	for (int i = 0; i < dev; i++)
	{
		char temp[256];
		getCaptureDeviceName(i, temp, 256);
		cout << temp << endl;
	}


	struct SimpleCapParams capture;
	capture.mWidth = 24;
	capture.mHeight = 18;
	capture.mTargetBuf = new int[24 * 18];

	/* Initialize capture - only one capture may be active per device,
	* but several devices may be captured at the same time.
	*
	* 0 is the first device.
	*/

	if (initCapture(0, &capture) == 0)
	{
		cout << "Capture failed - device may already be in use" << endl;
		return 1;
	}





	system("pause");
	return 0;
}
If I recall correctly, SDL renames your main function. To SDL_main , I think. This is done with a macro in the header. So your code above actually looks like this to the compiler:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include "SDL.h"
#include "escapi.h"


using namespace std;

int SDL_main(int argc, char *argv[]){

	int dev = setupESCAPI();
        ...


Elsewhere in the SDL libraries is another main function, and THAT function is the entry point, and that function calls SDL_main.

You need to link to the SDL libraries, because the main function is in there somewhere.

This is done because SDL takes care of a bunch of cross-platform initialisation for you in the main it provides, which needs to happen before your code takes over.

One of the SDL libs you need to link agianst is called SDL2main.lib - I think that's the one containing the relevant actual main function (which on windows, could actually be winMain or some such).
Last edited on
hey repeater,

yeah I thought that may have been problem, tried it previously but no luck, still gives the same error,

on codeblocks using mingw 32 ( also have SDL set up ) it seems to compile fine and only complains about a linker issue when I call a SDL function without linking the necessary lib files.
I expect that the exact operation and needs of the SDL system will depends on your environment. That's how it works its cross-platform magic.
I added the .lib files to the dependencies followed this video to 100% make sure I did it right as I don't use MSVC very much - https://www.youtube.com/watch?v=Sfn7yOiwJLw

but still the same error :/ entry point must be defined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

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


using namespace std;

int SDL_main(int argc, char *argv[]){

	int dev = setupESCAPI();
	cout << dev << endl;
	

	for (int i = 0; i < dev; i++)
	{
		char temp[256];
		getCaptureDeviceName(i, temp, 256);
		cout << temp << endl;
	}


	struct SimpleCapParams capture;
	capture.mWidth = 24;
	capture.mHeight = 18;
	capture.mTargetBuf = new int[24 * 18];

	/* Initialize capture - only one capture may be active per device,
	* but several devices may be captured at the same time.
	*
	* 0 is the first device.
	*/

	if (initCapture(0, &capture) == 0)
	{
		cout << "Capture failed - device may already be in use" << endl;
		return 1;
	}





	system("pause");
	return 0;
}
*update

so I got it to run, but not sure how?? I followed a comment on youtube that told me to define sdl_main as main, I did this and the program built and ran successfully but I'm baffled as to how?

whats the difference? I mean by using the define macro in this case we are just telling the pre processor to replace SDL_main with main??? isn't this basically the same as typing SDL_main, I wonder why the define will make this work and not hard typing it in?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

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

#define SDL_main main

using namespace std;

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

	int dev = setupESCAPI();
	cout << dev << endl;
	

	for (int i = 0; i < dev; i++)
	{
		char temp[256];
		getCaptureDeviceName(i, temp, 256);
		cout << temp << endl;
	}


	struct SimpleCapParams capture;
	capture.mWidth = 24;
	capture.mHeight = 18;
	capture.mTargetBuf = new int[24 * 18];

	/* Initialize capture - only one capture may be active per device,
	* but several devices may be captured at the same time.
	*
	* 0 is the first device.
	*/

	if (initCapture(0, &capture) == 0)
	{
		cout << "Capture failed - device may already be in use" << endl;
		return 1;
	}

	system("pause");
	return 0;
}
I wonder why the define will make this work and not hard typing it in?


Here is what you think you wrote originally:
int main(int argc, char *argv[]){

Here is what that was transformed into when you included an SDL header:
int SDL_main(int argc, char *argv[]){

Here is what that was transformed into when you added #define SDL_main main

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

So the compiler saw the last one, and the linker found the main function, and both were happy.

The cost of this is that whatever initialisation, whatever setup the SDL team really wanted to happen, now has not happened. They really wanted it to happen. There is now almost certainly something very wrong with your program, and you won't find it until you use something that was really relying on that initialisation.

I mean by using the define macro in this case we are just telling the pre processor to replace SDL_main with main??? isn't this basically the same as typing SDL_main,

No. It's the exact OPPOSITE of that.


I'll restate:

Original problem - your code HAS NO main FUNCTION. You thought it did. but it didn't. You did type main, but a #define in a header then transformed it into SDL_main. So where was your main function? Nowhere. There wasn't one. Where are you meant to get one? It's already been written, and is inside an SDL library. Use that one.
Last edited on
oh ok, I removed the define and just defined the main function as normal with params, but again when I do this the linker again throws up the same error message - entry point must be defined.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

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

//#define SDL_main main

using namespace std;

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

	int dev = setupESCAPI();
	cout << dev << endl;

	

	for (int i = 0; i < dev; i++)
	{
		char temp[256];
		getCaptureDeviceName(i, temp, 256);
		cout << temp << endl;
	}


	struct SimpleCapParams capture;
	capture.mWidth = 24;
	capture.mHeight = 18;
	capture.mTargetBuf = new int[24 * 18];

	/* Initialize capture - only one capture may be active per device,
	* but several devices may be captured at the same time.
	*
	* 0 is the first device.
	*/

	if (initCapture(0, &capture) == 0)
	{
		cout << "Capture failed - device may already be in use" << endl;
		return 1;
	}

	system("pause");
	return 0;
}


I followed this to a tee - https://www.youtube.com/watch?v=Sfn7yOiwJLw , there also doesn't seem to be much people facing the same issues , I created a few new projects and still getting the same error message :/
Last edited on
* update

ok after a very frustrating couple of hours I tried :: (Right click on project name -> Properties -> Expand Linker tab -> System -> SubSystem: make sure that it is Console (/SUBSYSTEM:CONSOLE) ) again on yet another project,

and it seemed to work eventually, not sure what I was doing wrong first time around ...

but as a matter if interest, how come the linker was not finding the entry point or main when this option wasn't specified to the linker?

thanks
Last edited on
How come the linker was not finding the entry point or main when this option wasn't specified to the linker?
Windows CRT tries to call a user-defined WinMain function unless you tell it otherwise:
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-winmain
thanks mbozzi :) but I never specified winMain, I defined main as of course main not winMain

I created an empty C++ project in MSVC, by default if an empty project is created does the visual c++ compiler look for winMain as an entry point?

but how would this affect SDL_main?


============================================

also while I'm on the subject - https://stackoverflow.com/questions/11976084/why-sdl-defines-main-macro

so it seems like SDL defines it's own main function to run initialisation/set up, so it redefines your main function as SDL_main and calls SDL_main after it calls it's main function.

but if that is the case, why the need for the SDL_init function if this initialisation is done by SDL?

also I am guessing that when the your compiled SDL program runs, your main function is not called instead the entry point or main function from SDLs static library is run and that then calls your main function in your program?

thanks
Last edited on

When you compile and link using the MS toolchain (i.e. Visual Studio), the code that you give it must have an "entry point". This is the function where your code starts.

Conventionally, this is main. However, MS allows you to also have winMain. Whichever one you have, you must tell the linker which one you've chosen. You do this through the project configuration; for example, with /SUBSYSTEM:CONSOLE


but how would this affect SDL_main?

Not at all. It's completely irrelevant. SDL renames your main function (to SDL_main), and provides its own main function to be used instead. So if you told the build tools that your code has a winMain instead of a main, it won't work, because where is the winMain? Nowhere. You didn't write winMain.

You were telling your build tools that the start wasn't main, but winMain. Did you code have a winMain? No. You had TWO separate problems:

1) No main function, because it was in a library that you hadn't linked.
2) The build tools weren't even looking for main, they were looking for winMain.
Last edited on
I haven’t bothered to look at this topic until now — I assumed all help needed was being received — but the topic is becoming long and I figured something interesting might be happening (but it’s not).

Every SDL tutorial and all the SDL docs explain exactly what you must do to compile and link an SDL program. You have not done that.

You must compile with the CONSOLE subsystem. That is pretty much given if the compiler can find a source module with int main() function defined.

As already (repeatedly) mentioned to you, SDL defines main for itself. But you must link to it in order to use it. Otherwise the compiler will assume you screwed up. (Because you did.)

From VS, go to your linker options and make sure you are linking with “SDL_main.lib”. Make sure you have the proper directory in the library path for the SDL lib files too. (Online tutorials cover this.)

From the command line, make sure to list the required library files as necessary. For example, if SDL_main.lib is in C:\Users\Adam\Documents\source\SDL, then make sure to compile with “C:\Users\Adam\Documents\source\SDL\SDL_main.lib” listed as part of your command line invocation:

C:\Users\Adam\Documents\source\mygame> cl /EHsc /Ox /std:c++17 mygame.cpp C:\Users\Adam\Documents\source\SDL\SDL_main.lib ...

(The elipsis means “and any other required libraries, like SDL_image, etc.)

Again, online tutorials all take care to run you through this. Particularly good are Lazy Foo’s SDL2 tutorials, which you should have bookmarked.

Good luck!
thanks guys,

that makes sense, and yes I've actually dabbled in lazyfoos tutorials before, but admittedly never finished them, I'm not a huge fan of games programming but SDL can do many things that I'm interested in such as physics simulations which I really want to get into.

I normally use codeblocks with SDL and I'm so used to the set up that I overlooked the set up for MSVC, I just assumed it would be similar but I guess not but yes as far as I know lazyfoo's tutorials actually explain the set up on MSVC.

I'm probably looking too far into this and should probably just accept that something works rather than diving into it's nuances, but I really like to understand what is going on at a lower level also. I feel this gives me a better understanding on how the whole process works.

As mentioned the SDL2main.lib or SDL2.lib has the entry point main defined so once you link and compile your program with SDL, the entry point will be loaded from SDLs static library, reason being? well from what I read is that SDL needs to take care of initialisation. but why there is a need for an SDL_init function if SDL takes care of this in the main function?
Good questions!

I'm not a huge fan of games programming ... I'm interested in...physics simulations [etc]

You will find that a physics simulation is, basically, the same as a game. You have an event loop, input to respond to (at minimum, the ability to stop a simulation), things to track and display (particle systems, in particular, require some care), refresh and FPS tracking and adjustment, etc.

I just assumed [MSVC == Code::Blocks]

LazyFoo explains both, IIRC. Each IDE is different, but the basics are the same: You must provide a include path, a library path, proper compiler switches, etc.

but I really like to understand what is going on at a lower level

Good. That shows someone with intelligence.

[why link with SDL’s main() instead of just having SDL_init() do everything?]

One word: cleanup.

The basis of RAII is that if you acquire a resource, you are responsible for cleaning it up. In C++ we use object lifetime for that. When a heavy object is created and initialized, its destructor will clean up for it. This keeps things clean.

When it comes to a basic executable, however, there are fewer avenues for doing this. SDL is designed to work for C or C++, so, lowest common denominator == take over main(). It probably has a hook on atexit() too.

There is also the possibility that there are initializations going on there that have nothing to do with SDL_init(). There are always structures behind the scenes that make things go, and with SDL’s extensibility, these things should be ready to use by an extension’s behind-the-scenes stuff before SDL_init() is called. (I’m not saying this is the way it is, but it is a potential reason — I have not looked at SDL sources.)


The reason that taking over main() is common and desireable is not just that it is low-hanging fruit — it is about the only simple method available cross-platform and cross-compiler.

With MSVC, and on Linux with GCC, for example, you can easily declare your own entry point. The way you do this is different for each compiler. However, once you start moving from your standard Linux and Windows, these things don’t work as easily, nor do they guarantee the same behavior on different systems. This is because different systems have their own startup code, and each one is targeted for that specific system.

At this point we are starting to get into a lot of worms that SDL’s author(s) don’t really care for. Simply taking over main means that it works everywhere, with minimal effort.

Hope this helps. :O)
very good points, I would have never thought of that, so in a sense SDL_main will initialise certain properties on a system needed for SDL_init() before the call to SDL_init() even takes place and this can vary from OS to OS and from compiler to compiler?

thanks :)
Close. By commandeering main(), SDL can avoid multiplying code for each OS/Compiler combination.

:O)
Topic archived. No new replies allowed.