将 SDL2 与 CMake 结合使用

Using SDL2 with CMake

本文关键字:结合 CMake SDL2      更新时间:2023-10-16

我正在尝试使用 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})

我的测试主要.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。

这篇博文展示了如何做到这一点: 将 SDL2 与 CMake 结合使用

在 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变量。您必须将其指向提取开发包并重新配置的 SDL2 目录,然后一切应该可以正常工作。

然后,您只需编写 #include "SDL.h" 即可包含 SDL2 标头。

不要手动设置 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,它的使用可能会更容易,请参阅如何将 SDL2 和 SDL_image 与 cmake 一起使用

如果您觉得使用类似于 CMake 提供的 FindSDL.cmake 文件的 FindSDL2.cmake 文件更舒服,请参阅 https://brendanwhitfield.wordpress.com/2015/02/26/using-cmake-with-sdl2/

我最近发现最新版本的 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 Studio2019CommunityVCAuxiliaryBuildvcvars64.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()

您还可以将 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标签开始,可能更早。

使用我开发的 SDL2 CMake 模块,您可以以现代和可移植的方法轻松集成 SDL2 库。

您应该只在项目中复制cmake/sdl2中的模块(或者只是克隆模块存储库(:

git clone https://github.com/aminosbh/sdl2-cmake-modules cmake/sdl2

然后在 CMakeList 中添加以下行.txt:

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/sdl2)
find_package(SDL2 REQUIRED)
target_link_libraries(${PROJECT_NAME} SDL2::Main)

注意:如果 CMake 没有找到 SDL2 库(在 Windows 中(,我们可以指定 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:

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

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选项之前添加的。为了使-lmingw32选项出现在 SDL2 库之前,我们还必须指定 mingw32 作为第一个target_link_libraries .这将使此配置正常工作。

我用于构建它的命令是:

$ mkdir build && cd build && cmake .. -G"MinGW Makefiles" && cmake --build .

这里唯一的小问题是在最终生成的编译器选项中,-lmingw32选项是重复的。但由于它不影响链接过程,所以我暂时忽略了它。

在 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})

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

更改 CMakeLists.txt以包含

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

而不是

C:/SDL/SDL2-2.0.3/include

我遇到了同样的问题,其他解决方案都不起作用。但是我最终通过遵循以下解决方案使其工作:如何正确将库与cmake链接?

简而言之,问题在于 SDL2 库在我的 CMakeLists.txt 中没有正确链接。通过将其写入文件,它起作用了(另一个线程中的更多解释(:

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)

重点介绍我如何使用 FindSDL2.cmake 模块最终完成此操作的步骤:

  • 下载 SDL2-devel-2.0.9-VC.zip(或发布此答案后发布的任何版本(在下载页面的"开发库"部分下。
  • 解压缩 zip 文件夹,您应该会看到一个类似于"SDL2-2.0.9"的文件夹。将此文件夹粘贴到 C:\Program Files(x86(\ 目录中。
  • 复制 FindSDL2.cmake 模块并将其放在项目中新的"cmake"目录中。我在接受的答案中引用的答案中找到了一个 FindSDL2.cmake 文件:https://brendanwhitfield.wordpress.com/2015/02/26/using-cmake-with-sdl2/
  • 在 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对我有用。我包括我的CMakeList的其余部分,以防它进一步澄清我可能遗漏的任何内容:

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 提供了 sdl2-config 可执行文件(据我了解,开发人员称他为"实验性"(。"安装"SDL2 后,您可以尝试从终端调用它 sdl2-config --cflags --libs看看它输出了什么。

然后,您可以在生成文件中添加对它的调用:

set(PROJECT_NAME SomeProject)
project(${PROJECT_NAME})
execute_process(COMMAND /usr/local/bin/sdl2-config --libs RESULT_VARIABLE CMD_RES OUTPUT_VARIABLE SDL2_CFLAGS_LIBS ERROR_VARIABLE ERR_VAR OUTPUT_STRIP_TRAILING_WHITESPACE)
message("SDL2_CFLAGS_LIBS=${SDL2_CFLAGS_LIBS}; CMD_RES=${CMD_RES}; ERR_VAR=${ERR_VAR}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${SDL2_CFLAGS_LIBS}")
set(SOURCE_FILES main.cpp)
add_executable(${PROJECT_NAME} ${SOURCE_FILES})

在这里我有一个问题 - 如果我只放一个没有路径的可执行文件名称,比如

execute_process(COMMAND sdl2-config --libs <...>

我收到错误"没有这样的文件",即 cmake 没有在当前路径中搜索,我现在不知道如何正确编写它。

还有一个注意事项:在我的 makefile 中,我没有用户--cflags选项,因为 cmake 找到正确包含,我不需要明确指定它们。

供您参考,我能够在链接到 SDL2 源代码的同时成功制作和编译SDL2_ttf。

起初,由于 cmake 无法找到 SDL2,我遇到了错误,即使它是使用 cmake 中的 SLD2_DIR 变量在 cmake 中指定的。

似乎由于某种原因,cmaking SDL2无法创建由SDL2_ttf搜索的SDL2Targets.cmake文件

如果是这种情况,请从 https://bugs.archlinux.org/task/57972 获取 SDL2Targets.cmake 文件并按如下所示修改该文件:

您可以删除以下行:

get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
    set(_IMPORT_PREFIX "")
endif()

并添加这个:

set(_IMPORT_PREFIX "C:/SDL2-2.0.12")

显然将文件路径更改为解压缩 SDL2 源代码的位置

我不确定这是否正是您的问题,但事实就是如此。