Freitag, 26. Juni 2020

Setting up SDL2 on Windows with CMake and MinGW-W64 (Minimal Example)




Coming from SFML i noticed that setting up SDL2 on Windows using CMake can be...quite tricky. The official Wiki at https://wiki.libsdl.org/Installation gives only little information on how to build and install SDL2 on Windows to utilize the library for your projects.

There is an older article describing how to setup SDL2 with CMake and some StackOverflow discussions regarding this topic. They all had in common that they did not work for me - i could not get my project using SDL2-facilities to run on my Windows machine, no matter what.

While SFML 2.5 Source Code comes with an own SFMLConfig.cmake file that takes care of finding the corresponding libraries when invoking find_package(...) in CMake, this seems to be broken for the SDL2 Source Code that can be downloaded from the official SDL2-Website - at least for the Windows Plattform.
So there is no working  find_package(SDL2 REQUIRED) out of the box.


The "Using FindSDL2.cmake" Route

Another approach is using some FindSDL2.cmake file that is floating around in the internet. You could create a modules-directory in the source directory of your project (where the CMakeLists.txt file resides). CMake should be informed about the modules folder where it will look for a FindXXX.cmake file:

set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/modules)

In theory find_package(SDL2 REQUIRED) should now find the SDL2 files. However this did not work for me either, CMake was not able to find SDL2 on Windows despite using a FindSDL2.cmake-file. Grrr.
The available FindSDL2.cmake files you can find online are tailored for UNIX-derived operating systems (such as Linux or OSX), and do not consider Windows as a Target Plattform. In short: The usual FindSDL2.cmake files you can find online do not search for Windows folders. So you would basically need to adjust the FindSDL2.cmake file to get it to work in Windows.
Such FindSDL2.cmake file for example can be found here or here.
If you installed SDL2 in "C:/Program files (x86)/SDL2" you would have to adjust the FindSDL2.cmake-file as follow:

before:
SET(SDL2_SEARCH_PATHS
 ~/Library/Frameworks
 /Library/Frameworks
 /usr/local
 /usr
 /sw # Fink
 /opt/local # DarwinPorts
 /opt/csw # Blastwave
 /opt
)

after:
SET(SDL2_SEARCH_PATHS
 ~/Library/Frameworks
 /Library/Frameworks
 /usr/local
 /usr
 /sw # Fink
 /opt/local # DarwinPorts
 /opt/csw # Blastwave
 /opt
 "C:/Program Files (x86)/SDL2"
)

Now CMake should find the SDL2-files - given you installed them in this location. The CMakeLists.txt file could now be written as follow:

cmake_minimum_required(VERSION 3.0)
project(game)
set(SOURCES main.cpp)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/modules)
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIR})
add_executable(game ${SOURCES})
target_link_libraries(game ${SDL2_LIBRARY})

Keep in mind that due to how the used FindSDL2.cmake file is written you don't write
#include <SDL2/SDL.h> 
in your *.hpp/cpp Project-files but simply
#include <SDL.h>
given that your SDL2-include-files are stored in C:/Program files (x86)/SDL2/include/.

 

The "Straight-Forward" Route

If you don't like fiddling with the FindSDL2.cmake-File you can just directly tell CMake about SDL2 as straight forward as possible. This turned out to be bumpy, but it works too.

cmake_minimum_required(VERSION 3.0)
project(game)
set(SOURCES main.cpp)
set(SDL2_INCLUDE_DIR "C:/Program Files (x86)/SDL2/include")
set(SDL2_LIBRARY_DIR "C:/Program Files (x86)/SDL2/lib")
include_directories(${SDL2_INCLUDE_DIR})
add_executable(game ${SOURCES})
target_link_libraries(game -lmingw32 ${SDL2_LIBRARY_DIR}/libSDL2main.a ${SDL2_LIBRARY_DIR}/libSDL2.dll.a -mwindows)
The important bits here are the following:
The FindSDL2.cmake file did hide some specifics from us that we now need to take care of:
The FindSDL2.cmake file suggests that you need to link against following files: -lmingw32 -lSDL2main -lSDL2 -mwindows
Since we don't use a FindSDL2.cmake-file, we do have to do this manually.
  • libSDL2main.a must be linked before libSDL2.dll.a, otherwise you will get a plethora of linking-errors when you try to compile your project.
  • you must link against -lmingw32 when using mingw-w64 compiler, otherwise during compilation the compiler will complain about some "undefined reference to `WinMain'". The position matters, -lmingw32 has to be the first entry that is linked against in target_link_libraries.
I noticed that omitting -mwindows does not have a negative effect, but who knows - so keep it in there.

Compile and run

Having everything in place as described you should be now good to go when using a mingw-w64 compiler:
Given that the path to CMake and your mingw-w64-compiler (where g++.exe resides) is added to the environment variables PATH and your Project-Folder contains the described CMakeLists-file, open the command line tool of windows ("CMD"), go to your /ProjectFolder/build directory and create the Makefile with

cmake .. -G "MinGW Makefiles"

The created Makefile can be compiled with

mingw32-make

Now your project should compile with SDL2 included. Don't forget to add SDL2.dll to your build-folder where the *.exe of your application is created.