Quake2(quake2sdl)移植 SerenityOS:平台适配补丁与构建运行全解析
2026/9/20 17:49:30 网站建设 项目流程

Quake2(quake2sdl)移植 SerenityOS:平台适配补丁与构建运行全解析

【免费下载链接】serenityThe Serenity Operating System 🐞项目地址: https://gitcode.com/GitHub_Trending/se/serenity

导读:本文围绕 SerenityOS 仓库中 quake2 移植端口 的补丁文档展开,深入剖析0001-Add-SerenityOS-platform-support.patch如何将经典 FPS《雷神之锤 II》(基于 quake2sdl 0.17 源码)从 Linux 平台移植到 SerenityOS。读者将掌握该移植涉及的构建系统改造、平台 API 适配(内存管理、网络、音频、视频渲染)以及数据文件与 OpenGL 模式的配置运行方法,并理解 SerenityOS 移植第三方软件的一般思路。

一、移植背景:为什么需要这份补丁

SerenityOS 是一个从零开始构建的类 Unix 操作系统,其 Ports 体系 允许将上游开源软件以"端口(port)"的形式交叉编译进系统。Quake II 的移植选用了quake2sdl(版本 0.17,提交d26d00845e95dc7d781459d0c1a7fd48ea4b6be3),这是一份基于 SDL2 的 Quake II 引擎分支。

由于上游 quake2sdl 主要面向 Linux/FreeBSD 平台,代码中充斥着__linux__/__FreeBSD__条件编译、stricmp等非 POSIX 调用、以及对 OpenGL/JPEG 等外部库的强依赖,因此无法直接编译运行。仓库中的补丁文档 Ports/quake2/patches/ReadMe.md 只做了简短说明,真正的技术细节全部沉淀在补丁文件 0001-Add-SerenityOS-platform-support.patch 与构建脚本 package.sh 中。本补丁由 Jelle Raaijmakers 提交,Jesse Buhagiar 共同参与,改动横跨 10 个文件,共 99 行新增、125 行删除。

上游信息:quake2sdl 源码托管于外部 GitHub 仓库,SerenityOS 通过commit_hasharchive_hash(SHA-256)固定版本,具体见 package.sh。

二、构建系统改造:从通用 CMake 到 Serenity Port

2.1 顶层 CMakeLists.txt:精简外部依赖

补丁对上游根目录CMakeLists.txt做了大幅精简,核心差异如下:

  • 移除CMAKE_MODULE_PATH设置:不再依赖上游Modules/目录中的查找模块;
  • 保留find_package(SDL2 REQUIRED):SDL2 是唯一必需的第三方库;
  • 删除find_package(OpenGL REQUIRED):SerenityOS 自研的 LibGL 不作为构建期硬依赖,而是在运行期通过动态加载方式接入;
  • 删除可选编译选项WITH_RETEX(纹理替换包支持)与WITH_QMAX(改进图形渲染)两个 CMake 选项及其对应的find_package(JPEG REQUIRED)逻辑被整体移除。

这意味着 SerenityOS 上的 Quake II 始终使用标准的软件渲染路径,不再编译可选的高画质 OpenGL 渲染器变体。

2.2 src/CMakeLists.txt:源码清单与链接目标调整

子目录src/CMakeLists.txt的改动更加深入:

改动点上游(Linux)SerenityOS 移植后
编译宏-DHAVE_IPV6-DLINUX_VERSION="1"、FreeBSD 下-DHAVE_SIN6_LEN、Linux 下-D_GNU_SOURCE全部移除
网络源码linux/net_udp6.c(IPv6)linux/net_udp.c(IPv4)
特效源码WITH_QMAX时用cl_fxmax.c,否则cl_fx.c固定使用cl_fx.c
链接库SDL2 m(Linux 追加dldl SDL2 pthread gfx gui c m
GL 渲染器包含linux/joystick.c移除该文件

从源码结构可以推断,SerenityOS 的 LibGL 以libgl.so.serenity形式存在,因此补丁通过gfx gui两个链接目标接入图形与 GUI 子系统,而pthread则补足线程支持。

2.3 package.sh:端口声明与构建入口

package.sh 是 SerenityOS 端口体系的标准入口脚本,其声明信息完整还原了该移植的构建与部署方式:

#!/usr/bin/env -S bash ../.port_include.sh port='quake2' version='0.1' useconfigure='true' commit_hash='d26d00845e95dc7d781459d0c1a7fd48ea4b6be3' archive_hash='f940d71e0a4e15c040776979c6c99cb3520208744b3c22921f484d70ba82d675' files=( "https://github.com/shamazmazum/quake2sdl/archive/${commit_hash}.tar.gz#${archive_hash}" ) workdir="quake2sdl-${commit_hash}" makeopts=() configopts=( "-DCMAKE_TOOLCHAIN_FILE=${SERENITY_BUILD_DIR}/CMakeToolchain.txt" ) depends=('SDL2') launcher_name='Quake II' launcher_category='&Games' launcher_command='/usr/local/bin/quake2' icon_file='docs/quake2.gif' configure() { run cmake "${configopts[@]}" } install() { run make install }

要点解读:

  • 版本固定useconfigure='true'表示使用 CMake 配置流程,archive_hash用于校验下载包完整性;
  • 工具链:通过-DCMAKE_TOOLCHAIN_FILE=${SERENITY_BUILD_DIR}/CMakeToolchain.txt指定 SerenityOS 交叉编译工具链,这是所有基于 CMake 的端口(如 SDL2)的统一做法;
  • 依赖depends=('SDL2')声明前置端口,构建时会自动先构建 SDL2;
  • 桌面集成launcher_*系列字段将该游戏注册进 SerenityOS 的启动菜单(分类&Games,命令/usr/local/bin/quake2),图标取自上游docs/quake2.gif
  • 安装install()直接执行make install,产物安装到/usr/local前缀下。

构建时在Ports/quake2目录下直接运行./package.sh即可,这正是补丁文档中"Build like a regular Serenity Port"的含义。

三、平台 API 适配:逐文件源码级剖析

这是补丁的核心价值所在——将 Linux 专用代码逐一替换为 SerenityOS 可用的等价实现。

3.1 内存管理:Hunk 分配器的页面对齐处理

src/linux/q_shlinux.c中的Hunk_End()负责收缩游戏内存块(hunk)。上游 Linux 实现使用mremap()系统调用,而 FreeBSD/SerenityOS 分支则改用munmap()收缩。补丁的关键改动:

// FIXME: 64-bit???? #define PAGE_SIZE 4096 #if defined(__FreeBSD__) || defined(__serenity__) size_t old_size = maxhunksize; size_t new_size = curhunksize + sizeof(int); void * unmap_base; size_t unmap_len; new_size = ((new_size + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1))); old_size = ((old_size + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1))); if (new_size > old_size) n = 0; /* error */ else if (new_size < old_size) { unmap_base = (caddr_t)(membase + new_size); unmap_len = old_size - new_size; n = munmap(unmap_base, unmap_len) + membase; } #endif

要点:

  • 通过defined(__serenity__)宏识别 SerenityOS,与 FreeBSD 共用munmap收缩路径;
  • PAGE_SIZE被硬编码为 4096(源码注释中留有 "FIXME: 64-bit????" 的疑问,说明这是临时性处理),新旧尺寸均向上对齐到页边界后再计算待释放区间;
  • 之所以避开mremap,从源码结构可以推断 SerenityOS 内核未实现该 Linux 特有系统调用。

3.2 网络:去掉 stricmp 非标准调用

src/linux/net_udp.cNET_Socket()中,判断绑定接口是否为 localhost 时,上游使用stricmp(非标准、大小写不敏感比较),SerenityOS 的 LibC 不提供该函数,因此改为标准strcmp

- if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost")) + if (!net_interface || !net_interface[0] || !strcmp(net_interface, "localhost")) address.sin_addr.s_addr = INADDR_ANY;

同时,构建清单中由net_udp6.c换为net_udp.c,表明该移植仅启用 IPv4 网络支持。

3.3 音频与渲染:SDL2 头文件与软件渲染

  • 头文件路径rw_sdl.csnd_sdl.c中的#include <SDL.h>全部改为#include <SDL2/SDL.h>,适配 SerenityOS 端口安装的头文件布局;
  • 软件渲染强制启用rw_sdl.cSWimp_InitGraphics()中,渲染器创建标志由SDL_RENDERER_ACCELERATED改为SDL_RENDERER_SOFTWARE
- renderer = SDL_CreateRenderer (window, -1, SDL_RENDERER_ACCELERATED); + renderer = SDL_CreateRenderer (window, -1, SDL_RENDERER_SOFTWARE);

这说明 SerenityOS 上 SDL2 的 2D 渲染走软件路径,与系统图形栈的兼容性优先于 GPU 加速。

  • 新增空实现:补丁在rw_sdl.c末尾追加了UpdateHardwareGamma()的空实现(Noop),用于满足引擎对硬件伽马校正函数的引用,但 SerenityOS 端不执行任何实际校正。

3.4 系统层:控制台输入与错误处理

src/linux/sys_linux.c的改动体现了两点平台差异:

  1. 移除 SysV IPC 头文件<sys/ipc.h><sys/shm.h>不再引入;
  2. 注释掉 fcntl 非阻塞 stdin 调用Sys_Quit()Sys_Error()main()中的fcntl(0, F_SETFL, ... | FNDELAY)系列调用全部被注释。从源码结构可以推断,SerenityOS 对终端非阻塞模式的fcntl支持与 Linux 存在差异,移植时选择放弃这部分能力以保证稳定;
  3. console 输入路径调整Sys_ConsoleInput()中原本用select()轮询 stdin 就绪状态的逻辑被注释掉,直接执行read(),避免 select 在 SerenityOS 终端环境下不可用;
  4. 版本标识:启动横幅由printf ("Quake 2 -- Version %s\n", LINUX_VERSION)改为printf ("Quake 2 -- Version %s Serenity\n", "0.1"),输出 "Quake 2 -- Version 0.1 Serenity",与 package.sh 中version='0.1'保持一致。

3.5 视频模式与渲染库加载

src/linux/vid_so.c是平台差异最集中的文件之一:

  • 规避视频模式切换崩溃vid_modes[]表中 Mode 0 的分辨率由320x240改为640x480,源码注释明确说明这是 HACK——"Trying to access graphics options or setting video mode kills the program"(访问图形选项或设置视频模式会导致程序崩溃),因此用 640x480 作为安全默认值;
  • 硬编码渲染库路径VID_LoadRefresh()原本用RESOURCE_LIBDIR拼接动态库路径,但该宏在 SerenityOS 交叉编译环境下指向无效路径(注释:RESOURCE_LIBDIR is a completely invalid path!),补丁临时硬编码为:
// FIXME: RESOURCE_LIBDIR is a completely invalid path! // Un-hardcode me eventually please! //snprintf (fn, MAX_OSPATH, "%s/%s", RESOURCE_LIBDIR, name ); snprintf (fn, MAX_OSPATH, "%s/%s", "/usr/local/lib/quake2sdl", name ); Com_Printf("%s\n", fn);

即渲染器动态库(如ref-softsdlref-sdlgl)将从/usr/local/lib/quake2sdl/目录加载,make install会将库安装到该位置。

3.6 平台头文件:解除编译期报错

src/linux/glw_linux.h顶部原本对非 Unix 平台直接#error,补丁将其注释掉:

#if !defined(__linux__) && !defined(__FreeBSD__) // #error You shouldnt be including this file on non-unix platforms #endif

这使得 GL 相关的窗口包装代码能够在 SerenityOS 上继续编译,为运行期加载 LibGL 保留可能性。

四、运行配置:数据文件与 OpenGL 模式

补丁在修改上游 README 时,写入了 SerenityOS 专属的运行说明(这也是 ReadMe.md 所指向的权威操作指南):

4.1 获取游戏数据文件

Quake II 引擎本体不含游戏内容,需要自行获取Quake II 演示版(demo)的pak0.pak数据包。补丁文档说明:iD Software 的 FTP 已下线,但演示包可在多处找到。下载后将pak0.pak放到如下目录:

/home/anon/.quake2/baseq2/

随后在命令行直接运行quake2即可进入游戏。

4.2 切换 OpenGL 渲染模式

SerenityOS 移植版默认使用软件渲染。软件渲染与 LibGL 之间尚不支持运行时动态切换,若要以 OpenGL 模式运行,需要手动编辑配置文件~/.quake2/baseq2/config.cfg,追加两条指令:

set vid_ref "sdlgl" set gl_driver "libgl.so.serenity"
  • vid_ref "sdlgl"指示引擎加载 SDL 驱动的 GL 渲染器(对应构建出的ref-sdlgl动态库);
  • gl_driver "libgl.so.serenity"指向 SerenityOS 自研 OpenGL 实现 LibGL 的共享库文件名。

这两条配置与补丁中保留的ref-sdlgl目标(src/CMakeLists.txt 的补丁片段)相互印证:GL 渲染路径在编译期被保留,但仅能通过配置文件显式启用。

4.3 端口可用性登记

在 Ports/AvailablePorts.md 中,该端口被登记为:

端口说明版本上游
quake2QuakeII0.1quake2sdl

同一列表中还包含quake(Quake 1,SerenityQuake 移植)与quake3(ioquake3),三者共同构成了 SerenityOS 上的雷神之锤系列游戏阵容。

五、移植方法论小结

纵观整份补丁,Quake II 移植到 SerenityOS 的技术路径可以归纳为四条可复用的经验:

  1. 构建系统适配先行:移除上游对 OpenGL/JPEG 等外部库的强制查找与可选特性宏,将链接目标替换为 SerenityOS 的gfx gui等系统库,保持最小依赖面;
  2. 平台宏分支复用:优先复用 FreeBSD 分支(munmap收缩、非mremap路径),通过新增defined(__serenity__)条件并入现有分支,最大限度减少重复代码;
  3. 非标准 API 逐一替换stricmp → strcmpSDL.h → SDL2/SDL.hfcntl(FNDELAY)select()直接禁用,属于典型的 POSIX 兼容性收敛;
  4. 运行期降级与 HACK 记录:软件渲染兜底、视频模式固定 640x480、渲染库路径硬编码等临时手段均在源码中以FIXME/HACK注释明确标注,为后续完善留下线索。

对于希望深入理解该移植的读者,建议按以下顺序阅读仓库中的对应文件:补丁说明文档 → 完整补丁 → 构建脚本 → SDL2 端口,即可完整还原从上游代码到 SerenityOS 可玩游戏的整个移植链路。

【免费下载链接】serenityThe Serenity Operating System 🐞项目地址: https://gitcode.com/GitHub_Trending/se/serenity

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询