The overarching mistake here is not using a proper build toolchain (build system and package manager). I especially take issue with this assertion:
> The correct SDL2 include is the following:
> #include "SDL.h"
Including headers with the library prefix (#include <SDL2/SDL.h>) is our only hope to have an inter-operable ecosystem of C/C++ libraries. Let me illustrate this with a concrete example. What the article suggests is having the header search path (i.e., -I option from sdl2-config) pointing to the location of the SDL.h header (say, /usr/include/SDL2). But there are other headers[1]in there. Thankfully, most of them have the SDL_ prefix (by all means an exception rather than the rule, when it comes to C/C++ libraries), but not all. For example, there is the generically-named begin_code.h header.
Imagine now that your project is using another library with the same arrangement which also contains a bunch of generically-named headers and one of them happened to be called begin_code.h. Now which one gets picked up depends on the order of the -I options that are passed to the compiler.
If you use '#include <SDL2/SDL.h>', your software will refuse to compile under a whole lot of circumstances. It assumes a Linux-style situation where you have one 'include' directory with headers from all libraries in it. A lot of systems won't have that; they will instead have separate include directories for the different libraries, and use pkg-config or an equivalent to provide the -I flags. And these systems will all provide flags which make '#include "SDL.h"' work, while '#include <SDL2/SDL.h>' won't work.
Of course, all of this is moot if you don't intend to use a system-provided SDL. If you bundle your own SDL and take care of that with your build system, you can do whatever you want. But if you intend to use a system-provided SDL, and you intend for your software to be somewhat portable, you must use '#include "SDL.h"'.
Now I will agree that it would've been better if SDL decided to make '#include <SDL2/SDL.h>' the canonical include path. And the fact that SDL pollutes your header search space with generically named header is terrible. SDL is not a very good library, it's a "bad citizen". But that's the world we live in. The only ones who can change it are the people behind SDL (and I certainly hope they do change it with a potential future SDL3).
Yes for the sake of everything holy, the only time it's remotely acceptable to include with "" is for a header file corresponding to a source file. Otherwise always always include with <> and with the complete library prefix if possible, e.g. <SDL2/foo.h>, <libavcodec/codec.h>, etc etc and add as few include paths as you can, anything else is calling for subtle bugs if you're unlucky in how your third-party deps name their things
There's something much worse than including a library header with "", which is a library including its own headers (in the same directory) with <>! That means the user has no choice but to modify the include path.
> SDL may rename the application’s main to SDL_main and substitute its own C main
Wow ok. This FAQ[0] is for windows but I guess the same applied for linux.
> A software renderer fallback is exactly the behavior you want!
Apart from the fact that I don't see this situation happening in the context of gaming, if it were to happen, I am not sure that this behavior is always desirable. If your game has a sufficiently complex render loop, a software renderer might be too slow and will generate support calls. You might want to be upfront with the user and fail with a meaningful error message especially if you claim the need of a GPU on your system as a minimal requirement. The user might have a GPU but badly configured on their system for example.
So the gist of this article is that SDL is a framework and if you commit to a framework you might has well commit fully. SDL having an API that goes beyond graphics, you might find the API you need for a particular purpose and not use the system one to keep you software as portable as possible.
The thing is, I see SDL as a way to get a graphical window as cheaply as possible. I don't necessarily see it as a framework. I actually have a deep, and probably irrational, mistrust of frameworks.
I think you've misunderstood SDL a bit. It's just a very low-level framework to get access to the canvas, events, inputs, sound etc., on multiple platforms. The hardware acceleration is for simple blits and texture painting which is fine for most 2d games.
If you want anything more than the very basics, there's always Godot or Unity.
Set up windowing (to get to your OpenGL/Vulkan/DX/whatever), input (is it low latency), maybe timers and maybeeee audio. .so loading and function lookup is useful, but is anyone actually using SDL threads and networking?
What really surprised me about SDL2 is how bad the documentstion is given that it's a very stable bit of software with a wide backing from industry.
There were apparently some efforts to move the wiki from one technology to another which somehow left it in a semi-broken limbo which hasn't been fixed for years.
It seems to be one of those technologies you get mostly taught by the seniors at your studio and they don't need no documentation cause they all got it in their heads.
In my experience SDL2 is one of those libraries for which you have to be willing to read the source code itself, and the tests which contain handy implementation examples.
That said, I haven't had a problem with the wiki being inaccurate, but a lot of things do seem to not be documented there.
Well, I disagree with this assertion, but only partially. You should use either pkg-config or the CMake package definition, depending on how your application is being built. sdl2-config is deprecated and won't be available in SDL3.
SDL2 really is quite something! I didn't have to make any changes to my program when I tried to build it on FreeBSD yesterday. It just worked, so I was quite impressed! I did manage to break FreeBSD after a while - I think by just installing mesa-devel - which broke swrast. After removing the package I could get glxgears to work again.
> My solution [for generating random numbers] has been to mix event timestamps into the random state: [...]
That's a good, old, and proven technique that is worth highlighting (I would use only the youngest 2-3 bits however).
I wonder though if the author is not shooting themselves in the foot long-term for things like games, where you want to be able to replay the random number stream to hunt down bugs, or for networked game clients that need to run the simulation deterministically and in lockstep.
If it's deterministic it's not random, it's a hash function. yes I know, it's called rand(). it is still a hash function(except on openbsd), just one with no standard.
For games you don't need randomness; you need a function that returns next in a series of uniformly distributed numbers (which RNGs happen to satisfy). But more importantly, you do need determinism, for the reasons I stated above. We're calling that function "random" for the same reasons we'd call another function "dial", even though there's no telephone involved.
I think you have a choice to make between writing "a C application" which also uses SDL but probably only runs easily on computers, or writing "an SDL application" which can be easily ported to all weirdo SDL platforms without a complete standard library like maybe Vita or PSP or GP2x or RISC OS or BeOS or something obscure.
Say you're writing a game where you want to decouple the game logic from the render, so your game can be more easily ported to different output formats like ncurses or even a different graphics library like raylib. In that situation I think it would be an error to depend on any SDL library functions like `SDL_calloc`. Or if you did, you'd need to have your own function pointer set for everything you used, like a global ops struct of function pointers with `my_ops->calloc()` (which is how I'm handling cross-render implementation too).
The SDL set is also missing some things, like I need locale support for wchar.
Overall, I don't want to write "SDL C", I want to write C99.
Sdl predates pkg-config. In the late 90s it used to be common for libraries on Linux to have a little script like that. Gtk+ was the first one i remember noticing. Most of them migrated to pkg-config if they're still around.
It's fun how most of these are "Using the normal mechanism instead of the SDL specific mechanism". I think we somehow end up biased against special-purpose mechanisms, so I'm not surprised these are common mistakes.
Nice list. I haven't looked for the answer, but I immediately thought "why not both" in the section about SDL_WaitEvent vs SDL_PoolEvent. Is it not possible to VSYNC ImGUI apps with animation?
my problem with learning sdl2 is every article I’ve encountered already assumes I know sdl2. but I could hardly find documentation to grok it.
if I have to read the source code for it. what prereq knowledge do I need if I’m from a web dev background trying to build graphical desktop apps with sdl2
If you can get past the layout, one of the best online resources for learning SDL are Lazyfoo's tutorials[0] and maybe Parallel Realities[1].
But SDL is too low level to consider as a framework for GUI, it's basically a cross platform library for hardware (screen, graphics, input, audio) and event handling. You're still going to have to write everything yourself.
You should at least know C or C++, although there are ports to several languages, and several GUI frameworks like Dear ImGui and I think Pygame use SDL in the background.
SDL does pretty much only the parts you still need after choosing Vulkan or WebGPU (or OpenGL, or anything else); audio, windowing, input handling, etc.
The point is that those apis will be used in browsers and the browsers will become the new SDL. The browsers will handle sound and windowing and also sandboxing and networking.
> Mistake 2: Including SDL2/SDL.h
The overarching mistake here is not using a proper build toolchain (build system and package manager). I especially take issue with this assertion:
> The correct SDL2 include is the following:
> #include "SDL.h"
Including headers with the library prefix (#include <SDL2/SDL.h>) is our only hope to have an inter-operable ecosystem of C/C++ libraries. Let me illustrate this with a concrete example. What the article suggests is having the header search path (i.e., -I option from sdl2-config) pointing to the location of the SDL.h header (say, /usr/include/SDL2). But there are other headers[1]in there. Thankfully, most of them have the SDL_ prefix (by all means an exception rather than the rule, when it comes to C/C++ libraries), but not all. For example, there is the generically-named begin_code.h header.
Imagine now that your project is using another library with the same arrangement which also contains a bunch of generically-named headers and one of them happened to be called begin_code.h. Now which one gets picked up depends on the order of the -I options that are passed to the compiler.
[1] https://packages.debian.org/stable/amd64/libsdl2-dev/filelis...