summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SConstruct13
-rw-r--r--core/SCsub129
-rw-r--r--editor/SCsub83
-rw-r--r--methods.py244
-rw-r--r--modules/SCsub65
-rw-r--r--modules/modules_builders.py15
-rw-r--r--platform/SCsub65
-rw-r--r--platform_methods.py27
8 files changed, 361 insertions, 280 deletions
diff --git a/SConstruct b/SConstruct
index 81ce4bca52..cfedcc84ed 100644
--- a/SConstruct
+++ b/SConstruct
@@ -61,7 +61,6 @@ _helper_module("platform_methods", "platform_methods.py")
_helper_module("version", "version.py")
_helper_module("core.core_builders", "core/core_builders.py")
_helper_module("main.main_builders", "main/main_builders.py")
-_helper_module("modules.modules_builders", "modules/modules_builders.py")
# Local
import methods
@@ -69,7 +68,7 @@ import glsl_builders
import gles3_builders
import scu_builders
from methods import print_warning, print_error
-from platform_methods import architectures, architecture_aliases, generate_export_icons
+from platform_methods import architectures, architecture_aliases
if ARGUMENTS.get("target", "editor") == "editor":
_helper_module("editor.editor_builders", "editor/editor_builders.py")
@@ -107,7 +106,6 @@ for x in sorted(glob.glob("platform/*")):
if os.path.exists(x + "/export/export.cpp"):
platform_exporters.append(platform_name)
- generate_export_icons(x, platform_name)
if os.path.exists(x + "/api/api.cpp"):
platform_apis.append(platform_name)
if detect.can_build():
@@ -428,7 +426,7 @@ for name, path in modules_detected.items():
sys.path.remove(path)
sys.modules.pop("config")
-methods.write_modules(modules_detected)
+env.modules_detected = modules_detected
# Update the environment again after all the module options are added.
opts.Update(env)
@@ -544,7 +542,7 @@ env.Append(CFLAGS=env.get("cflags", "").split())
env.Append(LINKFLAGS=env.get("linkflags", "").split())
# Feature build profile
-disabled_classes = []
+env.disabled_classes = []
if env["build_profile"] != "":
print('Using feature build profile: "{}"'.format(env["build_profile"]))
import json
@@ -552,7 +550,7 @@ if env["build_profile"] != "":
try:
ft = json.load(open(env["build_profile"]))
if "disabled_classes" in ft:
- disabled_classes = ft["disabled_classes"]
+ env.disabled_classes = ft["disabled_classes"]
if "disabled_build_options" in ft:
dbo = ft["disabled_build_options"]
for c in dbo:
@@ -560,7 +558,6 @@ if env["build_profile"] != "":
except:
print_error('Failed to open feature build profile: "{}"'.format(env["build_profile"]))
Exit(255)
-methods.write_disabled_classes(disabled_classes)
# Platform specific flags.
# These can sometimes override default options.
@@ -926,7 +923,7 @@ if env.editor_build:
print_error("Not all modules required by editor builds are enabled.")
Exit(255)
-methods.generate_version_header(env.module_version_string)
+env.version_info = methods.get_version_info(env.module_version_string)
env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"]
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
diff --git a/core/SCsub b/core/SCsub
index 91620cb075..640c6de6a1 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -4,44 +4,9 @@ Import("env")
import core_builders
import methods
-
-env.core_sources = []
-
-
-# Generate AES256 script encryption key
import os
-txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0"
-if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ:
- key = os.environ["SCRIPT_AES256_ENCRYPTION_KEY"]
- ec_valid = True
- if len(key) != 64:
- ec_valid = False
- else:
- txt = ""
- for i in range(len(key) >> 1):
- if i > 0:
- txt += ","
- txts = "0x" + key[i * 2 : i * 2 + 2]
- try:
- int(txts, 16)
- except Exception:
- ec_valid = False
- txt += txts
- if not ec_valid:
- methods.print_error(
- f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{key}".\n'
- "Unset 'SCRIPT_AES256_ENCRYPTION_KEY' in your environment "
- "or make sure that it contains exactly 64 hexadecimal characters."
- )
- Exit(255)
-
-
-script_encryption_key_contents = (
- '#include "core/config/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n"
-)
-
-methods.write_file_if_needed("script_encryption_key.gen.cpp", script_encryption_key_contents)
+env.core_sources = []
# Add required thirdparty code.
@@ -193,8 +158,96 @@ env.core_sources += thirdparty_obj
# Godot source files
env.add_source_files(env.core_sources, "*.cpp")
-env.add_source_files(env.core_sources, "script_encryption_key.gen.cpp")
-env.add_source_files(env.core_sources, "version_hash.gen.cpp")
+
+
+# Generate disabled classes
+def disabled_class_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for c in source[0].read():
+ cs = c.strip()
+ if cs != "":
+ file.write(f"#define ClassDB_Disable_{cs} 1")
+
+
+env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(disabled_class_builder))
+
+
+# Generate version info
+def version_info_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ """\
+#define VERSION_SHORT_NAME "{short_name}"
+#define VERSION_NAME "{name}"
+#define VERSION_MAJOR {major}
+#define VERSION_MINOR {minor}
+#define VERSION_PATCH {patch}
+#define VERSION_STATUS "{status}"
+#define VERSION_BUILD "{build}"
+#define VERSION_MODULE_CONFIG "{module_config}"
+#define VERSION_WEBSITE "{website}"
+#define VERSION_DOCS_BRANCH "{docs_branch}"
+#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
+""".format(
+ **env.version_info
+ )
+ )
+
+
+env.CommandNoCache("version_generated.gen.h", "#version.py", env.Run(version_info_builder))
+
+
+# Generate version hash
+def version_hash_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ """\
+#include "core/version.h"
+
+const char *const VERSION_HASH = "{git_hash}";
+const uint64_t VERSION_TIMESTAMP = {git_timestamp};
+""".format(
+ **env.version_info
+ )
+ )
+
+
+gen_hash = env.CommandNoCache(
+ "version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(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(target) 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))
+env.add_source_files(env.core_sources, gen_encrypt)
+
# Certificates
env.Depends(
diff --git a/editor/SCsub b/editor/SCsub
index e3b17b83f8..e613a71238 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -10,40 +10,59 @@ import editor_builders
import methods
-def _make_doc_data_class_path(to_path):
- file_path = os.path.join(to_path, "doc_data_class_path.gen.h")
-
- class_path_data = ""
- class_path_data += "static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n"
- class_path_data += "struct _DocDataClassPath { const char* name; const char* path; };\n"
- class_path_data += (
- "static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n"
- )
- for c in sorted(env.doc_class_path):
- class_path_data += '\t{"' + c + '", "' + env.doc_class_path[c] + '"},\n'
- class_path_data += "\t{nullptr, nullptr}\n"
- class_path_data += "};\n"
-
- methods.write_file_if_needed(file_path, class_path_data)
-
-
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(target) as file:
+ file.write(
+ f"""\
+static const int _doc_data_class_path_count = {len(paths)};
+
+struct _DocDataClassPath {{
+ const char *name;
+ const char *path;
+}};
+
+static const _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))
+
# Register exporters
- reg_exporters_inc = '#include "register_exporters.h"\n\n'
- reg_exporters = "void register_exporters() {\n"
+ 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(target) 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)
+ )
for e in env.platform_exporters:
# Add all .cpp files in export folder
- env.add_source_files(env.editor_sources, "../platform/" + e + "/export/" + "*.cpp")
-
- reg_exporters += "\tregister_" + e + "_exporter();\n"
- reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n'
- reg_exporters += "}\n\n"
- reg_exporters += "void register_exporter_types() {\n"
- for e in env.platform_exporters:
- reg_exporters += "\tregister_" + e + "_exporter_types();\n"
- reg_exporters += "}\n"
-
- methods.write_file_if_needed("register_exporters.gen.cpp", reg_exporters_inc + reg_exporters)
+ env.add_source_files(env.editor_sources, f"../platform/{e}/export/*.cpp")
# Core API documentation.
docs = []
@@ -61,8 +80,6 @@ if env.editor_build:
else:
docs += Glob(d + "/*.xml") # Custom.
- _make_doc_data_class_path(env.Dir("#editor").abspath)
-
docs = sorted(docs)
env.Depends("#editor/doc_data_compressed.gen.h", docs)
env.CommandNoCache(
@@ -115,7 +132,7 @@ if env.editor_build:
)
env.add_source_files(env.editor_sources, "*.cpp")
- env.add_source_files(env.editor_sources, "register_exporters.gen.cpp")
+ env.add_source_files(env.editor_sources, gen_exporters)
SConscript("debugger/SCsub")
SConscript("export/SCsub")
diff --git a/methods.py b/methods.py
index 0c29632f10..da221cc0ea 100644
--- a/methods.py
+++ b/methods.py
@@ -3,13 +3,16 @@ import sys
import re
import glob
import subprocess
+import contextlib
from collections import OrderedDict
from collections.abc import Mapping
from enum import Enum
-from typing import Iterator
+from typing import Generator, Optional
+from io import TextIOWrapper, StringIO
from pathlib import Path
from os.path import normpath, basename
+
# Get the "Godot" folder name ahead of time
base_folder_path = str(os.path.abspath(Path(__file__).parent)) + "/"
base_folder_only = os.path.basename(os.path.normpath(base_folder_path))
@@ -277,79 +280,6 @@ def get_version_info(module_version_string="", silent=False):
return version_info
-_cleanup_env = None
-_cleanup_bool = False
-
-
-def write_file_if_needed(path, string):
- """Generates a file only if it doesn't already exist or the content has changed.
-
- Utilizes a dedicated SCons environment to ensure the files are properly removed
- during cleanup; will not attempt to create files during cleanup.
-
- - `path` - Path to the file in question; used to create cleanup logic.
- - `string` - Content to compare against an existing file.
- """
- global _cleanup_env
- global _cleanup_bool
-
- if _cleanup_env is None:
- from SCons.Environment import Environment
-
- _cleanup_env = Environment()
- _cleanup_bool = _cleanup_env.GetOption("clean")
-
- _cleanup_env.Clean("#", path)
- if _cleanup_bool:
- return
-
- try:
- with open(path, "r", encoding="utf-8", newline="\n") as f:
- if f.read() == string:
- return
- except FileNotFoundError:
- pass
-
- with open(path, "w", encoding="utf-8", newline="\n") as f:
- f.write(string)
-
-
-def generate_version_header(module_version_string=""):
- version_info = get_version_info(module_version_string)
-
- version_info_header = """\
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#ifndef VERSION_GENERATED_GEN_H
-#define VERSION_GENERATED_GEN_H
-#define VERSION_SHORT_NAME "{short_name}"
-#define VERSION_NAME "{name}"
-#define VERSION_MAJOR {major}
-#define VERSION_MINOR {minor}
-#define VERSION_PATCH {patch}
-#define VERSION_STATUS "{status}"
-#define VERSION_BUILD "{build}"
-#define VERSION_MODULE_CONFIG "{module_config}"
-#define VERSION_WEBSITE "{website}"
-#define VERSION_DOCS_BRANCH "{docs_branch}"
-#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
-#endif // VERSION_GENERATED_GEN_H
-""".format(
- **version_info
- )
-
- version_hash_data = """\
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#include "core/version.h"
-const char *const VERSION_HASH = "{git_hash}";
-const uint64_t VERSION_TIMESTAMP = {git_timestamp};
-""".format(
- **version_info
- )
-
- write_file_if_needed("core/version_generated.gen.h", version_info_header)
- write_file_if_needed("core/version_hash.gen.cpp", version_hash_data)
-
-
def parse_cg_file(fname, uniforms, sizes, conditionals):
with open(fname, "r", encoding="utf-8") as fs:
line = fs.readline()
@@ -465,63 +395,6 @@ def is_module(path):
return True
-def write_disabled_classes(class_list):
- file_contents = ""
-
- file_contents += "/* THIS FILE IS GENERATED DO NOT EDIT */\n"
- file_contents += "#ifndef DISABLED_CLASSES_GEN_H\n"
- file_contents += "#define DISABLED_CLASSES_GEN_H\n\n"
- for c in class_list:
- cs = c.strip()
- if cs != "":
- file_contents += "#define ClassDB_Disable_" + cs + " 1\n"
- file_contents += "\n#endif\n"
-
- write_file_if_needed("core/disabled_classes.gen.h", file_contents)
-
-
-def write_modules(modules):
- includes_cpp = ""
- initialize_cpp = ""
- uninitialize_cpp = ""
-
- for name, path in modules.items():
- try:
- with open(os.path.join(path, "register_types.h")):
- includes_cpp += '#include "' + path + '/register_types.h"\n'
- initialize_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
- initialize_cpp += "\tinitialize_" + name + "_module(p_level);\n"
- initialize_cpp += "#endif\n"
- uninitialize_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
- uninitialize_cpp += "\tuninitialize_" + name + "_module(p_level);\n"
- uninitialize_cpp += "#endif\n"
- except OSError:
- pass
-
- modules_cpp = """// register_module_types.gen.cpp
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#include "register_module_types.h"
-
-#include "modules/modules_enabled.gen.h"
-
-%s
-
-void initialize_modules(ModuleInitializationLevel p_level) {
-%s
-}
-
-void uninitialize_modules(ModuleInitializationLevel p_level) {
-%s
-}
-""" % (
- includes_cpp,
- initialize_cpp,
- uninitialize_cpp,
- )
-
- write_file_if_needed("modules/register_module_types.gen.cpp", modules_cpp)
-
-
def convert_custom_modules_path(path):
if not path:
return path
@@ -1649,3 +1522,112 @@ def generate_vs_project(env, original_args, project_name="godot"):
if get_bool(original_args, "vsproj_gen_only", True):
sys.exit()
+
+
+def generate_copyright_header(filename: str) -> str:
+ MARGIN = 70
+ TEMPLATE = """\
+/**************************************************************************/
+/* %s*/
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+"""
+ filename = filename.split("/")[-1].ljust(MARGIN)
+ if len(filename) > MARGIN:
+ print(f'WARNING: Filename "{filename}" too large for copyright header.')
+ return TEMPLATE % filename
+
+
+@contextlib.contextmanager
+def generated_wrapper(
+ path, # FIXME: type with `Union[str, Node, List[Node]]` when pytest conflicts are resolved
+ guard: Optional[bool] = None,
+ prefix: str = "",
+ suffix: str = "",
+) -> Generator[TextIOWrapper, None, None]:
+ """
+ Wrapper class to automatically handle copyright headers and header guards
+ for generated scripts. Meant to be invoked via `with` statement similar to
+ creating a file.
+
+ - `path`: The path of the file to be created. Can be passed a raw string, an
+ isolated SCons target, or a full SCons target list. If a target list contains
+ multiple entries, produces a warning & only creates the first entry.
+ - `guard`: Optional bool to determine if a header guard should be added. If
+ unassigned, header guards are determined by the file extension.
+ - `prefix`: Custom prefix to prepend to a header guard. Produces a warning if
+ provided a value when `guard` evaluates to `False`.
+ - `suffix`: Custom suffix to append to a header guard. Produces a warning if
+ provided a value when `guard` evaluates to `False`.
+ """
+
+ # Handle unfiltered SCons target[s] passed as path.
+ if not isinstance(path, str):
+ if isinstance(path, list):
+ if len(path) > 1:
+ print_warning(
+ "Attempting to use generated wrapper with multiple targets; "
+ f"will only use first entry: {path[0]}"
+ )
+ path = path[0]
+ if not hasattr(path, "get_abspath"):
+ raise TypeError(f'Expected type "str", "Node" or "List[Node]"; was passed {type(path)}.')
+ path = path.get_abspath()
+
+ path = str(path).replace("\\", "/")
+ if guard is None:
+ guard = path.endswith((".h", ".hh", ".hpp", ".inc"))
+ if not guard and (prefix or suffix):
+ print_warning(f'Trying to assign header guard prefix/suffix while `guard` is disabled: "{path}".')
+
+ header_guard = ""
+ if guard:
+ if prefix:
+ prefix += "_"
+ if suffix:
+ suffix = f"_{suffix}"
+ split = path.split("/")[-1].split(".")
+ header_guard = (f"{prefix}{split[0]}{suffix}.{'.'.join(split[1:])}".upper()
+ .replace(".", "_").replace("-", "_").replace(" ", "_").replace("__", "_")) # fmt: skip
+
+ with open(path, "wt", encoding="utf-8", newline="\n") as file:
+ file.write(generate_copyright_header(path))
+ file.write("\n/* THIS FILE IS GENERATED. EDITS WILL BE LOST. */\n\n")
+
+ if guard:
+ file.write(f"#ifndef {header_guard}\n")
+ file.write(f"#define {header_guard}\n\n")
+
+ with StringIO(newline="\n") as str_io:
+ yield str_io
+ file.write(str_io.getvalue().strip() or "/* NO CONTENT */")
+
+ if guard:
+ file.write(f"\n\n#endif // {header_guard}")
+
+ file.write("\n")
diff --git a/modules/SCsub b/modules/SCsub
index 6fb2aa67f4..739c5de0b5 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-import modules_builders
+import methods
import os
Import("env")
@@ -12,15 +12,51 @@ env_modules.Append(CPPDEFINES=["GODOT_MODULE"])
Export("env_modules")
-# Header with MODULE_*_ENABLED defines.
-env.Depends("modules_enabled.gen.h", Value(env.module_list))
-env.CommandNoCache(
- "modules_enabled.gen.h",
- Value(env.module_list),
- env.Run(modules_builders.generate_modules_enabled),
+
+def register_module_types_builder(target, source, env):
+ modules = source[0].read()
+ mod_inc = "\n".join([f'#include "{p}/register_types.h"' for p in modules.values()])
+ mod_init = "\n".join(
+ [f"#ifdef MODULE_{n.upper()}_ENABLED\n\tinitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
+ )
+ mod_uninit = "\n".join(
+ [f"#ifdef MODULE_{n.upper()}_ENABLED\n\tuninitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
+ )
+ with methods.generated_wrapper(target) 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), env.Run(register_module_types_builder)
)
+# Header with MODULE_*_ENABLED defines.
+def modules_enabled_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for module in source[0].read():
+ file.write(f"#define MODULE_{module.upper()}_ENABLED\n")
+
+
+env.CommandNoCache("modules_enabled.gen.h", env.Value(env.module_list), env.Run(modules_enabled_builder))
+
+
vs_sources = []
test_headers = []
# libmodule_<name>.a for each active module.
@@ -47,18 +83,19 @@ 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"]:
- env.Depends("modules_tests.gen.h", test_headers)
- env.CommandNoCache(
- "modules_tests.gen.h",
- test_headers,
- env.Run(modules_builders.generate_modules_tests),
- )
+
+ def modules_tests_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for header in source:
+ file.write('#include "{}"\n'.format(os.path.normpath(header.path).replace("\\", "/")))
+
+ env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(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
# in the linker command.
env.modules_sources = []
-env_modules.add_source_files(env.modules_sources, "register_module_types.gen.cpp")
+env_modules.add_source_files(env.modules_sources, register_module_types)
lib = env_modules.add_library("modules", env.modules_sources)
env.Prepend(LIBS=[lib])
if env["vsproj"]:
diff --git a/modules/modules_builders.py b/modules/modules_builders.py
deleted file mode 100644
index 5db7c88a90..0000000000
--- a/modules/modules_builders.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Functions used to generate source files during build time"""
-
-
-def generate_modules_enabled(target, source, env):
- with open(target[0].path, "w", encoding="utf-8", newline="\n") as f:
- for module in env.module_list:
- f.write("#define %s\n" % ("MODULE_" + module.upper() + "_ENABLED"))
-
-
-def generate_modules_tests(target, source, env):
- import os
-
- with open(target[0].path, "w", encoding="utf-8", newline="\n") as f:
- for header in source:
- f.write('#include "%s"\n' % (os.path.normpath(header.path)))
diff --git a/platform/SCsub b/platform/SCsub
index ca282e3e68..b24c189848 100644
--- a/platform/SCsub
+++ b/platform/SCsub
@@ -1,27 +1,64 @@
#!/usr/bin/env python
import methods
+from glob import glob
+from pathlib import Path
Import("env")
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]), "rb") as file:
+ svg = "".join([f"\\{hex(x)[1:]}" for x in file.read()])
+ with methods.generated_wrapper(target, prefix=platform) as file:
+ file.write(
+ f"""\
+static const char *_{platform}_{src_name}_svg = "{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))
+
+
# Register platform-exclusive APIs
-reg_apis_inc = '#include "register_platform_apis.h"\n'
-reg_apis = "void register_platform_apis() {\n"
-unreg_apis = "void unregister_platform_apis() {\n"
+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(target) 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)
+)
+env.add_source_files(env.platform_sources, register_platform_apis)
for platform in env.platform_apis:
- platform_dir = env.Dir(platform)
- env.add_source_files(env.platform_sources, platform + "/api/api.cpp")
- reg_apis += "\tregister_" + platform + "_api();\n"
- unreg_apis += "\tunregister_" + platform + "_api();\n"
- reg_apis_inc += '#include "' + platform + '/api/api.h"\n'
-reg_apis_inc += "\n"
-reg_apis += "}\n\n"
-unreg_apis += "}\n"
-
-methods.write_file_if_needed("register_platform_apis.gen.cpp", reg_apis_inc + reg_apis + unreg_apis)
-env.add_source_files(env.platform_sources, "register_platform_apis.gen.cpp")
+ env.add_source_files(env.platform_sources, f"{platform}/api/api.cpp")
lib = env.add_library("platform", env.platform_sources)
env.Prepend(LIBS=[lib])
diff --git a/platform_methods.py b/platform_methods.py
index 57b11d1a47..5326e36077 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -43,33 +43,6 @@ def detect_arch():
return "x86_64"
-def generate_export_icons(platform_path, platform_name):
- """
- Generate headers for logo and run icon for the export plugin.
- """
- export_path = platform_path + "/export"
- svg_names = []
- if os.path.isfile(export_path + "/logo.svg"):
- svg_names.append("logo")
- if os.path.isfile(export_path + "/run_icon.svg"):
- svg_names.append("run_icon")
-
- for name in svg_names:
- with open(export_path + "/" + name + ".svg", "rb") as svgf:
- b = svgf.read(1)
- svg_str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n"
- svg_str += " static const char *_" + platform_name + "_" + name + '_svg = "'
- while len(b) == 1:
- svg_str += "\\" + hex(ord(b))[1:]
- b = svgf.read(1)
-
- svg_str += '";\n'
-
- wf = export_path + "/" + name + "_svg.gen.h"
-
- methods.write_file_if_needed(wf, svg_str)
-
-
def get_build_version(short):
import version