- 游戏开发
【免费下载链接】mgba
mGBA Game Boy Advance Emulator
mGBA 是一个以 C 和 C++ 编写的 Game Boy Advance 模拟器,同时支持 Game Boy / Game Boy Color 与 Super Game Boy,代码覆盖 ARM7 核心、GBA/GB 两套模拟核心、Qt 与 SDL 前后端以及 3DS、Switch、Vita、Wii 等多个移植平台。本文以仓库根目录下的 CONTRIBUTING.md 为骨架,结合仓库源码与目录结构,系统讲解向 mGBA 提交 Issue、发起 Pull Request 时必须遵循的流程、组件命名、编码风格与许可要求。读完本文,你将能规范地提报带完整诊断信息的 bug 报告,写出符合 mGBA 风格的 C/C++ 代码,并避免在合并环节被要求返工或直接关闭 PR。
提报 Issue:一份高质量 bug 报告的三要素
mGBA 的 Issue 需要提交到项目的问题跟踪器。在提报时,官方要求至少包含三部分信息,它们共同决定了问题能否被快速定位与复现。
构建版本号:定位问题的第一把钥匙
mGBA 要求提供你正在使用的构建版本。对于近期构建,版本号直接显示在标题栏中,格式形如:
0.3-2134-4ec19aa这个字符串由四段组成,从左到右依次是:
- 版本号:如
0.3,对应当前开发版本; - 分支名:若不在
master分支上会显式标注(示例中未标注即为master); - 修订计数:如
2134,即当前提交在历史中的序号; - 截断的修订哈希:如
4ec19aa,即该提交的短哈希。
如果本地存在尚未提交的改动,版本号末尾还会追加-dirty后缀。
这套版本号的生成逻辑可以在仓库根目录的 version.cmake 中找到:构建系统通过git describe --always --dirty、git symbolic-ref --short HEAD、git rev-list HEAD --count等命令分别抓取短哈希、分支名与修订计数,再按master/非master分支组合出VERSION_STRING,最终通过configure_file写入版本源文件。版本数据最终以全局变量的形式暴露给运行时,定义在 include/mgba/core/version.h(如gitCommit、gitCommitShort、gitBranch、gitRevision、projectVersion等),其取值在 src/core/version.c.in 中由 CMake 模板展开,Qt 前端的“关于”对话框(见 AboutScreen.cpp)与更新器(见 ApplicationUpdater.cpp)都会读取这些常量用于显示与比对。
对于0.2.1这类旧版构建,标题栏没有版本号,此时需要手动说明你下载或编译的是哪个具体版本。如果你是从源码自行构建,git describe --always输出的描述字符串就是最准确的标识。
运行环境:软硬件信息缺一不可
- 操作系统:例如 Windows 7 32-bit 或 Ubuntu 15.04 64-bit;
- CPU 与显卡:如 Core i5-3570K 与 AMD Radeon R9 280X(通常不是必需的,仅在怀疑与硬件相关的渲染、性能问题时提供)。
问题描述:越详细越好
请尽可能详尽地描述问题,包括:
- 复现问题的游戏名称;
- 进入异常状态的具体操作路径(如何一步步触发 bug)。
若适用,mGBA 还允许将存档文件(savestate)重命名为.png后缀后直接作为附件挂到 Issue 上——存档本身即附带了运行快照,维护者可以直接加载复现,这比纯文字描述高效得多。
提交 Pull Request:组件命名与提交信息规范
发起 PR 之前,请确认你的改动符合下述编码风格,并了解许可要求(见后文“许可”一节)。此外,所有提交必须满足两点:
- 提交信息前后一致、可读;
- 提交信息中包含被修改组件的名称。
重要提醒:mGBA 明确声明不接受 AI 生成的代码。若 PR 中的代码由 AI 生成,该 PR 将被直接关闭(summarily closed)。
组件命名表
mGBA 将代码库划分为多个组件,PR 提交信息应以组件名开头。官方组件列表如下:
| 组件名 | 含义 |
|---|---|
| ARM7 | ARM 核心 |
| GBA | GBA 代码 |
| GBA Memory | 内存相关 |
| GBA Video | 视频、渲染 |
| GBA Audio | 音频处理 |
| GBA SIO | 串行 I/O、多人联机、link |
| GBA Hardware | 附加设备,如陀螺仪、光传感器 |
| GBA BIOS | 高层 BIOS |
| GB | GB 代码 |
| GB Memory | 内存相关 |
| GB Video | 视频、渲染 |
| GB Audio | 音频处理 |
| GB MBC | 内存控制器 / 卡带硬件 |
| GB SIO | 串行 I/O、多人联机、link |
| Core | 各模拟核心共享的基础设施 |
| Qt | Qt 移植相关代码 |
| SDL | SDL 移植相关代码(含其他移植中的使用) |
| Util | 公共工具代码 |
| Tools | 杂项工具 |
| Debugger | 内置调试功能 |
| 3DS | 3DS 移植 |
| Switch | Switch 移植 |
| Vita | Vita 移植 |
| Wii | Wii 移植 |
| mGUI | 各 homebrew 移植共享的 UI 代码 |
| All | 不涉及特定组件、影响整个项目的改动 |
需要注意的是,该列表并非穷尽,涉及具体文件时,查看相关文件的提交日志(commit log)往往能给出更准确的组件归属。在仓库中,这些组件与目录结构一一对应:ARM 核心在 src/arm,GBA 与 GB 的代码分别在 src/gba 与 src/gb,共享基础设施在 src/core,Qt 与 SDL 前端分别在 src/platform/qt 与 src/platform/sdl,工具代码在 src/util 与 src/tools,各移植平台则位于 src/platform 下。
编码风格:mGBA 的代码书写规范
mGBA 致力于保持代码库的一致与整洁,因此对贡献代码有明确约束。PR 中存在风格错误时,维护者会要求先修正再合并。以下规范全部以“好/坏”对照的形式给出,可直接作为自查清单。
命名规则
- 变量名(含函数参数):一律使用 camelCase。
- 文件作用域 static 变量:必须以下划线
_开头。 - C 结构体名:以大写字母开头;与该结构体相关的函数应以“类名”(含大写字母)开头、后续使用 camelCase。C 结构体不得被
typedef。 - 与结构体无关的函数:整体使用 camelCase;此类 static 函数必须以下划线
_开头。 - 枚举值与
#define:全部大写、以下划线分隔。
正确示例:
static int _localVariable; struct LocalStruct { void (*methodName)(struct LocalStruct struct, param); int memberName; }; enum { ENUM_ITEM_1, ENUM_ITEM_2 }; void LocalStructCreate(struct LocalStruct* struct); void functionName(int argument); static void _LocalStructUse(struct LocalStruct* struct); static void _function2(int argument2);在仓库源码中可以大量观察到这套规则的落地。例如 include/mgba/core/core.h 中,struct mCore以大写m开头且未被 typedef,枚举mPlatform使用全大写mPLATFORM_GBA、mPLATFORM_GB形式,其成员与相关函数(如mCoreInit、mCoreLoadFile系列)均遵循“类名前缀 + camelCase”的命名模式;核心内部则普遍采用_前缀的 file-scoped static 变量。
C++ 命名规则:C++ 类应限定在命名空间内。对于 Qt 移植,该命名空间名为QGBA——在 src/platform/qt 下几乎所有头文件(如 AboutScreen.h、Action.h)都可见namespace QGBA { ... }的包裹。类名的处理方式与 C 结构体类似;成员字段按作用域加前缀:
m_:非 static 成员;s_:static 成员。
花括号
- 花括号不独占一行,只有收尾的
}单独成行; - 条件子句与花括号之间要有一个空格;
- 即使是单行块,也必须使用花括号。
正确写法:
if (condition) { block; } else if (condition2) { block2; } else { block3; }错误写法(花括号独占一行):
if (condition) { block; } else if (condition2) { block2; } else { block3; }错误写法(缺失花括号):
if (condition) statement; else if (condition2) statement2; else statement3;错误写法(缺少空格):
if (condition){ block; }缩进与对齐
- 缩进使用制表符(tab),并与花括号层级保持一致;
- 行内对齐应尽量克制使用,且只能用空格做对齐。
头文件保护宏(Header Guards)
C 头文件:保护宏应为文件名(含H后缀)的全大写形式,标点替换为下划线,且#endif后不得加注释:
#ifndef FILE_NAME_H #define FILE_NAME_H // Header #endif仓库中几乎所有 C 头文件都遵循这一模式,例如 include/mgba/core/core.h 的M_CORE_H、include/mgba/core/version.h 的VERSION_H等。
Qt(C++)头文件:保护宏以QGBA_开头,且不包含_H后缀,其余规则相同。这是出于历史兼容原因,未来可能调整:
#ifndef QGBA_FILE_NAME #define QGBA_FILE_NAME // Header #endif其他规则
块语句(
if、while、for)的关键字与括号之间必须有一个空格:正确:
while (condition) {;错误:while(condition) {。C 代码中:用
0而非NULL(历史原因,未来可能调整);布尔场景应使用bool类型及true/false,而不是1/0。C++ 代码中:使用
nullptr,而不是NULL或0。无函数体的语句:不必加花括号,可以直接用分号收尾。这是建议而非强制:
正确:
while (f());;错误:while (f()) {}。内部含有
break的无限循环:优先使用while (true),而非for (;;)。
许可:MPL 2.0 下的代码引入边界
mGBA 采用 Mozilla Public License version 2.0(仓库根目录的 LICENSE 文件即该许可证全文)。向 mGBA 贡献代码时,这一点会带来若干明确约束:
- 新增代码将默认以MPL 2.0授权;
- GPL 许可的代码不能合入上游,但可以在编译时与 mGBA 链接;
- MIT、BSD、CC0 等宽松许可的代码可以合入上游,但如适用,优先放入
third-party区域。
仓库中对此已有清晰的实践佐证:第三方代码统一收拢在 src/third-party(如 inih、libpng、lzma、sqlite3、zlib、discord-rpc 等),并在 res/licenses 下保存了各第三方组件的许可文本(如 inih.txt、rapidjson.txt 等)。mGBA 自身源文件则普遍带有 MPL 2.0 的版权头,例如 include/mgba/core/core.h 与 src/core/version.c.in 开头均为 “This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0”。
因此,在提交 PR 前请先确认:你的代码是否可被 MPL 2.0 授权?若是 GPL 衍生代码,它只能作为外链模块存在,不能进入 mGBA 上游代码树。
小结:提交前的最终自查清单
综合 CONTRIBUTING.md 的要点,向 mGBA 贡献之前建议逐项核对:
- Issue 提报:附上标题栏版本号(旧版注明具体版本)、操作系统与关键硬件、游戏名称与进入 bug 状态的操作路径,必要时将 savestate 改名
.png后上传; - PR 提交:提交信息以组件名开头(如
GBA Video:、Core:、Qt:)且内容一致可读,不提交 AI 生成代码; - 编码风格:变量 camelCase、结构体大写开头且不 typedef、枚举与宏全大写、static 变量加
_前缀;C++ 类放入QGBA命名空间,成员用m_/s_前缀; - 书写细节:花括号不独占行且单行块也必须加花括号、tab 缩进、头文件保护宏按 C(
FILE_NAME_H)与 Qt(QGBA_FILE_NAME)两套规则书写、块语句关键字与括号间留空格、C 用0/bool、C++ 用nullptr、无限循环用while (true); - 许可合规:新代码可接受 MPL 2.0 授权,GPL 代码仅可链接不可合入,宽松许可代码优先放入
third-party区域。
遵循这些约定,你的 Issue 将更易被复现、PR 将更易被合并,代码也会与 mGBA 十余年沉淀下来的工程风格保持一致。
- 游戏开发
【免费下载链接】mgba
mGBA Game Boy Advance Emulator
相关推荐
Label Studio 贡献者指南:从 Issue 提报到代码合入的完整贡献流程与工程规范
Label Studio 贡献者指南:从 Issue 提报到代码合入的完整贡献流程与工程规范 导读 Label Studio 是一个支持多类型数据标注的开源工具
数据标注人工智能John the Ripper jumbo 贡献指南:从编码规范到许可证要求的完整实践
John the Ripper jumbo 贡献指南:从编码规范到许可证要求的完整实践 John the Ripper jumbo 是社区增强版的密码破解器,支
网络安全密码学渗透测试应用安全Atom 开源贡献指南:从 Issue 提报到 Pull Request 合入的完整流程与代码规范
Atom 开源贡献指南:从 Issue 提报到 Pull Request 合入的完整流程与代码规范 本文以 Atom 仓库根目录的 CONTRIBUTING.m
代码编辑器桌面应用开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考