[英]How to link SDL_ttf and SDL_image libraries using cmake in windows?
我无法将SDL_ttf
和SDL_image
包含并链接到我的项目。 我有一个仅适用于 Clion 上的SDL
和SDL_gfx
的 cmake 文件。 我想问题出在 cmake 文件中。 我在构建项目时遇到了几个错误: undefined reference to `FUNCTION'
我用于项目的库: https://github.com/satayyeb/sdl2-libraries
sdl2 文件夹(库文件所在的位置)树:
sdl2-|
|-sdl2-image-include
| |-SDL_image.h
|
|-sdl2-image-lib
| |-libSDL2_image.a
| |-libSDL2_image.dll.a
| |-libSDL2_image.la
|
|-sdl2-ttf-include
| |-SDL_ttf.h
|
|-sdl2-ttf-lib
|-libSDL2_ttf.a
|-libSDL2_ttf.dll.a
|-libSDL2_ttf.la
CMakeLists.txt:
set(SOURCE src/main.c)
set(PROJECT_NAME state.SAT)
cmake_minimum_required(VERSION 3.19)
project(${PROJECT_NAME} C)
set(CMAKE_C_STANDARD 11)
set(SDL2_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-include")
set(SDL2_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-lib")
set(SDL2_GFX_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-gfx-include")
set(SDL2_GFX_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-gfx-lib")
set(SDL2_IMAGE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-image-include")
set(SDL2_IMAGE_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-image-lib")
set(SDL2_TTF_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-ttf-include")
set(SDL2_TTF_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-ttf-lib")
set(SDL2_FLAGS "-mwindows -Wl,--no-undefined -static-libgcc")
add_library(SDL2 STATIC IMPORTED)
add_library(SDL2main STATIC IMPORTED)
add_library(SDL2_GFX STATIC IMPORTED)
add_library(SDL2_IMAGE STATIC IMPORTED)
add_library(SDL2_TTF STATIC IMPORTED)
set_property(TARGET SDL2 PROPERTY IMPORTED_LOCATION "${SDL2_LIB_DIR}/libSDL2.a")
set_property(TARGET SDL2main PROPERTY IMPORTED_LOCATION "${SDL2_LIB_DIR}/libSDL2main.a")
set_property(TARGET SDL2_GFX PROPERTY IMPORTED_LOCATION "${SDL2_GFX_LIB_DIR}/libsdl-gfx.a")
set_property(TARGET SDL2_IMAGE PROPERTY IMPORTED_LOCATION "${SDL2_IMAGE_LIB_DIR}/libSDL2_image.a")
set_property(TARGET SDL2_TTF PROPERTY IMPORTED_LOCATION "${SDL2_TTF_LIB_DIR}/libSDL2_ttf.a")
set(SDL2_LIBS SDL2 SDL2main SDL2_GFX SDL2_TTF SDL2_IMAGE m dinput8 dxguid dxerr8 user32 gdi32 winmm imm32 ole32 oleaut32 shell32 version uuid)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${SDL2_FLAGS}")
file(GLOB_RECURSE SOURCE "src/*.c" "src/*.h")
add_executable("${PROJECT_NAME}" "${SOURCE}")
include_directories(${SDL2_INCLUDE_DIR} ${SDL2_GFX_INCLUDE_DIR} ${SDL2_IMAGE_INCLUDE_DIR} ${SDL2_TTF_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBS})
简短的回答是您使用的库不兼容,因为 SDL2_ttf 和 SDL2_image 是针对比您存档中的更新版本的 SDL2 构建的(有问题的链接)。 获取较新的 SDL2,或较旧的 SDL2_ttf 和 SDL2_image,则无需更改任何内容。 写了冗长的解释后更正我注意到在你的档案中,即使是 static 和同一库的动态版本也有不同的版本; 我建议从 SDL 网站重新下载全部内容,因为您拥有的是一团糟。
请注意,我的回答不包括您的 CMakeLists.txt。 你所拥有的是非常特定于 Windows 的; 如果您不关心其他系统 - 就按照您的方式吧。 您的程序可以使用您在原始问题中想到的 CMakeLists 构建,这不是您问题的根源。
首先是否要使用 static 库是值得怀疑的。 如果没有充分的理由专门使用 static 库,我建议您切换到动态库,即与.dll.a
链接(或直接支持工具链的.dll
链接), 这样,您就不需要dinput8 dxguid dxerr8 user32 gdi32 winmm imm32 ole32 oleaut32 shell32 version uuid
的长列表,如果您不知道,它们是您使用的 SDL2 版本的依赖项。 这意味着如果您更新您的 static libSDL2.a,此列表可能会有所不同,因为它现在取决于更多的东西(这不是理论上的 - 最新的 SDL 2.0.20 实际上有更长的依赖列表)。
库不兼容性的解释(很长,技术性很强,而且主要是 mingw/gcc 特定的;如果您对这些细节不感兴趣,请查看最后的注释):
您在问题中提到undefined reference to 'FUNCTION'
,但是FUNCTION
非常重要; 如果您有这些信息,请不要从您未来的问题中忽略这些信息。 谢天谢地,您后来提供了完整库存档的链接,我们可以自己查看构建尝试的结果,即:
../sdl2/sdl2-ttf-lib/libSDL2_ttf.a(libSDL2_ttf_la-SDL_ttf.o): In function `RWread':
/Users/valve/release/SDL_ttf/SDL2_ttf-2.0.18-source/foo-x64/../SDL_ttf.c:1583: undefined reference to `SDL_RWseek'
/Users/valve/release/SDL_ttf/SDL2_ttf-2.0.18-source/foo-x64/../SDL_ttf.c:1587: undefined reference to `SDL_RWread'
../sdl2/sdl2-ttf-lib/libSDL2_ttf.a(libSDL2_ttf_la-SDL_ttf.o): In function `TTF_CloseFont':
/Users/valve/release/SDL_ttf/SDL2_ttf-2.0.18-source/foo-x64/../SDL_ttf.c:2544: undefined reference to `SDL_RWclose'
../sdl2/sdl2-ttf-lib/libSDL2_ttf.a(libSDL2_ttf_la-SDL_ttf.o): In function `TTF_OpenFontIndexDPIRW':
/Users/valve/release/SDL_ttf/SDL2_ttf-2.0.18-source/foo-x64/../SDL_ttf.c:1614: undefined reference to `SDL_RWtell'
/Users/valve/release/SDL_ttf/SDL2_ttf-2.0.18-source/foo-x64/../SDL_ttf.c:1647: undefined reference to `SDL_RWsize'
/Users/valve/release/SDL_ttf/SDL2_ttf-2.0.18-source/foo-x64/../SDL_ttf.c:1603: undefined reference to `SDL_RWclose'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__vecang':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvg.h:2096: undefined reference to `SDL_acosf'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__addActive':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:873: undefined reference to `SDL_floorf'
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:874: undefined reference to `SDL_floorf'
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:871: undefined reference to `SDL_floorf'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__parseStrokeDashArray':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvg.h:1722: undefined reference to `SDL_fabsf'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__parseRect':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvg.h:2364: undefined reference to `SDL_fabsf'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__parseCircle':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvg.h:2413: undefined reference to `SDL_fabsf'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__pathArcTo':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvg.h:2112: undefined reference to `SDL_fabsf'
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvg.h:2113: undefined reference to `SDL_fabsf'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o):/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvg.h:2115: more undefined references to `SDL_fabsf' follow
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__curveDivs':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:598: undefined reference to `SDL_acosf'
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:599: undefined reference to `SDL_ceilf'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__roundJoin':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:548: undefined reference to `SDL_atan2f'
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:549: undefined reference to `SDL_atan2f'
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:556: undefined reference to `SDL_ceilf'
../sdl2/sdl2-image-lib/libSDL2_image.a(IMG_svg.o): In function `nsvg__flattenShapeStroke':
/Users/valve/release/SDL_image/SDL2_image-2.0.5-source/foo-x64/../nanosvgrast.h:786: undefined reference to `SDL_fmodf'
好的,实际上不是一个长列表。 那么什么是未定义的? 少数SDL_RW*
函数和少数 SDL 数学函数。 请注意,这不是SDL2_ttf 和 SDL2_image 使用的唯一 SDL 函数,其他所有函数都可以找到。 为什么在您的构建中找不到该功能?.. Linker 说没有具有该名称的功能,嗯,有吗? 由于您使用 mingw 工具链,因此您应该可以访问更多工具,而不仅仅是编译器,例如nm
工具(在控制台中):
> nm -a sdl2/sdl-libs/libSDL2.a | grep SDL_RWseek
>
(如果您没有grep
,请使用findstr
)是的,不在那里。 好吧,我们有 SDL2 源代码,包括版本历史,让我们看看为什么会这样。
让我们从例如SDL_RWseek
开始。 There is a function with that name in SDL2, which we can view at https://github.com/libsdl-org/SDL/blob/120c76c84bbce4c1bfed4e9eb74e10678bd83120/include/SDL_rwops.h#L401 (just did a search for function name on github并打开了 header 文件)。 function 之前的评论有一个答案: Prior to SDL 2.0.10, this function was a macro.
... This function is available since SDL 2.0.10.
. 哦。 因此,无论您拥有什么,似乎都低于 2.0.10,并且 SDL2_ttf 显然是为更新的东西而构建的,这已经是 function。
好的,SDL2_image 使用的数学函数怎么样。 Well, github search again points to https://github.com/libsdl-org/SDL/blob/120c76c84bbce4c1bfed4e9eb74e10678bd83120/include/SDL_stdinc.h#L572 , which seems to say that it was added at 2.0.2; 不幸的是,评论仅涵盖SDL_acos
function,其他未评论。 但是,如果您将 github 视图切换为“责备”(顺便说一下,这并不特定于 github)以查看每行最后一次修改的时间,您可以看到许多这些数学函数是通过不同的提交添加的,并且跨越多个年。 什么没找到? SDL_fmodf
- 4 年前添加,第一个版本是 2.0.8。 对于所有其他“未定义”函数也是如此。
因此,这些库需要 SDL2 2.0.10 和 2.0.8。 你有什么版本? 我没有看到快速检查的方法,但是有一个SDL_GetVersion
function,为什么不制作调用它的最小程序:
#include "SDL.h"
#include <stdio.h>
int main(int argc, char **argv) {
SDL_version v = {};
SDL_GetVersion(&v);
printf("%d.%d.%d\n", v.major, v.minor, v.patch);
return 0;
}
构建和执行(重要的是它必须在您拥有的相同环境中构建,因此,出于所有意图和目的,这是您的main.c
的内容),
2.0.7
哦。 所以是的,它无法与该版本一起使用,它没有想要调用的函数。
在您自己的回答中,您说您已经通过添加指向libSDL2_ttf.dll.a
和libSDL2_image.dll.a
的链接来构建它,大概是由于库顺序。 首先,图书馆顺序只对动态图书馆很重要(甚至在那里——不是每个 linker 实现),所以不是这样。 但它为什么建起来? 我们这里要到 windows 特定领域,其概念是“导入库”; .dll.a
就是这样,一个包含“这将在运行时稍后加载”的符号的存根。 它的作用是使您的结果程序取决于例如SDL2_ttf.dll
。 动态库与可执行文件非常相似,并且实际上有自己的依赖项列表(静态库没有 - 这就是为什么您在 cmakelists 中有长长的 SDL2 依赖项列表的原因),因此 SDL2_ttf.dll 中有一个条目表示它依赖于 SDL2 .dll。 再一次,您可以使用值得信赖的编译器工具链进行检查:
> ldd sdl2/sdl2-ttf-bin/SDL2_ttf.dll | grep SDL2
SDL2.dll => /c/WINDOWS/SYSTEM32/SDL2.dll (0x5ccb0000)
What it means is it depends on SDL2.dll
, and if i launch it in my current environment, it'll use C:\Windows\system32\SDL2.dll
that I have in my default dll search path (your environment could be different )。 如果您使用相同的ldd
工具检查生成的 exe,您会看到您现在依赖于SDL2_ttf.dll
,但正因为如此 - 也依赖于SDL2.dll
。 因此,现在您在程序中静态链接了 SDL2,但由于依赖关系,还拉动了动态 SDL2.dll。 所以它可以构建,甚至可以运行,但很难想象它会按预期工作。 我很确定当您尝试实际进行纹理或字体处理时,它会全部崩溃。
在编写所有内容时,我发现您的 SDL2.dll 实际上是 2.0.20,但 libSDL2.a 是 2.0.7。 也许最好的做法是核对您的整个库存档并从 SDL 网站重新下载所有内容。
我发现了问题:
在sdl2-image-lib
和sdl2-ttf-lib
目录中有libSDL2_image.dll.a
和libSDL2_ttf.dll.a
二进制文件必须链接。
顺序在链接中很重要。 例如libSDL2_image.dll.a
必须在 libSDL2_image.a 之前传递给libSDL2_image.a
我用于项目的库: https://github.com/satayyeb/sdl2-libraries
和修改后的CMakeLists.txt:
set(SOURCE src/main.c)
set(PROJECT_NAME state.SAT)
cmake_minimum_required(VERSION 3.19)
project(${PROJECT_NAME} C)
set(CMAKE_C_STANDARD 11)
set(SDL2_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-include")
set(SDL2_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-lib")
set(SDL2_GFX_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-gfx-include")
set(SDL2_GFX_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-gfx-lib")
set(SDL2_IMAGE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-image-include")
set(SDL2_IMAGE_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-image-lib")
set(SDL2_TTF_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-ttf-include")
set(SDL2_TTF_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/sdl2/sdl2-ttf-lib")
set(SDL2_FLAGS "-mwindows -Wl,--no-undefined -static-libgcc")
add_library(SDL2 STATIC IMPORTED)
add_library(SDL2main STATIC IMPORTED)
add_library(SDL2_GFX STATIC IMPORTED)
add_library(SDL2_IMAGE_DLL STATIC IMPORTED)
add_library(SDL2_IMAGE STATIC IMPORTED)
add_library(SDL2_TTF_DLL STATIC IMPORTED)
add_library(SDL2_TTF STATIC IMPORTED)
set_property(TARGET SDL2 PROPERTY IMPORTED_LOCATION "${SDL2_LIB_DIR}/libSDL2.a")
set_property(TARGET SDL2main PROPERTY IMPORTED_LOCATION "${SDL2_LIB_DIR}/libSDL2main.a")
set_property(TARGET SDL2_GFX PROPERTY IMPORTED_LOCATION "${SDL2_GFX_LIB_DIR}/libsdl-gfx.a")
set_property(TARGET SDL2_IMAGE_DLL PROPERTY IMPORTED_LOCATION "${SDL2_IMAGE_LIB_DIR}/libSDL2_image.dll.a")
set_property(TARGET SDL2_IMAGE PROPERTY IMPORTED_LOCATION "${SDL2_IMAGE_LIB_DIR}/libSDL2_image.a")
set_property(TARGET SDL2_TTF_DLL PROPERTY IMPORTED_LOCATION "${SDL2_TTF_LIB_DIR}/libSDL2_ttf.dll.a")
set_property(TARGET SDL2_TTF PROPERTY IMPORTED_LOCATION "${SDL2_TTF_LIB_DIR}/libSDL2_ttf.a")
# Order is important! SDL2_IMAGE_DLL must called before SDL2_IMAGE and SDL2_TTF_DLL before SDL2_TTF
set(SDL2_LIBS mingw32 SDL2 SDL2main SDL2_GFX SDL2_TTF_DLL SDL2_TTF SDL2_IMAGE_DLL SDL2_IMAGE m dinput8 dxguid dxerr8 user32 gdi32 winmm imm32 ole32 oleaut32 shell32 version uuid)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${SDL2_FLAGS}")
file(GLOB_RECURSE SOURCE "src/*.c" "src/*.h")
add_executable("${PROJECT_NAME}" "${SOURCE}")
include_directories(${SDL2_INCLUDE_DIR} ${SDL2_GFX_INCLUDE_DIR} ${SDL2_IMAGE_INCLUDE_DIR} ${SDL2_TTF_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBS})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.