1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-18 14:21:41 +00:00

Merge pull request #43057 from Xrayez/custom_modules_recursive

SCons: Add an option to detect C++ modules recursively
This commit is contained in:
Rémi Verschelde
2021-02-08 16:00:03 +01:00
committed by GitHub
2 changed files with 77 additions and 18 deletions

View File

@@ -120,6 +120,7 @@ opts.Add(BoolVariable("deprecated", "Enable deprecated features", True))
opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True)) opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True))
opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False)) opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False))
opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "") opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "")
opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
# Advanced options # Advanced options
opts.Add(BoolVariable("dev", "If yes, alias for verbose=yes warnings=extra werror=yes", False)) opts.Add(BoolVariable("dev", "If yes, alias for verbose=yes warnings=extra werror=yes", False))
@@ -237,8 +238,14 @@ if env_base["custom_modules"]:
Exit(255) Exit(255)
for path in module_search_paths: for path in module_search_paths:
if path == "modules":
# Built-in modules don't have nested modules,
# so save the time it takes to parse directories.
modules = methods.detect_modules(path, recursive=False)
else: # External.
modules = methods.detect_modules(path, env_base["custom_modules_recursive"])
# Note: custom modules can override built-in ones. # Note: custom modules can override built-in ones.
modules_detected.update(methods.detect_modules(path)) modules_detected.update(modules)
include_path = os.path.dirname(path) include_path = os.path.dirname(path)
if include_path: if include_path:
env_base.Prepend(CPPPATH=[include_path]) env_base.Prepend(CPPPATH=[include_path])

View File

@@ -145,34 +145,88 @@ def parse_cg_file(fname, uniforms, sizes, conditionals):
fs.close() fs.close()
def detect_modules(at_path): def detect_modules(search_path, recursive=False):
module_list = OrderedDict() # name : path """Detects and collects a list of C++ modules at specified path
modules_glob = os.path.join(at_path, "*") `search_path` - a directory path containing modules. The path may point to
files = glob.glob(modules_glob) a single module, which may have other nested modules. A module must have
files.sort() # so register_module_types does not change that often, and also plugins are registered in alphabetic order "register_types.h", "SCsub", "config.py" files created to be detected.
for x in files: `recursive` - if `True`, then all subdirectories are searched for modules as
if not is_module(x): specified by the `search_path`, otherwise collects all modules under the
continue `search_path` directory. If the `search_path` is a module, it is collected
name = os.path.basename(x) in all cases.
path = x.replace("\\", "/") # win32
module_list[name] = path
return module_list 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:
version = {}
exec(f.read(), version)
if version.get("short_name") == "godot":
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): 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_modules(modules):
includes_cpp = "" includes_cpp = ""
preregister_cpp = "" preregister_cpp = ""
register_cpp = "" register_cpp = ""
unregister_cpp = "" unregister_cpp = ""
for name, path in module_list.items(): for name, path in modules.items():
try: try:
with open(os.path.join(path, "register_types.h")): with open(os.path.join(path, "register_types.h")):
includes_cpp += '#include "' + path + '/register_types.h"\n' includes_cpp += '#include "' + path + '/register_types.h"\n'
@@ -230,8 +284,6 @@ def convert_custom_modules_path(path):
raise ValueError(err_msg % "point to an existing directory.") raise ValueError(err_msg % "point to an existing directory.")
if path == os.path.realpath("modules"): if path == os.path.realpath("modules"):
raise ValueError(err_msg % "be a directory other than built-in `modules` directory.") 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 return path