尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

SDL3和其附属的编译记录

SDL3和其附属的编译记录
📅 发布时间:2026/6/18 22:35:46

SDL3的构建记录

环境

windows11 + msys2 + gcc + cmake
编辑器使用vscode,插件为cmake tool,c++和clangd。

子模块

神奇的 sdl3-mixer 还在设计阶段 vcpkg 没有,如果从0构建需要的版本 vcpkg 也不支持。
正常情况下可以选择relase导入include和dll进行构建,这是最方便的手法。
mixer在本文写的时候是2.8.1。
不过看commit修复了很多bug,因此我决定直接子模块构建。

本文写完之后,发现 Conan 有现成的库可以导入,不需要我这么麻烦。

首先初始化git,然后把所有的子模块放在 extern 文件夹里。

git submodule add https://github.com/libsdl-org/SDL.git extern/SDL3
git submodule add https://github.com/libsdl-org/SDL_image.git extern/SDL3_image
git submodule add https://github.com/libsdl-org/SDL_mixer.git extern/SDL3_mixer
git submodule add https://github.com/libsdl-org/SDL_ttf.git extern/SDL3_ttf

sdl3 的附属模块有大量的子模块,我们需要把子模块也拉取进来。

git submodule update --init --recursive

无尽的等待之后,子模块也拉去结束了。

Cmake 构建

在项目根目录下创建一个 CMakeLists.txt,开始写这个折磨人的过程。

cmake_minimum_required(VERSION 3.16...3.25)# 抑制第三方库的 CMake 弃用警告
set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS ON CACHE BOOL "" FORCE)# clangd 使用
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)# 设置构建目录
# set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}/build" CACHE PATH "Build directory")# 输出目录配置
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIGURATION>")
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE INTERNAL "")# SDL 是 C 语言构建,即使用 C++,这里也需要 C。
project(RougeLike VERSION 1.0.0 LANGUAGES C CXX)# 设置标准
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)if(WIN32)# 禁用 getpagesize,让 SDL3 使用 Windows 的 GetSystemInfoset(HAVE_GETPAGESIZE OFF CACHE BOOL "" FORCE)set(HAVE_SYSCONF OFF CACHE BOOL "" FORCE)# 确保 Windows 平台定义被设置add_compile_definitions(SDL_PLATFORM_WINDOWS)
endif()# SDL3 库构建
add_subdirectory(extern/SDL3 EXCLUDE_FROM_ALL)# SDL3-ttf
set(SDLTTF_VENDORED ON CACHE BOOL "" FORCE)
add_subdirectory(extern/SDL3_ttf EXCLUDE_FROM_ALL)# SDL3_mixer
set(SDLMIXER_VENDORED ON CACHE BOOL "" FORCE)
set(SDLMIXER_MP3_DRMP3 ON CACHE BOOL "" FORCE)
set(SDLMIXER_VORBIS_STB ON CACHE BOOL "" FORCE)
set(SDLMIXER_FLAC_DRFLAC ON CACHE BOOL "" FORCE)
set(SDLMIXER_OPUS ON CACHE BOOL "" FORCE)set(SDLMIXER_MP3_MPG123 OFF CACHE BOOL "" FORCE) # windows 下禁用了add_subdirectory(extern/SDL3_mixer EXCLUDE_FROM_ALL)# SDL_image
set(SDLIMAGE_VENDORED ON CACHE BOOL "" FORCE)
set(SDLIMAGE_AVIF OFF CACHE BOOL "" FORCE)
set(SDLIMAGE_BMP OFF CACHE BOOL "" FORCE)
set(SDLIMAGE_JPEG OFF CACHE BOOL "" FORCE)
set(SDLIMAGE_WEBP OFF CACHE BOOL "" FORCE)
add_subdirectory(extern/SDL3_image EXCLUDE_FROM_ALL)# EnTT 头文件库
add_subdirectory(extern/entt EXCLUDE_FROM_ALL)add_executable(${PROJECT_NAME})target_sources(${PROJECT_NAME} 
PRIVATE src/main.cpp
)# 显示决定目录
target_include_directories(${PROJECT_NAME} PRIVATE${CMAKE_CURRENT_SOURCE_DIR}/src # 项目头文件路径
)# 链接 SDL 库
target_link_libraries(${PROJECT_NAME} PUBLIC SDL3_ttf::SDL3_ttfSDL3_mixer::SDL3_mixerSDL3_image::SDL3_imageSDL3::SDL3EnTT::EnTT
)# 自动复制 DLL 文件到可执行文件目录
if(WIN32)# 查找所有依赖的 DLL 文件add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy_if_different$<TARGET_FILE:SDL3::SDL3>$<TARGET_FILE_DIR:${PROJECT_NAME}>COMMAND ${CMAKE_COMMAND} -E copy_if_different$<TARGET_FILE:SDL3_image::SDL3_image>$<TARGET_FILE_DIR:${PROJECT_NAME}>COMMAND ${CMAKE_COMMAND} -E copy_if_different$<TARGET_FILE:SDL3_mixer::SDL3_mixer>$<TARGET_FILE_DIR:${PROJECT_NAME}>COMMAND ${CMAKE_COMMAND} -E copy_if_different$<TARGET_FILE:SDL3_ttf::SDL3_ttf>$<TARGET_FILE_DIR:${PROJECT_NAME}>COMMENT "Copying DLL files to output directory")
endif()# 配置资源文件目录
set(ASSETS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/assets")
set(ASSETS_DEST_DIR "$<TARGET_FILE_DIR:${PROJECT_NAME}>/assets")# 检查资源目录是否存在
if(EXISTS ${ASSETS_SOURCE_DIR})message(STATUS "Found assets directory: ${ASSETS_SOURCE_DIR}")# 使用自定义目标确保目录创建和文件复制add_custom_target(copy_assets ALLCOMMAND ${CMAKE_COMMAND} -E make_directory "${ASSETS_DEST_DIR}"COMMAND ${CMAKE_COMMAND} -E copy_directory"${ASSETS_SOURCE_DIR}" "${ASSETS_DEST_DIR}"COMMENT "Copying assets to output directory"DEPENDS ${PROJECT_NAME})# 确保主目标在资源复制之前构建add_dependencies(copy_assets ${PROJECT_NAME})else()message(WARNING "Assets directory not found: ${ASSETS_SOURCE_DIR}")
endif()

之后编译就基本能用了。

踩坑记录-神奇的错误

写了个程序,编译之后发现了这个。

[build] [  6%] Building C object extern/SDL3/CMakeFiles/SDL3-shared.dir/src/cpuinfo/SDL_cpuinfo.c.obj
[build] rougelike\extern\SDL3\src\cpuinfo\SDL_cpuinfo.c: In function 'SDL_GetSystemPageSize_REAL':
[build] rougelike\extern\SDL3\src\cpuinfo\SDL_cpuinfo.c:1257:34: error: implicit declaration of function 'getpagesize' [-Wimplicit-function-declaration]
[build]  1257 |             SDL_SystemPageSize = getpagesize();
[build]       |                                  ^~~~~~~~~~~
[build] mingw32-make[3]: *** [extern\SDL3\CMakeFiles\SDL3-shared.dir\build.make:487: extern/SDL3/CMakeFiles/SDL3-shared.dir/src/cpuinfo/SDL_cpuinfo.c.obj] Error 1
[build] mingw32-make[2]: *** [CMakeFiles\Makefile2:958: extern/SDL3/CMakeFiles/SDL3-shared.dir/all] Error 2
[build] mingw32-make[1]: *** [CMakeFiles\Makefile2:933: CMakeFiles/RougeLike.dir/rule] Error 2
[build] mingw32-make: *** [Makefile:189: RougeLike] Error 2
[proc] 命令“msys64\ucrt64\bin\cmake.EXE --build rougelike/out/build --target RougeLike --”已退出,代码为 2
[driver] 生成完毕: 00:00:15.460
[build] 生成已完成,退出代码为 2

可能是 mingW 的原因,我在 MSVC 没有遇到过这个问题。
注意到错误里面有 getpagesize(),这不是 windows 下能编译的东西,说明函数执行错了。
查找 SDL3/src/cpuinfo/SDL_cpuinfo.c,有下面的段落:


```static int SDL_SystemPageSize = -1;int SDL_GetSystemPageSize(void)
{if (SDL_SystemPageSize == -1) {
#ifdef SDL_PLATFORM_SYSTEM_PAGE_SIZE_PRIVATE  // consoles will define this in a platform-specific internal header.SDL_SystemPageSize = SDL_PLATFORM_SYSTEM_PAGE_SIZE_PRIVATE;
#endif
#ifdef SDL_PLATFORM_3DSSDL_SystemPageSize = 4096;  // It's an ARM11 CPU; I assume this is 4K.
#endif
#ifdef SDL_PLATFORM_VITASDL_SystemPageSize = 4096;  // It's an ARMv7 CPU; I assume this is 4K.
#endif
#ifdef SDL_PLATFORM_PS2SDL_SystemPageSize = 4096;  // It's a MIPS R5900 CPU; I assume this is 4K.
#endif// 这里还有一大堆 省略了
#ifdef HAVE_GETPAGESIZEif (SDL_SystemPageSize <= 0) {SDL_SystemPageSize = getpagesize(); // 问题在这里}
#endif
#if defined(SDL_PLATFORM_WINDOWS)if (SDL_SystemPageSize <= 0) {SYSTEM_INFO sysinfo;GetSystemInfo(&sysinfo);SDL_SystemPageSize = (int) sysinfo.dwPageSize;}
#endif

问题在 HAVE_GETPAGESIZE 宏上, MSYS2 是模拟的 unix 环境,这个宏会通过,但 windows 下执行 cmake 可不会通过。

在cmake禁止这个宏就可以了。

if(WIN32)# 禁用 getpagesize,让 SDL3 使用 Windows 的 GetSystemInfoset(HAVE_GETPAGESIZE OFF CACHE BOOL "" FORCE)set(HAVE_SYSCONF OFF CACHE BOOL "" FORCE)# 确保 Windows 平台定义被设置add_compile_definitions(SDL_PLATFORM_WINDOWS)
endif()# SDL3 库构建
add_subdirectory(extern/SDL3 EXCLUDE_FROM_ALL)

MP3问题

是的,问题不止一个。

[build] [ 93%] Building C object extern/SDL3_mixer/external/libmpg123-build/ports/cmake/src/libmpg123/CMakeFiles/libmpg123.dir/__/__/__/__/src/libmpg123/lfs_wrap.c.obj
[build] 
rougelike\extern\SDL3_mixer\external\mpg123\src\libmpg123\lfs_wrap.c:62:23: error: size of array 'MPG123_STATIC_ASSERT' is negative
[build]    62 | typedef unsigned char MPG123_STATIC_ASSERT[(SIZEOF_OFF_T == sizeof(off_t)) ? 1 : -1];
[build]       |                       ^~~~~~~~~~~~~~~~~~~~
[build] mingw32-make[3]: *** [extern\SDL3_mixer\external\libmpg123-build\ports\cmake\src\libmpg123\CMakeFiles\libmpg123.dir\build.make:424: extern/SDL3_mixer/external/libmpg123-build/ports/cmake/src/libmpg123/CMakeFiles/libmpg123.dir/__/__/__/__/src/libmpg123/lfs_wrap.c.obj] Error 1
[build] mingw32-make[2]: *** [CMakeFiles\Makefile2:1840: extern/SDL3_mixer/external/libmpg123-build/ports/cmake/src/libmpg123/CMakeFiles/libmpg123.dir/all] Error 2
[build] mingw32-make[1]: *** [CMakeFiles\Makefile2:933: CMakeFiles/RougeLike.dir/rule] Error 2
[build] mingw32-make: *** [Makefile:189: RougeLike] Error 2
[proc] 命令“\msys64\ucrt64\bin\cmake.EXE --build 
rougelike/out/build --target RougeLike --”已退出,代码为 2
[driver] 生成完毕: 00:03:24.208
[build] 生成已完成,退出代码为 2

这就很简单了,是 MPG123 的问题,我们开启了替代品 DRMP3,就不需要编译这个了。

set(SDLMIXER_MP3_MPG123 OFF CACHE BOOL "" FORCE)
add_subdirectory(extern/SDL3_mixer EXCLUDE_FROM_ALL)

编译结果

之后就编译成功了。
代码使用 sdl3-sample 的代码,做了点修改。

#define SDL_MAIN_USE_CALLBACKS  // This is necessary for the new callbacks API. To use the legacy API, don't define this. 
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3/SDL_init.h>
#include <SDL3_ttf/SDL_ttf.h>
#include <SDL3_mixer/SDL_mixer.h>
#include <SDL3_image/SDL_image.h>
#include <cmath>
#include <string_view>
#include <filesystem>
#include <thread>constexpr uint32_t windowStartWidth = 400;
constexpr uint32_t windowStartHeight = 400;struct AppContext {SDL_Window* window;SDL_Renderer* renderer;SDL_Texture* messageTex, *imageTex;SDL_FRect messageDest;SDL_AudioDeviceID audioDevice;MIX_Track* track;SDL_AppResult app_quit = SDL_APP_CONTINUE;
};SDL_AppResult SDL_Fail(){SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());return SDL_APP_FAILURE;
}SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {// init the library, here we make a window so we only need the Video capabilities.if (not SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)){return SDL_Fail();}// init TTFif (not TTF_Init()) {return SDL_Fail();}// init Mixerif (not MIX_Init()) {return SDL_Fail();}// create a windowSDL_Window* window = SDL_CreateWindow("SDL Minimal Sample", windowStartWidth, windowStartHeight, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY);if (not window){return SDL_Fail();}// create a rendererSDL_Renderer* renderer = SDL_CreateRenderer(window, NULL);if (not renderer){return SDL_Fail();}// load the font
#if __ANDROID__std::filesystem::path basePath = "";   // on Android we do not want to use basepath. Instead, assets are available at the root directory.
#elseauto basePathPtr = SDL_GetBasePath();if (not basePathPtr){return SDL_Fail();}const std::filesystem::path basePath = basePathPtr;
#endifconst auto fontPath = basePath / "assets/fonts/Inter-VariableFont.ttf";TTF_Font* font = TTF_OpenFont(fontPath.string().c_str(), 36);if (not font) {return SDL_Fail();}// render the font to a surfaceconst std::string_view text = "Hello SDL!";SDL_Surface* surfaceMessage = TTF_RenderText_Solid(font, text.data(), text.length(), { 255,255,255 });// make a texture from the surfaceSDL_Texture* messageTex = SDL_CreateTextureFromSurface(renderer, surfaceMessage);// we no longer need the font or the surface, so we can destroy those now.TTF_CloseFont(font);SDL_DestroySurface(surfaceMessage);// load the SVGauto svg_surface = IMG_Load((basePath / "assets/images/gs_tiger.svg").string().c_str());SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, svg_surface);SDL_DestroySurface(svg_surface);// get the on-screen dimensions of the text. this is necessary for rendering itauto messageTexProps = SDL_GetTextureProperties(messageTex);SDL_FRect text_rect{.x = 0,.y = 0,.w = float(SDL_GetNumberProperty(messageTexProps, SDL_PROP_TEXTURE_WIDTH_NUMBER, 0)),.h = float(SDL_GetNumberProperty(messageTexProps, SDL_PROP_TEXTURE_HEIGHT_NUMBER, 0))};// init SDL MixerMIX_Mixer* mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);if (mixer == nullptr) {return SDL_Fail();}auto mixerTrack = MIX_CreateTrack(mixer);// load the musicauto musicPath = basePath / "assets/sounds/the_entertainer.ogg";auto music = MIX_LoadAudio(mixer,musicPath.string().c_str(),false);if (not music) {return SDL_Fail();}// play the music (does not loop)SDL_PropertiesID props = SDL_CreateProperties();MIX_SetTrackAudio(mixerTrack, music);MIX_PlayTrack(mixerTrack, props);SDL_DestroyProperties(props);// print some information about the windowSDL_ShowWindow(window);{int width, height, bbwidth, bbheight;SDL_GetWindowSize(window, &width, &height);SDL_GetWindowSizeInPixels(window, &bbwidth, &bbheight);SDL_Log("Window size: %ix%i", width, height);SDL_Log("Backbuffer size: %ix%i", bbwidth, bbheight);if (width != bbwidth){SDL_Log("This is a highdpi environment.");}}// set up the application data*appstate = new AppContext{.window = window,.renderer = renderer,.messageTex = messageTex,.imageTex = tex,.messageDest = text_rect,.track = mixerTrack,};SDL_SetRenderVSync(renderer, -1);   // enable vysncSDL_Log("Application started successfully!");return SDL_APP_CONTINUE;
}SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event* event) {auto* app = (AppContext*)appstate;if (event->type == SDL_EVENT_QUIT) {app->app_quit = SDL_APP_SUCCESS;}return SDL_APP_CONTINUE;
}SDL_AppResult SDL_AppIterate(void *appstate) {auto* app = (AppContext*)appstate;// draw a colorauto time = SDL_GetTicks() / 1000.f;auto red = (std::sin(time) + 1) / 2.0 * 255;auto green = (std::sin(time / 2) + 1) / 2.0 * 255;auto blue = (std::sin(time) * 2 + 1) / 2.0 * 255;SDL_SetRenderDrawColor(app->renderer, red, green, blue, SDL_ALPHA_OPAQUE);SDL_RenderClear(app->renderer);// Renderer uses the painter's algorithm to make the text appear above the image, we must render the image first.SDL_RenderTexture(app->renderer, app->imageTex, NULL, NULL);SDL_RenderTexture(app->renderer, app->messageTex, NULL, &app->messageDest);SDL_RenderPresent(app->renderer);return app->app_quit;
}void SDL_AppQuit(void* appstate, SDL_AppResult result) {auto* app = (AppContext*)appstate;if (app) {SDL_DestroyRenderer(app->renderer);SDL_DestroyWindow(app->window);// prevent the music from abruptly ending.MIX_StopTrack(app->track, MIX_TrackMSToFrames(app->track, 1000));std::this_thread::sleep_for(std::chrono::milliseconds(1000));//Mix_FreeMusic(app->music); // this call blocks until the music has finished fadingSDL_CloseAudioDevice(app->audioDevice);delete app;}TTF_Quit();MIX_Quit();SDL_Log("Application quit successfully!");SDL_Quit();
}

接下来编译就没什么大问题了。

相关新闻

  • 机器学习比赛
  • 牙科诊所借力AI营销4个月创收13万
  • P4653 [CEOI 2017] Sure Bet

最新新闻

  • 2026年洛阳西工TOP5不坑人电器门店,凭啥成为市民首选?
  • Fcitx5-android输入法框架架构深度解析:模块化设计的艺术与实践
  • 5分钟免费激活IDM:开源脚本让你的下载速度永久加速
  • 卡梅德生物解析EGFR(表皮生长因子受体):细胞调控的关键靶点
  • 深度解析:ComfyUI_smZNodes 如何实现跨平台 Stable Diffusion 生成一致性
  • 视觉具身智能:从多模态模型到可执行AI工作流的范式升级

日新闻

  • 2026年不锈钢卷板厂家推荐排行榜:冷轧热轧/304/201不锈钢卷板,高颜值耐腐蚀源头厂家实力精选 - 企业推荐官【官方】
  • FLUX.1-dev FP8模型实战指南:24GB以下显卡高效部署方案
  • 2026佛山长途搬家价目表:跨省跨市搬家费用完整计算指南 - 从来都是英雄出少年

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号