Search code examples
c++ccmakesdlsdl-2

cmake using SDL2 and SDL2_Image via FetchContent


I've a small cmake project that uses SDL via FetchContent, this work well with just SDL.

cmake_minimum_required(VERSION 3.24)
project(sdl_test)

set(CMAKE_CXX_STANDARD 20)

include(FetchContent)
Set(FETCHCONTENT_QUIET FALSE)

FetchContent_Declare(
        SDL2
        GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
        GIT_TAG release-2.26.3
        GIT_SHALLOW TRUE
        GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(SDL2)
include_directories(${SDL2_SOURCE_DIR}/include})

add_executable(sdl_test main.cpp)
target_link_libraries(sdl_test SDL2::SDL2main SDL2::SDL2-static)

I try to use the same approach to include SDL_Image, however I can not get it to work.

cmake_minimum_required(VERSION 3.24)
project(sdl_test)

set(CMAKE_CXX_STANDARD 20)

include(FetchContent)
Set(FETCHCONTENT_QUIET FALSE)

FetchContent_Declare(
        SDL2
        GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
        GIT_TAG release-2.26.3
        GIT_SHALLOW TRUE
        GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(SDL2)
include_directories(${SDL2_SOURCE_DIR}/include})

FetchContent_Declare(
        SDL2_image
        GIT_REPOSITORY https://github.com/libsdl-org/SDL_image.git
        GIT_TAG release-2.6.3
        GIT_SHALLOW TRUE
        GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(SDL2_image)
include_directories(${SDL2IMAGE_INCLUDE_DIRS}/include})

add_executable(sdl_test main.cpp)
target_link_libraries(sdl_test SDL2::SDL2main SDL2::SDL2-static SDL2_image::SDL2_image-static)

Produce the following error:

CMake Error: install(EXPORT "SDL2ImageExports" ...) includes target "SDL2_image" which requires target "SDL2" that is not in any export set.
CMake Error at CMakeLists.txt:30 (target_link_libraries):
  Target "sdl_test" links to:

    SDL2_image::SDL2_image-static

  but the target was not found.  Possible reasons include:

    * There is a typo in the target name.
    * A find_package call is missing for an IMPORTED target.
    * An ALIAS target is missing.

Note: Maybe some people dislike using FetchContent, however I like it and been using for many other dependencies in the past, so I'm trying to make this approach to work.


Solution

  • I create an issue on SLD_Image repository, and they give the following answer, that actually work.

    The CMake script of SDL2_image builds only a shared or static library, not both. So you need to set BUILD_SHARED_LIBS to a false-ish value.

    Also, you need to disable the installation targets of SDL2_image (this has been fixed in git).

    So your cmake script should become:

    cmake_minimum_required(VERSION 3.24)
    project(sdl_test)
    
    set(CMAKE_CXX_STANDARD 20)
    
    include(FetchContent)
    Set(FETCHCONTENT_QUIET FALSE)
    
    FetchContent_Declare(
            SDL2
            GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
            GIT_TAG release-2.26.3
            GIT_SHALLOW TRUE
            GIT_PROGRESS TRUE
    )
    FetchContent_MakeAvailable(SDL2)
    
    FetchContent_Declare(
            SDL2_image
            GIT_REPOSITORY https://github.com/libsdl-org/SDL_image.git
            GIT_TAG release-2.6.3
            GIT_SHALLOW TRUE
            GIT_PROGRESS TRUE
    )
    
    # START ADDITION
    set(SDL2IMAGE_INSTALL OFF)
    set(BUILD_SHARED_LIBS FALSE)
    # END ADDITION
    
    FetchContent_MakeAvailable(SDL2_image)
    
    add_executable(sdl_test main.cpp)
    target_link_libraries(sdl_test SDL2::SDL2main SDL2::SDL2-static SDL2_image::SDL2_image-static)
    

    They clarify further the behaviour.

    SDL2 is able to create a shared and static library, configurable through SDL_SHARED and SDL_STATIC. Both are enabled by default. SDL2_image is only able to configure one at a time (using BUILD_SHARED_LIBS).

    SDL3's default has changed: SDL_SHARED and SDL_STATIC are initialized by BUILD_SHARED_LIBS (during first configuration). If BUILD_SHARED_LIBS is not defined, then only SDL_SHARED is enabled. If BUILD_SHARED_LIBS is defined, it can build tdecides what one). Either ways SDL_SHARED and SDL_STATIC remain the ultimate options.

    It isn't implemented yet, but SDL3_image will probably follow the same behavior as SDL3 and be able to build both shared and static configurations.