使用CMake与SDL2

51

我想使用CLion创建一个SDL2项目。

问题在于,当使用#include时,无法找到SDL头文件。

我的CMakeLists.txt文件:

cmake_minimum_required(VERSION 2.8.4)
project(ChickenShooter)

set(SDL2_INCLUDE_DIR C:/SDL/SDL2-2.0.3/include)
set(SDL2_LIBRARY C:/SDL/SDL2-2.0.3/lib/x64)

include_directories(${SDL2_INCLUDE_DIR})
set(SOURCE_FILES main.cpp)

add_executable(ChickenShooter ${SOURCE_FILES})
target_link_libraries(ChickenShooter ${SDL2_LIBRARY})

我的测试 main.cpp 文件:

#include <iostream>
#include "SDL.h" /* This one can't be found */

int main(){
    if (SDL_Init(SDL_INIT_VIDEO) != 0){
        std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
        return 1;
    }
    SDL_Quit();
    return 0;
}

感谢您能给我提供任何帮助。

编辑: 我正在使用Windows,CLion已配置为使用cygwin64。

12个回答

32

该博客文章展示了如何做到这一点:使用CMake与SDL2

在Linux上,您可以使用最新的CMake(例如3.7版本),并且直接使用SDL2即可。

cmake_minimum_required(VERSION 3.7)
project(SDL2Test)

find_package(SDL2 REQUIRED)
include_directories(SDL2Test ${SDL2_INCLUDE_DIRS})

add_executable(SDL2Test Main.cpp)
target_link_libraries(SDL2Test ${SDL2_LIBRARIES})

在Windows下,您可以下载SDL2开发包,将其解压到某个位置,然后在提取的位置创建一个sdl-config.cmake文件,并使用以下内容:

set(SDL2_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/include")

# Support both 32 and 64 bit builds
if (${CMAKE_SIZEOF_VOID_P} MATCHES 8)
  set(SDL2_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/x64/SDL2.lib;${CMAKE_CURRENT_LIST_DIR}/lib/x64/SDL2main.lib")
else ()
  set(SDL2_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/x86/SDL2.lib;${CMAKE_CURRENT_LIST_DIR}/lib/x86/SDL2main.lib")
endif ()

string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES)
当你现在在CMake-GUI应用程序内进行配置时,将会有一个名为 SDL2_DIR 的变量。你需要将其指向你提取dev包的SDL2目录,然后重新配置,一切都应该可以正常工作。
之后,您只需编写 #include "SDL.h" 即可包含SDL2头文件。

这在Windows上不适用于Mingw。SDL2 Mingw包中的库目录和文件名与此不同。 - emlai
2
只是补充一下,查找软件包的配置文件名称应为sdl2-config.cmake。 - Groshh

27

不要手动设置SDL2路径。使用适当的查找命令,该命令使用FindSDL。应该是这样的:

find_file(SDL2_INCLUDE_DIR NAME SDL.h HINTS SDL2)
find_library(SDL2_LIBRARY NAME SDL2)
add_executable(ChickenShooter main.cpp)
target_include_directories(ChickenShooter ${SDL2_INCLUDE_DIR})
target_link_libraries(ChickenShooter ${SDL2_LIBRARY})    
如果未找到SDL2,则需要将SDL2的路径添加到CMAKE_PREFIX_PATH中,这是CMake查找安装软件的地方。
如果可以使用Pkg-config,则使用可能更容易,请参见如何在cmake中使用SDL2和SDL_image
如果您更喜欢使用类似于CMake提供的FindSDL.cmake文件的FindSDL2.cmake文件,请参见https://brendanwhitfield.wordpress.com/2015/02/26/using-cmake-with-sdl2/

1
我遇到了一个 Unknown CMake command "find" 的问题。但是我可以使用 find_library(SDL) 来解决它。 - Charles
2
@charlesrockbass:谢谢你的提示,应该是find_package。 - usr1234567
7
SDL不同于SDL2,而默认的FindSDL.cmake不会寻找SDL2。 - Cubic
https://github.com/fastogt/fastoplayer/blob/master/src/CMakeLists.txt#L352 跨平台 - Topilski Alexandr
@FRR 很好的问题,但与此答案无关。请提出一个问题,我很乐意回答它。 - usr1234567

12

我最近发现SDL2的最新版本(版本2.0.12)现在已经带有所有所需的CMake配置/安装脚本,因此不再需要使用FindSDL。

我从https://www.libsdl.org/download-2.0.php下载了SDL源代码,然后从根目录运行了...

cmake -S . -B build/debug -G Ninja -DCMAKE_INSTALL_PREFIX=./install -DCMAKE_BUILD_TYPE=Debug
cmake --build build/debug --target install

这将构建并安装库的调试版本,您还可以运行...

cmake -S . -B build/release -G Ninja -DCMAKE_INSTALL_PREFIX=./install -DCMAKE_BUILD_TYPE=Release
cmake --build build/release --target install

这将构建并安装库的发行版本(因为SDL CMake脚本使用DEBUG_POSTFIX,所以发布版本的库不会覆盖调试版本的库,因为调试版本的所有名称都添加了“d”)。

在您的CMakeLists.txt文件中,您可以简单地执行以下操作:

find_package(SDL2 REQUIRED)

add_executable(${PROJECT_NAME} ...)

target_link_libraries(
    ${PROJECT_NAME} PRIVATE
    SDL2::SDL2
    SDL2::SDL2main
你需要告诉你的应用程序在哪里找到SDL安装文件夹,如果你像我一样使用了自定义位置。要做到这一点,请从你的应用程序根目录运行以下命令:
cmake -S . -B build/debug -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH=</absolute/path/to/install/dir>
cmake --build build/debug

注意:你可以使用$(pwd)(*nix/macOS)或者%cd%(Windows)来创建一个混合相对路径,这对你非常有用。

如果你想要把SDL安装到默认的系统位置,那么你可以省略DCMAKE_INSTALL_PREFIXDCMAKE_PREFIX_PATH

在示例中,我选择使用Ninja生成器,因为它在macOS/Windows上的表现是一致的——它可以与MSVC/Visual Studio一起使用,只需要确保运行以下命令(路径可能因年份/版本而略有不同),将Ninja添加到你的路径中。

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat

更新:

我记得在Windows上还有一个非常实用的方法,就是将SDL .dll文件复制到应用程序二进制目录中,具体操作如下:

if (WIN32)
# copy the .dll file to the same folder as the executable
add_custom_command(
    TARGET ${PROJECT_NAME} POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_FILE:SDL2::SDL2>
    $<TARGET_FILE_DIR:${PROJECT_NAME}>
    VERBATIM)
endif()

有没有一种不需要安装它就可以使用它的方法?我想获取它并使用它。 - eri0o
3
如果您愿意,可以使用FetchContent代替 - 它应该能够完成相同的工作。这里有一些信息可能会对您有用 - https://github.com/pr0g/cmake-examples/tree/main/examples/more/fetch-content。以下是使用ExternalProject_Add添加SDL的示例(基本上自动化了上述步骤 - https://github.com/pr0g/sdl-bgfx-imgui-starter/blob/main/third-party/CMakeLists.txt)。 - Tom
谢谢!这些链接很有用! :) 最后一个正是我在寻找的!谢谢! - eri0o
太棒了! :D 很高兴能帮到你,谢谢让我知道。 - Tom

10

您还可以将SDL源代码作为子模块拉入并通过add_subdirectory()target_link_libraries()与您的主程序静态构建/链接:

cmake_minimum_required( VERSION 3.18.0 )
project( sdl2-demo )

set( SDL_STATIC ON CACHE BOOL "" FORCE )
set( SDL_SHARED OFF CACHE BOOL "" FORCE )
# 'external/sdl' should point at a SDL
# repo clone or extracted release tarball
add_subdirectory( external/sdl )

add_executable(
    ${CMAKE_PROJECT_NAME}
    "src/main.cpp"
    )
target_link_libraries( ${CMAKE_PROJECT_NAME} SDL2main SDL2-static )

(至少在 release-2.0.9 标签,可能更早。)


1
请注意,如果项目路径中包含空格(至少在Mac OS上),则此cmake脚本可能会失败。除此之外,确实是一种静态链接到SDL2的简单方法。 - Max Klint
如何使用SDL2图像库实现这个功能? - jksevend
1
@jksevend:类似的方式。别忘了在根目录的CMakeLists.txt中添加add_subdirectory()(https://github.com/genpfault/sdl-base/blob/main/CMakeLists.txt#L22)。 - genpfault
谢谢,这很有帮助。我在尝试从源代码构建SDL_image仓库时遇到了问题,SDL运行良好。我会尝试您的方法。 - jksevend

2
在Linux上,在Clion中,这个可以工作:
cmake_minimum_required(VERSION 3.20)
project(first_game)

set(CMAKE_CXX_STANDARD 14)

find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARIES})

你的答案只适用于2.0.12或更新版本。它缺少一些解释。 - usr1234567

2
使用我开发的SDL2 CMake模块,您可以轻松地以现代和可移植的方式集成SDL2库。
您只需将该模块复制到项目中的cmake/sdl2目录中(或者直接克隆模块仓库)即可。
git clone https://github.com/aminosbh/sdl2-cmake-modules cmake/sdl2

请在您的CMakeLists.txt文件中添加以下几行代码:
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/sdl2)
find_package(SDL2 REQUIRED)
target_link_libraries(${PROJECT_NAME} SDL2::Main)

注意:如果在Windows中CMake没有找到SDL2库,我们可以通过以下方式指定CMake选项SDL2_PATH

最初的回答
cmake .. -DSDL2_PATH="/path/to/sdl2"

更多细节请阅读README.md文件。
SDL2 CMake模块支持其他相关库:SDL2_image,SDL2_ttf,SDL2_mixer,SDL2_net和SDL2_gfx。
您可以在此处找到使用这些模块的示例/样本和项目列表:https://github.com/aminosbh/sdl-samples-and-projects

2

我使用在Windows上使用MinGW-w64编译的SDL2-2.0.9版本,以下配置对我有效:

Original Answer翻译成"最初的回答"

find_package(SDL2 REQUIRED)

add_executable(sdl-test ${SOURCES})

target_link_libraries(sdl-test
  mingw32
  SDL2::SDL2main
  SDL2::SDL2
)
<最初的回答> 通过阅读 SDL2Targets.cmake 文件,我了解到 SDL2 提供了几个目标:
  • SDL2::SDL2main (lib/libSDL2main.a)
  • SDL2::SDL2 (lib/libSDL2.dll.a)
  • SDL2::SDL2-static (lib/libSDL2-static.a)
每个目标都有INTERFACE_INCLUDE_DIRECTORIES定义,这意味着我们不需要手动指定 SDL2 的include_directories
但是仅将SDL2::SDL2mainSDL2::SDL2添加为target_link_libraries是不够的。g++编译器可能会抱怨“未定义对`WinMain'的引用”。
通过检查编译器选项,我发现 SDL2 库是在 -lmingw32选项之前添加的。为了在 SDL2 库之前使 -lmingw32选项生效,我们还必须将mingw32指定为第一个 target_link_libraries。这样就可以使此配置正常工作。
我用于构建程序的命令是:
$ mkdir build && cd build && cmake .. -G"MinGW Makefiles" && cmake --build .

这里唯一的小问题在于最终生成的编译器选项中,-lmingw32选项被重复了。但由于它不会影响链接过程,所以我现在忽略了它。"Original Answer"翻译成“最初的回答”。

0

你在生成Make文件时似乎没有CMake错误。但是,我认为你的问题是SDL头文件位于名为"SDL2"的子文件夹中。

更改你的CMakeLists.txt以包含

C:/SDL/SDL2-2.0.3/include/SDL2

不是

C:/SDL/SDL2-2.0.3/include

0

我曾经遇到同样的问题,但其他解决方案都没有起作用。 但是我最终通过遵循这个解决方案使其正常工作:如何使用cmake正确链接库?

简而言之,问题在于我的CMakeLists.txt文件中未正确链接SDL2库。通过将以下内容写入文件,它就可以工作了(更多解释请参见其他线程):

project (MyProgramExecBlaBla)  #not sure whether this should be the same name of the executable, but I always see that "convention"
cmake_minimum_required(VERSION 2.8)

ADD_LIBRARY(LibsModule 
    file1.cpp
    file2.cpp
)

target_link_libraries(LibsModule -lpthread)
target_link_libraries(LibsModule liblapack.a)
target_link_libraries(LibsModule -L/home/user/libs/somelibpath/)
ADD_EXECUTABLE(MyProgramExecBlaBla main.cpp)
target_link_libraries(MyProgramExecBlaBla LibsModule)

0

强调如何使用FindSDL2.cmake模块最终实现这一目标的步骤:

  • 在下载页面的开发库部分下载SDL2-devel-2.0.9-VC.zip(或此答案发布后的任何版本)。
  • 解压缩zip文件夹,您应该会看到一个类似于“SDL2-2.0.9”的文件夹。将此文件夹粘贴到您的C:\ Program Files(x86)\目录中。
  • 复制FindSDL2.cmake模块,并将其放置在项目内的新“cmake”目录中。我在被接受的答案引用的 https://brendanwhitfield.wordpress.com/2015/02/26/using-cmake-with-sdl2/中找到了FindSDL2.cmake文件。
  • 在FindSDL2.cmake中找到SET(SDL2_SEARCH_PATHS行,并将您复制的SDL2开发目录作为新行添加:"/Program Files (x86)/SDL2-2.0.9" # Windows
  • 在我的CMakeLists.txt中添加此行:set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

之后,我成功地运行了CMake。为了进一步澄清可能遗漏的任何内容,我包含了我的CMakeLists的其余部分:

cmake_minimum_required(VERSION 2.8.4)
project(Test_Project)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

# includes cmake/FindSDL2.cmake
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)

set(SOURCE_FILES src/main.cpp src/test.cpp)
add_executable(test ${SOURCE_FILES})

# The two lines below have been removed to run on my Windows machine
#INCLUDE(FindPkgConfig)
#PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2)
find_package(SDL2 REQUIRED)

INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(chip8 ${SDL2_LIBRARY})

希望这能在不久的将来帮助到某些人。

它是 ${SDL2_LIBRARIES}(复数形式)。单数也可能有效,但那只是巧合。 - Alexis Wilke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接