diff --git a/SConstruct b/SConstruct index 70aff5c..ee1385f 100644 --- a/SConstruct +++ b/SConstruct @@ -8,6 +8,10 @@ from typing import List, Union import SCons +_SCRIPTS_DIR = Dir(".").abspath +if _SCRIPTS_DIR not in sys.path: + sys.path.insert(0, _SCRIPTS_DIR) + # Local from build.option_handler import OptionsClass from build.glob_recursive import GlobRecursive @@ -15,6 +19,7 @@ from build.git_info import get_git_info, git_builder from build.license_info import license_builder from build.author_info import author_builder from build.cache import show_progress +from build.pch import setup_pch def normalize_path(val, env): return val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val) @@ -167,9 +172,14 @@ def SetupOptions(): ) ) - # Add platform options + # Add platform options. Iterate deterministically with the current platform + # registered last so its defaults win tools = {} - for pl in set(platforms) - set(unsupported_known_platforms): + current_platform = env.get("platform", default_platform) + supported = sorted(set(platforms) - set(unsupported_known_platforms)) + if current_platform in supported: + supported = [pl for pl in supported if pl != current_platform] + [current_platform] + for pl in supported: tool = Tool(pl, toolpath=env.TOOLPATH) if hasattr(tool, "options"): tool.options(opts) @@ -205,6 +215,7 @@ def SetupOptions(): opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False)) opts.Add(BoolVariable("intermediate_delete", "Enables automatically deleting unassociated intermediate binary files.", True)) opts.Add(BoolVariable("progress", "Show a progress indicator during compilation", True)) + opts.Add(BoolVariable("use_pch", "Enable precompiled headers when the toolchain supports it", True)) # Targets flags tool (optimizations, debug symbols) target_tool = Tool("targets", toolpath=env.TOOLPATH) @@ -261,10 +272,11 @@ def FinalizeOptions(): target_tool.generate(env) tool.generate(env) + Decider("MD5-timestamp") + scons_cache_path = os.environ.get("SCONS_CACHE") if scons_cache_path != None: CacheDir(scons_cache_path) - Decider("MD5") print("Scons cache enabled... (path: '" + scons_cache_path + "')") if env["compiledb"] and is_standalone: @@ -279,6 +291,7 @@ env.get_git_info = get_git_info env.license_builder = license_builder env.git_builder = git_builder env.author_builder = author_builder +env.SetupPCH = lambda header, source: setup_pch(env, header, source) def to_raw_cstring(value: Union[str, List[str]]) -> str: diff --git a/build/__init__.py b/build/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/build/glob_recursive.py b/build/glob_recursive.py index a8cae4e..5024696 100644 --- a/build/glob_recursive.py +++ b/build/glob_recursive.py @@ -1,5 +1,6 @@ def GlobRecursive(pattern, nodes=["."], exclude=None): import fnmatch + import os import SCons @@ -11,15 +12,20 @@ def GlobRecursive(pattern, nodes=["."], exclude=None): results = [] for node in nodes: - nnodes = [] - for f in Glob(str(node) + "/*", source=True): + node_str = str(node) + + for f in Glob(node_str + "/*", source=True): if type(f) is SCons.Node.FS.Dir: - nnodes.append(f) - results += GlobRecursive(pattern, nnodes) - results += Glob(str(node) + "/" + pattern, source=True) - if isinstance(exclude, list): - for val in results: - for pat in exclude: - if fnmatch.fnmatch(str(val), pat): - results.remove(val) + child = node_str + "/" + os.path.basename(str(f)) + results += GlobRecursive(pattern, [child]) + + results += Glob(node_str + "/" + pattern) + + if isinstance(exclude, list): + + def norm(s): + return str(s).replace("\\", "/") + + norm_exclude = [norm(p) for p in exclude] + results = [r for r in results if not any(fnmatch.fnmatch(norm(r), p) for p in norm_exclude)] return results diff --git a/build/pch.py b/build/pch.py new file mode 100644 index 0000000..a93271e --- /dev/null +++ b/build/pch.py @@ -0,0 +1,25 @@ +def setup_pch(env, header_rel, source_cpp_variant): + if not env.get("use_pch", True): + return + + handler = _select_handler(env) + if handler is None: + return + + name = handler(env, header_rel, source_cpp_variant) + print(f"[PCH] enabled ({name}): {header_rel}") + + +def _select_handler(env): + if env.get("is_msvc", False): + return _msvc_pch + # TODO: GCC/Clang/MinGW + return None + + +def _msvc_pch(env, header_rel, source_cpp_variant): + env["PCHSTOP"] = header_rel + pch_pch, _pch_obj = env.PCH(source_cpp_variant) + env["PCH"] = pch_pch + env.Append(CCFLAGS=["/FI" + header_rel]) + return "msvc"