Browse Source

Merge pull request #105621 from Repiteo/scons/begin-decouple

SCons: Begin decoupling generation & build code
Thaddeus Crews 4 months ago
parent
commit
60726563c9

+ 14 - 76
core/SCsub

@@ -1,14 +1,14 @@
 #!/usr/bin/env python
 from misc.utility.scons_hints import *
 
-Import("env")
-
 import os
 
 import core_builders
 
 import methods
 
+Import("env")
+
 env.core_sources = []
 
 # Add required thirdparty code.
@@ -161,96 +161,34 @@ env.core_sources += thirdparty_obj
 
 
 # Godot source files
-
 env.add_source_files(env.core_sources, "*.cpp")
 
-
 # Generate disabled classes
-def disabled_class_builder(target, source, env):
-    with methods.generated_wrapper(str(target[0])) as file:
-        for c in source[0].read():
-            if cs := c.strip():
-                file.write(f"#define ClassDB_Disable_{cs} 1\n")
-
-
-env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(disabled_class_builder))
-
+env.CommandNoCache(
+    "disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(core_builders.disabled_class_builder)
+)
 
 # Generate version info
-def version_info_builder(target, source, env):
-    with methods.generated_wrapper(str(target[0])) as file:
-        file.write(
-            """\
-#define GODOT_VERSION_SHORT_NAME "{short_name}"
-#define GODOT_VERSION_NAME "{name}"
-#define GODOT_VERSION_MAJOR {major}
-#define GODOT_VERSION_MINOR {minor}
-#define GODOT_VERSION_PATCH {patch}
-#define GODOT_VERSION_STATUS "{status}"
-#define GODOT_VERSION_BUILD "{build}"
-#define GODOT_VERSION_MODULE_CONFIG "{module_config}"
-#define GODOT_VERSION_WEBSITE "{website}"
-#define GODOT_VERSION_DOCS_BRANCH "{docs_branch}"
-#define GODOT_VERSION_DOCS_URL "https://docs.godotengine.org/en/" GODOT_VERSION_DOCS_BRANCH
-""".format(**source[0].read())
-        )
-
-
 env.CommandNoCache(
     "version_generated.gen.h",
     env.Value(methods.get_version_info(env.module_version_string)),
-    env.Run(version_info_builder),
+    env.Run(core_builders.version_info_builder),
 )
 
-
 # Generate version hash
-def version_hash_builder(target, source, env):
-    with methods.generated_wrapper(str(target[0])) as file:
-        file.write(
-            """\
-#include "core/version.h"
-
-const char *const GODOT_VERSION_HASH = "{git_hash}";
-const uint64_t GODOT_VERSION_TIMESTAMP = {git_timestamp};
-""".format(**source[0].read())
-        )
-
-
-gen_hash = env.CommandNoCache("version_hash.gen.cpp", env.Value(methods.get_git_info()), env.Run(version_hash_builder))
+gen_hash = env.CommandNoCache(
+    "version_hash.gen.cpp", env.Value(methods.get_git_info()), env.Run(core_builders.version_hash_builder)
+)
 env.add_source_files(env.core_sources, gen_hash)
 
-
 # Generate AES256 script encryption key
-def encryption_key_builder(target, source, env):
-    with methods.generated_wrapper(str(target[0])) as file:
-        file.write(
-            f"""\
-#include "core/config/project_settings.h"
-
-uint8_t script_encryption_key[32] = {{
-	{source[0]}
-}};"""
-        )
-
-
-gdkey = os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY", "0" * 64)
-ec_valid = len(gdkey) == 64
-if ec_valid:
-    try:
-        gdkey = ", ".join([str(int(f"{a}{b}", 16)) for a, b in zip(gdkey[0::2], gdkey[1::2])])
-    except Exception:
-        ec_valid = False
-if not ec_valid:
-    methods.print_error(
-        f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{gdkey}".\n'
-        "Unset `SCRIPT_AES256_ENCRYPTION_KEY` in your environment "
-        "or make sure that it contains exactly 64 hexadecimal characters."
-    )
-    Exit(255)
-gen_encrypt = env.CommandNoCache("script_encryption_key.gen.cpp", env.Value(gdkey), env.Run(encryption_key_builder))
+gen_encrypt = env.CommandNoCache(
+    "script_encryption_key.gen.cpp",
+    env.Value(os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY")),
+    env.Run(core_builders.encryption_key_builder),
+)
 env.add_source_files(env.core_sources, gen_encrypt)
 
-
 # Certificates
 env.CommandNoCache(
     "#core/io/certs_compressed.gen.h",

+ 67 - 2
core/core_builders.py

@@ -6,6 +6,71 @@ from io import TextIOWrapper
 import methods
 
 
+# Generate disabled classes
+def disabled_class_builder(target, source, env):
+    with methods.generated_wrapper(str(target[0])) as file:
+        for c in source[0].read():
+            if cs := c.strip():
+                file.write(f"#define ClassDB_Disable_{cs} 1\n")
+
+
+# Generate version info
+def version_info_builder(target, source, env):
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(
+            """\
+#define GODOT_VERSION_SHORT_NAME "{short_name}"
+#define GODOT_VERSION_NAME "{name}"
+#define GODOT_VERSION_MAJOR {major}
+#define GODOT_VERSION_MINOR {minor}
+#define GODOT_VERSION_PATCH {patch}
+#define GODOT_VERSION_STATUS "{status}"
+#define GODOT_VERSION_BUILD "{build}"
+#define GODOT_VERSION_MODULE_CONFIG "{module_config}"
+#define GODOT_VERSION_WEBSITE "{website}"
+#define GODOT_VERSION_DOCS_BRANCH "{docs_branch}"
+#define GODOT_VERSION_DOCS_URL "https://docs.godotengine.org/en/" GODOT_VERSION_DOCS_BRANCH
+""".format(**source[0].read())
+        )
+
+
+def version_hash_builder(target, source, env):
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(
+            """\
+#include "core/version.h"
+
+const char *const GODOT_VERSION_HASH = "{git_hash}";
+const uint64_t GODOT_VERSION_TIMESTAMP = {git_timestamp};
+""".format(**source[0].read())
+        )
+
+
+def encryption_key_builder(target, source, env):
+    src = source[0].read() or "0" * 64
+    try:
+        buffer = bytes.fromhex(src)
+        if len(buffer) != 32:
+            raise ValueError
+    except ValueError:
+        methods.print_error(
+            f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{src}".\n'
+            "Unset `SCRIPT_AES256_ENCRYPTION_KEY` in your environment "
+            "or make sure that it contains exactly 64 hexadecimal characters."
+        )
+        raise
+
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(
+            f"""\
+#include "core/config/project_settings.h"
+
+uint8_t script_encryption_key[32] = {{
+	{methods.format_buffer(buffer, 1)}
+}};"""
+        )
+
+
 def make_certs_header(target, source, env):
     buffer = methods.get_buffer(str(source[0]))
     decomp_size = len(buffer)
@@ -13,8 +78,8 @@ def make_certs_header(target, source, env):
 
     with methods.generated_wrapper(str(target[0])) as file:
         # System certs path. Editor will use them if defined. (for package maintainers)
-        file.write('#define _SYSTEM_CERTS_PATH "{}"\n'.format(env["system_certs_path"]))
-        if env["builtin_certs"]:
+        file.write(f'#define _SYSTEM_CERTS_PATH "{source[2]}"\n')
+        if source[1].read():
             # Defined here and not in env so changing it does not trigger a full rebuild.
             file.write(f"""\
 #define BUILTIN_CERTS_ENABLED

+ 9 - 48
editor/SCsub

@@ -1,64 +1,25 @@
 #!/usr/bin/env python
 from misc.utility.scons_hints import *
 
-Import("env")
-
-env.editor_sources = []
-
 import os
 
 import editor_builders
 
-import methods
+Import("env")
+
+env.editor_sources = []
 
 if env.editor_build:
     # Generate doc data paths
-    def doc_data_class_path_builder(target, source, env):
-        paths = dict(sorted(source[0].read().items()))
-        data = "\n".join([f'\t{{"{key}", "{value}"}},' for key, value in paths.items()])
-        with methods.generated_wrapper(str(target[0])) as file:
-            file.write(
-                f"""\
-struct _DocDataClassPath {{
-	const char *name;
-	const char *path;
-}};
-
-inline constexpr int _doc_data_class_path_count = {len(paths)};
-inline constexpr _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) + 1}] = {{
-{data}
-	{{nullptr, nullptr}},
-}};
-"""
-            )
-
-    env.CommandNoCache("doc_data_class_path.gen.h", env.Value(env.doc_class_path), env.Run(doc_data_class_path_builder))
+    env.CommandNoCache(
+        "doc_data_class_path.gen.h", env.Value(env.doc_class_path), env.Run(editor_builders.doc_data_class_path_builder)
+    )
 
     # Register exporters
-    def register_exporters_builder(target, source, env):
-        platforms = source[0].read()
-        exp_inc = "\n".join([f'#include "platform/{p}/export/export.h"' for p in platforms])
-        exp_reg = "\n".join([f"\tregister_{p}_exporter();" for p in platforms])
-        exp_type = "\n".join([f"\tregister_{p}_exporter_types();" for p in platforms])
-        with methods.generated_wrapper(str(target[0])) as file:
-            file.write(
-                f"""\
-#include "register_exporters.h"
-
-{exp_inc}
-
-void register_exporters() {{
-{exp_reg}
-}}
-
-void register_exporter_types() {{
-{exp_type}
-}}
-"""
-            )
-
     gen_exporters = env.CommandNoCache(
-        "register_exporters.gen.cpp", env.Value(env.platform_exporters), env.Run(register_exporters_builder)
+        "register_exporters.gen.cpp",
+        env.Value(env.platform_exporters),
+        env.Run(editor_builders.register_exporters_builder),
     )
     for e in env.platform_exporters:
         # Add all .cpp files in export folder

+ 43 - 0
editor/editor_builders.py

@@ -9,6 +9,49 @@ import uuid
 import methods
 
 
+def doc_data_class_path_builder(target, source, env):
+    paths = dict(sorted(source[0].read().items()))
+    data = "\n".join([f'\t{{"{key}", "{value}"}},' for key, value in paths.items()])
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(
+            f"""\
+struct _DocDataClassPath {{
+	const char *name;
+	const char *path;
+}};
+
+inline constexpr int _doc_data_class_path_count = {len(paths)};
+inline constexpr _DocDataClassPath _doc_data_class_paths[{len(paths) + 1}] = {{
+	{data}
+	{{nullptr, nullptr}},
+}};
+"""
+        )
+
+
+def register_exporters_builder(target, source, env):
+    platforms = source[0].read()
+    exp_inc = "\n".join([f'#include "platform/{p}/export/export.h"' for p in platforms])
+    exp_reg = "\n\t".join([f"register_{p}_exporter();" for p in platforms])
+    exp_type = "\n\t".join([f"register_{p}_exporter_types();" for p in platforms])
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(
+            f"""\
+#include "register_exporters.h"
+
+{exp_inc}
+
+void register_exporters() {{
+	{exp_reg}
+}}
+
+void register_exporter_types() {{
+	{exp_type}
+}}
+"""
+        )
+
+
 def make_doc_header(target, source, env):
     buffer = b"".join([methods.get_buffer(src) for src in map(str, source)])
     decomp_size = len(buffer)

+ 4 - 59
modules/SCsub

@@ -3,7 +3,7 @@ from misc.utility.scons_hints import *
 
 import os
 
-import methods
+import modules_builders
 
 Import("env")
 
@@ -16,63 +16,15 @@ Export("env_modules")
 
 
 # Header with MODULE_*_ENABLED defines.
-def modules_enabled_builder(target, source, env):
-    modules = sorted(source[0].read())
-    with methods.generated_wrapper(str(target[0])) as file:
-        for module in modules:
-            file.write(f"#define MODULE_{module.upper()}_ENABLED\n")
-
-
 modules_enabled = env.CommandNoCache(
-    "modules_enabled.gen.h", env.Value(env.module_list), env.Run(modules_enabled_builder)
+    "modules_enabled.gen.h", env.Value(env.module_list), env.Run(modules_builders.modules_enabled_builder)
 )
 
 
-def register_module_types_builder(target, source, env):
-    modules = source[0].read()
-    mod_inc = "\n".join([f'#include "{value}/register_types.h"' for value in modules.values()])
-    mod_init = "\n".join(
-        [
-            f"""\
-#ifdef MODULE_{key.upper()}_ENABLED
-	initialize_{key}_module(p_level);
-#endif"""
-            for key in modules.keys()
-        ]
-    )
-    mod_uninit = "\n".join(
-        [
-            f"""\
-#ifdef MODULE_{key.upper()}_ENABLED
-	uninitialize_{key}_module(p_level);
-#endif"""
-            for key in modules.keys()
-        ]
-    )
-    with methods.generated_wrapper(str(target[0])) as file:
-        file.write(
-            f"""\
-#include "register_module_types.h"
-
-#include "modules/modules_enabled.gen.h"
-
-{mod_inc}
-
-void initialize_modules(ModuleInitializationLevel p_level) {{
-{mod_init}
-}}
-
-void uninitialize_modules(ModuleInitializationLevel p_level) {{
-{mod_uninit}
-}}
-"""
-        )
-
-
 register_module_types = env.CommandNoCache(
     "register_module_types.gen.cpp",
     [env.Value(env.modules_detected), modules_enabled],
-    env.Run(register_module_types_builder),
+    env.Run(modules_builders.register_module_types_builder),
 )
 
 
@@ -99,14 +51,7 @@ for name, path in env.module_list.items():
 
 # Generate header to be included in `tests/test_main.cpp` to run module-specific tests.
 if env["tests"]:
-
-    def modules_tests_builder(target, source, env):
-        headers = sorted([os.path.relpath(src.path, methods.base_folder).replace("\\", "/") for src in source])
-        with methods.generated_wrapper(str(target[0])) as file:
-            for header in headers:
-                file.write(f'#include "{header}"\n')
-
-    env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_tests_builder))
+    env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_builders.modules_tests_builder))
 
 # libmodules.a with only register_module_types.
 # Must be last so that all libmodule_<name>.a libraries are on the right side

+ 60 - 0
modules/modules_builders.py

@@ -0,0 +1,60 @@
+"""Functions used to generate source files during build time"""
+
+import os
+
+import methods
+
+
+def modules_enabled_builder(target, source, env):
+    modules = sorted(source[0].read())
+    with methods.generated_wrapper(str(target[0])) as file:
+        for module in modules:
+            file.write(f"#define MODULE_{module.upper()}_ENABLED\n")
+
+
+def register_module_types_builder(target, source, env):
+    modules = source[0].read()
+    mod_inc = "\n".join([f'#include "{value}/register_types.h"' for value in modules.values()])
+    mod_init = "\n".join(
+        [
+            f"""\
+#ifdef MODULE_{key.upper()}_ENABLED
+	initialize_{key}_module(p_level);
+#endif"""
+            for key in modules.keys()
+        ]
+    )
+    mod_uninit = "\n".join(
+        [
+            f"""\
+#ifdef MODULE_{key.upper()}_ENABLED
+	uninitialize_{key}_module(p_level);
+#endif"""
+            for key in modules.keys()
+        ]
+    )
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(
+            f"""\
+#include "register_module_types.h"
+
+#include "modules/modules_enabled.gen.h"
+
+{mod_inc}
+
+void initialize_modules(ModuleInitializationLevel p_level) {{
+{mod_init}
+}}
+
+void uninitialize_modules(ModuleInitializationLevel p_level) {{
+{mod_uninit}
+}}
+"""
+        )
+
+
+def modules_tests_builder(target, source, env):
+    headers = sorted([os.path.relpath(src.path, methods.base_folder).replace("\\", "/") for src in source])
+    with methods.generated_wrapper(str(target[0])) as file:
+        for header in headers:
+            file.write(f'#include "{header}"\n')

+ 4 - 21
modules/text_server_adv/SCsub

@@ -1,32 +1,13 @@
 #!/usr/bin/env python
 from misc.utility.scons_hints import *
 
-import methods
+import text_server_adv_builders
 
 Import("env")
 Import("env_modules")
 
 env_text_server_adv = env_modules.Clone()
 
-
-def make_icu_data(target, source, env):
-    buffer = methods.get_buffer(str(source[0]))
-    with methods.generated_wrapper(str(target[0])) as file:
-        file.write(f"""\
-/* (C) 2016 and later: Unicode, Inc. and others. */
-/* License & terms of use: https://www.unicode.org/copyright.html */
-
-#include <unicode/utypes.h>
-#include <unicode/udata.h>
-#include <unicode/uversion.h>
-
-extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = {len(buffer)};
-extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {{
-	{methods.format_buffer(buffer, 1)}
-}};
-""")
-
-
 # Thirdparty source files
 
 thirdparty_obj = []
@@ -512,7 +493,9 @@ if env["builtin_icu4c"]:
 
     if env.editor_build:
         icudata = env_icu.CommandNoCache(
-            "#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/icudt_godot.dat", env.Run(make_icu_data)
+            "#thirdparty/icu4c/icudata.gen.h",
+            "#thirdparty/icu4c/icudt_godot.dat",
+            env.Run(text_server_adv_builders.make_icu_data),
         )
         env_text_server_adv.Prepend(CPPEXTPATH=["#thirdparty/icu4c/"])
         env_icu.Depends(lib, icudata)

+ 21 - 0
modules/text_server_adv/text_server_adv_builders.py

@@ -0,0 +1,21 @@
+"""Functions used to generate source files during build time"""
+
+import methods
+
+
+def make_icu_data(target, source, env):
+    buffer = methods.get_buffer(str(source[0]))
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(f"""\
+/* (C) 2016 and later: Unicode, Inc. and others. */
+/* License & terms of use: https://www.unicode.org/copyright.html */
+
+#include <unicode/utypes.h>
+#include <unicode/udata.h>
+#include <unicode/uversion.h>
+
+extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = {len(buffer)};
+extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {{
+	{methods.format_buffer(buffer, 1)}
+}};
+""")

+ 5 - 41
platform/SCsub

@@ -2,9 +2,8 @@
 from misc.utility.scons_hints import *
 
 from glob import glob
-from pathlib import Path
 
-import methods
+import platform_builders
 
 Import("env")
 
@@ -12,51 +11,16 @@ env.platform_sources = []
 
 
 # Generate export icons
-def export_icon_builder(target, source, env):
-    src_path = Path(str(source[0]))
-    src_name = src_path.stem
-    platform = src_path.parent.parent.stem
-    with open(str(source[0]), "r") as file:
-        svg = file.read()
-    with methods.generated_wrapper(str(target[0])) as file:
-        file.write(
-            f"""\
-inline constexpr const char *_{platform}_{src_name}_svg = {methods.to_raw_cstring(svg)};
-"""
-        )
-
-
 for platform in env.platform_exporters:
     for path in glob(f"{platform}/export/*.svg"):
-        env.CommandNoCache(path.replace(".svg", "_svg.gen.h"), path, env.Run(export_icon_builder))
+        env.CommandNoCache(path.replace(".svg", "_svg.gen.h"), path, env.Run(platform_builders.export_icon_builder))
 
 
 # Register platform-exclusive APIs
-def register_platform_apis_builder(target, source, env):
-    platforms = source[0].read()
-    api_inc = "\n".join([f'#include "{p}/api/api.h"' for p in platforms])
-    api_reg = "\n".join([f"\tregister_{p}_api();" for p in platforms])
-    api_unreg = "\n".join([f"\tunregister_{p}_api();" for p in platforms])
-    with methods.generated_wrapper(str(target[0])) as file:
-        file.write(
-            f"""\
-#include "register_platform_apis.h"
-
-{api_inc}
-
-void register_platform_apis() {{
-{api_reg}
-}}
-
-void unregister_platform_apis() {{
-{api_unreg}
-}}
-"""
-        )
-
-
 register_platform_apis = env.CommandNoCache(
-    "register_platform_apis.gen.cpp", env.Value(env.platform_apis), env.Run(register_platform_apis_builder)
+    "register_platform_apis.gen.cpp",
+    env.Value(env.platform_apis),
+    env.Run(platform_builders.register_platform_apis_builder),
 )
 env.add_source_files(env.platform_sources, register_platform_apis)
 for platform in env.platform_apis:

+ 5 - 28
platform/android/SCsub

@@ -2,9 +2,10 @@
 from misc.utility.scons_hints import *
 
 import platform
-import subprocess
 import sys
 
+import platform_android_builders
+
 from methods import print_warning
 
 Import("env")
@@ -101,33 +102,9 @@ if lib_arch_dir != "" and host_subpath != "":
     stl_lib_path = f"{env['ANDROID_NDK_ROOT']}/toolchains/llvm/prebuilt/{host_subpath}/sysroot/usr/lib/{triple_target_dir}/libc++_shared.so"
     env_android.CommandNoCache(out_dir + "/libc++_shared.so", stl_lib_path, Copy("$TARGET", "$SOURCE"))
 
-    def generate_android_binaries(target, source, env):
-        gradle_process = []
-
-        if sys.platform.startswith("win"):
-            gradle_process = [
-                "cmd",
-                "/c",
-                "gradlew.bat",
-            ]
-        else:
-            gradle_process = ["./gradlew"]
-
-        if env["target"] == "editor":
-            gradle_process += ["generateGodotEditor", "generateGodotHorizonOSEditor", "generateGodotPicoOSEditor"]
-        else:
-            gradle_process += ["generateGodotTemplates"]
-        gradle_process += ["--quiet"]
-
-        if env["gradle_do_not_strip"]:
-            gradle_process += ["-PdoNotStrip=true"]
-
-        subprocess.run(
-            gradle_process,
-            cwd="platform/android/java",
-        )
-
     if env["generate_android_binaries"]:
         env_android.AlwaysBuild(
-            env_android.CommandNoCache("generate_android_binaries", lib, env.Run(generate_android_binaries))
+            env_android.CommandNoCache(
+                "generate_android_binaries", lib, env.Run(platform_android_builders.generate_android_binaries)
+            )
         )

+ 31 - 0
platform/android/platform_android_builders.py

@@ -0,0 +1,31 @@
+"""Functions used to generate source files during build time"""
+
+import subprocess
+import sys
+
+
+def generate_android_binaries(target, source, env):
+    gradle_process = []
+
+    if sys.platform.startswith("win"):
+        gradle_process = [
+            "cmd",
+            "/c",
+            "gradlew.bat",
+        ]
+    else:
+        gradle_process = ["./gradlew"]
+
+    if env["target"] == "editor":
+        gradle_process += ["generateGodotEditor", "generateGodotHorizonOSEditor", "generateGodotPicoOSEditor"]
+    else:
+        gradle_process += ["generateGodotTemplates"]
+    gradle_process += ["--quiet"]
+
+    if env["gradle_do_not_strip"]:
+        gradle_process += ["-PdoNotStrip=true"]
+
+    subprocess.run(
+        gradle_process,
+        cwd="platform/android/java",
+    )

+ 6 - 69
platform/ios/SCsub

@@ -1,63 +1,9 @@
 #!/usr/bin/env python
 from misc.utility.scons_hints import *
 
-Import("env")
-
-import os
-import shutil
-
-from platform_methods import detect_mvk, lipo
-
-
-def generate_bundle(target, source, env):
-    bin_dir = Dir("#bin").abspath
-
-    # Template bundle.
-    app_prefix = "godot." + env["platform"]
-    rel_prefix = "libgodot." + env["platform"] + "." + "template_release"
-    dbg_prefix = "libgodot." + env["platform"] + "." + "template_debug"
-    if env.dev_build:
-        app_prefix += ".dev"
-        rel_prefix += ".dev"
-        dbg_prefix += ".dev"
-    if env["precision"] == "double":
-        app_prefix += ".double"
-        rel_prefix += ".double"
-        dbg_prefix += ".double"
-
-    # Lipo template libraries.
-    rel_target_bin = lipo(bin_dir + "/" + rel_prefix, env.extra_suffix + ".a")
-    dbg_target_bin = lipo(bin_dir + "/" + dbg_prefix, env.extra_suffix + ".a")
-    rel_target_bin_sim = lipo(bin_dir + "/" + rel_prefix, ".simulator" + env.extra_suffix + ".a")
-    dbg_target_bin_sim = lipo(bin_dir + "/" + dbg_prefix, ".simulator" + env.extra_suffix + ".a")
-
-    # Assemble Xcode project bundle.
-    app_dir = Dir("#bin/ios_xcode").abspath
-    templ = Dir("#misc/dist/ios_xcode").abspath
-    if os.path.exists(app_dir):
-        shutil.rmtree(app_dir)
-    shutil.copytree(templ, app_dir)
-    if rel_target_bin != "":
-        shutil.copy(rel_target_bin, app_dir + "/libgodot.ios.release.xcframework/ios-arm64/libgodot.a")
-    if dbg_target_bin != "":
-        shutil.copy(dbg_target_bin, app_dir + "/libgodot.ios.debug.xcframework/ios-arm64/libgodot.a")
-    if rel_target_bin_sim != "":
-        shutil.copy(
-            rel_target_bin_sim, app_dir + "/libgodot.ios.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a"
-        )
-    if dbg_target_bin_sim != "":
-        shutil.copy(
-            dbg_target_bin_sim, app_dir + "/libgodot.ios.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a"
-        )
-    mvk_path = detect_mvk(env, "ios-arm64")
-    if mvk_path != "":
-        shutil.copytree(mvk_path, app_dir + "/MoltenVK.xcframework")
-
-    # ZIP Xcode project bundle.
-    zip_dir = Dir("#bin/" + (app_prefix + env.extra_suffix).replace(".", "_")).abspath
-    shutil.make_archive(zip_dir, "zip", root_dir=app_dir)
-    shutil.rmtree(app_dir)
+import platform_ios_builders
 
+Import("env")
 
 ios_lib = [
     "godot_ios.mm",
@@ -86,20 +32,11 @@ ios_lib = env_ios.add_library("ios", ios_lib)
 env_ios.Append(CCFLAGS=["-fmodules", "-fcxx-modules"])
 
 
-def combine_libs(target=None, source=None, env=None):
-    lib_path = target[0].srcnode().abspath
-    if "osxcross" in env:
-        libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}libtool"
-    else:
-        libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/libtool"
-    env.Execute(
-        libtool + ' -static -o "' + lib_path + '" ' + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source])
-    )
-
-
 combine_command = env_ios.CommandNoCache(
-    "#bin/libgodot" + env_ios["LIBSUFFIX"], [ios_lib] + env_ios["LIBS"], env.Run(combine_libs)
+    "#bin/libgodot" + env_ios["LIBSUFFIX"], [ios_lib] + env_ios["LIBS"], env.Run(platform_ios_builders.combine_libs)
 )
 
 if env["generate_bundle"]:
-    env.AlwaysBuild(env.CommandNoCache("generate_bundle", combine_command, env.Run(generate_bundle)))
+    env.AlwaysBuild(
+        env.CommandNoCache("generate_bundle", combine_command, env.Run(platform_ios_builders.generate_bundle))
+    )

+ 67 - 0
platform/ios/platform_ios_builders.py

@@ -0,0 +1,67 @@
+"""Functions used to generate source files during build time"""
+
+import os
+import shutil
+
+from platform_methods import detect_mvk, lipo
+
+
+def combine_libs(target, source, env):
+    lib_path = target[0].srcnode().abspath
+    if "osxcross" in env:
+        libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}libtool"
+    else:
+        libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/libtool"
+    env.Execute(
+        libtool + ' -static -o "' + lib_path + '" ' + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source])
+    )
+
+
+def generate_bundle(target, source, env):
+    bin_dir = env.Dir("#bin").abspath
+
+    # Template bundle.
+    app_prefix = "godot." + env["platform"]
+    rel_prefix = "libgodot." + env["platform"] + "." + "template_release"
+    dbg_prefix = "libgodot." + env["platform"] + "." + "template_debug"
+    if env.dev_build:
+        app_prefix += ".dev"
+        rel_prefix += ".dev"
+        dbg_prefix += ".dev"
+    if env["precision"] == "double":
+        app_prefix += ".double"
+        rel_prefix += ".double"
+        dbg_prefix += ".double"
+
+    # Lipo template libraries.
+    rel_target_bin = lipo(bin_dir + "/" + rel_prefix, env.extra_suffix + ".a")
+    dbg_target_bin = lipo(bin_dir + "/" + dbg_prefix, env.extra_suffix + ".a")
+    rel_target_bin_sim = lipo(bin_dir + "/" + rel_prefix, ".simulator" + env.extra_suffix + ".a")
+    dbg_target_bin_sim = lipo(bin_dir + "/" + dbg_prefix, ".simulator" + env.extra_suffix + ".a")
+
+    # Assemble Xcode project bundle.
+    app_dir = env.Dir("#bin/ios_xcode").abspath
+    templ = env.Dir("#misc/dist/ios_xcode").abspath
+    if os.path.exists(app_dir):
+        shutil.rmtree(app_dir)
+    shutil.copytree(templ, app_dir)
+    if rel_target_bin != "":
+        shutil.copy(rel_target_bin, app_dir + "/libgodot.ios.release.xcframework/ios-arm64/libgodot.a")
+    if dbg_target_bin != "":
+        shutil.copy(dbg_target_bin, app_dir + "/libgodot.ios.debug.xcframework/ios-arm64/libgodot.a")
+    if rel_target_bin_sim != "":
+        shutil.copy(
+            rel_target_bin_sim, app_dir + "/libgodot.ios.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a"
+        )
+    if dbg_target_bin_sim != "":
+        shutil.copy(
+            dbg_target_bin_sim, app_dir + "/libgodot.ios.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a"
+        )
+    mvk_path = detect_mvk(env, "ios-arm64")
+    if mvk_path != "":
+        shutil.copytree(mvk_path, app_dir + "/MoltenVK.xcframework")
+
+    # ZIP Xcode project bundle.
+    zip_dir = env.Dir("#bin/" + (app_prefix + env.extra_suffix).replace(".", "_")).abspath
+    shutil.make_archive(zip_dir, "zip", root_dir=app_dir)
+    shutil.rmtree(app_dir)

+ 2 - 110
platform/macos/SCsub

@@ -1,117 +1,9 @@
 #!/usr/bin/env python
 from misc.utility.scons_hints import *
 
-Import("env")
-
-import os
-import shutil
-import subprocess
-
 import platform_macos_builders
 
-from platform_methods import get_build_version, lipo
-
-
-def generate_bundle(target, source, env):
-    bin_dir = Dir("#bin").abspath
-
-    if env.editor_build:
-        # Editor bundle.
-        prefix = "godot." + env["platform"] + "." + env["target"]
-        if env.dev_build:
-            prefix += ".dev"
-        if env["precision"] == "double":
-            prefix += ".double"
-
-        # Lipo editor executable.
-        target_bin = lipo(bin_dir + "/" + prefix, env.extra_suffix + env.module_version_string)
-
-        # Assemble .app bundle and update version info.
-        app_dir = Dir(
-            "#bin/" + (prefix + env.extra_suffix + env.module_version_string).replace(".", "_") + ".app"
-        ).abspath
-        templ = Dir("#misc/dist/macos_tools.app").abspath
-        if os.path.exists(app_dir):
-            shutil.rmtree(app_dir)
-
-        # Create the .app bundle directory itself from scratch so that the creation
-        # date is accurate, but copy the rest of the template over.
-        os.mkdir(app_dir)
-        shutil.copytree(
-            os.path.join(templ, "Contents"),
-            os.path.join(app_dir, "Contents"),
-            ignore=shutil.ignore_patterns("Info.plist"),
-        )
-
-        if not os.path.isdir(app_dir + "/Contents/MacOS"):
-            os.mkdir(app_dir + "/Contents/MacOS")
-        if target_bin != "":
-            shutil.copy(target_bin, app_dir + "/Contents/MacOS/Godot")
-        if "mono" in env.module_version_string:
-            shutil.copytree(Dir("#bin/GodotSharp").abspath, app_dir + "/Contents/Resources/GodotSharp")
-        version = get_build_version(False)
-        short_version = get_build_version(True)
-        with open(Dir("#misc/dist/macos").abspath + "/editor_info_plist.template", "rt", encoding="utf-8") as fin:
-            with open(app_dir + "/Contents/Info.plist", "wt", encoding="utf-8", newline="\n") as fout:
-                for line in fin:
-                    line = line.replace("$version", version)
-                    line = line.replace("$short_version", short_version)
-                    fout.write(line)
-
-        # Sign .app bundle.
-        if env["bundle_sign_identity"] != "":
-            sign_command = [
-                "codesign",
-                "-s",
-                env["bundle_sign_identity"],
-                "--deep",
-                "--force",
-                "--options=runtime",
-                "--entitlements",
-            ]
-            if env.dev_build:
-                sign_command += [Dir("#misc/dist/macos").abspath + "/editor_debug.entitlements"]
-            else:
-                sign_command += [Dir("#misc/dist/macos").abspath + "/editor.entitlements"]
-            sign_command += [app_dir]
-            subprocess.run(sign_command)
-
-    else:
-        # Template bundle.
-        app_prefix = "godot." + env["platform"]
-        rel_prefix = "godot." + env["platform"] + "." + "template_release"
-        dbg_prefix = "godot." + env["platform"] + "." + "template_debug"
-        if env.dev_build:
-            app_prefix += ".dev"
-            rel_prefix += ".dev"
-            dbg_prefix += ".dev"
-        if env["precision"] == "double":
-            app_prefix += ".double"
-            rel_prefix += ".double"
-            dbg_prefix += ".double"
-
-        # Lipo template executables.
-        rel_target_bin = lipo(bin_dir + "/" + rel_prefix, env.extra_suffix + env.module_version_string)
-        dbg_target_bin = lipo(bin_dir + "/" + dbg_prefix, env.extra_suffix + env.module_version_string)
-
-        # Assemble .app bundle.
-        app_dir = Dir("#bin/macos_template.app").abspath
-        templ = Dir("#misc/dist/macos_template.app").abspath
-        if os.path.exists(app_dir):
-            shutil.rmtree(app_dir)
-        shutil.copytree(templ, app_dir)
-        if not os.path.isdir(app_dir + "/Contents/MacOS"):
-            os.mkdir(app_dir + "/Contents/MacOS")
-        if rel_target_bin != "":
-            shutil.copy(rel_target_bin, app_dir + "/Contents/MacOS/godot_macos_release.universal")
-        if dbg_target_bin != "":
-            shutil.copy(dbg_target_bin, app_dir + "/Contents/MacOS/godot_macos_debug.universal")
-
-        # ZIP .app bundle.
-        zip_dir = Dir("#bin/" + (app_prefix + env.extra_suffix + env.module_version_string).replace(".", "_")).abspath
-        shutil.make_archive(zip_dir, "zip", root_dir=bin_dir, base_dir="macos_template.app")
-        shutil.rmtree(app_dir)
-
+Import("env")
 
 files = [
     "os_macos.mm",
@@ -144,4 +36,4 @@ if env["debug_symbols"] and env["separate_debug_symbols"]:
     env.AddPostAction(prog, env.Run(platform_macos_builders.make_debug_macos))
 
 if env["generate_bundle"]:
-    env.AlwaysBuild(env.CommandNoCache("generate_bundle", prog, env.Run(generate_bundle)))
+    env.AlwaysBuild(env.CommandNoCache("generate_bundle", prog, env.Run(platform_macos_builders.generate_bundle)))

+ 107 - 0
platform/macos/platform_macos_builders.py

@@ -1,6 +1,113 @@
 """Functions used to generate source files during build time"""
 
 import os
+import shutil
+import subprocess
+
+from platform_methods import get_build_version, lipo
+
+
+def generate_bundle(target, source, env):
+    bin_dir = env.Dir("#bin").abspath
+
+    if env.editor_build:
+        # Editor bundle.
+        prefix = "godot." + env["platform"] + "." + env["target"]
+        if env.dev_build:
+            prefix += ".dev"
+        if env["precision"] == "double":
+            prefix += ".double"
+
+        # Lipo editor executable.
+        target_bin = lipo(bin_dir + "/" + prefix, env.extra_suffix + env.module_version_string)
+
+        # Assemble .app bundle and update version info.
+        app_dir = env.Dir(
+            "#bin/" + (prefix + env.extra_suffix + env.module_version_string).replace(".", "_") + ".app"
+        ).abspath
+        templ = env.Dir("#misc/dist/macos_tools.app").abspath
+        if os.path.exists(app_dir):
+            shutil.rmtree(app_dir)
+
+        # Create the .app bundle directory itself from scratch so that the creation
+        # date is accurate, but copy the rest of the template over.
+        os.mkdir(app_dir)
+        shutil.copytree(
+            os.path.join(templ, "Contents"),
+            os.path.join(app_dir, "Contents"),
+            ignore=shutil.ignore_patterns("Info.plist"),
+        )
+
+        if not os.path.isdir(app_dir + "/Contents/MacOS"):
+            os.mkdir(app_dir + "/Contents/MacOS")
+        if target_bin != "":
+            shutil.copy(target_bin, app_dir + "/Contents/MacOS/Godot")
+        if "mono" in env.module_version_string:
+            shutil.copytree(env.Dir("#bin/GodotSharp").abspath, app_dir + "/Contents/Resources/GodotSharp")
+        version = get_build_version(False)
+        short_version = get_build_version(True)
+        with open(env.Dir("#misc/dist/macos").abspath + "/editor_info_plist.template", "rt", encoding="utf-8") as fin:
+            with open(app_dir + "/Contents/Info.plist", "wt", encoding="utf-8", newline="\n") as fout:
+                for line in fin:
+                    line = line.replace("$version", version)
+                    line = line.replace("$short_version", short_version)
+                    fout.write(line)
+
+        # Sign .app bundle.
+        if env["bundle_sign_identity"] != "":
+            sign_command = [
+                "codesign",
+                "-s",
+                env["bundle_sign_identity"],
+                "--deep",
+                "--force",
+                "--options=runtime",
+                "--entitlements",
+            ]
+            if env.dev_build:
+                sign_command += [env.Dir("#misc/dist/macos").abspath + "/editor_debug.entitlements"]
+            else:
+                sign_command += [env.Dir("#misc/dist/macos").abspath + "/editor.entitlements"]
+            sign_command += [app_dir]
+            subprocess.run(sign_command)
+
+    else:
+        # Template bundle.
+        app_prefix = "godot." + env["platform"]
+        rel_prefix = "godot." + env["platform"] + "." + "template_release"
+        dbg_prefix = "godot." + env["platform"] + "." + "template_debug"
+        if env.dev_build:
+            app_prefix += ".dev"
+            rel_prefix += ".dev"
+            dbg_prefix += ".dev"
+        if env["precision"] == "double":
+            app_prefix += ".double"
+            rel_prefix += ".double"
+            dbg_prefix += ".double"
+
+        # Lipo template executables.
+        rel_target_bin = lipo(bin_dir + "/" + rel_prefix, env.extra_suffix + env.module_version_string)
+        dbg_target_bin = lipo(bin_dir + "/" + dbg_prefix, env.extra_suffix + env.module_version_string)
+
+        # Assemble .app bundle.
+        app_dir = env.Dir("#bin/macos_template.app").abspath
+        templ = env.Dir("#misc/dist/macos_template.app").abspath
+        if os.path.exists(app_dir):
+            shutil.rmtree(app_dir)
+        shutil.copytree(templ, app_dir)
+        if not os.path.isdir(app_dir + "/Contents/MacOS"):
+            os.mkdir(app_dir + "/Contents/MacOS")
+        if rel_target_bin != "":
+            shutil.copy(rel_target_bin, app_dir + "/Contents/MacOS/godot_macos_release.universal")
+        if dbg_target_bin != "":
+            shutil.copy(dbg_target_bin, app_dir + "/Contents/MacOS/godot_macos_debug.universal")
+
+        # ZIP .app bundle.
+        zip_dir = env.Dir(
+            "#bin/" + (app_prefix + env.extra_suffix + env.module_version_string).replace(".", "_")
+        ).abspath
+        shutil.make_archive(zip_dir, "zip", root_dir=bin_dir, base_dir="macos_template.app")
+        shutil.rmtree(app_dir)
 
 
 def make_debug_macos(target, source, env):

+ 44 - 0
platform/platform_builders.py

@@ -0,0 +1,44 @@
+"""Functions used to generate source files during build time"""
+
+from pathlib import Path
+
+import methods
+
+
+def export_icon_builder(target, source, env):
+    src_path = Path(str(source[0]))
+    src_name = src_path.stem
+    platform = src_path.parent.parent.stem
+
+    with open(str(source[0]), "r") as file:
+        svg = file.read()
+
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(
+            f"""\
+inline constexpr const char *_{platform}_{src_name}_svg = {methods.to_raw_cstring(svg)};
+"""
+        )
+
+
+def register_platform_apis_builder(target, source, env):
+    platforms = source[0].read()
+    api_inc = "\n".join([f'#include "{p}/api/api.h"' for p in platforms])
+    api_reg = "\n\t".join([f"register_{p}_api();" for p in platforms])
+    api_unreg = "\n\t".join([f"unregister_{p}_api();" for p in platforms])
+    with methods.generated_wrapper(str(target[0])) as file:
+        file.write(
+            f"""\
+#include "register_platform_apis.h"
+
+{api_inc}
+
+void register_platform_apis() {{
+	{api_reg}
+}}
+
+void unregister_platform_apis() {{
+	{api_unreg}
+}}
+"""
+        )