diff --git a/SConscript b/SConscript index 7ee315f..5706a1d 100644 --- a/SConscript +++ b/SConscript @@ -1,5 +1,6 @@ import copy +from dataclasses import dataclass import enum import glob import inspect @@ -49,6 +50,12 @@ class _Target: dependencies: list = [] target = None +@dataclass +class _Module: + name: str + description: str + cxx_namespace: str + def _find_recipe(env: Environment, recipe_name: str): if recipe_name in env['SPP_RECIPES']: return env['SPP_RECIPES'][recipe_name] @@ -89,9 +96,28 @@ def _cook(env: Environment, recipe_name: str): _run_cook(dependency) return dependency.cook_result +def _normalize_module_path(env: Environment, path: str) -> str: + module_root = env.Dir('#/private').abspath + return os.path.relpath(path, module_root) + def _module(env: Environment, file: str): + folder = _normalize_module_path(env, env.File(file).dir.abspath) + dirname = os.path.basename(folder) + env.Append(SPP_MODULES = {folder: _Module( + name=dirname, + description='', + cxx_namespace=dirname + )}) return SConscript(file, exports = 'env', variant_dir = env['VARIANT_DIR'], src_dir = '.') +def _module_config(env: Environment, **kwargs) -> None: + module_folder = _normalize_module_path(env, env.Dir('.').abspath) + module = env['SPP_MODULES'].get(module_folder) + if module is None: + env.Warn(f'No module config found for module at {module_folder}') + return + module.__dict__.update(kwargs) + def _parse_lib_conf(env: Environment, lib_conf: dict) -> None: env.Append(CPPPATH = lib_conf.get('CPPPATH', []), CPPDEFINES = lib_conf.get('CPPDEFINES', []), @@ -249,7 +275,10 @@ def _info(env: Environment, message: str) -> None: if not GetOption('silent'): print(message) -def _error(env: Environment, message: str): +def _warn(env: Environment, message: str) -> None: + print(message, file=sys.stderr) + +def _error(env: Environment, message: str) -> None: print(message, file=sys.stderr) Exit(1) @@ -477,6 +506,8 @@ def _version_to_string(version) -> str: return '.'.join([str(v) for v in version]) def _finalize(env: Environment): + if dump is not None: + _dump() if generate_project: _generate_project(generate_project) Exit(0) @@ -654,6 +685,39 @@ def _generate_project(project_type: str) -> None: except Exception as e: print(f'Error writing uuid cache: {e}') +def _dump() -> None: + def _dump_as_text(data: Any) -> str: + from pprint import pformat + dump_name = { + 'env': 'Environment', + 'config': 'Configuration', + 'modules': 'Modules' + }[dump] + + return '\n'.join(( + f'==== Begin {dump_name} Dump ====', + pformat(data), + f'==== End {dump_name} Dump ====' + )) + def _dump_as_json(data: Any) -> str: + class _Encoder(json.JSONEncoder): + def default(self, o) -> dict: + if isinstance(o, object): + return o.__dict__ + return super().default(o) + return json.dumps(data, cls=_Encoder) + + data = { + 'env': env.Dictionary, + 'config': lambda: config, + 'modules': lambda: env['SPP_MODULES'] + }[dump]() + dump_fn = { + 'text': _dump_as_text, + 'json': _dump_as_json + }[dump_format] + print(dump_fn(data)) + Exit(0) Import('config') @@ -741,7 +805,7 @@ AddOption( '--dump', dest = 'dump', type = 'choice', - choices = ('env', 'config'), + choices = ('env', 'config', 'modules'), nargs = 1, action = 'store' ) @@ -875,6 +939,7 @@ env['SPP_DEFAULT_TARGETS'] = [] env['SPP_TARGET_DEPENDENCIES'] = [] env['SPP_DEPENDENCIES'] = {} env['SPP_RECIPES'] = {} +env['SPP_MODULES'] = {} # maps from folder to _Module env['OBJSUFFIX'] = f".{env['BUILD_TYPE']}{env['OBJSUFFIX']}" if variant: @@ -1035,6 +1100,7 @@ env.AddMethod(_lib_filename, 'LibFilename') env.AddMethod(_find_executable, 'FindExecutable') env.AddMethod(_find_lib, 'FindLib') env.AddMethod(_info, 'Info') +env.AddMethod(_warn, 'Warn') env.AddMethod(_error, 'Error') env.AddMethod(_wrap_builder(env.Library, TargetType.STATIC_LIBRARY), 'Library') env.AddMethod(_wrap_builder(env.StaticLibrary, TargetType.STATIC_LIBRARY), 'StaticLibrary') @@ -1048,6 +1114,7 @@ env.AddMethod(_wrap_builder(env.UnityLibrary, TargetType.STATIC_LIBRARY), 'Unity env.AddMethod(_wrap_builder(env.UnityStaticLibrary, TargetType.STATIC_LIBRARY), 'UnityStaticLibrary') env.AddMethod(_wrap_builder(env.UnitySharedLibrary, TargetType.SHARED_LIBRARY), 'UnitySharedLibrary') env.AddMethod(_module, 'Module') +env.AddMethod(_module_config, 'ModuleConfig') env.AddMethod(_finalize, 'Finalize') env.AddMethod(_find_target, 'FindTarget') @@ -1057,28 +1124,4 @@ if hasattr(env, 'Gch'): for addon_file in env.Glob('addons/*.py'): env = SConscript(addon_file, exports = 'env') -if dump is not None: - def _dump_as_text(data: Any) -> str: - from pprint import pformat - dump_name = { - 'env': 'Environment', - 'config': 'Configuration' - }[dump] - - return '\n'.join(( - f'==== Begin {dump_name} Dump ====', - pformat(data), - f'==== End {dump_name} Dump ====' - )) - data = { - 'env': env.Dictionary, - 'config': lambda: config - }[dump]() - dump_fn = { - 'text': _dump_as_text, - 'json': json.dumps - }[dump_format] - print(dump_fn(data)) - Exit(0) - Return('env')