Skip to content

Commit

Permalink
SCons: Add emitter to declutter build objects
Browse files Browse the repository at this point in the history
  • Loading branch information
Repiteo committed Jan 18, 2025
1 parent 7b1ed52 commit 5fbfc44
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 8 deletions.
16 changes: 16 additions & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ from importlib.util import module_from_spec, spec_from_file_location
from types import ModuleType

from SCons import __version__ as scons_raw_version
from SCons.Builder import ListEmitter

# Explicitly resolve the helper modules, this is done to avoid clash with
# modules of the same name that might be randomly added (e.g. someone adding
Expand Down Expand Up @@ -251,6 +252,13 @@ opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the
opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False))
opts.Add("cache_path", "Path to a directory where SCons cache files will be stored. No value disables the cache.", "")
opts.Add("cache_limit", "Max size (in GiB) for the SCons cache. 0 means no limit.", "0")
opts.Add(
BoolVariable(
"redirect_build_objects",
"Enable redirecting built objects/libraries to `bin/obj/` to declutter the repository.",
True,
)
)

# Thirdparty libraries
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
Expand Down Expand Up @@ -1057,6 +1065,14 @@ if env["ninja"]:
if env["threads"]:
env.Append(CPPDEFINES=["THREADS_ENABLED"])

# Ensure build objects are put in their own folder.
env.Prepend(LIBEMITTER=methods.redirect_emitter)
env.Prepend(SHLIBEMITTER=methods.redirect_emitter)
for key in (emitters := env.StaticObject.builder.emitter):
emitters[key] = ListEmitter([methods.redirect_emitter] + env.Flatten(emitters[key]))
for key in (emitters := env.SharedObject.builder.emitter):
emitters[key] = ListEmitter([methods.redirect_emitter] + env.Flatten(emitters[key]))

# Build subdirs, the build order is dependent on link order.
Export("env")

Expand Down
33 changes: 30 additions & 3 deletions methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
from misc.utility.color import print_error, print_info, print_warning

# Get the "Godot" folder name ahead of time
base_folder_path = str(os.path.abspath(Path(__file__).parent)) + "/"
base_folder_only = os.path.basename(os.path.normpath(base_folder_path))
base_folder = Path(__file__).parent.resolve()

# Listing all the folders we have converted
# for SCU in scu_builders.py
Expand Down Expand Up @@ -79,6 +78,34 @@ def add_source_files(self, sources, files, allow_gen=False):
return True


def redirect_emitter(target, source, env):
"""
Emitter to automatically redirect object/library build files to the `bin/obj` directory,
retaining subfolder structure. External build files will attempt to retain subfolder
structure relative to their environment's parent directory, sorted under `bin/obj/external`.
If `redirect_build_objects` is `False`, or an external build file isn't relative to the
passed environment, this emitter does nothing.
"""
if not env["redirect_build_objects"]:
return target, source
redirected_targets = []
for item in env.Flatten(target):
if isinstance(item, str):
item = env.File(item)
path = Path(item.get_abspath()).resolve()
try:
item = env.File(f"#bin/obj/{path.relative_to(base_folder)}")
except ValueError:
# External file; most likely a custom module. Assume relevant environment was passed.
alt_base = Path(env.Dir(".").get_abspath()).parent.resolve()
try:
item = env.File(f"#bin/obj/external/{path.relative_to(alt_base)}")
except ValueError:
pass
redirected_targets.append(item)
return redirected_targets, source


def disable_warnings(self):
# 'self' is the environment
if self.msvc and not using_clang(self):
Expand Down Expand Up @@ -754,7 +781,7 @@ def show_progress(env):
if env["ninja"]:
return

NODE_COUNT_FILENAME = f"{base_folder_path}.scons_node_count"
NODE_COUNT_FILENAME = base_folder / ".scons_node_count"

class ShowProgress:
def __init__(self):
Expand Down
6 changes: 2 additions & 4 deletions platform/android/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ env_thirdparty.disable_warnings()
thirdparty_obj = env_thirdparty.SharedObject("#thirdparty/misc/ifaddrs-android.cc")
android_objects.append(thirdparty_obj)

lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSUFFIX=env["SHLIBSUFFIX"])
lib = env_android.add_shared_library("#bin/libgodot", android_objects, redirect_build_objects=False)

# Needed to force rebuilding the platform files when the thirdparty code is updated.
env.Depends(lib, thirdparty_obj)
Expand Down Expand Up @@ -77,9 +77,7 @@ if lib_arch_dir != "":
lib_tools_dir = ""

out_dir = "#platform/android/java/lib/libs/" + lib_tools_dir + lib_type_dir + "/" + lib_arch_dir
env_android.Command(
out_dir + "/libgodot_android.so", "#bin/libgodot" + env["SHLIBSUFFIX"], Move("$TARGET", "$SOURCE")
)
env_android.Command(out_dir + "/libgodot_android.so", lib, Move("$TARGET", "$SOURCE"))

stl_lib_path = (
str(env["ANDROID_NDK_ROOT"]) + "/sources/cxx-stl/llvm-libc++/libs/" + lib_arch_dir + "/libc++_shared.so"
Expand Down
3 changes: 3 additions & 0 deletions platform/windows/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ from pathlib import Path

import platform_windows_builders

from methods import redirect_emitter

sources = []

common_win = [
Expand Down Expand Up @@ -49,6 +51,7 @@ def arrange_program_clean(prog):
Clean(prog, extra_files_to_clean)


env["BUILDERS"]["RES"].emitter = redirect_emitter
res_file = "godot_res.rc"
res_target = "godot_res" + env["OBJSUFFIX"]
res_obj = env.RES(res_target, res_file)
Expand Down
2 changes: 1 addition & 1 deletion platform/windows/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
from tempfile import mkstemp

# Ensure we have a location to write captured output to, in case of false positives.
capture_path = methods.base_folder_path + "platform/windows/msvc_capture.log"
capture_path = methods.base_folder / "platform" / "windows" / "msvc_capture.log"
with open(capture_path, "wt", encoding="utf-8"):
pass

Expand Down

0 comments on commit 5fbfc44

Please sign in to comment.