Issue Including SDL2 and SDL2_image With CMake

Viewed 534

The Problem

  • SDL2_image is unable to locate SDL.h from SDL2.
  • References to SDL2 within the project files are able to locate SDL2 and SDL2_image.

CMakeLists.txt

# Minimum CMAKE Version Requirement
cmake_minimum_required(VERSION 3.20.3)

# Find Modules - SDL2
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

# Project Fields - TEST PLATFORM
project(library_test
    LANGUAGES C
    VERSION 0.1.0
)

set(SDL2_LIBRARY "C:/lib/SDL2-2.0.14/i686-w64-mingw32/bin")
set(SDL2_INCLUDE_DIR "C:/lib/SDL2-2.0.14/i686-w64-mingw32/include")

set(SDL2_IMAGE_LIBRARY "C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/bin")
set(SDL2_IMAGE_INCLUDE_DIR "C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/include")

find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)

# C99 Standard Requirement
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED YES)
set(CMAKE_C_EXTENSIONS OFF)

# RESET Library Content
add_library(reset STATIC)
target_link_libraries(reset SDL2::Main SDL2::Image)
target_include_directories(reset PUBLIC include/reset)
add_subdirectory(src)

# Test Platform Content
add_executable(test_platform test_platform/test_platform.c)
target_link_libraries(test_platform STATIC reset)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -ggdb")

CMake Build Output

See the full output here:

[main] Building folder: reset 
[build] Starting build
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build c:/C99/reset/build --config Debug --target all -j 6 --
[build] -- Configuring done
[build] -- Generating done
[build] -- Build files have been written to: C:/C99/reset/build
[build] Consolidate compiler generated dependencies of target reset
[build] [ 10%] Building C object CMakeFiles/reset.dir/src/data/provider.c.obj
[build] [ 20%] Building C object CMakeFiles/reset.dir/src/data/rrcon.c.obj
[build] [ 30%] Building C object CMakeFiles/reset.dir/src/internal/rsetup.c.obj
[build] [ 40%] Building C object CMakeFiles/reset.dir/src/spatial/rlevelmap.c.obj
[build] [ 50%] Building C object CMakeFiles/reset.dir/src/spatial/rtilemap.c.obj
[build] [ 60%] Building C object CMakeFiles/reset.dir/src/visual/rfocus.c.obj
[build] In file included from C:/C99/reset/include/reset/depn.h:12:0,
[build]                  from C:/C99/reset/include/reset/provider.h:13,
[build]                  from C:\C99\reset\src\data\provider.c:2:
[build] C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/include/SDL2/SDL_image.h:27:17: fatal error: SDL.h: No such file or directory
[build]  #include "SDL.h"
[build]                  ^
[build] compilation terminated.
[build] In file included from C:/C99/reset/include/reset/depn.h:12:0,
[build]                  from C:/C99/reset/include/reset/rrcon.h:15,
[build]                  from C:\C99\reset\src\data\rrcon.c:4:
[build] C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/include/SDL2/SDL_image.h:27:17: fatal error: SDL.h: No such file or directory
[build]  #include "SDL.h"
[build]                  ^
[build] compilation terminated.
[build] CMakeFiles\reset.dir\build.make:75: recipe for target 'CMakeFiles/reset.dir/src/data/provider.c.obj' failed
[build] mingw32-make.exe[2]: *** [CMakeFiles/reset.dir/src/data/provider.c.obj] Error 1
[build] mingw32-make.exe[2]: *** Waiting for unfinished jobs....
[build] CMakeFiles\reset.dir\build.make:90: recipe for target 'CMakeFiles/reset.dir/src/data/rrcon.c.obj' failed
[build] mingw32-make.exe[2]: *** [CMakeFiles/reset.dir/src/data/rrcon.c.obj] Error 1
[build] In file included from C:/C99/reset/include/reset/depn.h:12:0,
[build]                  from C:/C99/reset/include/reset/rsetup.h:11,
[build]                  from C:\C99\reset\src\internal\rsetup.c:2:
[build] C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/include/SDL2/SDL_image.h:27:17: fatal error: SDL.h: No such file or directory
[build]  #include "SDL.h"
[build]                  ^
[build] compilation terminated.
[build] CMakeFiles\reset.dir\build.make:120: recipe for target 'CMakeFiles/reset.dir/src/internal/rsetup.c.obj' failed
[build] mingw32-make.exe[2]: *** [CMakeFiles/reset.dir/src/internal/rsetup.c.obj] Error 1
[build] In file included from C:/C99/reset/include/reset/depn.h:12:0,
[build]                  from C:/C99/reset/include/reset/rlevelmap.h:5,
[build]                  from C:\C99\reset\src\spatial\rlevelmap.c:2:
[build] C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/include/SDL2/SDL_image.h:27:17: fatal error: SDL.h: No such file or directory
[build]  #include "SDL.h"
[build]                  ^
[build] compilation terminated.
[build] CMakeFiles\reset.dir\build.make:135: recipe for target 'CMakeFiles/reset.dir/src/spatial/rlevelmap.c.obj' failed
[build] mingw32-make.exe[2]: *** [CMakeFiles/reset.dir/src/spatial/rlevelmap.c.obj] Error 1
[build] In file included from C:/C99/reset/include/reset/depn.h:12:0,
[build]                  from C:/C99/reset/include/reset/rtilemap.h:9,
[build]                  from C:\C99\reset\src\spatial\rtilemap.c:2:
[build] C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/include/SDL2/SDL_image.h:27:17: fatal error: SDL.h: No such file or directory
[build]  #include "SDL.h"
[build]                  ^
[build] compilation terminated.
[build] CMakeFiles\reset.dir\build.make:150: recipe for target 'CMakeFiles/reset.dir/src/spatial/rtilemap.c.obj' failed
[build] mingw32-make.exe[2]: *** [CMakeFiles/reset.dir/src/spatial/rtilemap.c.obj] Error 1
[build] In file included from C:/C99/reset/include/reset/depn.h:12:0,
[build]                  from C:/C99/reset/include/reset/rfocus.h:11,
[build]                  from C:\C99\reset\src\visual\rfocus.c:2:
[build] C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/include/SDL2/SDL_image.h:27:17: fatal error: SDL.h: No such file or directory
[build]  #include "SDL.h"
[build]                  ^
[build] compilation terminated.
[build] CMakeFiles\reset.dir\build.make:165: recipe for target 'CMakeFiles/reset.dir/src/visual/rfocus.c.obj' failed
[build] mingw32-make.exe[2]: *** [CMakeFiles/reset.dir/src/visual/rfocus.c.obj] Error 1
[build] CMakeFiles\Makefile2:169: recipe for target 'CMakeFiles/reset.dir/all' failed
[build] mingw32-make.exe[1]: *** [CMakeFiles/reset.dir/all] Error 2
[build] Makefile:89: recipe for target 'all' failed
[build] mingw32-make.exe: *** [all] Error 2
[build] Build finished with exit code 2

The current CMake setup resolved previous issues I had with #include <SDL.h> causing a file not found error, but now this occurs within SDL_image as it tries to access SDL. Note that the source of the errors is SDL_image.h as it attempts to #include "SDL.h".

Currently, the SDL packages are found using some FindSDL2 cmake files that I found on this page: https://edgarluque.com/blog/sdl2-cmake

This is also the first page I found that actually resolved any of the previous errors I have had. I am on windows instead of linux so there are naturally issues.

I did try adding -l compiler arguments for the SDL components but these seemingly had no effect.

Attempted Solutions

I tried changing the last line in the CMake_lists.txt file (compiler flags):

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lmingw32 -lSDL2main -lSDL2 -lSDL2_image -ggdb -IC:/lib/SDL2-2.0.14/i686-w64-mingw32/include/SDL2")

and this produced a different error:

[main] Building folder: reset 
[build] Starting build
[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --build c:/C99/reset/build --config Debug --target all -j 6 --
[build] -- Configuring done
[build] -- Generating done
[build] -- Build files have been written to: C:/C99/reset/build
[build] Consolidate compiler generated dependencies of target reset
[build] [ 10%] Building C object CMakeFiles/reset.dir/src/data/provider.c.obj
[build] [ 20%] Building C object CMakeFiles/reset.dir/src/data/rrcon.c.obj
[build] [ 30%] Building C object CMakeFiles/reset.dir/src/data/rvector.c.obj
[build] [ 40%] Building C object CMakeFiles/reset.dir/src/internal/rsetup.c.obj
[build] [ 50%] Building C object CMakeFiles/reset.dir/src/spatial/rlevelmap.c.obj
[build] [ 60%] Building C object CMakeFiles/reset.dir/src/spatial/rtilemap.c.obj
[build] [ 70%] Building C object CMakeFiles/reset.dir/src/visual/rfocus.c.obj
[build] [ 80%] Linking C static library libreset.a
[build] [ 80%] Built target reset
[build] Consolidate compiler generated dependencies of target test_platform
[build] [ 90%] Building C object CMakeFiles/test_platform.dir/test_platform/test_platform.c.obj
[build] [100%] Linking C executable test_platform.exe
[build] c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/ld.exe: cannot find -lSDL2main
[build] c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/ld.exe: cannot find -lSDL2
[build] c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/ld.exe: cannot find -lSDL2_image
[build] CMakeFiles\test_platform.dir/objects.a(test_platform.c.obj): In function `main':
[build] C:/C99/reset/test_platform/test_platform.c:18: multiple definition of `main'
[build] c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../libmingw32.a(main.o):(.text.startup+0x0): first defined here
[build] c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/ld.exe: cannot find -lSTATIC
[build] c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/ld.exe: cannot find C:/lib/SDL2_image-2.0.5/i686-w64-mingw32/bin: Permission denied
[build] c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/ld.exe: cannot find C:/lib/SDL2-2.0.14/i686-w64-mingw32/bin: Permission denied
[build] collect2.exe: error: ld returned 1 exit status
[build] CMakeFiles\test_platform.dir\build.make:101: recipe for target 'test_platform.exe' failed
[build] mingw32-make.exe[2]: *** [test_platform.exe] Error 1
[build] CMakeFiles\Makefile2:195: recipe for target 'CMakeFiles/test_platform.dir/all' failed
[build] mingw32-make.exe[1]: *** [CMakeFiles/test_platform.dir/all] Error 2
[build] Makefile:89: recipe for target 'all' failed
[build] mingw32-make.exe: *** [all] Error 2
[build] Build finished with exit code 2

Here is also the test_platform.c file, because it is relevant to the new error:

//#define SDL_MAIN_HANDLED

#include "depn.h"
#include "rsetup.h"
#include "rrcon.h"
#include "provider.h"
#include "rfocus.h"
#include "rvector.h"
#include "rtilemap.h"
#include "rlevelmap.h"

#undef main

/// Main Function

int main ( int argc, char ** argv )
{
    fprintf ( stderr, "Received %d argument%s:\n", argc, argc == 1 ? "" : "s" );

    forsi ( argc ) fprintf ( stderr, "\t%s\n", argv [ ix ] );

    CFG_WIN cfg =
    {
        1920, 1080,
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        "Reset"
    };

    r_sdlset(); // SDL2 module init

    DATA_WIN display = r_dispset ( cfg );

    RRCON rrcon = rrcon_inst ( display.renderer, TEXTURE );
    register_directory ( "tile" );
    rrcon_import ( rrcon, "grass", "grass.png" );

    RTILEMAP tilemap = rtilemap_static ( );
//    RTILEMAP tilemap = rtilemap_dynamic ( 72, 72 );
    RTILE tile = rtile_inst ( "grass" );

    VEC2U pos = { 0, 0 };
    VEC2U pos2 = { 63, 31 };

    rtilemap_set ( tilemap, tile, pos );
    rtilemap_set ( tilemap, tile, pos2 );

//    RFOCUS focus = rfocus_inst ( F_FLAT_TILEMAP );
//
//    focus -> tilemap = tilemap;

    VEC2I tilemap_start = { 30, 0 };

    SDL_Event ev;

    while ( 1 )
    {
        if ( SDL_WaitEvent ( &ev ) )
        {
            if ( ev.type == SDL_QUIT )
            {
                rrcon_clr ( rrcon );

                SDL_DestroyRenderer ( display.renderer );
                SDL_DestroyWindow ( display.window );
                SDL_Quit ();
                IMG_Quit ();

                return EXIT_SUCCESS;
            }
        }

        // SDL_SetRenderDrawColor ( display.renderer, 0, 0, 0, 255 );
        SDL_RenderClear ( display.renderer );

        rtilemap_render_tiles ( tilemap, rrcon, tilemap_start, 1.0 );

        SDL_RenderPresent ( display.renderer );
    }

    return 0;
}
1 Answers

After looking over your information and the modules' documentation, here are the issues I'm seeing:

CMAKE_C_FLAGS:

Avoiding direct manipulation of this in modern CMake solutions is strongly encouraged. CMake provides specialized functions for defining things like compiler flags, linker libraries, etc. and their relationships to specific targets in your project, which allow it to manage things more carefully.

SDL2_ variables:

According to the documentation at https://github.com/aminosbh/sdl2-cmake-modules these should be cache variables rather than local ones. I'm not sure if this actually matters, but it may be worth noting for troubleshooting purposes. It's also just a good idea in general to use cache variables for this kind of thing, because then people can override them on the CMake command line or in cmake-gui.

Note that cache variable values get stored in a CMakeCache.txt file in your build directory, which will likely need to be deleted if you want to use different values.

I should also point out here that the modules' documentation suggests that you should be able to just set SDL2_PATH and SDL2_IMAGE_PATH. However, this apparently requires that the libraries be under lib/ in your installation, rather than under bin/.

SDL2_LIBRARY/SDL2_IMAGE_LIBRARY:

If you choose to stick with defining these directly, I think you may need to point them at the full path and filename of the actual library file, and not just the containing directory.

SDL2_INCLUDE_DIR/SDL2_IMAGE_INCLUDE_DIR:

It appears that these are meant to point to the SDL2 directories containing the actual library headers (e.g. SDL.h), and not to the parent directory containing the SDL2 directory. This is likely why SDL2_image is failing to find SDL.h during compile time.

This also means you are expected to omit SDL2/ path prefixes from the #include directives in your own code; however, you could use target_include_directories to add ${SDL2_INCLUDE_DIR}/.. etc. to each dependent target that you're building in order to end up with both directory levels in the compiler's header search paths.

SDL::Core and SDL::Main:

The module documentation suggests that any SDL-dependent libraries you're building (e.g. reset) must link against SDL::Core, not SDL::Main.

Only SDL-dependent executables (e.g. test_platform) that you're building should link against SDL::Main, as this represents the library that wraps your main() (or similar OS-specific) function with SDL's main function.

Note that if you were only to build an application and not a library, you would only need to link SDL::Main because the module defines an internal dependency on SDL::Core.

Related