1

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.

Juan Medina
  • 533
  • 1
  • 5
  • 12
  • Out of curiosity, is `include_directories(${SDL2_SOURCE_DIR}/include})` really necessary when you later do `target_link_libraries(sdl_test SDL2::SDL2main SDL2::SDL2-static)`? – starball Feb 23 '23 at 23:41
  • What's the value of `BUILD_SHARED_LIBS` when you `FetchContent_MakeAvailable(SDL2_image)`? It needs to be `"STATIC"` for you to use `SDL2_image::SDL2_image-static`. ([link to source](https://github.com/libsdl-org/SDL_image/blob/SDL2/CMakeLists.txt)) – starball Feb 24 '23 at 00:01
  • I'm a `cmake` novice. But, I assume you've looked at `ExternalProject_Add`? Did you try this to see if it behaves better? In addition to _fetching_ content, don't you have to tell it to _build_ the external project? Also, could the `-static` be an issue? Did you try _without_ it as the package may build the dynamic version but _not_ the static version by default? – Craig Estey Feb 24 '23 at 02:47
  • @CraigEstey `FetchContent` makes the fetched project part of the same generated buildsystem instead of a separate generated buildsystem (`ExternalProject`). The approaches are quite different and each require different considerations. You don't need to do anything to tell fetched targets to be built other than link whatever uses it to it. As for the `-static`, see my second comment. – starball Feb 24 '23 at 02:51
  • @user For me, I'd probably want the external project to stay external. I saw your comment [and looked at the link--it's quite _thorough_ ;-)]. But, it's been 2 hours and OP hasn't responded to your comment(s). If it were me, I'd build the `SDL*` images with dynamic, get _that_ working, and then figure out how to get the static versions working. So, for me, I'd do simple first: external projects and dynamic. Then, add back the other options, one by one. – Craig Estey Feb 24 '23 at 02:59
  • I can remove the include_directories and still work without SDL_Image but still not work with SDL_Image, same error – Juan Medina Feb 24 '23 at 06:54
  • I don't want to use ExternalProject_Add, that implied to usually implied to have the project as a git submodule of my project, as someone point it out I want just to be external, a reference to a particular tag/version – Juan Medina Feb 24 '23 at 06:55
  • BUILD_SHARED_LIBS: value is OFF before FetchContent_Declare SDL2_image, I try to force to "STATIC" and get CMake Error: The INTERFACE_SDL2_SHARED property of "SDL2" does not agree with the value of SDL2_SHARED already determined, I change it to OFF and get exactly the same error that in my original post – Juan Medina Feb 24 '23 at 07:10
  • I try as well to build it not -static, target_link_libraries(sdl_test SDL2::SDL2 SDL2_image::SDL2_image), and get similar error : CMake Error: install(EXPORT "SDL2ImageExports" ...) includes target "SDL2_image" which requires target "SDL2" that is not in any export set. – Juan Medina Feb 24 '23 at 07:14
  • whoops. I meant "OFF" and not "STATIC". but if it was already "OFF", then I don't know the cause of the issue. – starball Feb 24 '23 at 07:21

2 Answers2

0

The answer that I'm outlining here is just a possible solution, it may not work. But it's worth a try. The best way to make this work is to not use the SHALLOW fetch, but I assume here that you don't want that. Correction from @user.


Possible solution:

Most of the people in the comments focus on the "wrong" part of the error message. What you should be focusing on are the first 2 lines, i.e.:

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):

Because the target is not found, the actual library that you link against doesn't exist. Hence why the BUILD_SHARED_LIBS option doesn't do anything.

It says that SDL2_image requires the target SDL2 which is defined in the previous FetchContent invokation, but this isn't available to the other one during build time. The real question now is, how to make it available.

I believe the only way is pretty much a "hacky" way. Let's check what the SDL_Images CMakeLists.txt looks like, specifically the line right here: Line 748.

It seems to be that SDL2 as a package is referred to as SDL2main, please note that in versions 3.0.0+ it's just SDL3.

So the best chance at making this work would probably be to change the first FetchContent_Declare as such (Note that you need CMake 3.24+):

FetchContent_Declare(
        SDL2main # <--- new name of our target
        GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
        GIT_TAG release-2.26.3
        GIT_SHALLOW TRUE
        GIT_PROGRESS TRUE
        OVERRIDE_FIND_PACKAGE #<--- and we also need to add this
)

This should hopefully override subsequent find_package(SDL2main) calls and might fix your issue.


Last option: if the above won't work, you could just "not build" the SDL2_Image samples, i.e. by enforcing SDL2IMAGE_SAMPLES to be False.

Milan Š.
  • 1,353
  • 1
  • 2
  • 11
  • Unfortunately, it does not work. I did the rename to SDL2 to SDL2main, I add the OVERRIDE_FIND_PACKAGE and set SDL2IMAGE_SAMPLES to off (forced), and did remove the SHALLOW as well, and now the error is *CMake Error: install(EXPORT "SDL2ImageExports" ...) includes target "SDL2_image" which requires target "SDL2" that is not in any export set.* – Juan Medina Feb 26 '23 at 14:46
  • forgot to mention I've *cmake version 3.25.2* – Juan Medina Feb 26 '23 at 14:49
  • @JuanMedina did you clear the caches, i.e. removed the build folder? Also regarding the shallow options, it is a bit more complicated and isn't only about removing the `SHALLOW` option. I know that it has some very weird behavior that is more related to `git` then `CMake`. In regards to the `SHALLOW` option I would start by creating a completely new and clean project. This is based on my experience. – Milan Š. Feb 26 '23 at 17:25
  • @JuanMedina removing the `SHALLOW` option should fix the issue, because in that case you are going to download **all** the subrepositories in that git project and building them from scratch. So if you don't see `zlib` and other dependencies being built, then it is not `SHALLOW FALSE`. – Milan Š. Feb 26 '23 at 17:26
  • Milan, I thought `GIT_SHALLOW` and `GIT_SUBMODULES` are mostly orthogonal (mostly do different things). It sounds like you mean to be talking about `GIT_SUBMODULES`, which by default (if unspecified), ExternalProject fetches all submodules. – starball Feb 26 '23 at 19:19
  • @user that's what I'm saying here. With the `GIT_SHALLOW` option externalproject_add / fetchcontent doesn't download git submodules. – Milan Š. Feb 26 '23 at 19:26
  • weird. that's not what has happened for me in my experience using `GIT_SHALLOW`. For example, FetchContent of `git@github.com:ericniebler/range-v3.git` with `GIT_SHALLOW` still fetches the `doc/gh-pages` submodule. I need to explicitly say `GIT_SUBMODULES ""` (fetch no submodules) – starball Feb 26 '23 at 19:39
  • @user are you specifying a tag? – Milan Š. Feb 26 '23 at 20:00
  • yep: `GIT_TAG "0.12.0"` why do you ask? – starball Feb 26 '23 at 20:01
  • 1
    @user ahh two things - my bad first and foremost secondly you're right. Too bad I can't correct my comments. I've mistaken a different command for git shallow clone. I was asking due to the fact that shallow only works if you specify a tag in `CMake` but that is completely unrelated to this as my brain experienced a huge segfault. Consider my previous comments void – Milan Š. Feb 26 '23 at 20:04
  • I understand the confusion, I use shallow to just get the last commit from that particular tag and no previous commits/history, that make the clone process faster – Juan Medina Feb 26 '23 at 21:06
  • I find something interesting, I may try latter: find-package args in the docs https://cmake.org/cmake/help/latest/module/FetchContent.html#integrating-with-find-package – Juan Medina Feb 26 '23 at 21:07
0

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.

Juan Medina
  • 533
  • 1
  • 5
  • 12