diff options
Diffstat (limited to 'methods.py')
-rw-r--r-- | methods.py | 230 |
1 files changed, 132 insertions, 98 deletions
diff --git a/methods.py b/methods.py index 649072d098..7ede2592ff 100644 --- a/methods.py +++ b/methods.py @@ -1,21 +1,12 @@ import os -import re import sys +import re import glob import subprocess from collections import OrderedDict from collections.abc import Mapping from typing import Iterator -# We need to define our own `Action` method to control the verbosity of output -# and whenever we need to run those commands in a subprocess on some platforms. -from SCons import Node -from SCons.Script import Action -from SCons.Script import ARGUMENTS -from SCons.Script import Glob -from SCons.Variables.BoolVariable import _text2bool -from platform_methods import run_in_subprocess - def add_source_files(self, sources, files): # Convert string to list of absolute paths (including expanding wildcard) @@ -49,72 +40,65 @@ def disable_warnings(self): if self.msvc: # We have to remove existing warning level defines before appending /w, # otherwise we get: "warning D9025 : overriding '/W3' with '/w'" - warn_flags = ["/Wall", "/W4", "/W3", "/W2", "/W1", "/WX"] - self.Append(CCFLAGS=["/w"]) - self.Append(CFLAGS=["/w"]) - self.Append(CXXFLAGS=["/w"]) - self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x in warn_flags] - self["CFLAGS"] = [x for x in self["CFLAGS"] if not x in warn_flags] - self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x in warn_flags] + self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not (x.startswith("/W") or x.startswith("/w"))] + self["CFLAGS"] = [x for x in self["CFLAGS"] if not (x.startswith("/W") or x.startswith("/w"))] + self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not (x.startswith("/W") or x.startswith("/w"))] + self.AppendUnique(CCFLAGS=["/w"]) else: - self.Append(CCFLAGS=["-w"]) - self.Append(CFLAGS=["-w"]) - self.Append(CXXFLAGS=["-w"]) + self.AppendUnique(CCFLAGS=["-w"]) def force_optimization_on_debug(self): # 'self' is the environment - if self["target"] != "debug": + if self["target"] != "template-release": return if self.msvc: - self.Append(CCFLAGS=["/O2"]) + # We have to remove existing optimization level defines before appending /O2, + # otherwise we get: "warning D9025 : overriding '/0d' with '/02'" + self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x.startswith("/O")] + self["CFLAGS"] = [x for x in self["CFLAGS"] if not x.startswith("/O")] + self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x.startswith("/O")] + self.AppendUnique(CCFLAGS=["/O2"]) else: - self.Append(CCFLAGS=["-O3"]) + self.AppendUnique(CCFLAGS=["-O3"]) def add_module_version_string(self, s): self.module_version_string += "." + s -def update_version(module_version_string=""): +def get_version_info(module_version_string="", silent=False): build_name = "custom_build" if os.getenv("BUILD_NAME") != None: build_name = str(os.getenv("BUILD_NAME")) - print("Using custom build name: " + build_name) + if not silent: + print(f"Using custom build name: '{build_name}'.") import version - # NOTE: It is safe to generate this file here, since this is still executed serially - f = open("core/version_generated.gen.h", "w") - f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - f.write("#ifndef VERSION_GENERATED_GEN_H\n") - f.write("#define VERSION_GENERATED_GEN_H\n") - f.write('#define VERSION_SHORT_NAME "' + str(version.short_name) + '"\n') - f.write('#define VERSION_NAME "' + str(version.name) + '"\n') - f.write("#define VERSION_MAJOR " + str(version.major) + "\n") - f.write("#define VERSION_MINOR " + str(version.minor) + "\n") - f.write("#define VERSION_PATCH " + str(version.patch) + "\n") + version_info = { + "short_name": str(version.short_name), + "name": str(version.name), + "major": int(version.major), + "minor": int(version.minor), + "patch": int(version.patch), + "status": str(version.status), + "build": str(build_name), + "module_config": str(version.module_config) + module_version_string, + "year": int(version.year), + "website": str(version.website), + "docs_branch": str(version.docs), + } + # For dev snapshots (alpha, beta, RC, etc.) we do not commit status change to Git, # so this define provides a way to override it without having to modify the source. - godot_status = str(version.status) if os.getenv("GODOT_VERSION_STATUS") != None: - godot_status = str(os.getenv("GODOT_VERSION_STATUS")) - print("Using version status '{}', overriding the original '{}'.".format(godot_status, str(version.status))) - f.write('#define VERSION_STATUS "' + godot_status + '"\n') - f.write('#define VERSION_BUILD "' + str(build_name) + '"\n') - f.write('#define VERSION_MODULE_CONFIG "' + str(version.module_config) + module_version_string + '"\n') - f.write("#define VERSION_YEAR " + str(version.year) + "\n") - f.write('#define VERSION_WEBSITE "' + str(version.website) + '"\n') - f.write('#define VERSION_DOCS_BRANCH "' + str(version.docs) + '"\n') - f.write('#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH\n') - f.write("#endif // VERSION_GENERATED_GEN_H\n") - f.close() + version_info["status"] = str(os.getenv("GODOT_VERSION_STATUS")) + if not silent: + print(f"Using version status '{version_info['status']}', overriding the original '{version.status}'.") - # NOTE: It is safe to generate this file here, since this is still executed serially - fhash = open("core/version_hash.gen.cpp", "w") - fhash.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - fhash.write('#include "core/version.h"\n') + # Parse Git hash if we're in a Git repo. githash = "" gitfolder = ".git" @@ -127,6 +111,10 @@ def update_version(module_version_string=""): head = open(os.path.join(gitfolder, "HEAD"), "r", encoding="utf8").readline().strip() if head.startswith("ref: "): ref = head[5:] + # If this directory is a Git worktree instead of a root clone. + parts = gitfolder.split("/") + if len(parts) > 2 and parts[-2] == "worktrees": + gitfolder = "/".join(parts[0:-2]) head = os.path.join(gitfolder, ref) packedrefs = os.path.join(gitfolder, "packed-refs") if os.path.isfile(head): @@ -144,7 +132,49 @@ def update_version(module_version_string=""): else: githash = head - fhash.write('const char *const VERSION_HASH = "' + githash + '";\n') + version_info["git_hash"] = githash + + return version_info + + +def generate_version_header(module_version_string=""): + version_info = get_version_info(module_version_string) + + # NOTE: It is safe to generate these files here, since this is still executed serially. + + f = open("core/version_generated.gen.h", "w") + f.write( + """/* 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_YEAR {year} +#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 + ) + ) + f.close() + + fhash = open("core/version_hash.gen.cpp", "w") + fhash.write( + """/* THIS FILE IS GENERATED DO NOT EDIT */ +#include "core/version.h" +const char *const VERSION_HASH = "{git_hash}"; +""".format( + **version_info + ) + ) fhash.close() @@ -185,6 +215,9 @@ def get_cmdline_bool(option, default): """We use `ARGUMENTS.get()` to check if options were manually overridden on the command line, and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings. """ + from SCons.Script import ARGUMENTS + from SCons.Variables.BoolVariable import _text2bool + cmdline_val = ARGUMENTS.get(option) if cmdline_val is not None: return _text2bool(cmdline_val) @@ -455,29 +488,29 @@ def use_windows_spawn_fix(self, platform=None): def save_active_platforms(apnames, ap): for x in ap: - names = ["logo"] - if os.path.isfile(x + "/run_icon.png"): - names.append("run_icon") - - for name in names: - pngf = open(x + "/" + name + ".png", "rb") - b = pngf.read(1) - str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n" - str += " static const unsigned char _" + x[9:] + "_" + name + "[]={" + svg_names = [] + if os.path.isfile(x + "/logo.svg"): + svg_names.append("logo") + if os.path.isfile(x + "/run_icon.svg"): + svg_names.append("run_icon") + + for name in svg_names: + svgf = open(x + "/" + name + ".svg", "rb") + b = svgf.read(1) + svg_str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n" + svg_str += " static const char *_" + x[9:] + "_" + name + '_svg = "' while len(b) == 1: - str += hex(ord(b)) - b = pngf.read(1) - if len(b) == 1: - str += "," + svg_str += "\\" + hex(ord(b))[1:] + b = svgf.read(1) - str += "};\n" + svg_str += '";\n' - pngf.close() + svgf.close() # NOTE: It is safe to generate this file here, since this is still executed serially - wf = x + "/" + name + ".gen.h" - with open(wf, "w") as pngw: - pngw.write(str) + wf = x + "/" + name + "_svg.gen.h" + with open(wf, "w") as svgw: + svgw.write(svg_str) def no_verbose(sys, env): @@ -628,7 +661,6 @@ def detect_visual_c_compiler_version(tools_env): if vc_x86_amd64_compiler_detection_index > -1 and ( vc_chosen_compiler_index == -1 or vc_chosen_compiler_index > vc_x86_amd64_compiler_detection_index ): - vc_chosen_compiler_index = vc_x86_amd64_compiler_detection_index vc_chosen_compiler_str = "x86_amd64" return vc_chosen_compiler_str @@ -669,6 +701,9 @@ def generate_cpp_hint_file(filename): def glob_recursive(pattern, node="."): + from SCons import Node + from SCons.Script import Glob + results = [] for f in Glob(str(node) + "/*", source=True): if type(f) is Node.FS.Dir: @@ -702,20 +737,19 @@ def generate_vs_project(env, num_jobs): if batch_file: class ModuleConfigs(Mapping): - # This version information (Win32, x64, Debug, Release, Release_Debug seems to be + # This version information (Win32, x64, Debug, Release) seems to be # required for Visual Studio to understand that it needs to generate an NMAKE # project. Do not modify without knowing what you are doing. PLATFORMS = ["Win32", "x64"] PLATFORM_IDS = ["x86_32", "x86_64"] - CONFIGURATIONS = ["debug", "release", "release_debug"] - CONFIGURATION_IDS = ["tools", "opt", "opt.tools"] + CONFIGURATIONS = ["editor", "template_release", "template_debug"] + DEV_SUFFIX = ".dev" if env["dev_build"] else "" @staticmethod def for_every_variant(value): return [value for _ in range(len(ModuleConfigs.CONFIGURATIONS) * len(ModuleConfigs.PLATFORMS))] def __init__(self): - shared_targets_array = [] self.names = [] self.arg_dict = { @@ -744,8 +778,8 @@ def generate_vs_project(env, num_jobs): for platform in ModuleConfigs.PLATFORMS ] self.arg_dict["runfile"] += [ - f'bin\\godot.windows.{config_id}.{plat_id}{f".{name}" if name else ""}.exe' - for config_id in ModuleConfigs.CONFIGURATION_IDS + f'bin\\godot.windows.{config}{ModuleConfigs.DEV_SUFFIX}{".double" if env["precision"] == "double" else ""}.{plat_id}{f".{name}" if name else ""}.exe' + for config in ModuleConfigs.CONFIGURATIONS for plat_id in ModuleConfigs.PLATFORM_IDS ] self.arg_dict["cpppaths"] += ModuleConfigs.for_every_variant(env["CPPPATH"] + [includes]) @@ -753,7 +787,6 @@ def generate_vs_project(env, num_jobs): self.arg_dict["cmdargs"] += ModuleConfigs.for_every_variant(cli_args) def build_commandline(self, commands): - configuration_getter = ( "$(Configuration" + "".join([f'.Replace("{name}", "")' for name in self.names[1:]]) @@ -764,8 +797,6 @@ def generate_vs_project(env, num_jobs): common_build_prefix = [ 'cmd /V /C set "plat=$(PlatformTarget)"', '(if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))', - 'set "tools=%s"' % env["tools"], - f'(if "{configuration_getter}"=="release" (set "tools=no"))', 'call "' + batch_file + '" !plat!', ] @@ -778,16 +809,24 @@ def generate_vs_project(env, num_jobs): "platform=windows", f"target={configuration_getter}", "progress=no", - "tools=!tools!", "-j%s" % num_jobs, ] - if env["tests"]: + if env["dev_build"]: + common_build_postfix.append("dev_build=yes") + + if env["dev_mode"]: + common_build_postfix.append("dev_mode=yes") + + elif env["tests"]: common_build_postfix.append("tests=yes") if env["custom_modules"]: common_build_postfix.append("custom_modules=%s" % env["custom_modules"]) + if env["precision"] == "double": + common_build_postfix.append("precision=double") + result = " ^& ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)]) return result @@ -811,7 +850,8 @@ def generate_vs_project(env, num_jobs): add_to_vs_project(env, env.servers_sources) if env["tests"]: add_to_vs_project(env, env.tests_sources) - add_to_vs_project(env, env.editor_sources) + if env.editor_build: + add_to_vs_project(env, env.editor_sources) for header in glob_recursive("**/*.h"): env.vs_incs.append(str(header)) @@ -819,21 +859,12 @@ def generate_vs_project(env, num_jobs): module_configs = ModuleConfigs() if env.get("module_mono_enabled"): - import modules.mono.build_scripts.mono_configure as mono_configure - - app_host_dir = mono_configure.find_dotnet_app_host_dir(env) - if app_host_dir and os.path.isdir(app_host_dir): - mono_defines = [("NETHOST_USE_AS_STATIC",)] - if env["tools"]: - mono_defines += [("GD_MONO_HOT_RELOAD",)] - module_configs.add_mode( - "mono", - includes=app_host_dir, - cli_args="module_mono_enabled=yes", - defines=mono_defines, - ) - else: - print(".NET App Host directory not found. Generated project will not have build variants for .NET.") + mono_defines = [("GD_MONO_HOT_RELOAD",)] if env.editor_build else [] + module_configs.add_mode( + "mono", + cli_args="module_mono_enabled=yes", + defines=mono_defines, + ) env["MSVSBUILDCOM"] = module_configs.build_commandline("scons") env["MSVSREBUILDCOM"] = module_configs.build_commandline("scons vsproj=yes") @@ -883,6 +914,9 @@ def CommandNoCache(env, target, sources, command, **args): def Run(env, function, short_message, subprocess=True): + from SCons.Script import Action + from platform_methods import run_in_subprocess + output_print = short_message if not env["verbose"] else "" if not subprocess: return Action(function, output_print) |