diff --git a/test/SConstruct b/test/SConstruct index 9c25917b..b3716c51 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -35,8 +35,13 @@ elif env["platform"] == "ios": source=sources, ) else: + library_path = "project/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]) + + if env.get("is_msvc", False) and env["debug_symbols"] and env["use_hot_reload"]: + env.MSVCTryRenamePDB(library_path) + library = env.SharedLibrary( - "project/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]), + library_path, source=sources, ) diff --git a/test/project/example.gdextension b/test/project/example.gdextension index 4f599ced..5b25986b 100644 --- a/test/project/example.gdextension +++ b/test/project/example.gdextension @@ -1,7 +1,8 @@ [configuration] entry_symbol = "example_library_init" -compatibility_minimum = "4.1" +compatibility_minimum = "4.2" +reloadable = true [libraries] diff --git a/tools/godotcpp.py b/tools/godotcpp.py index 0b02eea2..6f4f2703 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -1,4 +1,5 @@ import os, sys, platform +import methods from SCons.Variables import EnumVariable, PathVariable, BoolVariable from SCons.Tool import Tool @@ -319,6 +320,9 @@ def generate(env): env.Append(BUILDERS={"GodotCPPBindings": Builder(action=scons_generate_bindings, emitter=scons_emit_files)}) env.AddMethod(_godot_cpp, "GodotCPP") + # Global methods + env.AddMethod(methods.msvc_try_rename_pdb, "MSVCTryRenamePDB") + def _godot_cpp(env): extension_dir = normalize_path(env.get("gdextension_dir", env.Dir("gdextension").abspath), env) diff --git a/tools/methods.py b/tools/methods.py new file mode 100644 index 00000000..7254ed0a --- /dev/null +++ b/tools/methods.py @@ -0,0 +1,61 @@ +import os + +# Useful methods for custom scripts + + +# A utility function for getting the name of an unblocked file +def _get_unblocked_file_name(original_file_path, new_file_ext, max_files=256, keep_newest_one=True): + lib_dir = os.path.normpath(os.path.dirname(original_file_path)) + lib_name = os.path.splitext(os.path.basename(original_file_path))[0] + + # Collect all matching files + found_files = [ + f + for f in os.listdir(lib_dir) + if os.path.isfile(os.path.join(lib_dir, f)) and f.startswith(lib_name) and f.endswith("." + new_file_ext) + ] + found_files = sorted(found_files, key=lambda x: os.path.getmtime(os.path.join(lib_dir, x))) + + # Clean up the old files if possible, except for the newest one + if found_files: + if keep_newest_one: + found_files.pop() + for f in found_files: + try: + os.remove(os.path.join(lib_dir, f)) + except: + pass + + # Search for a unblocked file name + file_name = "" + for s in range(max_files): + file_name = "{}_{}.{}".format(os.path.join(lib_dir, lib_name), s, new_file_ext) + if not os.path.exists(file_name): + break + try: + with open(file_name, "a") as f: + pass + except IOError: + continue + break + + return file_name + + +# This is necessary to support debugging and Hot-Reload at the same time when building using MSVC +def msvc_try_rename_pdb(env, full_lib_path): + if not env.get("is_msvc", False): + print("Renaming the PDB file will be ignored because of a compiler mismatch.") + return + if not env["debug_symbols"]: + print("Renaming the PDB file will be ignored because debug symbols generation is disabled.") + return + if not env["use_hot_reload"]: + print("Renaming the PDB file will be ignored because Hot-Reload is disabled.") + return + + pdb_name = _get_unblocked_file_name(full_lib_path, "pdb") + print("New path to the PDB: " + pdb_name) + + # Explicit assignment of the PDB path + env.Append(LINKFLAGS=["/PDB:" + pdb_name])