本文原链接见 Godot-GDExtension C++ 环境搭建 (Docker+MinGW/跨平台) | Convexwf's Kirakira Blog。
Godot 在4.X 之后推出了 GDExtension
,通过第三方绑定扩展功能,目前官方支持的语言只有 C++。通过使用 GDExtension C++
编写扩展插件,可以作为库文件在 Godot 中交互使用。GDExtension
可以使用 C++ 原生库,提高了性能,还可以自编写游戏逻辑,无需和引擎一同编译。
背景与介绍
笔者刚开始学习 Godot 游戏开发,发现关于 GDExtension 的介绍资料较少,官方文档也很简略,导致我在一开始的环境配置时就踩了不少坑。我主要在 Windows
环境下进行 Godot 开发,Windows
平台下的 C++ 环境可以通过 Microsoft Visual Studio(cl)
或者 MinGW(gcc)
两种方式来进行配置,考虑到 Visual Studio
本身体积庞大,我最后选择了 MinGW-w64
作为 C++ 的编译环境。
一开始我尝试着通过 msysy2
安装 MinGW
,但是问题层出不穷,因为平时笔者平时编码都是在 Linux
操作系统,Windows
下的环境配置并不算熟悉,之后还要考虑动态库链接和 Python
环境等问题,于是我在 Github
上找了一圈,看见有人通过 Docker
配置编译环境,只需要本地电脑安装 Git bash
和 Docker
即可,这种方式简单快捷,并且解耦了环境配置与实际开发环境,以后我即使换电脑,甚至换操作系统,也可以很快搭建成功工作流,开箱即用。我在该方案上做了些许调整,接下来介绍一下具体的配置过程。
代码仓库地址:https://github.com/convexwf/godot-gdextension-cpp-examples
打包镜像地址:convexwf/godot-gdextension-cpp-builder
宿主机环境
- OS: Windows 10
- Docker Desktop 4.29.0
- Git version 2.37.3
- Godot 4.2.2 + godot-cpp 4.2
镜像环境
- Python 3.11.9
- scons 4.5.2
- MinGW-w64 10.2.1(gcc-10)
环境和工具介绍
MinGW
的全称是 Minimalist GNU for Windows
,本质是将包括 gcc
在内的 GNU
工具链移植到 Windows
平台,可以将源代码编译成为 Windows
平台下的后缀为 .exe
的可执行文件。MinGW 也可以在 Linux
平台下使用。
MinGW
的编译目标仅兼容 32 位应用程序,于是衍生出了 MinGW-w64
,支持 32 位和 64 位的应用程序。MinGW-w64
下载链接见 Downloads - MinGW-w64。
而 Scons 是一个基于 Python
的软件构建工具,类似于 make
和 cmake
,由于使用 Python
语法,编写上更加灵活,适用于复杂的项目场景。GDExtension
的 godot-cpp
绑定工具就需要使用 scons
进行编译,所以需要配置 Python 和 scons 环境。
scons
版本依赖于 Python
版本,考虑到之后 scons
的版本更新,不能将基础镜像指定为特定版本的 Python
,所以这里选择了 conda
虚拟环境,可以在镜像构建时指定 Python 版本和 scons 版本。conda
虚拟环境可以使用 Anaconda
或者 Miniconda
,其中 Anaconda
是一个包含了 conda
、Python
和超过 150 个科学包及其依赖项的科学 Python
发行版,体量上非常庞大,而 Miniconda
相对轻量,只包含了 conda
和 Python
,需要用户手动安装需要的包。MiniConda
的环境更加简洁,适用于 Docker
镜像构建。
Dockerfile 编写
方案参照的是 mrt-prodz/docker-godot-gdextension-builder: Building Godot 4 GDExtension C++ example with Docker。
这个方案在本地进行测试时,发现镜像构建时会报错,具体原因是找不到特定版本的 g++-mingw-w64-x86-64
。于是我调整了一下配置,在一些地方进行了微调。
基础镜像选择的是 continuumio/miniconda3
,默认安装了 conda
环境,方便指定 Python
版本和安装 scons
编译工具。
FROM continuumio/miniconda3:latest
这里的 Python 选择的是 3.11.9
版本,一开始我试着配置 Python 3.12.3 + scons 4.7
,编译 godot-cpp
时报错找不到 ctypes
模块,努力了下但还是没解决,希望后续哪位同学可以解决这个问题。最新 Python 版本见 Download Python | Python.org。
SHELL ["/bin/bash", "--login", "-c"]
RUN conda init bash
RUN set -ex \
\
&& conda create -y -n py311 python=3.11.9 \
&& conda activate py311 \
&& conda install -c conda-forge -y scons=${SCONS_VERSION} \
&& ln -s /opt/conda/envs/py311/bin/python /usr/bin/python311
Dockerfile 中使用 conda
命令时,需要注意这是一个交互式命令,首先需要切换终端为 bash
,然后使用 conda init bash
初始化 conda
环境,如果不初始化,后续使用 conda
命令会报错 Run 'conda init' before 'conda activate'
。之后指定 Python 版本建立激活虚拟环境并安装 scons
编译工具,最后创建一个软链接,方便后续使用。
接下来需要配置 C++ 的编译环境,镜像基于 Debian
,使用 apt
包管理器,使用官方源可能会出现部分包下载失败的情况,具体错误为 503 Service Unavailable
,这种情况下需要更换为国内源。
# replace the default sources.list with aliyun mirrors
RUN sed -i 's#http://deb.debian.org/#http://mirrors.aliyun.com/#' /etc/apt/sources.list
然后是安装 MingW-w64
的相关库依赖,可以指定相关版本号。
RUN set -ex \
&& DEBIAN_FRONTEND=noninteractive apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
build-essential \
g++-mingw-w64-x86-64=${MINGW_VERSION} \
binutils-mingw-w64=${MINGW_BINUTIL_VERSION}
其中 set -ex
是用来设置 shell
的行为,-e
选项表示当前命令执行失败时,停止执行后续命令,-x
选项表示输出具体的执行命令和过程。
这样 Dockfile
的编写就完成了,可以通过 docker build
命令构建镜像。
docker build -t convexwf/godot-gdextension-cpp-builder .
构建 C++ 绑定库
构建的目录结构如下(部分省略):
.
|-- .gitignore
|-- Dockerfile
|-- SConstruct
|-- demo
| |-- .godot
| |-- gdextension
| | |-- gdexample.gdextension
| | `-- libgdexample.windows.template_debug.x86_64.dll
| |-- icon.svg
| |-- icon.svg.import
| `-- project.godot
|-- godot-cpp
| |-- bin
| |-- cmake
| |-- gdextension
| |-- gen
| |-- include
| |-- misc
| |-- src
| |-- test
| `-- tools
`-- src
|-- gdexample.cpp
|-- gdexample.h
|-- register_types.cpp
`-- register_types.h
其中 godot-cpp
是 Godot
官方提供的 C++
绑定库,通过 git clone
下载到本地。
git clone -b 4.2 git@github.com:godotengine/godot-cpp.git godot-cpp
src
目录用于存放 GDExtension C++
的源码,构建产物在 godot-cpp/bin
目录下生成,也可以通过 SConstruct
指定构建目标和生成位置。本文使用的 src
目录下的文件是 Godot 4.2
官方文档中的示例代码,具体见 GDExtension C++ example — Godot Engine (stable) documentation in English。
demo
目录用于存放 Godot 项目,一般需要通过 Godot 的编辑器打开。
SConstruct
文件是 scons
编译时的配置文件,可以指定编译目标、编译器、编译选项等,需要用户根据实际需求编写。官方提供了一个 SConstruct 文件 作为参考。
本文涉及的 SConstruct
文件如下:
#!/usr/bin/env python
import os
import sys
GODOT_PROJECT_NAME = "demo"
env = SConscript("godot-cpp/SConstruct")
env.Append(CPPPATH=["src/"])
sources = Glob("src/*.cpp")
# env['platform'] = windows
# env['target'] = template_debug
# env['suffix'] = .windows.template_debug.x86_64
# env['SHLIBSUFFIX'] = .dll
if env["platform"] == "macos":
library = env.SharedLibrary(
"{}/gdextension/libgdexample.{}.{}.framework/libgdexample.{}.{}".format(
GODOT_PROJECT_NAME, env["platform"], env["target"], env["platform"], env["target"]
),
source=sources,
)
else:
library = env.SharedLibrary(
"demo/gdextension/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)
Default(library)
文件中指定 Windows
平台下的最终编译产物为 demo/gdextension/libgdexample.windows.template_debug.x86_64.dll
。
剩下的文件中,.gitignore
文件来自 godot/.gitignore at master · godotengine/godot。
demo/gdexetension
目录下的 gdexample.gdextension
文件是为了能让 Godot 识别载入动态链接库,具体内容会在下一节说明。
因为我们之前已经写好了 Dockerfile
,搭配 SConstruct
就可以执行正式构建,执行 shell/build.sh
脚本,或者手动执行下面的命令。
docker run --rm \
-v ${WorkingDir}:/app \
convexwf/godot-gdextension-cpp-builder \
bash -c "cd /app/godot-cpp && source activate gde && scons platform=windows custom_api_file=../extension_api.json"
其中 ${WorkingDir}
是当前工作目录,需要替换为实际的绝对路径。注意 Windows
平台下的 git bash
挂载路径需要使用 //
开头,比如 //d/project
。
第一次构建时需要等待较长时间,笔者的八核笔记本构建时间大约在 10 分钟左右,后续构建时间会缩短。构建产物在 godot-cpp/bin
和 demo/gdextension
目录下。
构建 Godot 项目
首先通过 Godot 新建项目,也可以从已有项目导入,如上图所示。
demo
目录下的 gdextension
目录是用于存放 GDExtension 的相关文件,libgdexample.windows.template_debug.x86_64.dll
是编译产物,gdexample.gdextension
是 GDExtension 的配置文件,文件命名是任意的,只要保持后缀为 .gdextension
即可被 Godot 识别。其内容如下。
[configuration]
entry_symbol = "example_library_init"
compatibility_minimum = "4.2"
[libraries]
macos.debug = "res://gdextension/libgdexample.macos.template_debug.framework"
macos.release = "res://gdextension/libgdexample.macos.template_release.framework"
windows.debug.x86_32 = "res://gdextension/libgdexample.windows.template_debug.x86_32.dll"
windows.release.x86_32 = "res://gdextension/libgdexample.windows.template_release.x86_32.dll"
windows.debug.x86_64 = "res://gdextension/libgdexample.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://gdextension/libgdexample.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "res://gdextension/libgdexample.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://gdextension/libgdexample.linux.template_release.x86_64.so"
linux.debug.arm64 = "res://gdextension/libgdexample.linux.template_debug.arm64.so"
linux.release.arm64 = "res://gdextension/libgdexample.linux.template_release.arm64.so"
linux.debug.rv64 = "res://gdextension/libgdexample.linux.template_debug.rv64.so"
linux.release.rv64 = "res://gdextension/libgdexample.linux.template_release.rv64.so"
android.debug.x86_64 = "res://gdextension/libgdexample.android.template_debug.x86_64.so"
android.release.x86_64 = "res://gdextension/libgdexample.android.template_release.x86_64.so"
android.debug.arm64 = "res://gdextension/libgdexample.android.template_debug.arm64.so"
android.release.arm64 = "res://gdextension/libgdexample.android.template_release.arm64.so"
字段说明:
entry_symbol
:声明模块的入口函数,和 C++ 源码register_types.cpp
中的函数名保持一致。compatibility_minimum
:最低兼容版本,必填。libraries
:声明不同平台下需要识别的动态链接库路径。
保存后查看 Godot 编辑器的输出日志,如果出现 GDExtension configuration file must contain a "configuration/entry_symbol" key: res://gdextension/gdexample.gdextension
等类似错误,可以把 *.gdextension
中的注释和多余空行都删去再看看。
如果一切正常,可以在节点中找到插件 GDExample
,之后将其添加到场景中即可。之后的步骤不再赘述,可以参考官方文档进行操作。
总结和后续
至此,我们已经完成了 GDExtension C++
的环境搭建和构建,通过 Docker
镜像的方式,可以在不同的操作系统下快速搭建开发工作流,提高开发效率。后续开发过程中笔者还会持续调整和优化这个方案,欢迎大家多提 issue 和 PR,友好交流,共同进步!
Reference
- GDExtension 是什么? — Godot Engine (4.x) 简体中文文档
- GDExtension C++ example — Godot Engine (stable) documentation in English
- GDExtension的C++示例 - biiigwang - 博客园
- godot/.gitignore at master · godotengine/godot
- godotengine/godot-cpp: C++ bindings for the Godot script API
- MinGW、MinGW-w64 与TDM-GCC 应该如何选择? - 知乎
- 小贴士:Windows下docker挂载目录填坑记录-CSDN博客
- GDExtension C++环境搭建与使用-CSDN博客
- Docker构建镜像中的换源 - 知乎
- Docker使用conda构建Python项目踩坑日志 - 知乎