Godot Engine macOS 平台移植剖析:platform/macos 目录组织、SCons 构建配置与 .app 打包
本文以 platform/macos/README.md 为骨架,系统讲解 Godot Engine 的 macOS 平台移植:该目录由哪些 C++/Objective-C/ObjC++ 源文件构成、如何复用 drivers/apple 中的共享 Apple 代码、SCons 构建系统如何针对 macOS 选择工具链与渲染驱动,以及 misc/dist 下的 .app 模板与签名资源如何支撑编辑器与导出模板的打包。读完后,你将能够读懂整个 macOS 移植层的文件职责,并在 scons platform=macos 构建时正确理解每一个平台级选项的生效条件与底层影响。
目录定位:macOS 平台移植的主体
platform/macos 目录包含 macOS 平台移植的全部 C++、Objective-C 与 Objective-C++ 代码,这是 platform/macos/README.md 给出的核心定位。围绕这一定位,目录内的文件可以从源码结构中划分为五个功能组:
| 功能组 | 代表文件 | 职责 |
|---|---|---|
| OS 层 | os_macos.h、os_macos.mm、godot_application.mm、godot_application_delegate.mm | OS::MACOS 实现与 NSApplication 生命周期管理 |
| 显示与窗口 | display_server_macos.mm、display_server_macos_base.mm、godot_window.mm、godot_content_view.mm、key_mapping_macos.mm | DisplayServer 实现、NSWindow 封装、按键映射 |
| 图形驱动 | gl_manager_macos_angle.mm、gl_manager_macos_legacy.mm、rendering_context_driver_vulkan_macos.mm、platform_egl.h、platform_gl.h、platform_egl.h、macos_quartz_core_spi.h | OpenGL ES 3(原生/ANGLE)与 Vulkan(MoltenVK)上下文管理 |
| 系统交互 | dir_access_macos.mm、tts_macos.mm、native_menu_macos.mm、crash_handler_macos.mm、stack_trace_macos.h | 文件访问、语音播报、原生菜单栏、崩溃处理与堆栈回溯 |
| 构建脚本 | SCsub、detect.py、platform_macos_builders.py、msvs.py | SCons 源文件清单、平台探测与构建选项、Bundle 生成动作 |
此外还有大量 AppKit 辅助视图类,如 godot_button_view.mm、godot_progress_view.mm、godot_status_item.mm、godot_core_cursor.mm、godot_menu_item.mm、godot_open_save_delegate.mm,它们实现 Godot 在 macOS 上的窗口按钮、进度提示、光标与菜单委托等原生 UI 行为。
入口文件按产物类型二选一,这一选择在 platform/macos/SCsub 中完成:
if env["library_type"] == "executable":
files += ["godot_main_macos.mm"] # 可执行文件入口
else:
files += ["libgodot_macos.mm"] # 作为 libgodot 库时的入口
这与 platform/macos/detect.py 中 get_flags() 声明的 "supported": ["library", "metal", "mono"] 一致:macOS 移植支持构建为库(libgodot,供 GDExtension 等场景使用)、默认启用 Metal 渲染,并支持 .NET(Mono)构建。
共享 Apple 代码:drivers/apple
README 指出该移植复用了共享的 Apple 代码 drivers/apple。该目录包含三个与 iOS/macOS 共用的组件:
- foundation_helpers.h / foundation_helpers.mm:Foundation 框架辅助工具;
- os_log_logger.h / os_log_logger.cpp:将日志接入 Apple 的 os_log 系统日志;
- thread_apple.h / thread_apple.cpp:Apple 平台的线程抽象。
将这部分代码从 platform/macos 抽离,使得 macOS 与 iOS(platform/ios)可以共享同一套 Foundation、日志与线程实现,避免两份重复代码。
SCons 构建:平台探测与选项
在哪些环境下可以构建 macOS
platform/macos/detect.py 的 can_build() 决定了 scons platform=macos 是否可用:
def can_build():
if sys.platform == "darwin" or "OSXCROSS_ROOT" in os.environ or "APPLE_LLVM_CROSS" in os.environ:
return True
return False
即三种情形之一即可:在 macOS(darwin)上原生构建;通过 OSXCross 交叉工具链交叉构建;或通过 APPLE_LLVM_CROSS 路径从 Linux 用 clang 交叉编译(源码注释说明这是 godot-apple 构建容器采用的免 OSXCross 路径)。
平台级构建选项
get_opts()(platform/macos/detect.py)注册的构建选项及默认值如下:
| 选项 | 类型 | 默认值 | 作用 |
|---|---|---|---|
osxcross_sdk |
字符串 | darwin16 |
OSXCross SDK 版本 |
SWIFT_COMPILER / SWIFT_FRONTEND |
字符串 | 空 | swiftc 二进制路径(Mono 构建用) |
MACOS_SDK_PATH |
字符串 | 自动探测 | macOS SDK 路径 |
vulkan_sdk_path |
字符串 | 空 | MoltenVK / Vulkan SDK 路径 |
macports_clang |
枚举 | no |
改用 MacPorts 提供的 Clang(5.0 或 devel) |
use_ubsan / use_asan / use_tsan |
布尔 | 否 | 未定义行为 / 地址 / 线程 Sanitizer |
use_coverage |
布尔 | 否 | 生成覆盖率插桩代码 |
accesskit_sdk_path |
字符串 | 自动推导 | AccessKit C SDK 路径(屏幕阅读器支持) |
angle_libs |
字符串 | 自动推导 | ANGLE 静态库路径(OpenGL over Metal 回退) |
bundle_sign_identity |
字符串 | - |
签名编辑器 .app 所用的签名身份 |
generate_bundle |
布尔 | 否 | 构建后自动生成 .app Bundle |
其中 accesskit_sdk_path 与 angle_libs 的默认值推导逻辑在 platform/macos/detect.py:若设置了 LOCALAPPDATA 环境变量则取 %LOCALAPPDATA%/Godot/build_deps(该变量在 Windows 上才有),否则回退到构建脚本所在目录下的 bin/build_deps——源码注释自述这是交叉编译场景下依赖安装脚本的输出位置。
架构与最低系统版本
configure() 首先校验架构,仅接受 x86_64 与 arm64,随后按架构设定部署目标(platform/macos/detect.py):
supported_arches = ["x86_64", "arm64"]
validate_arch(env["arch"], get_name(), supported_arches)
if env["arch"] == "arm64":
print("Building for macOS 13.0+.")
env.Append(CCFLAGS=["-arch", "arm64", "-mmacosx-version-min=13.0"])
elif env["arch"] == "x86_64":
print("Building for macOS 11.0+.")
env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=11.0"])
也就是说 arm64 构建产物面向 macOS 13.0+,x86_64 构建产物面向 macOS 11.0+。所有 ASFLAGS/CCFLAGS/LINKFLAGS 都会带上对应 -arch 与 -mmacosx-version-min。随后还统一追加 -ffp-contract=off(禁用 FP 收缩以保证数值一致性)以及 -fobjc-arc -fvisibility=hidden(启用 Objective-C ARC、隐藏符号可见性)。
工具链选择
编译器选择按优先级分为四路(platform/macos/detect.py):
- OSXCross 交叉工具链:当环境变量
OSXCROSS_ROOT存在时,将CC/CXX/AR/RANLIB/AS指向$OSXCROSS_ROOT/target/bin/{arch}-apple-{osxcross_sdk}-前缀的 cctools-port 包装器; - APPLE_LLVM_CROSS 交叉编译:从 Linux 侧直接用 PATH 上的
clang/clang++,显式追加-target {arch}-apple-darwin与-isysroot $MACOS_SDK_PATH,部署目标仍由前述-mmacosx-version-min决定; - MacPorts Clang:
macports_clang非no时,使用$MACPORTS_PREFIX/libexec/llvm-{版本}/bin/下的 clang 与 llvm-ar 等工具; - 原生构建:直接使用
clang/clang++(支持CCACHE前缀加速),并调用detect_darwin_sdk_path探测 SDK 后追加-isysroot。
一个值得注意的细节是对 Xcode 15 链接器缺陷的临时规避(platform/macos/detect.py):
# Workaround for Xcode 15 linker bug.
if is_apple_clang(env) and cc_version_major == 1500 and cc_version_minor == 0:
env.Prepend(LINKFLAGS=["-ld_classic"])
仅在 Apple Clang 版本为 15.0 时切回旧版链接器。
渲染驱动的配置逻辑
渲染相关的配置最能体现 macOS 移植的平台约束:
- Metal(默认开启):
get_flags()中"metal": True。configure()在 platform/macos/detect.py 检查架构,非 arm64 时打印警告并关闭 Metal——即当前仓库中 Metal 驱动实质上是 arm64 专属路径;开启后定义METAL_ENABLED、RD_ENABLED并链接 Metal、MetalKit、MetalFX 框架; - OpenGL ES 3:
opengl3开启时定义GLES3_ENABLED;若同时启用angle,则链接预编译的 ANGLE 静态库(-lANGLE.macos.{arch}、-lEGL.macos.{arch}、-lGLES.macos.{arch})并额外链接 Metal 框架;找不到 ANGLE 库时会给出警告,提示运行misc/scripts/install_angle.py安装依赖或用angle=no显式关闭(见 platform/macos/detect.py); - Vulkan:macOS 上的 Vulkan 由 MoltenVK 提供。由于
get_flags()中"use_volk": False,构建时直接链接系统安装的 MoltenVK(platform/macos/detect.py):定义VULKAN_ENABLED、RD_ENABLED,追加-framework Metal与-lMoltenVK,并通过detect_mvk()在macos-arm64_x86_64与macos-{arch}两类目录中查找 SDK;找不到则报错退出,提示用vulkan_sdk_path指定路径。对应的运行时上下文驱动实现位于 rendering_context_driver_vulkan_macos.mm。
Sanitizer、LTO 与栈大小
Sanitizer 相关配置在 platform/macos/detect.py:任一 Sanitizer 启用时产物名追加 .san 后缀;UBSan 同时启用了 undefined 的一组细粒度检查与 nullability 检查,ASan 追加 pointer-subtract,pointer-compare,TSan 使用 -fsanitize=thread。栈大小上,普通可执行文件链接参数为 -Wl,-stack_size,0x800000(8 MiB,与 detect.py 中 STACK_SIZE = 8388608 一致),启用 Sanitizer 时提升到 30 MiB(STACK_SIZE_SANITIZERS = 30 * 1024 * 1024),以容纳 Sanitizer 的额外栈开销。
LTO 方面(platform/macos/detect.py),lto=auto 会被降为 none,源码注释说明“macOS 上 LTO 的收益(体积、性能)尚未被明确证实”;显式指定时支持 thin(-flto=thin)与普通 -flto。
系统框架链接清单
platform/macos/detect.py 为 macOS 移植统一追加宏定义与框架链接:
env.Append(CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED", "COREMIDI_ENABLED"])
env.Append(LINKFLAGS=[
"-framework", "Cocoa", "-framework", "Carbon", "-framework", "AudioUnit",
"-framework", "CoreAudio", "-framework", "CoreMIDI", "-framework", "IOKit",
"-framework", "GameController", "-framework", "CoreHaptics", "-framework", "CoreVideo",
"-framework", "AVFoundation", "-framework", "CoreMedia", "-framework", "QuartzCore",
"-framework", "Security", "-framework", "UniformTypeIdentifiers", "-framework", "IOSurface",
])
env.Append(LIBS=["pthread", "z"])
这些框架分别对应 UI(Cocoa/Carbon/QuartzCore)、音频(AudioUnit/CoreAudio)、MIDI、手柄(GameController/CoreHaptics)、视频采集(AVFoundation/CoreMedia/IOSurface)与压缩(z)能力。此外还统一设置了动态库搜索路径:
env.Append(LINKFLAGS=["-rpath", "@executable_path/../Frameworks", "-rpath", "@executable_path"])
这使得 .app Bundle 内 Contents/Frameworks 下的依赖库能被按相对路径解析。
SCsub:源文件清单与产物形态
platform/macos/SCsub 定义了参与编译的文件清单与产物形态:
- 基础文件清单(SCsub)覆盖 OS 层、显示服务器、窗口/按钮/进度视图、按键映射、原生菜单、目录访问、TTS、Vulkan 上下文与 OpenGL 管理器;
angle=yes时追加 gl_manager_macos_angle.mm;- 编辑器构建(
env.editor_build)追加嵌入运行所需的文件(SCsub):display_server_macos_embedded.mm、embedded_debugger.mm、embedded_gl_manager.mm,以及 editor/embedded_game_view_plugin.mm 与 editor/embedded_process_macos.mm——这组文件支撑编辑器“嵌入窗口运行游戏”与 macOS 内嵌调试器; - 产物形态(SCsub):
static_library、shared_library与executable三种library_type均输出到#bin/godot; debug_symbols且separate_debug_symbols时,通过 platform_macos_builders.make_debug_macos 分离调试符号;generate_bundle=yes时注册generate_bundle命令,调用 platform_macos_builders.generate_bundle,后者以 misc/dist/macos_tools.app 作为.app模板(platform_macos_builders.py 中templ = env.Dir("#misc/dist/macos_tools.app").abspath可直接证实这一关系)。
.app 打包资源与签名配置
README 提到的 misc/dist/macos 及两个 .app 模板,构成了 macOS 打包的静态资源层:
编辑器 Bundle 模板:misc/dist/macos_tools.app
misc/dist/macos_tools.app 是用于打包 macOS 编辑器的 .app 模板,其 Contents/ 下包含 Info.plist、PkgInfo 与 Resources/:资源中包含 GDScript、GodotLG(Godot 主图标)、Project、Resource、Scene、Shader 等 .icns 文件,以及约 60 个语言目录(en.lproj、zh_CN.lproj、ja.lproj 等)的 InfoPlist.strings,用于本地化 Bundle 显示名称。构建时 generate_bundle 动作会把编译出的可执行文件复制进该模板,形成完整的编辑器 Bundle;bundle_sign_identity 选项则指定对编辑器 Bundle 使用的签名身份。
导出模板 Bundle:misc/dist/macos_template.app
misc/dist/macos_template.app 用于打包 macOS 导出模板(export template),结构更精简:Contents/Info.plist、PkgInfo,以及 Resources/ 下的 icon.icns 与 PrivacyInfo.xcprivacy。可以推断该 .xcprivacy 隐私清单是为满足 Apple 平台对应用隐私披露的要求而随模板分发的。导出模板最终会供编辑器在“导出项目”时打入用户游戏。
图标与 entitlements
misc/dist/macos 还包含:
- GodotLG.icon:编辑器主图标的多图层 SVG 源(layer_0~2.svg + icon.json),供重新生成
.icns; - editor_info_plist.template:编辑器
Info.plist模板; - editor.entitlements 与 editor_debug.entitlements:编辑器的沙箱/安全 entitlements 配置(正式版与调试版各一份)。
其中正式版 editor.entitlements 声明了以下权限:
| entitlement | 含义 |
|---|---|
com.apple.security.cs.allow-dyld-environment-variables |
允许 dyld 环境变量 |
com.apple.security.cs.allow-jit |
允许 JIT |
com.apple.security.cs.allow-unsigned-executable-memory |
允许未签名可执行内存 |
com.apple.security.cs.disable-executable-page-protection |
关闭可执行页保护 |
com.apple.security.cs.disable-library-validation |
关闭库验证 |
com.apple.security.device.audio-input |
允许访问麦克风 |
com.apple.security.device.camera |
允许访问摄像头 |
这些项对应 Godot 编辑器的典型运行时需求:GDScript/Jolt 等组件可能写入或加载内存页、需要 dlopen 外部库,而音频输入与摄像头权限服务于编辑器内对麦克风和摄像头设备的测试(对应 detect.py 中链接的 AudioUnit/CoreAudio/AVFoundation 框架)。
编辑器导出功能
macOS 移植的另一半职责是在编辑器内提供“导出到 macOS”的能力,实现位于 platform/macos/export 目录:export.cpp / export.h 与 export_plugin.cpp / export_plugin.h,以及 logo.svg、run_icon.svg 等图标资源。其暴露给脚本与文档的编辑器类由 platform/macos/detect.py 中 get_doc_classes() 声明,文档类定义见 platform/macos/doc_classes/EditorExportPlatformMacOS.xml(对应 EditorExportPlatformMacOS 类,get_doc_path() 指向 doc_classes)。这一层负责在用户点击“导出项目”时调用 misc/dist/macos_template.app 模板完成 macOS 目标的打包。
相关文档章节
platform/macos/README.md 末尾的 Documentation 小节指向官方文档站点的三篇配套文章,本篇不复制外部链接,仅列出其覆盖的操作范围,供查阅:
- Compiling for macOS:从源码构建 macOS 平台移植的步骤,对应本文“SCons 构建”一节的各项选项;
- Exporting for macOS:使用已编译的导出模板导出项目的步骤,对应 platform/macos/export 的导出逻辑;
- Running Godot apps on macOS:在 macOS 上运行 Godot 项目的说明。
小结
macOS 移植在仓库中的形态可以概括为三层:
- 代码层(platform/macos):以
os_macos.mm为核心的 OS 实现、AppKit 窗口与视图封装、OpenGL/Metal/Vulkan 三种图形路径的上下文管理,以及编辑器的内嵌运行/调试支持;共享的 Apple 基础代码上提至 drivers/apple 与 iOS 复用; - 构建层(detect.py + SCsub):按架构锁定部署目标(arm64 面向 macOS 13+、x86_64 面向 macOS 11+),在原生 clang、OSXCross、
APPLE_LLVM_CROSS、MacPorts Clang 四条工具链路径间切换,并按opengl3/angle/metal/vulkan组合链接 Metal、MoltenVK、ANGLE 与全套系统框架; - 打包层(misc/dist/macos + 两个
.app模板):编辑器 Bundle 模板、导出模板 Bundle、本地化资源、图标源文件与两版 entitlements 共同保证签名与沙箱行为。
三层层层对应,读懂这一目录即掌握了 Godot 在 macOS 上“从源码到签名 .app”的完整链路。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00