PAYATHON 2026

如何使用 Emscripten 将 SDL3 编译为 WebAssembly?

数据阿明

可以使用 Emscripten 将 SDL3 编译为 WebAssembly。建议在同一个已加载 emsdk 环境的终端中,用 Ninja 配置一个新的构建目录,再执行 cmake --build。SDL3 的 CMake 配置会选择平台源码,应用程序通过 SDL3::SDL3 链接 SDL。

这些报错涉及不同环节:在构建阶段使用了 emcmake、向不接受 -G 的命令传入了该参数,以及手动加入了 Windows 平台源码和头文件。MSYS2 的预编译头错误还需要检查路径与缓存,现有信息不足以确定唯一原因。

1. 区分配置与构建命令

Emscripten 官方给出的 CMake 流程是:

emcmake cmake -S . -B build-web -G Ninja
cmake --build build-web

emcmake 在配置时传入 Emscripten toolchain。生成的构建文件已经记录了编译器设置,因此构建时直接调用 cmake --build 即可。Emscripten 构建说明

在 Windows 上,如果 emcmake 未收到 -G,它会查找 mingw32-make 或 ninja。因此,emcmake cmake --build build 可能先报“找不到兼容生成器”。这个错误来自包装脚本的生成器检查,不能据此判断原构建目录是否有效。emcmake 实现

-G 只用于配置阶段,不能放在 cmake --build 后面。已有构建目录也不能直接切换生成器;从 Visual Studio 改用 Ninja 时,应使用新目录。CMake 生成器说明

2. 用 CMake 同时构建 SDL3 和应用程序

假设项目结构如下,其中 hello.c 是已有的 SDL3 程序,vendored/SDL 是完整的 SDL3 源码:

project/
├── CMakeLists.txt
├── hello.c
└── vendored/
    └── SDL/

可以使用以下 CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(hello LANGUAGES C CXX)

add_subdirectory(vendored/SDL EXCLUDE_FROM_ALL)

add_executable(hello hello.c)
target_link_libraries(hello PRIVATE SDL3::SDL3)

if(EMSCRIPTEN)
    set_target_properties(hello PROPERTIES SUFFIX ".html")
endif()

这是 SDL 官方采用的子项目集成方式:SDL 的构建规则负责选择源码,SDL3::SDL3 提供链接所需的配置。安装的 CMake 还必须满足所用 SDL3 源码自身的最低版本要求。SDL3 Emscripten 入门说明

在 Windows 上,可以先在 emsdk 目录的 CMD 中执行 emsdk_env.bat,再在同一个终端中切换到项目根目录。确保 cmake、ninja 和 emcc 均可用,然后执行:

emcmake cmake -S . -B build-web -G Ninja -DCMAKE_BUILD_TYPE=Release -DSDL_SHARED=OFF -DSDL_STATIC=ON -DSDL_TESTS=OFF
cmake --build build-web --parallel

这里的 -S . 指向应用程序所在的项目根目录。如果使用 -S vendored/SDL,配置的只是 SDL 库,不会自动构建旁边的 hello.c。SDL_SHARED 和 SDL_STATIC 分别控制共享库与静态库构建。SDL3 CMake 说明

如果只想先编译 SDL3 库,也可以单独执行:

emcmake cmake -S vendored/SDL -B build-sdl-web -G Ninja -DCMAKE_BUILD_TYPE=Release -DSDL_SHARED=OFF -DSDL_STATIC=ON -DSDL_TESTS=OFF
cmake --build build-sdl-web --parallel

之后仍需将应用程序与生成的 SDL3 静态库链接。

3. 为什么会出现 windows.h 和 excpt.h 错误?

原始命令显式加入了:

vendored/SDL/src/thread/windows/*.c

这会让编译器处理 Windows 线程实现。另一个命令还通过 -I 加入了 Windows SDK 头文件目录。对于浏览器中的 Emscripten 目标,这些都不应手动加入。

补充 Windows SDK 或 MSVC include 路径无法解决平台选择问题。应移除手工拼接的 SDL 源文件列表,让 SDL 的 CMake 配置选择 Emscripten 对应的实现。直接调用 emcc 时,官方建议编译应用源码并链接已构建的 libSDL3.a。SDL3 Emscripten 构建说明

4. 如何排查 MSYS2 的预编译头路径错误?

cmake_pch.h 找不到 /home/xxxx/.../SDL_internal.h,说明生成的头文件包含了编译器当前无法访问的路径。可能涉及 MSYS2 路径与 Windows 路径混用、旧缓存或源码位置变化;仅凭这一条错误,不能确定是哪一种。

建议按以下顺序检查:

  1. 确认 SDL 源码中的 src/SDL_internal.h 实际存在。
  2. 配置和构建时使用同一个终端、同一套 CMake 与 emsdk。
  3. 使用未配置过的新构建目录重新生成文件,避免沿用修改过的 CMakeSystem.cmake。
  4. 打印完整构建命令,检查编译器与传入的路径:
cmake --build build-web --verbose

如果换用新目录后,仍然只有预编译头步骤失败,可以再换一个新目录,临时禁用 CMake 管理的预编译头,缩小排查范围:

emcmake cmake -S . -B build-web-no-pch -G Ninja -DCMAKE_BUILD_TYPE=Release -DSDL_SHARED=OFF -DSDL_STATIC=ON -DSDL_TESTS=OFF -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON
cmake --build build-web-no-pch --parallel

CMAKE_DISABLE_PRECOMPILE_HEADERS 控制目标的预编译头默认设置。它可以辅助定位问题,但不会修复仍然存在的源码路径错误。CMake 参数说明

5. 构建后如何运行?

浏览器目标应生成配套的 HTML、JavaScript 和 WebAssembly 文件。上面的 CMake 示例将应用输出后缀设为 .html;直接使用 emcc 时,对应形式为 -o hello.html。使用 .exe 文件名不会让 Emscripten 生成 Windows 原生程序。Emscripten 输出文件说明

通过本地 HTTP 服务访问生成的 hello.html。如果构建成功后页面仍无响应,还需检查 hello.c 是否采用适合浏览器的主循环,避免用阻塞循环占满浏览器主线程。这是应用运行阶段需要另行处理的问题。SDL3 Emscripten 运行说明

备注:内容仅供参考。