From 20459da6768f0f6e3a74fea341f70f4e881e1946 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Thu, 20 Jun 2024 09:38:54 +0300 Subject: [PATCH 01/13] Add support for LLVM/MinGW and ARM64 Windows builds. (cherry picked from commit f2353da5a35a5397a02d4fb47250244c988cfaeb) --- tools/common_compiler_flags.py | 2 +- tools/windows.py | 54 +++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/tools/common_compiler_flags.py b/tools/common_compiler_flags.py index 5bade45e..6a1fb693 100644 --- a/tools/common_compiler_flags.py +++ b/tools/common_compiler_flags.py @@ -74,7 +74,7 @@ def generate(env): else: env.Append(CCFLAGS=["-g2"]) else: - if using_clang(env) and not is_vanilla_clang(env): + if using_clang(env) and not is_vanilla_clang(env) and not env["use_mingw"]: # Apple Clang, its linker doesn't like -s. env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"]) else: diff --git a/tools/windows.py b/tools/windows.py index 9e2672a3..6fd4b038 100644 --- a/tools/windows.py +++ b/tools/windows.py @@ -1,3 +1,4 @@ +import os import sys import common_compiler_flags @@ -72,10 +73,14 @@ def silence_msvc(env): def options(opts): + mingw = os.getenv("MINGW_PREFIX", "") + opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler instead of MSVC - only effective on Windows", False)) opts.Add(BoolVariable("use_clang_cl", "Use the clang driver instead of MSVC - only effective on Windows", False)) opts.Add(BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True)) opts.Add(BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting errors to stderr.", True)) + opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler", False)) + opts.Add("mingw_prefix", "MinGW prefix", mingw) def exists(env): @@ -86,12 +91,22 @@ def generate(env): if not env["use_mingw"] and msvc.exists(env): if env["arch"] == "x86_64": env["TARGET_ARCH"] = "amd64" + elif env["arch"] == "arm64": + env["TARGET_ARCH"] = "arm64" + elif env["arch"] == "arm32": + env["TARGET_ARCH"] = "arm" elif env["arch"] == "x86_32": env["TARGET_ARCH"] = "x86" + + env["MSVC_SETUP_RUN"] = False # Need to set this to re-run the tool + env["MSVS_VERSION"] = None + env["MSVC_VERSION"] = None + env["is_msvc"] = True # MSVC, linker, and archiver. msvc.generate(env) + env.Tool("msvc") env.Tool("mslib") env.Tool("mslink") @@ -111,7 +126,7 @@ def generate(env): if env["silence_msvc"] and not env.GetOption("clean"): silence_msvc(env) - elif sys.platform == "win32" or sys.platform == "msys": + elif (sys.platform == "win32" or sys.platform == "msys") and not env["mingw_prefix"]: env["use_mingw"] = True mingw.generate(env) # Don't want lib prefixes @@ -137,12 +152,32 @@ def generate(env): else: env["use_mingw"] = True # Cross-compilation using MinGW - prefix = "i686" if env["arch"] == "x86_32" else env["arch"] - env["CXX"] = prefix + "-w64-mingw32-g++" - env["CC"] = prefix + "-w64-mingw32-gcc" - env["AR"] = prefix + "-w64-mingw32-ar" - env["RANLIB"] = prefix + "-w64-mingw32-ranlib" - env["LINK"] = prefix + "-w64-mingw32-g++" + prefix = "" + if env["mingw_prefix"]: + prefix = env["mingw_prefix"] + "/bin/" + + if env["arch"] == "x86_64": + prefix += "x86_64" + elif env["arch"] == "arm64": + prefix += "aarch64" + elif env["arch"] == "arm32": + prefix += "armv7" + elif env["arch"] == "x86_32": + prefix += "i686" + + if env["use_llvm"]: + env["CXX"] = prefix + "-w64-mingw32-clang++" + env["CC"] = prefix + "-w64-mingw32-clang" + env["AR"] = prefix + "-w64-mingw32-llvm-ar" + env["RANLIB"] = prefix + "-w64-mingw32-ranlib" + env["LINK"] = prefix + "-w64-mingw32-clang" + else: + env["CXX"] = prefix + "-w64-mingw32-g++" + env["CC"] = prefix + "-w64-mingw32-gcc" + env["AR"] = prefix + "-w64-mingw32-gcc-ar" + env["RANLIB"] = prefix + "-w64-mingw32-ranlib" + env["LINK"] = prefix + "-w64-mingw32-g++" + # Want dll suffix env["SHLIBSUFFIX"] = ".dll" @@ -156,6 +191,11 @@ def generate(env): "-static-libstdc++", ] ) + if env["use_llvm"]: + env.Append(LINKFLAGS=["-lstdc++"]) + + if sys.platform == "win32" or sys.platform == "msys": + my_spawn.configure(env) env.Append(CPPDEFINES=["WINDOWS_ENABLED"]) From e52b4ea4fdbea4e8778978367c6adec6fcde9c83 Mon Sep 17 00:00:00 2001 From: ytnuf <161308826+ytnuf@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:44:39 +0100 Subject: [PATCH 02/13] Add hot reload support when building with GCC and CMake (cherry picked from commit 05571971cc4b57f34c1fce180c2df20750c5bc90) --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96090611..af62675a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,10 +124,6 @@ else() endif() endif() -if (GODOT_ENABLE_HOT_RELOAD) - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D HOT_RELOAD_ENABLED") -endif() - # Generate source from the bindings file find_package(Python3 3.4 REQUIRED) # pathlib should be present if(GENERATE_TEMPLATE_GET_NODE) @@ -170,6 +166,11 @@ target_compile_features(${PROJECT_NAME} cxx_std_17 ) +if(GODOT_ENABLE_HOT_RELOAD) + target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED) + target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>) +endif() + target_compile_definitions(${PROJECT_NAME} PUBLIC $<$: DEBUG_ENABLED From fa0b4cffc0f054c88b7dd477e693271d5b4d1055 Mon Sep 17 00:00:00 2001 From: Andreas Pokorny Date: Mon, 26 Aug 2024 13:20:26 +0200 Subject: [PATCH 03/13] Add visibility-hidden This should make all symbols that are not marked otherwise have hidden visibility. There still may be exposed symbols if marked with respective attributes. (cherry picked from commit d18fa929fbbf6d886e9122e1de948da94c29f54f) --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index af62675a..fba65b31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,10 @@ # Generate the buildfiles in a sub directory to not clutter the root directory with build files: # mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build . # +# Ensure that you avoid exposing godot-cpp symbols - this might lead to hard to debug errors if you ever load multiple +# plugins using difference godot-cpp versions. Use visibility hidden whenever possible: +# set_target_properties( PROPERTIES CXX_VISIBILITY_PRESET hidden) +# # Todo # Test build for Windows, Mac and mingw. @@ -222,6 +226,7 @@ set_target_properties(${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS OFF POSITION_INDEPENDENT_CODE ON + CXX_VISIBILITY_PRESET hidden ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" From b12aeb1b38b930e8617c1d9a7aff4ed13d87305c Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Thu, 12 Sep 2024 13:41:18 +0930 Subject: [PATCH 04/13] Add GODOT_SYMBOL_VISIBILITY cache variable to match scons interface. (cherry picked from commit 02bdc6665af45777b4d57120690a829d1c4445fc) --- CMakeLists.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fba65b31..d86a07b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,18 @@ option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class option(GODOT_CPP_SYSTEM_HEADERS "Expose headers as SYSTEM." ON) option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF) +set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING "Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)") +set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" ) + +# CXX_VISIBILITY_PRESET supported values are: default, hidden, protected, and internal +# which is inline with the gcc -fvisibility= +# https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html +# To match the scons options we need to change the text to match the -fvisibility flag +# it is probably worth another PR which changes both to use the flag options +if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" ) + set( GODOT_SYMBOL_VISIBILITY "default" ) +endif () + # Add path to modules list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) @@ -226,7 +238,7 @@ set_target_properties(${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS OFF POSITION_INDEPENDENT_CODE ON - CXX_VISIBILITY_PRESET hidden + CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY} ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" From daf8ac1c330839304040fb0ed5e8ff5775980cc3 Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Fri, 13 Sep 2024 22:06:25 +0930 Subject: [PATCH 05/13] Updated all variable names to use GODOT_ prefix changed cache type for api file and api dir to FILEPATH and PATH respectively. Minor whitespace. docstring parity (cherry picked from commit 390a9a5590c9e162f838fb7ed5a58e45d5b14643) --- CMakeLists.txt | 60 ++++++++++++++++--------------- cmake/GodotCompilerWarnings.cmake | 2 +- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d86a07b6..d0a6547d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,19 @@ # cmake arguments -# CMAKE_BUILD_TYPE: Compilation target (Debug or Release defaults to Debug) +# CMAKE_BUILD_TYPE: Compilation target (Debug or Release defaults to Debug) # # godot-cpp cmake arguments -# GODOT_GDEXTENSION_DIR: Path to the directory containing GDExtension interface header and API JSON file -# GODOT_CPP_SYSTEM_HEADERS Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one. -# GODOT_CPP_WARNING_AS_ERROR Treat any warnings as errors -# GODOT_ENABLE_HOT_RELOAD Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds. -# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) -# FLOAT_PRECISION: Floating-point precision level ("single", "double") +# GODOT_GDEXTENSION_DIR: Path to the directory containing GDExtension interface header and API JSON file +# GODOT_SYSTEM_HEADERS: Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one. +# GODOT_WARNING_AS_ERROR: Treat any warnings as errors +# GODOT_USE_HOT_RELOAD: Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds. +# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) +# GODOT_PRECISION: Floating-point precision level ("single", "double") # # Android cmake arguments -# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake) -# ANDROID_NDK: The path to the android ndk root folder -# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9) -# ANDROID_PLATFORM: The android platform version (android-23) +# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake) +# ANDROID_NDK: The path to the android ndk root folder +# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9) +# ANDROID_PLATFORM: The android platform version (android-23) # More info here: https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html # # Examples @@ -45,9 +45,9 @@ cmake_minimum_required(VERSION 3.13) project(godot-cpp LANGUAGES CXX) -option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON) -option(GODOT_CPP_SYSTEM_HEADERS "Expose headers as SYSTEM." ON) -option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF) +option(GODOT_GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node. (ON|OFF)" ON) +option(GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." ON) +option(GODOT_WARNING_AS_ERROR "Treat warnings as errors" OFF) set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING "Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)") set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" ) @@ -76,9 +76,9 @@ endif() # Hot reload is enabled by default in Debug-builds if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - option(GODOT_ENABLE_HOT_RELOAD "Build with hot reload support" ON) + option(GODOT_USE_HOT_RELOAD "Enable the extra accounting required to support hot reload. (ON|OFF)" ON) else() - option(GODOT_ENABLE_HOT_RELOAD "Build with hot reload support" OFF) + option(GODOT_USE_HOT_RELOAD "Enable the extra accounting required to support hot reload. (ON|OFF)" OFF) endif() if(NOT DEFINED BITS) @@ -89,20 +89,22 @@ if(NOT DEFINED BITS) endif() # Input from user for GDExtension interface header and the API JSON file -set(GODOT_GDEXTENSION_DIR "gdextension" CACHE STRING "") -set(GODOT_CUSTOM_API_FILE "" CACHE STRING "") +set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH + "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" ) +set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH + "Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) ( /path/to/custom_api_file )") set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json") if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override. set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}") endif() -set(FLOAT_PRECISION "single" CACHE STRING "") -if ("${FLOAT_PRECISION}" STREQUAL "double") +set(GODOT_PRECISION "single" CACHE STRING "Set the floating-point precision level (single|double)") +if ("${GODOT_PRECISION}" STREQUAL "double") add_definitions(-DREAL_T_IS_DOUBLE) endif() -set(GODOT_COMPILE_FLAGS ) +set( GODOT_COMPILE_FLAGS ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # using Visual Studio C++ @@ -127,7 +129,7 @@ endif() # Disable exception handling. Godot doesn't use exceptions anywhere, and this # saves around 20% of binary size and very significant build time (GH-80513). -option(GODOT_DISABLE_EXCEPTIONS ON "Force disabling exception handling code") +option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON ) if (GODOT_DISABLE_EXCEPTIONS) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0") @@ -142,7 +144,7 @@ endif() # Generate source from the bindings file find_package(Python3 3.4 REQUIRED) # pathlib should be present -if(GENERATE_TEMPLATE_GET_NODE) +if(GODOT_GENERATE_TEMPLATE_GET_NODE) set(GENERATE_BINDING_PARAMETERS "True") else() set(GENERATE_BINDING_PARAMETERS "False") @@ -155,7 +157,7 @@ execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; ) add_custom_command(OUTPUT ${GENERATED_FILES_LIST} - COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${FLOAT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")" + COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${GODOT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")" VERBATIM WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE} @@ -182,7 +184,7 @@ target_compile_features(${PROJECT_NAME} cxx_std_17 ) -if(GODOT_ENABLE_HOT_RELOAD) +if(GODOT_USE_HOT_RELOAD) target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED) target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>) endif() @@ -206,12 +208,12 @@ target_link_options(${PROJECT_NAME} PRIVATE ) # Optionally mark headers as SYSTEM -set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE "") -if (GODOT_CPP_SYSTEM_HEADERS) - set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) +set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "") +if (GODOT_SYSTEM_HEADERS) + set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) endif () -target_include_directories(${PROJECT_NAME} ${GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC +target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC include ${CMAKE_CURRENT_BINARY_DIR}/gen/include ${GODOT_GDEXTENSION_DIR} diff --git a/cmake/GodotCompilerWarnings.cmake b/cmake/GodotCompilerWarnings.cmake index 423e6366..94556415 100644 --- a/cmake/GodotCompilerWarnings.cmake +++ b/cmake/GodotCompilerWarnings.cmake @@ -89,6 +89,6 @@ function( set_warning_as_error ) endif() endfunction() -if ( GODOT_CPP_WARNING_AS_ERROR ) +if ( GODOT_WARNING_AS_ERROR ) set_warning_as_error() endif() From 5fe58bcd1ea55a7b2a93f68b817dd373d2c5a64b Mon Sep 17 00:00:00 2001 From: David Snopek Date: Tue, 17 Sep 2024 09:18:08 -0500 Subject: [PATCH 06/13] Correctly set instance bindings on reload (cherry picked from commit cb543c192aef18b3e9b9d2c9f2ba770a4e574ad0) --- include/godot_cpp/classes/wrapped.hpp | 13 ++++-------- include/godot_cpp/core/class_db.hpp | 3 +-- src/classes/wrapped.cpp | 29 ++++++++++----------------- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index 0ffd783f..a0bcec7b 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -61,6 +61,10 @@ class Wrapped { thread_local static const StringName *_constructing_extension_class_name; thread_local static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks; +#ifdef HOT_RELOAD_ENABLED + thread_local static GDExtensionObjectPtr _constructing_recreate_owner; +#endif + template _ALWAYS_INLINE_ static void _set_construct_info() { _constructing_extension_class_name = T::_get_extension_class_name(); @@ -71,15 +75,6 @@ protected: virtual bool _is_extension_class() const { return false; } static const StringName *_get_extension_class_name(); // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned. -#ifdef HOT_RELOAD_ENABLED - struct RecreateInstance { - GDExtensionClassInstancePtr wrapper; - GDExtensionObjectPtr owner; - RecreateInstance *next; - }; - inline static RecreateInstance *recreate_instance = nullptr; -#endif - void _notification(int p_what) {} bool _set(const StringName &p_name, const Variant &p_property) { return false; } bool _get(const StringName &p_name, Variant &r_property) const { return false; } diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 988277b0..85bc0fb7 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -129,9 +129,8 @@ private: static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) { if constexpr (!std::is_abstract_v) { #ifdef HOT_RELOAD_ENABLED + Wrapped::_constructing_recreate_owner = obj; T *new_instance = (T *)memalloc(sizeof(T)); - Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance }; - Wrapped::recreate_instance = &recreate_data; memnew_placement(new_instance, T); return new_instance; #else diff --git a/src/classes/wrapped.cpp b/src/classes/wrapped.cpp index ffca4f97..d397d46d 100644 --- a/src/classes/wrapped.cpp +++ b/src/classes/wrapped.cpp @@ -42,6 +42,10 @@ namespace godot { thread_local const StringName *Wrapped::_constructing_extension_class_name = nullptr; thread_local const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr; +#ifdef HOT_RELOAD_ENABLED +thread_local GDExtensionObjectPtr Wrapped::_constructing_recreate_owner = nullptr; +#endif + const StringName *Wrapped::_get_extension_class_name() { return nullptr; } @@ -55,25 +59,14 @@ void Wrapped::_postinitialize() { Wrapped::Wrapped(const StringName p_godot_class) { #ifdef HOT_RELOAD_ENABLED - if (unlikely(Wrapped::recreate_instance)) { - RecreateInstance *recreate_data = Wrapped::recreate_instance; - RecreateInstance *previous = nullptr; - while (recreate_data) { - if (recreate_data->wrapper == this) { - _owner = recreate_data->owner; - if (previous) { - previous->next = recreate_data->next; - } else { - Wrapped::recreate_instance = recreate_data->next; - } - return; - } - previous = recreate_data; - recreate_data = recreate_data->next; - } - } + if (unlikely(Wrapped::_constructing_recreate_owner)) { + _owner = Wrapped::_constructing_recreate_owner; + Wrapped::_constructing_recreate_owner = nullptr; + } else #endif - _owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast(p_godot_class._native_ptr())); + { + _owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast(p_godot_class._native_ptr())); + } if (_constructing_extension_class_name) { godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast(_constructing_extension_class_name), this); From 2de650b82a45e295ac4fafbc509074aa253041b9 Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Thu, 19 Sep 2024 08:11:03 +0930 Subject: [PATCH 07/13] Re-Structure cmake solution to be closer to the scons solution. This is just a single step, re-arranging the code without actually changing its functionality. new docs/cmake.md moved the block of comments from the start of the CMakeLists.txt into the cmake.md file and converted content to markdown. new cmake/godotcpp.cmake Moved all exposed options into a new function godotcpp_options() Moved configuration and generation code into godotcpp_generate() To get all the options into the godotcpp_options() I changed the logic of GODOT_USE_HOT_RELOAD which I believe is a closer match to scons, that if the options is not set, and the build type is not release, then it defaults to ON. I msvc builds require the default flags to be modified or it will throw errors. I have added the links to articles in the commit, but its about removing the runtime error checks /RTC1 from the CMAKE_CXX_FLAGS_DEBUG variable. This needs to happen before the files are included. https://stackoverflow.com/questions/74426638/how-to-remove-rtc1-from-specific-target-or-file-in-cmake https://discourse.cmake.org/t/how-do-i-remove-compile-options-from-target/5965 Renamed GodotCompilerWarnings.cmake to common_compiler_flags.cmake to match scons Included files explicitly by path, as we dont need to append to the CMAKE_MODULES_PATH which effects the whole build tree. This prevents consumers of the library from clobbering the names of the cmake include files and breaking the build. (cherry picked from commit 2402a044ebc2189f6c725b9a64c66c9bc2e5c616) --- CMakeLists.txt | 254 ++---------------- ...ings.cmake => common_compiler_flags.cmake} | 0 cmake/godotcpp.cmake | 240 +++++++++++++++++ doc/cmake.md | 57 ++++ 4 files changed, 312 insertions(+), 239 deletions(-) rename cmake/{GodotCompilerWarnings.cmake => common_compiler_flags.cmake} (100%) create mode 100644 cmake/godotcpp.cmake create mode 100644 doc/cmake.md diff --git a/CMakeLists.txt b/CMakeLists.txt index d0a6547d..ff77368b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,248 +1,24 @@ -# cmake arguments -# CMAKE_BUILD_TYPE: Compilation target (Debug or Release defaults to Debug) -# -# godot-cpp cmake arguments -# GODOT_GDEXTENSION_DIR: Path to the directory containing GDExtension interface header and API JSON file -# GODOT_SYSTEM_HEADERS: Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one. -# GODOT_WARNING_AS_ERROR: Treat any warnings as errors -# GODOT_USE_HOT_RELOAD: Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds. -# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) -# GODOT_PRECISION: Floating-point precision level ("single", "double") -# -# Android cmake arguments -# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake) -# ANDROID_NDK: The path to the android ndk root folder -# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9) -# ANDROID_PLATFORM: The android platform version (android-23) -# More info here: https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html -# -# Examples -# -# Builds a debug version: -# cmake . -# cmake --build . -# -# Builds a release version with clang -# CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" . -# cmake --build . -# -# Builds an android armeabi-v7a debug version: -# cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \ -# -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug . -# cmake --build . -# -# Protip -# Generate the buildfiles in a sub directory to not clutter the root directory with build files: -# mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build . -# -# Ensure that you avoid exposing godot-cpp symbols - this might lead to hard to debug errors if you ever load multiple -# plugins using difference godot-cpp versions. Use visibility hidden whenever possible: -# set_target_properties( PROPERTIES CXX_VISIBILITY_PRESET hidden) -# -# Todo -# Test build for Windows, Mac and mingw. - cmake_minimum_required(VERSION 3.13) project(godot-cpp LANGUAGES CXX) -option(GODOT_GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node. (ON|OFF)" ON) -option(GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." ON) -option(GODOT_WARNING_AS_ERROR "Treat warnings as errors" OFF) - -set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING "Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)") -set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" ) - -# CXX_VISIBILITY_PRESET supported values are: default, hidden, protected, and internal -# which is inline with the gcc -fvisibility= -# https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html -# To match the scons options we need to change the text to match the -fvisibility flag -# it is probably worth another PR which changes both to use the flag options -if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" ) - set( GODOT_SYMBOL_VISIBILITY "default" ) +# Configure CMake +# https://discourse.cmake.org/t/how-do-i-remove-compile-options-from-target/5965 +# https://stackoverflow.com/questions/74426638/how-to-remove-rtc1-from-specific-target-or-file-in-cmake +if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) + if(NOT CMAKE_BUILD_TYPE MATCHES Debug) + STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + endif () endif () -# Add path to modules -list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) +include( ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake ) -# Set some helper variables for readability -set( compiler_is_clang "$,$>" ) -set( compiler_is_gnu "$" ) -set( compiler_is_msvc "$" ) +# I know this doesn't look like a typical CMakeLists.txt, but as we are +# attempting mostly feature parity with SCons, and easy maintenance, the closer +# the two build systems look the easier they will be to keep in lockstep. -# Default build type is Debug in the SConstruct -if("${CMAKE_BUILD_TYPE}" STREQUAL "") - set(CMAKE_BUILD_TYPE Debug) -endif() +# The typical target definitions are in ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake -# Hot reload is enabled by default in Debug-builds -if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - option(GODOT_USE_HOT_RELOAD "Enable the extra accounting required to support hot reload. (ON|OFF)" ON) -else() - option(GODOT_USE_HOT_RELOAD "Enable the extra accounting required to support hot reload. (ON|OFF)" OFF) -endif() +godotcpp_options() -if(NOT DEFINED BITS) - set(BITS 32) - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(BITS 64) - endif(CMAKE_SIZEOF_VOID_P EQUAL 8) -endif() - -# Input from user for GDExtension interface header and the API JSON file -set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH - "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" ) -set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH - "Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) ( /path/to/custom_api_file )") - -set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json") -if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override. - set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}") -endif() - -set(GODOT_PRECISION "single" CACHE STRING "Set the floating-point precision level (single|double)") -if ("${GODOT_PRECISION}" STREQUAL "double") - add_definitions(-DREAL_T_IS_DOUBLE) -endif() - -set( GODOT_COMPILE_FLAGS ) - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # using Visual Studio C++ - set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP - - if(CMAKE_BUILD_TYPE MATCHES Debug) - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi - else() - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy - STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) - endif(CMAKE_BUILD_TYPE MATCHES Debug) - - add_definitions(-DNOMINMAX) -else() # GCC/Clang - if(CMAKE_BUILD_TYPE MATCHES Debug) - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g") - else() - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3") - endif(CMAKE_BUILD_TYPE MATCHES Debug) -endif() - -# Disable exception handling. Godot doesn't use exceptions anywhere, and this -# saves around 20% of binary size and very significant build time (GH-80513). -option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON ) -if (GODOT_DISABLE_EXCEPTIONS) - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0") - else() - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions") - endif() -else() - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc") - endif() -endif() - -# Generate source from the bindings file -find_package(Python3 3.4 REQUIRED) # pathlib should be present -if(GODOT_GENERATE_TEMPLATE_GET_NODE) - set(GENERATE_BINDING_PARAMETERS "True") -else() - set(GENERATE_BINDING_PARAMETERS "False") -endif() - -execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE GENERATED_FILES_LIST - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -add_custom_command(OUTPUT ${GENERATED_FILES_LIST} - COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${GODOT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")" - VERBATIM - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py - COMMENT "Generating bindings" -) - -# Get Sources -file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**) -file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**) - -# Define our godot-cpp library -add_library(${PROJECT_NAME} STATIC - ${SOURCES} - ${HEADERS} - ${GENERATED_FILES_LIST} -) -add_library(godot::cpp ALIAS ${PROJECT_NAME}) - -include(GodotCompilerWarnings) - -target_compile_features(${PROJECT_NAME} - PRIVATE - cxx_std_17 -) - -if(GODOT_USE_HOT_RELOAD) - target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED) - target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>) -endif() - -target_compile_definitions(${PROJECT_NAME} PUBLIC - $<$: - DEBUG_ENABLED - DEBUG_METHODS_ENABLED - > - $<${compiler_is_msvc}: - TYPED_METHOD_BIND - > -) - -target_link_options(${PROJECT_NAME} PRIVATE - $<$: - -static-libgcc - -static-libstdc++ - -Wl,-R,'$$ORIGIN' - > -) - -# Optionally mark headers as SYSTEM -set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "") -if (GODOT_SYSTEM_HEADERS) - set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) -endif () - -target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC - include - ${CMAKE_CURRENT_BINARY_DIR}/gen/include - ${GODOT_GDEXTENSION_DIR} -) - -# Add the compile flags -set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS}) - -# Create the correct name (godot.os.build_type.system_bits) -string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME) -string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE) - -if(ANDROID) - # Added the android abi after system name - set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI}) - - # Android does not have the bits at the end if you look at the main godot repo build - set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}") -else() - set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}") -endif() - -set_target_properties(${PROJECT_NAME} - PROPERTIES - CXX_EXTENSIONS OFF - POSITION_INDEPENDENT_CODE ON - CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY} - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - OUTPUT_NAME "${OUTPUT_NAME}" -) +godotcpp_generate() diff --git a/cmake/GodotCompilerWarnings.cmake b/cmake/common_compiler_flags.cmake similarity index 100% rename from cmake/GodotCompilerWarnings.cmake rename to cmake/common_compiler_flags.cmake diff --git a/cmake/godotcpp.cmake b/cmake/godotcpp.cmake new file mode 100644 index 00000000..a5c66779 --- /dev/null +++ b/cmake/godotcpp.cmake @@ -0,0 +1,240 @@ +function( godotcpp_options ) + + #TODO platform + #TODO target + + # Input from user for GDExtension interface header and the API JSON file + set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH + "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" ) + set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH + "Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) ( /path/to/custom_api_file )") + + #TODO generate_bindings + + option(GODOT_GENERATE_TEMPLATE_GET_NODE + "Generate a template version of the Node class's get_node. (ON|OFF)" ON) + + #TODO build_library + + set(GODOT_PRECISION "single" CACHE STRING + "Set the floating-point precision level (single|double)") + + #TODO arch + #TODO threads + #TODO compiledb + #TODO compiledb_file + #TODO build_profile aka cmake preset + + set(GODOT_USE_HOT_RELOAD "" CACHE BOOL + "Enable the extra accounting required to support hot reload. (ON|OFF)") + + option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON ) + + set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING + "Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)") + set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" ) + + #TODO optimize + #TODO debug_symbols + #TODO dev_build + + # FIXME These options are not present in SCons, and perhaps should be added there. + option(GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." ON) + option(GODOT_WARNING_AS_ERROR "Treat warnings as errors" OFF) + + # Run options commands on the following to populate cache for all platforms. + # This type of thing is typically done conditionally + # But as scons shows all options so shall we. + #TODO ios_options() + #TODO linux_options() + #TODO macos_options() + #TODO web_options() + #TODO windows_options() +endfunction() + + +function( godotcpp_generate ) + # Set some helper variables for readability + set( compiler_is_clang "$,$>" ) + set( compiler_is_gnu "$" ) + set( compiler_is_msvc "$" ) + + # CXX_VISIBILITY_PRESET supported values are: default, hidden, protected, and internal + # which is inline with the gcc -fvisibility= + # https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html + # To match the scons options we need to change the text to match the -fvisibility flag + # it is probably worth another PR which changes both to use the flag options + if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" ) + set( GODOT_SYMBOL_VISIBILITY "default" ) + endif () + + # Default build type is Debug in the SConstruct + if("${CMAKE_BUILD_TYPE}" STREQUAL "") + set(CMAKE_BUILD_TYPE Debug) + endif() + + # Hot reload is enabled by default in Debug-builds + if( GODOT_USE_HOT_RELOAD STREQUAL "" AND NOT CMAKE_BUILD_TYPE STREQUAL "Release") + set(GODOT_USE_HOT_RELOAD ON) + endif() + + if(NOT DEFINED BITS) + set(BITS 32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BITS 64) + endif(CMAKE_SIZEOF_VOID_P EQUAL 8) + endif() + + + set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json") + if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override. + set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}") + endif() + + if ("${GODOT_PRECISION}" STREQUAL "double") + add_definitions(-DREAL_T_IS_DOUBLE) + endif() + + set( GODOT_COMPILE_FLAGS ) + + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # using Visual Studio C++ + set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP + + if(CMAKE_BUILD_TYPE MATCHES Debug) + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi + else() + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy + endif(CMAKE_BUILD_TYPE MATCHES Debug) + + add_definitions(-DNOMINMAX) + else() # GCC/Clang + if(CMAKE_BUILD_TYPE MATCHES Debug) + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g") + else() + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3") + endif(CMAKE_BUILD_TYPE MATCHES Debug) + endif() + + # Disable exception handling. Godot doesn't use exceptions anywhere, and this + # saves around 20% of binary size and very significant build time (GH-80513). + if (GODOT_DISABLE_EXCEPTIONS) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0") + else() + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions") + endif() + else() + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc") + endif() + endif() + + # Generate source from the bindings file + find_package(Python3 3.4 REQUIRED) # pathlib should be present + if(GODOT_GENERATE_TEMPLATE_GET_NODE) + set(GENERATE_BINDING_PARAMETERS "True") + else() + set(GENERATE_BINDING_PARAMETERS "False") + endif() + + execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE GENERATED_FILES_LIST + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + add_custom_command(OUTPUT ${GENERATED_FILES_LIST} + COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${GODOT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")" + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py + COMMENT "Generating bindings" + ) + + # Get Sources + # As this cmake file was added using 'include(godotcpp)' from the root CMakeLists.txt, + # the ${CMAKE_CURRENT_SOURCE_DIR} is still the root dir. + file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**) + file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**) + + # Define our godot-cpp library + add_library(${PROJECT_NAME} STATIC + ${SOURCES} + ${HEADERS} + ${GENERATED_FILES_LIST} + ) + add_library(godot::cpp ALIAS ${PROJECT_NAME}) + + include(${PROJECT_SOURCE_DIR}/cmake/common_compiler_flags.cmake) + + target_compile_features(${PROJECT_NAME} + PRIVATE + cxx_std_17 + ) + + if(GODOT_USE_HOT_RELOAD) + target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED) + target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>) + endif() + + target_compile_definitions(${PROJECT_NAME} PUBLIC + $<$: + DEBUG_ENABLED + DEBUG_METHODS_ENABLED + > + $<${compiler_is_msvc}: + TYPED_METHOD_BIND + > + ) + + target_link_options(${PROJECT_NAME} PRIVATE + $<$: + -static-libgcc + -static-libstdc++ + -Wl,-R,'$$ORIGIN' + > + ) + + # Optionally mark headers as SYSTEM + set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "") + if (GODOT_SYSTEM_HEADERS) + set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) + endif () + + target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC + include + ${CMAKE_CURRENT_BINARY_DIR}/gen/include + ${GODOT_GDEXTENSION_DIR} + ) + + # Add the compile flags + set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS}) + + # Create the correct name (godot.os.build_type.system_bits) + string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME) + string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE) + + if(ANDROID) + # Added the android abi after system name + set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI}) + + # Android does not have the bits at the end if you look at the main godot repo build + set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}") + else() + set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}") + endif() + + set_target_properties(${PROJECT_NAME} + PROPERTIES + CXX_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ON + CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY} + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" + OUTPUT_NAME "${OUTPUT_NAME}" + ) + +endfunction() diff --git a/doc/cmake.md b/doc/cmake.md new file mode 100644 index 00000000..3dd77f58 --- /dev/null +++ b/doc/cmake.md @@ -0,0 +1,57 @@ +## CMake + +### cmake arguments + +`CMAKE_BUILD_TYPE`: Compilation target (Debug or Release defaults to Debug) + +### godot-cpp cmake arguments +- `GODOT_GDEXTENSION_DIR`: Path to the directory containing GDExtension interface header and API JSON file +- `GODOT_SYSTEM_HEADERS`: Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one. +- `GODOT_WARNING_AS_ERROR`: Treat any warnings as errors +- `GODOT_USE_HOT_RELOAD`: Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds. +- `GODOT_CUSTOM_API_FILE`: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) +- `GODOT_PRECISION`: Floating-point precision level ("single", "double") + +### Android cmake arguments +- `CMAKE_TOOLCHAIN_FILE`: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake) +- `ANDROID_NDK`: The path to the android ndk root folder +- `ANDROID_TOOLCHAIN_NAME`: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9) +- `ANDROID_PLATFORM`: The android platform version (android-23) + +- More info [here](https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html) + +## Examples +```shell +Builds a debug version: +cmake . +cmake --build . +``` +Builds a release version with clang + +```shell +CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" . +cmake --build . +``` +Builds an android armeabi-v7a debug version: + +``` shell +cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \ + -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug . +cmake --build . +``` + +## Protip +Generate the buildfiles in a sub directory to not clutter the root directory with build files: + +```shell +mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build . +``` + +Ensure that you avoid exposing godot-cpp symbols - this might lead to hard to debug errors if you ever load multiple +plugins using difference godot-cpp versions. Use visibility hidden whenever possible: +```cmake +set_target_properties( PROPERTIES CXX_VISIBILITY_PRESET hidden) +``` + +## Todo +Test build for Windows, Mac and mingw. From e751531290ef0e80688c54037ae503e7185619ad Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Thu, 19 Sep 2024 21:38:35 +0930 Subject: [PATCH 08/13] update .gitignore to add .idea for the Jetbrains CLion IDE and also the default cmake build directory when building in clion cmake-build-* (cherry picked from commit 9f5daa2d904c8acae0540c11ee35cd1f78724429) --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 4183b24f..ee9a3f75 100644 --- a/.gitignore +++ b/.gitignore @@ -195,3 +195,7 @@ compile_commands.json # Python development .venv venv + +# Clion Configuration +.idea/ +cmake-build-* From a3d5d6d4d3218d83c928aa0e27cb0dc0b26baaa9 Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Sat, 21 Sep 2024 22:38:07 +0930 Subject: [PATCH 09/13] VSProj Configure type on build command - to resolve #1582 Visual Studio projects are multi-config projects like Ninja-MultiConfig which means you can't set the configuration at configure time as there are multiple, it always chooses the first one by default when not specified in the build command. Instead of this: cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 17 2022" . cmake --build . --verbose It should be this cmake -G"Visual Studio 17 2022" . cmake --build . --verbose --config Release Update ci.yml Because the current build system doesnt use generator expressions for multi config builds, both the CMAKE_BUILD_TYPE and the build --config options need to be set (cherry picked from commit 07704f8f48308b83fc99c67b33a10027aa5a7846) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76abdd57..13b7243e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -264,9 +264,9 @@ jobs: - name: Build godot-cpp run: | cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 16 2019" . - cmake --build . --verbose + cmake --build . --verbose --config Release - name: Build test GDExtension library run: | cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -G"Visual Studio 16 2019" . - cmake --build . --verbose + cmake --build . --verbose --config Release From 30a395bf439c7d7af90d55a4a95cba71aa7e9250 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Sun, 22 Sep 2024 13:39:06 +0200 Subject: [PATCH 10/13] [SCons] Remove use_clang_cl windows flag in favor of generic use_llvm This is consistent with Godot upstream. (cherry picked from commit 4717a781445d9d1e9044602925cd9640b73a1b28) --- tools/windows.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/windows.py b/tools/windows.py index 6fd4b038..2e8d609e 100644 --- a/tools/windows.py +++ b/tools/windows.py @@ -76,10 +76,9 @@ def options(opts): mingw = os.getenv("MINGW_PREFIX", "") opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler instead of MSVC - only effective on Windows", False)) - opts.Add(BoolVariable("use_clang_cl", "Use the clang driver instead of MSVC - only effective on Windows", False)) opts.Add(BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True)) opts.Add(BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting errors to stderr.", True)) - opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler", False)) + opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag)", False)) opts.Add("mingw_prefix", "MinGW prefix", mingw) @@ -114,7 +113,7 @@ def generate(env): env.Append(CCFLAGS=["/utf-8"]) env.Append(LINKFLAGS=["/WX"]) - if env["use_clang_cl"]: + if env["use_llvm"]: env["CC"] = "clang-cl" env["CXX"] = "clang-cl" From af78f2778fe5ba941e04b087d067625d090312fd Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 23 Sep 2024 13:29:40 +0200 Subject: [PATCH 11/13] [SCons] Enable WASM_BIGINT in web builds Required since Godot 4.3, which is also the first Godot version with wide WASM gdnative support (previous versions were Chrome-only, and very brittle). (cherry picked from commit 78498da7c329141ba3c54e43561bf470a86b3dab) --- tools/web.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/web.py b/tools/web.py index c8f07c55..e878a78f 100644 --- a/tools/web.py +++ b/tools/web.py @@ -42,6 +42,10 @@ def generate(env): env.Append(CCFLAGS=["-sSIDE_MODULE=1"]) env.Append(LINKFLAGS=["-sSIDE_MODULE=1"]) + # Enable WebAssembly BigInt <-> i64 conversion. + # This must match the flag used to build Godot (true in official builds since 4.3) + env.Append(LINKFLAGS=["-sWASM_BIGINT"]) + # Force wasm longjmp mode. env.Append(CCFLAGS=["-sSUPPORT_LONGJMP='wasm'"]) env.Append(LINKFLAGS=["-sSUPPORT_LONGJMP='wasm'"]) From bf26191ead2680fc59c51ffd60236627e4b606e6 Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Mon, 30 Sep 2024 11:26:06 -0500 Subject: [PATCH 12/13] SCons: Don't cache librarys (cherry picked from commit 83c0f15ab95d608f2c39eda942ee4a51cc1f0456) --- test/SConstruct | 1 + tools/godotcpp.py | 1 + 2 files changed, 2 insertions(+) diff --git a/test/SConstruct b/test/SConstruct index 1f1db0ff..b949bcac 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -42,4 +42,5 @@ else: source=sources, ) +env.NoCache(library) Default(library) diff --git a/tools/godotcpp.py b/tools/godotcpp.py index 9ceac02b..b2a63dc1 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -552,6 +552,7 @@ def _godot_cpp(env): if env["build_library"]: library = env.StaticLibrary(target=env.File("bin/%s" % library_name), source=sources) + env.NoCache(library) default_args = [library] # Add compiledb if the option is set From 94d74979cede0a18e66040ae58834b1cc16d18f2 Mon Sep 17 00:00:00 2001 From: Florent Guiocheau Date: Mon, 14 Oct 2024 21:45:17 +0200 Subject: [PATCH 13/13] Add p_use_model_front to Basis::looking_at() (cherry picked from commit 02fd535454773edb1a8c4b52d5b851e863660246) --- include/godot_cpp/variant/basis.hpp | 2 +- src/variant/basis.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/godot_cpp/variant/basis.hpp b/include/godot_cpp/variant/basis.hpp index e740a64a..f3ebe15f 100644 --- a/include/godot_cpp/variant/basis.hpp +++ b/include/godot_cpp/variant/basis.hpp @@ -224,7 +224,7 @@ struct _NO_DISCARD_ Basis { operator Quaternion() const { return get_quaternion(); } - static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); + static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false); Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); } Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); } diff --git a/src/variant/basis.cpp b/src/variant/basis.cpp index 200cd068..d8a99191 100644 --- a/src/variant/basis.cpp +++ b/src/variant/basis.cpp @@ -1037,12 +1037,15 @@ void Basis::rotate_sh(real_t *p_values) { p_values[8] = d4 * s_scale_dst4; } -Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) { +Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(p_target.is_zero_approx(), Basis(), "The target vector can't be zero."); ERR_FAIL_COND_V_MSG(p_up.is_zero_approx(), Basis(), "The up vector can't be zero."); #endif - Vector3 v_z = -p_target.normalized(); + Vector3 v_z = p_target.normalized(); + if (!p_use_model_front) { + v_z = -v_z; + } Vector3 v_x = p_up.cross(v_z); #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other.");