summaryrefslogtreecommitdiff
path: root/methods.py
diff options
context:
space:
mode:
Diffstat (limited to 'methods.py')
-rw-r--r--methods.py181
1 files changed, 147 insertions, 34 deletions
diff --git a/methods.py b/methods.py
index 15eb82ae74..0e71adb40d 100644
--- a/methods.py
+++ b/methods.py
@@ -6,9 +6,11 @@ from collections import OrderedDict
# 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.Script import Action
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
@@ -54,15 +56,25 @@ def disable_warnings(self):
self.Append(CXXFLAGS=["-w"])
+def force_optimization_on_debug(self):
+ # 'self' is the environment
+ if self["target"] != "debug":
+ return
+
+ if self.msvc:
+ self.Append(CCFLAGS=["/O2"])
+ else:
+ self.Append(CCFLAGS=["-O3"])
+
+
def add_module_version_string(self, s):
self.module_version_string += "." + s
def update_version(module_version_string=""):
-
build_name = "custom_build"
if os.getenv("BUILD_NAME") != None:
- build_name = os.getenv("BUILD_NAME")
+ build_name = str(os.getenv("BUILD_NAME"))
print("Using custom build name: " + build_name)
import version
@@ -77,7 +89,13 @@ def update_version(module_version_string=""):
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")
- f.write('#define VERSION_STATUS "' + str(version.status) + '"\n')
+ # 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")
@@ -145,34 +163,109 @@ def parse_cg_file(fname, uniforms, sizes, conditionals):
fs.close()
-def detect_modules(at_path):
- module_list = OrderedDict() # name : path
+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.
+ """
+ cmdline_val = ARGUMENTS.get(option)
+ if cmdline_val is not None:
+ return _text2bool(cmdline_val)
+ else:
+ return default
+
- modules_glob = os.path.join(at_path, "*")
- files = glob.glob(modules_glob)
- files.sort() # so register_module_types does not change that often, and also plugins are registered in alphabetic order
+def detect_modules(search_path, recursive=False):
+ """Detects and collects a list of C++ modules at specified path
- for x in files:
- if not is_module(x):
- continue
- name = os.path.basename(x)
- path = x.replace("\\", "/") # win32
- module_list[name] = path
+ `search_path` - a directory path containing modules. The path may point to
+ a single module, which may have other nested modules. A module must have
+ "register_types.h", "SCsub", "config.py" files created to be detected.
- return module_list
+ `recursive` - if `True`, then all subdirectories are searched for modules as
+ specified by the `search_path`, otherwise collects all modules under the
+ `search_path` directory. If the `search_path` is a module, it is collected
+ in all cases.
+
+ Returns an `OrderedDict` with module names as keys, and directory paths as
+ values. If a path is relative, then it is a built-in module. If a path is
+ absolute, then it is a custom module collected outside of the engine source.
+ """
+ modules = OrderedDict()
+
+ def add_module(path):
+ module_name = os.path.basename(path)
+ module_path = path.replace("\\", "/") # win32
+ modules[module_name] = module_path
+
+ def is_engine(path):
+ # Prevent recursively detecting modules in self and other
+ # Godot sources when using `custom_modules` build option.
+ version_path = os.path.join(path, "version.py")
+ if os.path.exists(version_path):
+ with open(version_path) as f:
+ if 'short_name = "godot"' in f.read():
+ return True
+ return False
+
+ def get_files(path):
+ files = glob.glob(os.path.join(path, "*"))
+ # Sort so that `register_module_types` does not change that often,
+ # and plugins are registered in alphabetic order as well.
+ files.sort()
+ return files
+
+ if not recursive:
+ if is_module(search_path):
+ add_module(search_path)
+ for path in get_files(search_path):
+ if is_engine(path):
+ continue
+ if is_module(path):
+ add_module(path)
+ else:
+ to_search = [search_path]
+ while to_search:
+ path = to_search.pop()
+ if is_module(path):
+ add_module(path)
+ for child in get_files(path):
+ if not os.path.isdir(child):
+ continue
+ if is_engine(child):
+ continue
+ to_search.insert(0, child)
+ return modules
def is_module(path):
- return os.path.isdir(path) and os.path.exists(os.path.join(path, "SCsub"))
+ if not os.path.isdir(path):
+ return False
+ must_exist = ["register_types.h", "SCsub", "config.py"]
+ for f in must_exist:
+ if not os.path.exists(os.path.join(path, f)):
+ return False
+ return True
-def write_modules(module_list):
+def write_disabled_classes(class_list):
+ f = open("core/disabled_classes.gen.h", "w")
+ f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+ f.write("#ifndef DISABLED_CLASSES_GEN_H\n")
+ f.write("#define DISABLED_CLASSES_GEN_H\n\n")
+ for c in class_list:
+ cs = c.strip()
+ if cs != "":
+ f.write("#define ClassDB_Disable_" + cs + " 1\n")
+ f.write("\n#endif\n")
+
+
+def write_modules(modules):
includes_cpp = ""
preregister_cpp = ""
register_cpp = ""
unregister_cpp = ""
- for name, path in module_list.items():
+ for name, path in modules.items():
try:
with open(os.path.join(path, "register_types.h")):
includes_cpp += '#include "' + path + '/register_types.h"\n'
@@ -230,8 +323,6 @@ def convert_custom_modules_path(path):
raise ValueError(err_msg % "point to an existing directory.")
if path == os.path.realpath("modules"):
raise ValueError(err_msg % "be a directory other than built-in `modules` directory.")
- if is_module(path):
- raise ValueError(err_msg % "point to a directory with modules, not a single module.")
return path
@@ -239,7 +330,7 @@ def disable_module(self):
self.disabled_modules.append(self.current_module)
-def module_check_dependencies(self, module, dependencies):
+def module_check_dependencies(self, module, dependencies, silent=False):
"""
Checks if module dependencies are enabled for a given module,
and prints a warning if they aren't.
@@ -253,11 +344,12 @@ def module_check_dependencies(self, module, dependencies):
missing_deps.append(dep)
if missing_deps != []:
- print(
- "Disabling '{}' module as the following dependencies are not satisfied: {}".format(
- module, ", ".join(missing_deps)
+ if not silent:
+ print(
+ "Disabling '{}' module as the following dependencies are not satisfied: {}".format(
+ module, ", ".join(missing_deps)
+ )
)
- )
return False
else:
return True
@@ -271,7 +363,7 @@ def use_windows_spawn_fix(self, platform=None):
# On Windows, due to the limited command line length, when creating a static library
# from a very high number of objects SCons will invoke "ar" once per object file;
# that makes object files with same names to be overwritten so the last wins and
- # the library looses symbols defined by overwritten objects.
+ # the library loses symbols defined by overwritten objects.
# By enabling quick append instead of the default mode (replacing), libraries will
# got built correctly regardless the invocation strategy.
# Furthermore, since SCons will rebuild the library from scratch when an object file
@@ -415,7 +507,7 @@ def detect_visual_c_compiler_version(tools_env):
# and not scons setup environment (env)... so make sure you call the right environment on it or it will fail to detect
# the proper vc version that will be called
- # There is no flag to give to visual c compilers to set the architecture, ie scons bits argument (32,64,ARM etc)
+ # There is no flag to give to visual c compilers to set the architecture, i.e. scons bits argument (32,64,ARM etc)
# There are many different cl.exe files that are run, and each one compiles & links to a different architecture
# As far as I know, the only way to figure out what compiler will be run when Scons calls cl.exe via Program()
# is to check the PATH variable and figure out which one will be called first. Code below does that and returns:
@@ -570,7 +662,7 @@ def generate_vs_project(env, num_jobs):
'call "' + batch_file + '" !plat!',
]
- # windows allows us to have spaces in paths, so we need
+ # Windows allows us to have spaces in paths, so we need
# to double quote off the directory. However, the path ends
# in a backslash, so we need to remove this, lest it escape the
# last double quote off, confusing MSBuild
@@ -583,6 +675,9 @@ def generate_vs_project(env, num_jobs):
"-j%s" % num_jobs,
]
+ if env["tests"]:
+ common_build_postfix.append("tests=yes")
+
if env["custom_modules"]:
common_build_postfix.append("custom_modules=%s" % env["custom_modules"])
@@ -595,6 +690,8 @@ def generate_vs_project(env, num_jobs):
add_to_vs_project(env, env.modules_sources)
add_to_vs_project(env, env.scene_sources)
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)
for header in glob_recursive("**/*.h"):
@@ -719,9 +816,18 @@ def get_compiler_version(env):
return None
else: # TODO: Implement for MSVC
return None
- match = re.search("[0-9]+\.[0-9.]+", version)
+ match = re.search(
+ "(?:(?<=version )|(?<=\) )|(?<=^))"
+ "(?P<major>\d+)"
+ "(?:\.(?P<minor>\d*))?"
+ "(?:\.(?P<patch>\d*))?"
+ "(?:-(?P<metadata1>[0-9a-zA-Z-]*))?"
+ "(?:\+(?P<metadata2>[0-9a-zA-Z-]*))?"
+ "(?: (?P<date>[0-9]{8}|[0-9]{6})(?![0-9a-zA-Z]))?",
+ version,
+ )
if match is not None:
- return list(map(int, match.group().split(".")))
+ return match.groupdict()
else:
return None
@@ -734,6 +840,10 @@ def using_clang(env):
return "clang" in os.path.basename(env["CC"])
+def using_emcc(env):
+ return "emcc" in os.path.basename(env["CC"])
+
+
def show_progress(env):
import sys
from SCons.Script import Progress, Command, AlwaysBuild
@@ -836,9 +946,12 @@ def show_progress(env):
def progress_finish(target, source, env):
nonlocal node_count, progressor
- with open(node_count_fname, "w") as f:
- f.write("%d\n" % node_count)
- progressor.delete(progressor.file_list())
+ try:
+ with open(node_count_fname, "w") as f:
+ f.write("%d\n" % node_count)
+ progressor.delete(progressor.file_list())
+ except Exception:
+ pass
try:
with open(node_count_fname) as f: