这个SConstruct文件是Godot引擎构建系统的核心配置文件,采用Python语言和SCons构建工具编写。下面我将详细解读其中的多平台处理部分。
1. 平台检测与配置
平台扫描与数据结构初始化
platform_list = [] # 平台列表
platform_opts = {} # 每个平台的选项
platform_flags = {} # 每个平台的标志
platform_doc_class_path = {}
platform_exporters = []
platform_apis = []
for x in sorted(glob.glob("platform/*")):
if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"):
continue
tmppath = "./" + x
sys.path.insert(0, tmppath)
import detect
# ... 导入平台相关信息
这段代码扫描platform
目录下的所有子目录,每个子目录代表一个支持的平台(如windows、macos、linuxbsd、android等)。每个平台目录必须包含一个detect.py
文件,该文件定义了特定平台的检测和配置逻辑。
自动平台检测
if not env["platform"]:
# 尝试自动检测平台
if (sys.platform.startswith("linux") or sys.platform.startswith("dragonfly") or
sys.platform.startswith("freebsd") or sys.platform.startswith("netbsd") or
sys.platform.startswith("openbsd")):
env["platform"] = "linuxbsd"
elif sys.platform == "darwin":
env["platform"] = "macos"
elif sys.platform == "win32":
env["platform"] = "windows"
if env["platform"]:
print(f"Automatically detected platform: {env['platform']}")
当用户未指定平台时,构建系统会根据sys.platform
的值自动检测当前操作系统并设置相应的平台。
平台别名和兼容性处理
# 处理已更名的平台名称
if env["platform"] in compatibility_platform_aliases:
alias = env["platform"]
platform = compatibility_platform_aliases[alias]
print_warning(f'Platform "{alias}" has been renamed to "{platform}" in Godot 4. Building for platform "{platform}".')
env["platform"] = platform
# 特殊处理linux和bsd平台
if env["platform"] in ["linux", "bsd"]:
env["platform"] = "linuxbsd"
这段代码处理平台别名和兼容性问题,确保旧版平台名称能正确映射到新的平台名称。特别是在Godot 4中,Linux和BSD平台被统一为linuxbsd
。
平台验证
if env["platform"] not in platform_list:
text = "The following platforms are available:\n\t{}\n".format("\n\t".join(platform_list))
# ... 显示错误信息并退出
验证用户指定的平台是否在支持的平台列表中,如果不在则显示错误信息。
2. 平台特定配置与标志
应用平台特定选项
# 添加平台特定的选项
if env["platform"] in platform_opts:
opts.AddVariables(*platform_opts[env["platform"]])
# 应用平台特定的标志
flag_list = platform_flags[env["platform"]]
for key, value in flag_list.items():
if key not in ARGUMENTS or ARGUMENTS[key] == "auto": # 允许命令行覆盖平台默认设置
env[key] = value
每个平台可能有特定的构建选项和标志。这段代码从前面收集的平台信息中提取选项和标志,并将它们应用到构建环境中。如果用户在命令行中指定了这些选项,则优先使用用户指定的值。
3. 平台特定工具配置
# 配置平台特定的工具
tmppath = "./platform/" + env["platform"]
sys.path.insert(0, tmppath)
import detect
custom_tools = ["default"]
try: # 平台特定工具是可选的
custom_tools = detect.get_tools(env)
except AttributeError:
pass
for tool in custom_tools:
env.Tool(tool)
每个平台可能需要使用特定的编译工具链。这段代码导入平台特定的detect
模块,并调用其get_tools
函数获取该平台需要的工具列表,然后将这些工具添加到SCons环境中。
4. 平台特定条件编译
# 根据平台设置条件编译宏
if env["disable_3d"]:
if env.editor_build:
print_error("Build option `disable_3d=yes` cannot be used for editor builds, only for export template builds.")
Exit(255)
else:
env.Append(CPPDEFINES=["_3D_DISABLED"])
env["disable_xr"] = True
代码中还包含了许多基于平台特性的条件编译开关,通过预处理宏来控制哪些代码会被编译到最终的二进制文件中。
5. 平台特定构建过程
# 构建主要模块
SConscript("core/SCsub")
SConscript("servers/SCsub")
SConscript("scene/SCsub")
if env.editor_build:
SConscript("editor/SCsub")
SConscript("drivers/SCsub")
SConscript("platform/SCsub")
SConscript("modules/SCsub")
if env["tests"]:
SConscript("tests/SCsub")
SConscript("main/SCsub")
# 构建平台特定代码
SConscript("platform/" + env["platform"] + "/SCsub") # 构建选定的平台
最后,在构建过程中会包含平台特定的构建脚本,这些脚本定义了如何构建平台特定的代码。
6. 架构相关处理
opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases))
# 默认架构标志
if env["arch"] == "x86_32":
if env.msvc:
env.Append(CCFLAGS=["/arch:SSE2"])
else:
env.Append(CCFLAGS=["-msse2"])
构建系统还支持不同的CPU架构配置,允许用户为特定架构优化构建。
7. 编译器和工具链适配
# 强制使用我们的最低编译器版本要求
cc_version = methods.get_compiler_version(env)
cc_version_major = cc_version["major"]
cc_version_minor = cc_version["minor"]
cc_version_metadata1 = cc_version["metadata1"]
if cc_version_major == -1:
print_warning("Couldn't detect compiler version, skipping version checks.")
elif methods.using_gcc(env):
if cc_version_major < 9:
print_error("Detected GCC version older than 9, which does not fully support C++17...")
Exit(255)
# ...更多gcc特定检查
elif methods.using_clang(env):
# Apple LLVM版本与上游LLVM版本不同
if methods.is_apple_clang(env):
# Apple Clang特定检查
else:
# 标准Clang特定检查
elif env.msvc:
# MSVC特定版本检查
这部分代码检查编译器版本和类型,确保它们满足Godot的构建要求,并针对不同的编译器应用不同的编译选项。
总结
Godot的SCons构建系统展示了一种高度模块化、灵活的跨平台构建方案:
- 平台抽象层:每个平台都有独立的目录和
detect.py
模块,封装了平台特定的检测和配置逻辑。
- 动态配置:根据目标平台自动调整构建选项、编译器标志和工具链。
- 插件式架构:通过模块系统支持可选功能的动态启用/禁用。
- 条件编译:使用预处理宏实现平台特定功能的条件编译。
- 命令行覆盖:允许用户通过命令行参数覆盖默认设置,提供更大的灵活性。
这种设计使得Godot引擎能够在保持核心代码统一的同时,适应不同平台的特殊需求,是一个复杂跨平台项目构建系统的优秀范例。