Search code examples
cmakesdl-2libm

Fetch, build and link of SDL2 fails with undefined `floor` references using CMake


I am having the error below when I link my program with SDL2

/usr/bin/ld: ../_deps/sdl2_content-build/libSDL2d.a(SDL_stdlib.c.o): in function `SDL_floor_REAL':
/home/user/myprogram/cmake-build-debug/_deps/sdl2_content-src/src/stdlib/SDL_stdlib.c:247: undefined reference to `floor'

I made a FetchSDL2.cmake file that is included that should theoretically get it and build and use it:

FetchContent_Declare(
    sdl2_content
    URL https://www.libsdl.org/release/SDL2-2.0.12.tar.gz
    URL_HASH MD5=783b6f2df8ff02b19bb5ce492b99c8ff
)

FetchContent_GetProperties(sdl2_content)
if(NOT sdl2_content_POPULATED)
  FetchContent_Populate(sdl2_content)
  if(ANDROID)
      set(SDL_SHARED ON CACHE BOOL "shared")
      set(SDL_STATIC ON CACHE BOOL "static")
      add_subdirectory(${sdl2_content_SOURCE_DIR} ${sdl2_content_BINARY_DIR} EXCLUDE_FROM_ALL)
      add_library(SDL2::SDL2 ALIAS SDL2)
      add_library(SDL2::SDL2main ALIAS SDL2main)
  elseif(WIN32 OR LINUX OR MACOS)
      set(SDL_SHARED OFF CACHE BOOL "no shared")
      set(SDL_STATIC ON CACHE BOOL "static")
      set(SDL_STATIC_PIC ON CACHE BOOL "Static version of the library should be built with Position Independent Code")
      set(SDL_SHARED OFF)
      set(SDL_STATIC ON)
      set(SDL_STATIC_PIC ON)
      set(FORCE_STATIC_VCRT ON CACHE BOOL "static windows static vcrc")
      add_subdirectory(${sdl2_content_SOURCE_DIR} ${sdl2_content_BINARY_DIR} EXCLUDE_FROM_ALL)
      add_library(SDL2::SDL2 ALIAS SDL2-static)
      add_library(SDL2::SDL2main ALIAS SDL2main)
  endif()

  if(NOT EXISTS "${sdl2_content_BINARY_DIR}/include/SDL2")
      execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${sdl2_content_SOURCE_DIR}/include ${sdl2_content_BINARY_DIR}/include/SDL2)
  endif()

  find_package(LibM)
  set(SDL2_INCLUDE_HINTS "${sdl2_content_BINARY_DIR}/include/" "${sdl2_content_BINARY_DIR}/include/SDL2/")
  set(SDL2_LIB_HINTS "${sdl2_content_BINARY_DIR}/")
  find_package(SDL2)
  list(APPEND SDL2_INCLUDE_DIRS "${sdl2_content_BINARY_DIR}/include/SDL2/")
  list(APPEND SDL2_INCLUDE_DIRS "${sdl2_content_BINARY_DIR}/include/")
  list(APPEND SDL2_INCLUDE_DIRS "${LIBM_INCLUDE_DIRS}")
  list(APPEND SDL2_LIBRARY_DIRS "${sdl2_content_BINARY_DIR}/")
  list(APPEND SDL2_LIBRARIES SDL2::SDL2)
  list(APPEND SDL2_LIBRARIES "${LIBM_LIBRARIES}")
endif()

But I keep get the error above. I do have LibM, and every other math function links correctly. I am on Ubuntu 20.04 .

Can you help fix this so it fetches SDL2 correctly? The reason I am not installing it is this script will be used by CMake in some platforms that have no package managers.


Solution

  • I figured out. Turns out SDL2 has two headers with the same name SDL_config.h. The one you want to include is the generated by CMake and not the one that comes with the library.

    Below is my CMake file that correctly removes and installs the right headers. Tested with SDL 2.0.12.

    FetchContent_Declare(
        sdl2_content
        URL https://www.libsdl.org/release/SDL2-2.0.12.tar.gz
        URL_HASH MD5=783b6f2df8ff02b19bb5ce492b99c8ff
    )
    
    FetchContent_GetProperties(sdl2_content)
    if(NOT sdl2_content_POPULATED)
        FetchContent_Populate(sdl2_content)
        if(ANDROID)
            set(SDL_SHARED ON CACHE BOOL "shared")
            set(SDL_STATIC OFF CACHE BOOL "static")
            add_subdirectory(${sdl2_content_SOURCE_DIR} ${sdl2_content_BINARY_DIR} EXCLUDE_FROM_ALL)
            add_library(SDL2::SDL2 ALIAS SDL2)
        elseif(WIN32 OR LINUX OR MACOS)
            set(SDL_SHARED OFF CACHE BOOL "shared")
            set(SDL_STATIC ON CACHE BOOL "static")
            set(SDL_STATIC_PIC ON CACHE BOOL "Static version of the library should be built with Position Independent Code")
            set(SDL_SHARED OFF)
            set(SDL_STATIC ON)
            set(SDL_STATIC_PIC ON)
            if(LINUX)
                set(SNDIO_SHARED ON CACHE BOOL "static")
                set(SNDIO_SHARED ON)
            endif()
            set(FORCE_STATIC_VCRT ON CACHE BOOL "static windows static vcrc")
            add_subdirectory(${sdl2_content_SOURCE_DIR} ${sdl2_content_BINARY_DIR} EXCLUDE_FROM_ALL)
            add_library(SDL2::SDL2 ALIAS SDL2-static)
        endif()
        add_library(SDL2::SDL2main ALIAS SDL2main)
    
        file(GLOB INCLUDE_FILES ${sdl2_content_SOURCE_DIR}/include/*.h)
        file(GLOB BIN_INCLUDE_FILES ${sdl2_content_BINARY_DIR}/include/*.h)
        foreach(_FNAME ${BIN_INCLUDE_FILES})
            get_filename_component(_INCNAME ${_FNAME} NAME)
            list(REMOVE_ITEM INCLUDE_FILES ${sdl2_content_SOURCE_DIR}/include/${_INCNAME})
        endforeach()
        list(APPEND INCLUDE_FILES ${BIN_INCLUDE_FILES})
    
        if(NOT EXISTS "${sdl2_content_BINARY_DIR}/include/SDL2")
            file(MAKE_DIRECTORY "${sdl2_content_BINARY_DIR}/include/SDL2")
            file(COPY ${INCLUDE_FILES}  DESTINATION "${sdl2_content_BINARY_DIR}/include/SDL2")
        endif()
        include_directories("${sdl2_content_BINARY_DIR}/include")
    
        if(EXISTS "${sdl2_content_SOURCE_DIR}/android-project")
            file(REMOVE_RECURSE "${sdl2_content_SOURCE_DIR}/android-project")
        endif()
    
        file(COPY CMake/Extra/sdl2-config.cmake DESTINATION ${sdl2_content_BINARY_DIR})
        set(SDL2_DIR ${sdl2_content_BINARY_DIR})
        list(APPEND SDL2_INCLUDE_DIRS "${sdl2_content_BINARY_DIR}/include/SDL2/")
        list(APPEND SDL2_INCLUDE_DIRS "${sdl2_content_BINARY_DIR}/include/")
        list(APPEND SDL2_LIBRARY_DIRS "${sdl2_content_BINARY_DIR}/")
        list(APPEND SDL2_LIBRARIES SDL2::SDL2)
        list(APPEND SDL2_LIBRARIES SDL2::SDL2main)
    endif()
    
    message("SDL2_LIBRARIES: ${SDL2_LIBRARIES}")
    message("SDL2_INCLUDE_DIRS: ${SDL2_INCLUDE_DIRS}")
    

    Note: I additionally removed the Android project files since they were conflicting when I was running SDL2 on Android, but this doesn't matter for this question.