From b5b5b024a5d2dcbb76b1d8947e12b7daf8bafba6 Mon Sep 17 00:00:00 2001 From: CCranney <11773171+CCranney@users.noreply.github.com> Date: Tue, 3 Nov 2026 13:05:22 -0800 Subject: [PATCH] Add visionOS platform support --- test/SConstruct | 4 +- tools/godotcpp.py | 8 ++-- tools/visionos.py | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 tools/visionos.py diff --git a/test/SConstruct b/test/SConstruct index b65b26d20..a6a24f53e 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -25,8 +25,8 @@ if env["platform"] == "macos": ), source=sources, ) -elif env["platform"] == "ios": - if env["ios_simulator"]: +elif env["platform"] in ["ios", "visionos"]: + if env["ios_simulator"] or env["visionos_simulator"]: library = env.StaticLibrary( "project/bin/libmytest.{}.{}.simulator.a".format(env["platform"], env["target"]), source=sources, diff --git a/tools/godotcpp.py b/tools/godotcpp.py index 3843294f6..f02179fa0 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -179,7 +179,7 @@ def scons_generate_bindings(target, source, env): supported_api_versions = ["4.3", "4.4", "4.5", "4.6", "4.7", "4.8"] -platforms = ["linux", "macos", "windows", "android", "ios", "web"] +platforms = ["linux", "macos", "windows", "android", "ios", "visionos", "web"] # CPU architecture options. architecture_array = [ @@ -428,12 +428,12 @@ def generate(env): # Process CPU architecture argument. if env["arch"] == "": - # No architecture specified. Default to arm64 if building for Android, + # No architecture specified. Default to arm64 if building for Android or visionOS, # universal if building for macOS or iOS, wasm32 if building for web, # otherwise default to the host architecture. if env["platform"] in ["macos", "ios"]: env["arch"] = "universal" - elif env["platform"] == "android": + elif env["platform"] in ["android", "visionos"]: env["arch"] = "arm64" elif env["platform"] == "web": env["arch"] = "wasm32" @@ -527,7 +527,7 @@ def generate(env): if env["precision"] == "double": suffix += ".double" suffix += "." + env["arch"] - if env["ios_simulator"]: + if env["ios_simulator"] or env["visionos_simulator"]: suffix += ".simulator" if not env["threads"]: suffix += ".nothreads" diff --git a/tools/visionos.py b/tools/visionos.py new file mode 100644 index 000000000..a49afd808 --- /dev/null +++ b/tools/visionos.py @@ -0,0 +1,102 @@ +import codecs +import os +import subprocess +import sys + +import common_compiler_flags +from SCons.Variables import BoolVariable + + +def has_visionos_osxcross(): + return "OSXCROSS_VISIONOS" in os.environ + + +def options(opts): + opts.Add(BoolVariable("visionos_simulator", "Target visionOS Simulator", False)) + opts.Add("visionos_min_version", "Target minimum xros/xrsimulator version", "26.0") + opts.Add( + "VISIONOS_TOOLCHAIN_PATH", + "Path to visionOS toolchain", + "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain", + ) + opts.Add("VISIONOS_SDK_PATH", "Path to the visionOS SDK", "") + + if has_visionos_osxcross(): + opts.Add("visionos_triple", "Triple for visionOS toolchain", "") + + +def exists(env): + return sys.platform == "darwin" or has_visionos_osxcross() + + +def generate(env): + if env["arch"] not in ("arm64", "x86_64"): + raise ValueError("Only arm64 and x86_64 are supported on visionOS. Exiting.") + + if env["visionos_simulator"]: + sdk_name = "xrsimulator" + target_os_flag = "-mtargetos=xros" + env["visionos_min_version"] + "-simulator" + env.Append(CPPDEFINES=["VISIONOS_SIMULATOR"]) + else: + sdk_name = "xros" + target_os_flag = "-mtargetos=xros" + env["visionos_min_version"] + + env.Append(CCFLAGS=[target_os_flag]) + env.Append(LINKFLAGS=[target_os_flag]) + + if sys.platform == "darwin": + if env["VISIONOS_SDK_PATH"] == "": + try: + env["VISIONOS_SDK_PATH"] = codecs.utf_8_decode( + subprocess.check_output(["xcrun", "--sdk", sdk_name, "--show-sdk-path"]).strip() + )[0] + except (subprocess.CalledProcessError, OSError): + raise ValueError( + "Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name) + ) + + compiler_path = env["VISIONOS_TOOLCHAIN_PATH"] + "/usr/bin/" + env["CC"] = compiler_path + "clang" + env["CXX"] = compiler_path + "clang++" + env["AR"] = compiler_path + "ar" + env["RANLIB"] = compiler_path + "ranlib" + env["SHLIBSUFFIX"] = ".dylib" + env["ENV"]["PATH"] = env["VISIONOS_TOOLCHAIN_PATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"] + + else: + compiler_path = "$VISIONOS_TOOLCHAIN_PATH/usr/bin/${visionos_triple}" + env["CC"] = compiler_path + "clang" + env["CXX"] = compiler_path + "clang++" + env["AR"] = compiler_path + "ar" + env["RANLIB"] = compiler_path + "ranlib" + env["SHLIBSUFFIX"] = ".dylib" + + env.Prepend( + CPPPATH=[ + "$VISIONOS_SDK_PATH/usr/include", + "$VISIONOS_SDK_PATH/System/Library/Frameworks/AudioUnit.framework/Headers", + ] + ) + + env.Append(CCFLAGS=["-stdlib=libc++"]) + + binpath = os.path.join(env["VISIONOS_TOOLCHAIN_PATH"], "usr", "bin") + if binpath not in env["ENV"]["PATH"]: + env.PrependENVPath("PATH", binpath) + + env.Append(LINKFLAGS=["-arch", env["arch"]]) + env.Append(CCFLAGS=["-arch", env["arch"]]) + + env.Append(CCFLAGS=["-isysroot", env["VISIONOS_SDK_PATH"]]) + env.Append(LINKFLAGS=["-isysroot", env["VISIONOS_SDK_PATH"], "-F" + env["VISIONOS_SDK_PATH"]]) + + env.Append(CCFLAGS=["-Wno-ambiguous-macro"]) + + env.Append(LINKFLAGS=["-Wl,-dead_strip"]) + + env.Append(CPPDEFINES=["VISIONOS_ENABLED", "APPLE_EMBEDDED_ENABLED", "UNIX_ENABLED"]) + + if env["lto"] == "auto": + env["lto"] = "none" + + common_compiler_flags.generate(env)