From 7f02301a91d3cb6688e510a89bc13550d956df0d Mon Sep 17 00:00:00 2001 From: David Snopek Date: Mon, 7 Oct 2024 11:22:52 -0500 Subject: [PATCH 01/15] Don't print an error when decoding a null Ref --- include/godot_cpp/classes/ref.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/godot_cpp/classes/ref.hpp b/include/godot_cpp/classes/ref.hpp index 137b677b..8511fe4c 100644 --- a/include/godot_cpp/classes/ref.hpp +++ b/include/godot_cpp/classes/ref.hpp @@ -230,7 +230,9 @@ template struct PtrToArg> { _FORCE_INLINE_ static Ref convert(const void *p_ptr) { GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr; - ERR_FAIL_NULL_V(p_ptr, Ref()); + if (unlikely(!p_ptr)) { + return Ref(); + } return Ref(reinterpret_cast(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref)))); } @@ -254,7 +256,9 @@ struct PtrToArg &> { _FORCE_INLINE_ static Ref convert(const void *p_ptr) { GDExtensionRefPtr ref = const_cast(p_ptr); - ERR_FAIL_NULL_V(p_ptr, Ref()); + if (unlikely(!p_ptr)) { + return Ref(); + } return Ref(reinterpret_cast(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref)))); } }; From 450c3d65cd182b3e33a1deeae250143e699f7972 Mon Sep 17 00:00:00 2001 From: Zhehang Ding Date: Mon, 7 Oct 2024 20:51:51 +0800 Subject: [PATCH 02/15] Use namespace in defs.hpp A global alias of godot::real_t is defined for backward compatibility --- include/godot_cpp/core/defs.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/godot_cpp/core/defs.hpp b/include/godot_cpp/core/defs.hpp index 16812c2b..5b985ffc 100644 --- a/include/godot_cpp/core/defs.hpp +++ b/include/godot_cpp/core/defs.hpp @@ -35,6 +35,8 @@ #include #include +namespace godot { + #if !defined(GDE_EXPORT) #if defined(_WIN32) #define GDE_EXPORT __declspec(dllexport) @@ -127,4 +129,10 @@ struct BuildIndexSequence : BuildIndexSequence {}; template struct BuildIndexSequence<0, Is...> : IndexSequence {}; +} //namespace godot + +// To maintain compatibility an alias is defined outside the namespace. +// Consider it deprecated. +using real_t = godot::real_t; + #endif // GODOT_DEFS_HPP From 8534e2104fce6bee62e0ff18e15fc013b7b7e432 Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Thu, 21 Nov 2024 11:00:48 +1030 Subject: [PATCH 03/15] Modernise Existing CMakeLists.txt - Added to .gitignore CMakeUserPresets.json ### Configuration: - Changed python command to use single quotes to make build output log more legible. - Added GODOT_DEV_BUILD to allow differentiation of debug or Release builds. - Added find logic for macos Cocoa library ### godot-cpp Changes - godot-cpp-test is changed to be incorporated into the cmake build as a target. - Duplicated godot-cpp target into [template_release, template_debug, editor] - Created {platform}.cmake files mirroring the style of the SCons build. CMake has a feature called generator expressions for its configuration variables that are evaluated at build time. This allows multi-configuration build systems to properly evaulate options. for msvc, xcode and nijna multi-config. - Moved configuration options to generator expressions with the notable exclusion of OSX_ARCHITECTURES. - Remove CMAKE_BUILD_TYPE from msvc CI target as Multi-Config generators ignore it ### godot-cpp-test Changes - Removed majority of the cmake code, now that the godot-cpp project is setup, the majority of the flags will be propagated as transient dependencies - Marked with EXCLUDE_FROM_ALL so that it isn't built as part of the 'all' target - Updated ci to build the godot-cpp-test target from the root directory using cmake - Tests passing for Windows, Linux, and Macos builds. ### Documentation Updated with new information Added Emscripten example Added Android example --- .github/workflows/ci.yml | 46 +--- .gitignore | 5 +- CMakeLists.txt | 108 +++++++-- cmake/android.cmake | 41 ++++ cmake/common_compiler_flags.cmake | 254 ++++++++++++-------- cmake/emsdkHack.cmake | 40 ++++ cmake/godotcpp.cmake | 376 +++++++++++++++++------------- cmake/ios.cmake | 22 ++ cmake/linux.cmake | 22 ++ cmake/macos.cmake | 59 +++++ cmake/web.cmake | 42 ++++ cmake/windows.cmake | 63 +++++ doc/cmake.md | 57 ----- doc/cmake.rst | 331 ++++++++++++++++++++++++++ test/CMakeLists.txt | 183 +++++---------- 15 files changed, 1153 insertions(+), 496 deletions(-) create mode 100644 cmake/android.cmake create mode 100644 cmake/emsdkHack.cmake create mode 100644 cmake/ios.cmake create mode 100644 cmake/linux.cmake create mode 100644 cmake/macos.cmake create mode 100644 cmake/web.cmake create mode 100644 cmake/windows.cmake delete mode 100644 doc/cmake.md create mode 100644 doc/cmake.rst diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 246689ae..33b2450d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -207,30 +207,6 @@ jobs: path: ${{ matrix.artifact-path }} if-no-files-found: error - linux-cmake: - name: 🐧 Build (Linux, GCC, CMake) - runs-on: ubuntu-22.04 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install dependencies - run: | - sudo apt-get update -qq - sudo apt-get install -qqq build-essential pkg-config cmake - - - name: Build godot-cpp - run: | - cmake -DCMAKE_BUILD_TYPE=Release . - make -j $(nproc) VERBOSE=1 - - - name: Build test GDExtension library - run: | - cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." . - make -j $(nproc) VERBOSE=1 - linux-cmake-ninja: name: 🐧 Build (Linux, GCC, CMake Ninja) runs-on: ubuntu-22.04 @@ -245,15 +221,12 @@ jobs: sudo apt-get update -qq sudo apt-get install -qqq build-essential pkg-config cmake ninja-build - - name: Build godot-cpp - run: | - cmake -DCMAKE_BUILD_TYPE=Release -GNinja . - cmake --build . -j $(nproc) --verbose - - name: Build test GDExtension library run: | - cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -GNinja . - cmake --build . -j $(nproc) --verbose + mkdir cmake-build + cd cmake-build + cmake ../ -DTEST_TARGET=template_release + cmake --build . --verbose -j $(nproc) -t godot-cpp-test --config Release windows-msvc-cmake: name: 🏁 Build (Windows, MSVC, CMake) @@ -264,12 +237,9 @@ jobs: with: submodules: recursive - - name: Build godot-cpp - run: | - cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 16 2019" . - 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 --config Release + mkdir cmake-build + cd cmake-build + cmake ../ -DTEST_TARGET=template_release + cmake --build . --verbose -t godot-cpp-test --config Release diff --git a/.gitignore b/.gitignore index ee9a3f75..9bb08ed3 100644 --- a/.gitignore +++ b/.gitignore @@ -198,4 +198,7 @@ venv # Clion Configuration .idea/ -cmake-build-* +cmake-build*/ + +# CMake related +CMakeUserPresets.json diff --git a/CMakeLists.txt b/CMakeLists.txt index ff77368b..926946d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,98 @@ -cmake_minimum_required(VERSION 3.13) -project(godot-cpp LANGUAGES CXX) - -# 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 () +cmake_minimum_required(VERSION 3.17) + +#[=======================================================================[.rst: + +CMake Version requirements +-------------------------- + +To enable use of the emscripten emsdk hack for pseudo shared library support +without polluting options for consumers we need to use the +CMAKE_PROJECT__INCLUDE which was introduced in version 3.17 + +Scons Compatibility +------------------- + +As we are attempting to maintain feature parity, and ease of maintenance, these +CMake scripts are built to resemble the SCons build system. -include( ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake ) +The file structure and file content are made to match, if not in content then +in spirit. The closer the two build systems look the easier they will be to +maintain. -# 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. +Where the SCons additional scripts in the tools directory, The CMake scripts +are in the cmake directory. -# The typical target definitions are in ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake +For example, the tools/godotcpp.py is sourced into SCons, and the 'options' +function is run. +.. highlight:: python + + cpp_tool = Tool("godotcpp", toolpath=["tools"]) + cpp_tool.options(opts, env) + + +The CMake equivalent is below. +]=======================================================================] + +include( cmake/godotcpp.cmake ) godotcpp_options() +#[=======================================================================[.rst: + +Configurations +-------------- + +There are two build main configurations, 'Debug' and 'Release', these are not +related to godot's DEBUG_FEATURES flag. Build configurations change the default +compiler and linker flags present when building the library, things like debug +symbols, optimization. + +The Scons build scripts don't have this concept, you can think of it like the +SCons solution has a single default configuration. In both cases overriding the +defaults is controlled by options on the command line, or in preset files. + +Because of this added configuration and that it can be undefined, it becomes +important to set a default, considering the SCons solution that does not enable +debug symbols by default, it seemed appropriate to set the default to 'Release' +if unspecified. This can always be overridden like below. + +.. highlight:: shell + + cmake -DCMAKE_BUILD_TYPE:STRING=Debug + +.. caution:: + +A complication arises from `Multi-Config Generators`_ that cannot have +their configuration set at configure time. This means that the configuration +must be set on the build command. This is especially important for Visual +Studio Generators which default to 'Debug' + +.. highlight:: shell + + cmake --build . --config Release + +.. _Multi-Config Generators:https://cmake.org/cmake/help/latest/prop_gbl/GENERATOR_IS_MULTI_CONFIG.html +]=======================================================================] +get_property( IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) +if( NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE ) + if( GODOT_DEV_BUILD ) + set( CMAKE_BUILD_TYPE Debug ) + else () + set( CMAKE_BUILD_TYPE Release ) + endif () +endif () + +#[[ Python is required for code generation ]] +find_package(Python3 3.4 REQUIRED) # pathlib should be present + +# Define our project. +project( godot-cpp + VERSION 4.4 + DESCRIPTION "C++ bindings for the Godot Engine's GDExtensions API." + HOMEPAGE_URL "https://github.com/godotengine/godot-cpp" + LANGUAGES CXX) + godotcpp_generate() + +# Test Example +add_subdirectory( test ) diff --git a/cmake/android.cmake b/cmake/android.cmake new file mode 100644 index 00000000..2227f89c --- /dev/null +++ b/cmake/android.cmake @@ -0,0 +1,41 @@ +#[=======================================================================[.rst: +Android +------- + +This file contains functions for options and configuration for targeting the +Android platform + +Configuration of the Android toolchain is done using toolchain files, +CMakePresets, or variables on the command line. + +The `Android SDK`_ provides toolchain files to help with configuration. + +CMake has its own `built-in support`_ for cross compiling to the +Android platforms. + +.. warning:: + + Android does not support or test the CMake built-in workflow, recommend + using their toolchain file. + +.. _Android SDK:https://developer.android.com/ndk/guides/cmake + +.. _built-in support:https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android + +There is further information and examples in the doc/cmake.rst file. + +]=======================================================================] +function( android_options ) + # Android Options +endfunction() + +function( android_generate TARGET_NAME ) + + target_compile_definitions(${TARGET_NAME} + PUBLIC + ANDROID_ENABLED + UNIX_ENABLED + ) + + common_compiler_flags( ${TARGET_NAME} ) +endfunction() diff --git a/cmake/common_compiler_flags.cmake b/cmake/common_compiler_flags.cmake index 94556415..1b185fe2 100644 --- a/cmake/common_compiler_flags.cmake +++ b/cmake/common_compiler_flags.cmake @@ -1,94 +1,162 @@ -# Add warnings based on compiler & version -# Set some helper variables for readability -set( compiler_less_than_v8 "$,8>" ) -set( compiler_greater_than_or_equal_v9 "$,9>" ) -set( compiler_greater_than_or_equal_v11 "$,11>" ) -set( compiler_less_than_v11 "$,11>" ) -set( compiler_greater_than_or_equal_v12 "$,12>" ) - -# These compiler options reflect what is in godot/SConstruct. -target_compile_options( ${PROJECT_NAME} PRIVATE - # MSVC only - $<${compiler_is_msvc}: - /W4 - - # Disable warnings which we don't plan to fix. - /wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism. - /wd4127 # C4127 (conditional expression is constant) - /wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89. - /wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale. - /wd4245 - /wd4267 - /wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid. - /wd4514 # C4514 (unreferenced inline function has been removed) - /wd4714 # C4714 (function marked as __forceinline not inlined) - /wd4820 # C4820 (padding added after construct) - > - - # Clang and GNU common options - $<$: - -Wall - -Wctor-dtor-privacy - -Wextra - -Wno-unused-parameter - -Wnon-virtual-dtor - -Wwrite-strings - > - - # Clang only - $<${compiler_is_clang}: - -Wimplicit-fallthrough - -Wno-ordered-compare-function-pointers - > - - # GNU only - $<${compiler_is_gnu}: - -Walloc-zero - -Wduplicated-branches - -Wduplicated-cond - -Wno-misleading-indentation - -Wplacement-new=1 - -Wshadow-local - -Wstringop-overflow=4 - > - $<$: - # Bogus warning fixed in 8+. - -Wno-strict-overflow - > - $<$: - -Wattribute-alias=2 - > - $<$: - # Broke on MethodBind templates before GCC 11. - -Wlogical-op - > - $<$: - # Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it. - -Wno-type-limits - > - $<$: - # False positives in our error macros, see GH-58747. - -Wno-return-type - > -) - -# Treat warnings as errors -function( set_warning_as_error ) - message( STATUS "[${PROJECT_NAME}] Treating warnings as errors") - if ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.24" ) - set_target_properties( ${PROJECT_NAME} - PROPERTIES - COMPILE_WARNING_AS_ERROR ON - ) - else() - target_compile_options( ${PROJECT_NAME} - PRIVATE - $<${compiler_is_msvc}:/WX> - $<$:-Werror> - ) - endif() -endfunction() +#[=======================================================================[.rst: +Common Compiler Flags +--------------------- + +This file contains a single function to configure platform agnostic compiler +flags like optimization levels, warnings, and features. For platform specific +flags look to each of the ``cmake/.cmake`` files. + +]=======================================================================] +#Generator Expression Helpers +set( IS_CLANG "$" ) +set( IS_APPLECLANG "$" ) +set( IS_GNU "$" ) +set( IS_MSVC "$" ) +set( NOT_MSVC "$>" ) + +set( GNU_LT_V8 "$,8>" ) +set( GNU_GE_V9 "$,9>" ) +set( GNU_GT_V11 "$,11>" ) +set( GNU_LT_V11 "$,11>" ) +set( GNU_GE_V12 "$,12>" ) + +set( HOT_RELOAD-UNSET "$") + +set( DISABLE_EXCEPTIONS "$") + + +function( common_compiler_flags TARGET_NAME ) + set( IS_RELEASE "$") + set( DEBUG_FEATURES "$,$>" ) + set( HOT_RELOAD "$,$>" ) + set( DEBUG_SYMBOLS "$" ) + + target_compile_features(${TARGET_NAME} + PUBLIC + cxx_std_17 + ) + + # These compiler options reflect what is in godot/SConstruct. + target_compile_options( ${TARGET_NAME} + PUBLIC + # Disable exception handling. Godot doesn't use exceptions anywhere, and this + # saves around 20% of binary size and very significant build time. + $<${DISABLE_EXCEPTIONS}: + $<${NOT_MSVC}:-fno-exceptions> + > + $<$: + $<${IS_MSVC}:/EHsc> + > + + # Enabling Debug Symbols + $<${DEBUG_SYMBOLS}: + $<${IS_MSVC}: /Zi /FS> + + # Adding dwarf-4 explicitly makes stacktraces work with clang builds, + # otherwise addr2line doesn't understand them. + $<${NOT_MSVC}: + -gdwarf-4 + $ + > + > + + $<${IS_DEV}: + $<${NOT_MSVC}:-fno-omit-frame-pointer -O0 -g> + > + + $<${HOT_RELOAD}: + $<${IS_GNU}:-fno-gnu-unique> + > + + # MSVC only + $<${IS_MSVC}: + "/MP ${PROC_N}" + /W4 + + # Disable warnings which we don't plan to fix. + /wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism. + /wd4127 # C4127 (conditional expression is constant) + /wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89. + /wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale. + /wd4245 + /wd4267 + /wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid. + /wd4514 # C4514 (unreferenced inline function has been removed) + /wd4714 # C4714 (function marked as __forceinline not inlined) + /wd4820 # C4820 (padding added after construct) + + /utf-8 + > -if ( GODOT_WARNING_AS_ERROR ) - set_warning_as_error() -endif() + # Clang and GNU common options + $<$: + -Wall + -Wctor-dtor-privacy + -Wextra + -Wno-unused-parameter + -Wnon-virtual-dtor + -Wwrite-strings + > + + # Clang only + $<${IS_CLANG}: + -Wimplicit-fallthrough + -Wno-ordered-compare-function-pointers + > + + # GNU only + $<${IS_GNU}: + -Walloc-zero + -Wduplicated-branches + -Wduplicated-cond + -Wno-misleading-indentation + -Wplacement-new=1 + -Wshadow-local + -Wstringop-overflow=4 + + # Bogus warning fixed in 8+. + $<${GNU_LT_V8}:-Wno-strict-overflow> + + $<${GNU_GE_V9}:-Wattribute-alias=2> + + # Broke on MethodBind templates before GCC 11. + $<${GNU_GT_V11}:-Wlogical-op> + + # Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it. + $<${GNU_LT_V11}:-Wno-type-limits> + + # False positives in our error macros, see GH-58747. + $<${GNU_GE_V12}:-Wno-return-type> + > + ) + + target_compile_definitions(${TARGET_NAME} + PUBLIC + GDEXTENSION + + # features + $<${DEBUG_FEATURES}:DEBUG_ENABLED DEBUG_METHODS_ENABLED> + + $<${HOT_RELOAD}:HOT_RELOAD_ENABLED> + + $<$:REAL_T_IS_DOUBLE> + + $<${IS_MSVC}:$<${DISABLE_EXCEPTIONS}:_HAS_EXCEPTIONS=0>> + ) + + target_link_options( ${TARGET_NAME} + PUBLIC + $<${IS_MSVC}: + /WX # treat link warnings as errors. + /MANIFEST:NO # We dont need a manifest + > + + $<${DEBUG_SYMBOLS}:$<${IS_MSVC}:/DEBUG:FULL>> + $<$: + $<${IS_GNU}:-s> + $<${IS_CLANG}:-s> + $<${IS_APPLECLANG}:-Wl,-S -Wl,-x -Wl,-dead_strip> + > + ) + +endfunction() diff --git a/cmake/emsdkHack.cmake b/cmake/emsdkHack.cmake new file mode 100644 index 00000000..6981a379 --- /dev/null +++ b/cmake/emsdkHack.cmake @@ -0,0 +1,40 @@ +#[=======================================================================[.rst: +emsdkHack +--------- + +The Emscripten platform doesn't support the use of shared libraries as known by cmake. + +* https://github.com/emscripten-core/emscripten/issues/15276 +* https://github.com/emscripten-core/emscripten/issues/17804 + +This workaround only works due to the way the cmake scripts are loaded. + +Prior to the use of ``project( ... )`` directive we need to set +``CMAKE_PROJECT_INCLUDE=cmake/emscripten.cmake``. +This file will be loaded after the toolchain overriding the settings that +prevent shared library building. + +CMAKE_PROJECT_INCLUDE was Added in version 3.15. +``CMAKE_PROJECT__INCLUDE`` was Added in version 3.17: + +More information on cmake's `code injection`_ + +.. _code injection:https://cmake.org/cmake/help/latest/command/project.html#code-injection + +Overwrite Shared Library Properties to allow shared libs to be generated. +]=======================================================================] +if( EMSCRIPTEN ) + set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) + set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-sSIDE_MODULE=1") + set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-sSIDE_MODULE=1") + set(CMAKE_SHARED_LIBRARY_SUFFIX) # remove the suffix from the shared lib + set(CMAKE_STRIP FALSE) # used by default in pybind11 on .so modules + + # The Emscripten toolchain sets the default value for EMSCRIPTEN_SYSTEM_PROCESSOR to x86 + # and CMAKE_SYSTEM_PROCESSOR to this value. I don't want that. + set(CMAKE_SYSTEM_PROCESSOR "wasm32" ) + # the above prevents the need for logic like: + #if( ${CMAKE_SYSTEM_NAME} STREQUAL Emscripten ) + # set( SYSTEM_ARCH wasm32 ) + #endif () +endif () diff --git a/cmake/godotcpp.cmake b/cmake/godotcpp.cmake index a5c66779..736d1e3e 100644 --- a/cmake/godotcpp.cmake +++ b/cmake/godotcpp.cmake @@ -1,13 +1,85 @@ -function( godotcpp_options ) +#[=======================================================================[.rst: +godotcpp.cmake +-------------- + +Because these files are included into the top level CMakelists.txt before the +project directive, it means that + +* ``CMAKE_CURRENT_SOURCE_DIR`` is the location of godot-cpp's CMakeLists.txt +* ``CMAKE_SOURCE_DIR`` is the location where any prior ``project(...)`` + directive was + +]=======================================================================] +include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/common_compiler_flags.cmake) +include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/android.cmake) +include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ios.cmake) +include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux.cmake) +include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos.cmake) +include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/web.cmake) +include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows.cmake) + +#Silence warning from unused CMAKE_C_COMPILER from toolchain +if( CMAKE_C_COMPILER ) +endif () + +include(ProcessorCount) +ProcessorCount(PROC_MAX) +message( "Auto-detected ${PROC_MAX} CPU cores available for build parallelism." ) + +# List of known platforms +set( PLATFORM_LIST linux macos windows android ios web ) + +# List of known architectures +set( ARCH_LIST universal x86_32 x86_64 arm32 arm64 rv64 ppc32 ppc64 wasm32 ) + +# Function to map processors to known architectures +function( godot_arch_map ALIAS PROC ) + string( TOLOWER "${PROC}" PROC ) + + if( "${PROC}" IN_LIST ARCH_LIST ) + set( ${ALIAS} "${PROC}" PARENT_SCOPE) + return() + endif() + + set( x86_64 "w64;amd64" ) + set( arm32 "armv7" ) + set( arm64 "armv8;arm64v8;aarch64" ) + set( rv64 "rv;riscv;riscv64" ) + set( ppc32 "ppcle;ppc" ) + set( ppc64 "ppc64le" ) + + if( PROC IN_LIST x86_64 ) + set(${ALIAS} "x86_64" PARENT_SCOPE ) + + elseif( PROC IN_LIST arm32 ) + set(${ALIAS} "arm32" PARENT_SCOPE ) + + elseif( PROC IN_LIST arm64 ) + set(${ALIAS} "arm64" PARENT_SCOPE ) + + elseif( PROC IN_LIST rv64 ) + set(${ALIAS} "rv64" PARENT_SCOPE ) + + elseif( PROC IN_LIST ppc32 ) + set(${ALIAS} "ppc32" PARENT_SCOPE ) - #TODO platform - #TODO target + elseif( PROC IN_LIST ppc64 ) + set(${ALIAS} "ppc64" PARENT_SCOPE ) + + else() + set(${ALIAS} "unknown" PARENT_SCOPE ) + endif () +endfunction() + +# Function to define all the options. +function( godotcpp_options ) + #NOTE: platform is managed using toolchain files. # 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 )") + "Path to a custom GDExtension API JSON file (takes precedence over `GODOT_GDEXTENSION_DIR`) ( /path/to/custom_api_file )") #TODO generate_bindings @@ -19,15 +91,22 @@ function( godotcpp_options ) set(GODOT_PRECISION "single" CACHE STRING "Set the floating-point precision level (single|double)") - #TODO arch + # The arch is typically set by the toolchain + # however for Apple multi-arch setting it here will override. + set( GODOT_ARCH "" CACHE STRING "Target CPU Architecture") + set_property( CACHE GODOT_ARCH PROPERTY STRINGS ${ARCH_LIST} ) + #TODO threads #TODO compiledb #TODO compiledb_file - #TODO build_profile aka cmake preset + + #NOTE: build_profile's equivalent in cmake is CMakePresets.json set(GODOT_USE_HOT_RELOAD "" CACHE BOOL "Enable the extra accounting required to support hot reload. (ON|OFF)") + # 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 ) set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING @@ -36,48 +115,67 @@ function( godotcpp_options ) #TODO optimize #TODO debug_symbols - #TODO dev_build + option( GODOT_DEBUG_SYMBOLS "" OFF ) + option( GODOT_DEV_BUILD "Developer build with dev-only debugging code (DEV_ENABLED)" OFF ) # 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() + option( GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." OFF ) + 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. + android_options() + ios_options() + linux_options() + macos_options() + web_options() + windows_options() endfunction() - +# Function to configure and generate the targets 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 + #[[ Multi-Threaded MSVC Compilation + + When using the MSVC compiler the build command -j only specifies + parallel jobs or targets, and not multi-threaded compilation To speed up + compile times on msvc, the /MP flag can be set. But we need to set it + at configure time. + + MSVC is true when the compiler is some version of Microsoft Visual C++ or + another compiler simulating the Visual C++ cl command-line syntax. ]] + if( MSVC ) + math( EXPR PROC_N "(${PROC_MAX}-1) | (${X}-2)>>31 & 1" ) + message( "Using ${PROC_N} cores for multi-threaded compilation.") + # TODO You can override it at configure time with ...." ) + else () + message( "Using ${CMAKE_BUILD_PARALLEL_LEVEL} cores, You can override" + " it at configure time by using -j or --parallel on the build" + " command.") + message( " eg. cmake --build . -j 7 ...") + endif () + + #[[ GODOT_SYMBOL_VISIBLITY + To match the SCons options, the allowed values are "auto", "visible", and "hidden" + This effects the compiler flag -fvisibility=[default|internal|hidden|protected] + The corresponding CMake option CXX_VISIBILITY_PRESET accepts the compiler values. + + TODO: It is probably worth a pull request which changes both to use the compiler values + https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fvisibility + + This performs the necessary conversion + ]] 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() + # Setup variable to optionally mark headers as SYSTEM + set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "") + if (GODOT_SYSTEM_HEADERS) + set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) + endif () + #[[ Generate Bindings ]] if(NOT DEFINED BITS) set(BITS 32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) @@ -85,67 +183,26 @@ function( godotcpp_generate ) 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 + # Code Generation option 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)" + 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}\")" + 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} @@ -153,88 +210,87 @@ function( godotcpp_generate ) 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' - > + ### Platform is derived from the toolchain target + # See GeneratorExpressions PLATFORM_ID and CMAKE_SYSTEM_NAME + set( SYSTEM_NAME + $<$:android.${ANDROID_ABI}> + $<$:ios> + $<$:linux> + $<$:macos> + $<$:web> + $<$:windows> + $<$:windows> ) + string(REPLACE ";" "" SYSTEM_NAME "${SYSTEM_NAME}") - # 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}") + ### Use the arch from the toolchain if it isn't set manually + if( GODOT_ARCH ) + set(SYSTEM_ARCH ${GODOT_ARCH}) else() - set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}") + godot_arch_map( SYSTEM_ARCH ${CMAKE_SYSTEM_PROCESSOR} ) 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}" - ) + ### Define our godot-cpp library targets + foreach ( TARGET_NAME template_debug template_release editor ) + + # Useful genex snippits used in subsequent genex's + set( IS_RELEASE "$") + set( IS_DEV "$") + set( DEBUG_FEATURES "$,$>" ) + set( HOT_RELOAD "$,$>" ) + + # the godot-cpp.* library targets + add_library( ${TARGET_NAME} STATIC ${EXCLUDE} ) + add_library( godot-cpp::${TARGET_NAME} ALIAS ${TARGET_NAME} ) + + file( GLOB_RECURSE GODOTCPP_SOURCES LIST_DIRECTORIES NO CONFIGURE_DEPENDS src/*.cpp ) + + target_sources( ${TARGET_NAME} + PRIVATE + ${GODOTCPP_SOURCES} + ${GENERATED_FILES_LIST} + ) + + target_include_directories( ${TARGET_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC + include + ${CMAKE_CURRENT_BINARY_DIR}/gen/include + ${GODOT_GDEXTENSION_DIR} + ) + + set_target_properties( ${TARGET_NAME} + PROPERTIES + CXX_STANDARD 17 + CXX_EXTENSIONS OFF + CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY} + + COMPILE_WARNING_AS_ERROR ${GODOT_WARNING_AS_ERROR} + POSITION_INDEPENDENT_CODE ON + BUILD_RPATH_USE_ORIGIN ON + + PREFIX lib + OUTPUT_NAME "${PROJECT_NAME}.${SYSTEM_NAME}.${TARGET_NAME}.${SYSTEM_ARCH}" + ARCHIVE_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/bin>" + + # Things that are handy to know for dependent targets + GODOT_PLATFORM "${SYSTEM_NAME}" + GODOT_TARGET "${TARGET_NAME}" + GODOT_ARCH "${SYSTEM_ARCH}" + ) + + if( CMAKE_SYSTEM_NAME STREQUAL Android ) + android_generate( ${TARGET_NAME} ) + elseif ( CMAKE_SYSTEM_NAME STREQUAL iOS ) + ios_generate( ${TARGET_NAME} ) + elseif ( CMAKE_SYSTEM_NAME STREQUAL Linux ) + linux_generate( ${TARGET_NAME} ) + elseif ( CMAKE_SYSTEM_NAME STREQUAL Darwin ) + macos_generate( ${TARGET_NAME} ) + elseif ( CMAKE_SYSTEM_NAME STREQUAL Emscripten ) + web_generate( ${TARGET_NAME} ) + elseif ( CMAKE_SYSTEM_NAME STREQUAL Windows ) + windows_generate( ${TARGET_NAME} ) + endif () + + endforeach () endfunction() diff --git a/cmake/ios.cmake b/cmake/ios.cmake new file mode 100644 index 00000000..bb964221 --- /dev/null +++ b/cmake/ios.cmake @@ -0,0 +1,22 @@ +#[=======================================================================[.rst: +Ios +--- + +This file contains functions for options and configuration for targeting the +Ios platform + +]=======================================================================] +function(ios_options) + # iOS options +endfunction() + +function(ios_generate TARGET_NAME) + + target_compile_definitions(${TARGET_NAME} + PUBLIC + IOS_ENABLED + UNIX_ENABLED + ) + + common_compiler_flags(${TARGET_NAME}) +endfunction() diff --git a/cmake/linux.cmake b/cmake/linux.cmake new file mode 100644 index 00000000..fae620e0 --- /dev/null +++ b/cmake/linux.cmake @@ -0,0 +1,22 @@ +#[=======================================================================[.rst: +Linux +----- + +This file contains functions for options and configuration for targeting the +Linux platform + +]=======================================================================] +function( linux_options ) + # Linux Options +endfunction() + +function( linux_generate TARGET_NAME ) + + target_compile_definitions( ${TARGET_NAME} + PUBLIC + LINUX_ENABLED + UNIX_ENABLED + ) + + common_compiler_flags( ${TARGET_NAME} ) +endfunction() diff --git a/cmake/macos.cmake b/cmake/macos.cmake new file mode 100644 index 00000000..1bb4dbcf --- /dev/null +++ b/cmake/macos.cmake @@ -0,0 +1,59 @@ +#[=======================================================================[.rst: +MacOS +----- + +This file contains functions for options and configuration for targeting the +MacOS platform + +]=======================================================================] + +# Find Requirements +IF(APPLE) + set( CMAKE_OSX_SYSROOT $ENV{SDKROOT} ) + find_library( COCOA_LIBRARY REQUIRED + NAMES Cocoa + PATHS ${CMAKE_OSX_SYSROOT}/System/Library + PATH_SUFFIXES Frameworks + NO_DEFAULT_PATH) +ENDIF (APPLE) + + +function( macos_options ) + # macos options here +endfunction() + + +function( macos_generate TARGET_NAME ) + + # OSX_ARCHITECTURES does not support generator expressions. + if( NOT GODOT_ARCH OR GODOT_ARCH STREQUAL universal ) + set( OSX_ARCH "x86_64;arm64" ) + set( SYSTEM_ARCH universal ) + else() + set( OSX_ARCH ${GODOT_ARCH} ) + endif() + + set_target_properties( ${TARGET_NAME} + PROPERTIES + + OSX_ARCHITECTURES "${OSX_ARCH}" + ) + + target_compile_definitions(${TARGET_NAME} + PUBLIC + MACOS_ENABLED + UNIX_ENABLED + ) + + target_link_options( ${TARGET_NAME} + PUBLIC + -Wl,-undefined,dynamic_lookup + ) + + target_link_libraries( ${TARGET_NAME} + INTERFACE + ${COCOA_LIBRARY} + ) + + common_compiler_flags( ${TARGET_NAME} ) +endfunction() diff --git a/cmake/web.cmake b/cmake/web.cmake new file mode 100644 index 00000000..b7d6c13a --- /dev/null +++ b/cmake/web.cmake @@ -0,0 +1,42 @@ +#[=======================================================================[.rst: +Web +--- + +This file contains functions for options and configuration for targeting the +Web platform + +]=======================================================================] + +# Emscripten requires this hack for use of the SHARED option +set( CMAKE_PROJECT_godot-cpp_INCLUDE cmake/emsdkHack.cmake ) + +function( web_options ) + # web options +endfunction() + + +function( web_generate TARGET_NAME ) + + target_compile_definitions(${TARGET_NAME} + PUBLIC + WEB_ENABLED + UNIX_ENABLED + ) + + target_compile_options( ${TARGET_NAME} + PUBLIC + -sSIDE_MODULE + -sSUPPORT_LONGJMP=wasm + -fno-exceptions + ) + + target_link_options( ${TARGET_NAME} + INTERFACE + -sWASM_BIGINT + -sSUPPORT_LONGJMP=wasm + -fvisibility=hidden + -shared + ) + + common_compiler_flags( ${TARGET_NAME} ) +endfunction() diff --git a/cmake/windows.cmake b/cmake/windows.cmake new file mode 100644 index 00000000..c46519e8 --- /dev/null +++ b/cmake/windows.cmake @@ -0,0 +1,63 @@ +#[=======================================================================[.rst: +Windows +------- + +This file contains functions for options and configuration for targeting the +Windows platform + +]=======================================================================] + +function( windows_options ) + + option( GODOT_USE_STATIC_CPP "Link MinGW/MSVC C++ runtime libraries statically" ON ) + + # The below scons variables are controlled via toolchain files instead + # "mingw_prefix" "MinGW prefix" + # "use_llvm" "Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag)" + # "use_mingw" "Use the MinGW compiler instead of MSVC - only effective on Windows" +endfunction() + +function( windows_generate TARGET_NAME ) + set( IS_MSVC "$" ) + set( IS_CLANG "$,$>" ) + set( NOT_MSVC "$" ) + set( STATIC_CPP "$") + set( DISABLE_EXCEPTIONS "$") + + set_target_properties( ${TARGET_NAME} + PROPERTIES + PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>" + ) + + target_compile_definitions( ${TARGET_NAME} + PUBLIC + WINDOWS_ENABLED + $<${IS_MSVC}: + TYPED_METHOD_BIND + NOMINMAX + > + ) + + target_compile_options( ${TARGET_NAME} + PUBLIC + $<${IS_MSVC}: + $$<${IS_DEV}:d> # Link microsoft runtime + > + ) + target_link_options( ${TARGET_NAME} + PUBLIC + + $<${NOT_MSVC}: + -Wl,--no-undefined + $<${STATIC_CPP}: + -static + -static-libgcc + -static-libstdc++ + > + > + + $<${IS_CLANG}:-lstdc++> + ) + + common_compiler_flags( ${TARGET_NAME} ) +endfunction() diff --git a/doc/cmake.md b/doc/cmake.md deleted file mode 100644 index 3dd77f58..00000000 --- a/doc/cmake.md +++ /dev/null @@ -1,57 +0,0 @@ -## 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. diff --git a/doc/cmake.rst b/doc/cmake.rst new file mode 100644 index 00000000..d47dadd8 --- /dev/null +++ b/doc/cmake.rst @@ -0,0 +1,331 @@ +CMake +===== + +.. warning:: + + The CMake scripts do not have feature parity with the SCons ones at this + stage and are still a work in progress. There are a number of people who + have been working on alternative CMake solutions that are frequently + referenced in the discord chats: Ivan's cmake-rewrite_ branch and + Vorlac's godot-roguelite_ Project + +.. _cmake-rewrite: https://github.com/IvanInventor/godot-cpp/tree/cmake-rewrite +.. _godot-roguelite: https://github.com/vorlac/godot-roguelite + +Introduction +------------ + +Compiling godot-cpp independently of an extension project is mainly for +godot-cpp developers, package maintainers, and CI/CD. Look to the +godot-cpp-template_ for a practical example on how to consume the godot-cpp +library as part of a Godot extension. + +Configuration examples are listed at the bottom of the page. + +.. _godot-cpp-template: https://github.com/godotengine/godot-cpp-template + +Basic walkthrough +----------------- + +.. topic:: Clone the git repository + + .. code-block:: + + git clone https://github.com/godotengine/godot-cpp.git + Cloning into 'godot-cpp'... + ... + cd godot-cpp + + +.. topic:: Out-of-tree build directory + + Create a build directory for CMake to put caches and build artifacts in and + change directory to it. This is typically as a sub-directory of the project + root but can be outside the source tree. This is so that generated files do + not clutter up the source tree. + + .. code-block:: + + mkdir cmake-build + cd cmake-build + +.. topic:: Configure the build + + CMake doesn't build the code, it generates the files that another tool uses + to build the code. To see the list of generators run ``cmake --help``. The + first phase of which is running through the configuration scripts. + + Configure and generate Ninja build files. + + .. code-block:: + + cmake ../ -G "Ninja" + + To list the available options CMake use the ``-L[AH]`` option. ``A`` is for + advanced, and ``H`` is for help strings. + + .. code-block:: + + cmake ../ -LH + + Options are specified on the command line when configuring + + .. code-block:: + + cmake ../ -DGODOT_USE_HOT_RELOAD:BOOL=ON \ + -DGODOT_PRECISION:STRING=double \ + -DCMAKE_BUILD_TYPE:STRING=Debug + + Review setting-build-variables_ and build-configurations_ for more information. + + .. _setting-build-variables: https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#setting-build-variables + .. _build-configurations: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations + + A non-exhaustive list of options: + + .. code-block:: + + // Path to a custom GDExtension API JSON file (takes precedence over `GODOT_GDEXTENSION_DIR`) ( /path/to/custom_api_file ) + `GODOT_CUSTOM_API_FILE:FILEPATH=` + + // Force disabling exception handling code (ON|OFF) + GODOT_DISABLE_EXCEPTIONS:BOOL=ON + + // Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir ) + GODOT_GDEXTENSION_DIR:PATH=gdextension + + // Generate a template version of the Node class's get_node. (ON|OFF) + GODOT_GENERATE_TEMPLATE_GET_NODE:BOOL=ON + + // Set the floating-point precision level (single|double) + GODOT_PRECISION:STRING=single + + // Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden) + GODOT_SYMBOL_VISIBILITY:STRING=hidden + + // Expose headers as SYSTEM. + GODOT_SYSTEM_HEADERS:BOOL=ON + + // Enable the extra accounting required to support hot reload. (ON|OFF) + GODOT_USE_HOT_RELOAD:BOOL= + + // Treat warnings as errors + GODOT_WARNING_AS_ERROR:BOOL=OFF + + +.. topic:: Compiling + + A target and a configuration is required, as the default ``all`` target does + not include anything and when using multi-config generators like ``Ninja + Multi-Config``, ``Visual Studio *`` or ``Xcode`` the build configuration + needs to be specified at build time. Build in Release mode unless you need + debug symbols. + + .. code-block:: + + cmake --build . -t template_debug --config Release + +Examples +-------- + +Windows and MSVC +~~~~~~~~~~~~~~~~ +So long as CMake is installed from the `CMake Downloads`_ page and in the PATH, +and Microsoft Visual Studio is installed with c++ support, CMake will detect +the MSVC compiler. + +.. _CMake downloads: https://cmake.org/download/ + +Assuming the current working directory is the godot-cpp project root: + +.. code-block:: + + mkdir build-msvc + cd build-msvc + cmake ../ + cmake --build . -t godot-cpp-test --config Release + + +MSys2/clang64, "Ninja", godot-cpp-test target with debug symbols +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Assumes the ming-w64-clang-x86_64-toolchain is installed + +Using the msys2/clang64 shell + +.. code-block:: + + mkdir build-clang + cd build-clang + cmake ../ -G"Ninja" -DCMAKE_BUILD_TYPE:STRING=Debug + cmake --build . -t godot-cpp-test + +MSys2/clang64, "Ninja Multi-Config", godot-cpp-test target with GODOT_DEV_BUILD +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Assumes the ming-w64-clang-x86_64-toolchain is installed + +Using the msys2/clang64 shell + +.. code-block:: + + mkdir build-clang + cd build-clang + cmake ../ -G"Ninja Multi-Config" -DGODOT_DEV_BUILD:BOOL=ON + cmake --build . -t godot-cpp-test --config Debug + +Emscripten for web, template_release target +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +I've only tested this on windows so far. + +I cloned, installed, and activating the latest Emscripten tools(for me it was +3.1.69) to ``c:\emsdk`` + +From a terminal running the ``c:\emsdk\emcmdprompt.bat`` puts me in a cmdprompt +context which I dislike, so after that I run pwsh to get my powershell 7.4.5 +context back. + +using the ``emcmake.bat`` command adds the emscripten toolchain to the CMake +command + +.. code-block:: + + C:\emsdk\emcmdprompt.bat + pwsh + cd + mkdir build-wasm32 + cd build-wasm32 + emcmake.bat cmake ../ + cmake --build . --verbose -t template_release + +Android Cross Compile from Windows +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There are two separate paths you can choose when configuring for android. + +Use the ``CMAKE_ANDROID_*`` variables specified on the commandline or in your +own toolchain file as listed in the cmake-toolchains_ documentation + +.. _cmake-toolchains: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android-with-the-ndk + +Or use the toolchain and scripts provided by the Android SDK and make changes +using the ``ANDROID_*`` variables listed there. Where ```` is whatever +ndk version you have installed ( tested with `23.2.8568313`) and ```` +is for android sdk platform, (tested with ``android-29``) + +.. warning:: + + The Android SDK website explicitly states that they do not support using + the CMake built-in method, and recommends you stick with their toolchain + files. + +.. topic:: Using your own toolchain file as described in the CMake documentation + + .. code-block:: + + mkdir build-android + cd build-android + cmake ../ --toolchain my_toolchain.cmake + cmake --build . -t template_release + + Doing the equivalent on just using the command line + + .. code-block:: + + mkdir build-android + cd build-android + cmake ../ \ + -DCMAKE_SYSTEM_NAME=Android \ + -DCMAKE_SYSTEM_VERSION= \ + -DCMAKE_ANDROID_ARCH_ABI= \ + -DCMAKE_ANDROID_NDK=/path/to/android-ndk + cmake --build . -t template_release + +.. topic:: Using the toolchain file from the Android SDK + + Defaults to minimum supported version( android-16 in my case) and armv7-a. + + .. code-block:: + + mkdir build-android + cd build-android + cmake ../ --toolchain $ANDROID_HOME/ndk//build/cmake/android.toolchain.cmake + cmake --build . -t template_release + + Specify Android platform and ABI + + .. code-block:: + + mkdir build-android + cd build-android + cmake ../ --toolchain $ANDROID_HOME/ndk//build/cmake/android.toolchain.cmake \ + -DANDROID_PLATFORM:STRING=android-29 \ + -DANDROID_ABI:STRING=armeabi-v7a + cmake --build . -t template_release + + +Toolchains +---------- +This section attempts to list the host and target combinations that have been +at tested. + +Info on cross compiling triplets indicates that the naming is a little more +freeform that expected, and tailored to its use case. Triplets tend to have the +format ``[sub][-vendor][-OS][-env]`` + +* `osdev.org `_ +* `stack overflow `_ +* `LLVM `_ +* `clang target triple `_ +* `vcpkg `_ +* `wasm32-unknown-emscripten `_ + +Linux Host +~~~~~~~~~~ + +:Target: x86_64-linux + +Macos Host +~~~~~~~~~~ + +:System: Mac Mini +:OS Name: Sequoia 15.0.1 +:Processor: Apple M2 + +Windows Host +~~~~~~~~~~~~ + +:OS Name: Microsoft Windows 11 Home, 10.0.22631 N/A Build 22631 +:Processor: AMD Ryzen 7 6800HS Creator Edition + +`Microsoft Visual Studio 17 2022 `_ + :Target: x86_64-w64 + +`LLVM `_ + :Target: x86_64-pc-windows-msvc + +`AndroidSDK `_ + armv7-none-linux-androideabi16 + +`Emscripten `_ + :Compiler: Emscripten + :Target: wasm32-unknown-emscripten + +`MinGW-w64 `_ based toolchains + + `MSYS2 `_ + Necessary reading about MSYS2 `environments `_ + + ucrt64 + :Compiler: gcc version 14.2.0 (Rev1, Built by MSYS2 project) + :Target: x86_64-w64-mingw32 + + clang64 + :Compiler: clang version 18.1.8 + :Target: x86_64-w64-windows-gnu + + `LLVM-MinGW `_ + + `MinGW-W64-builds `_ + :Compiler: gcc + :Target: x86_64-w64-mingw32-ucrt + + `Jetbrains-CLion `_ + :Target: x86_64-w64-mingw32-msvcrt diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f1c4c0d7..ab7397fa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,144 +1,67 @@ -cmake_minimum_required(VERSION 3.13) -project(godot-cpp-test) - -set(GODOT_GDEXTENSION_DIR ../gdextension/ CACHE STRING "Path to GDExtension interface header directory") -set(CPP_BINDINGS_PATH ../ CACHE STRING "Path to C++ bindings") - -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(TARGET_PATH x11) -elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(TARGET_PATH win64) -elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set(TARGET_PATH macos) -else() - message(FATAL_ERROR "Not implemented support for ${CMAKE_SYSTEM_NAME}") -endif() - -# Change the output directory to the bin directory -set(BUILD_PATH ${CMAKE_SOURCE_DIR}/bin/${TARGET_PATH}) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${BUILD_PATH}") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${BUILD_PATH}") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${BUILD_PATH}") -SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}") -SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}") -SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}") -SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}") -SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}") -SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}") - -# Set the c++ standard to c++17 -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - -set(GODOT_COMPILE_FLAGS ) -set(GODOT_LINKER_FLAGS ) - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # using Visual Studio C++ - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /WX") # /GF /MP - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /DTYPED_METHOD_BIND") - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /utf-8") - - 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) - - # Disable conversion warning, truncation, unreferenced var, signed mismatch - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /wd4244 /wd4305 /wd4101 /wd4018 /wd4267") - - add_definitions(-DNOMINMAX) - - # Unkomment for warning level 4 - #if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") - # string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - #endif() +# Testing Extension +# This is only linked to the template_release config. +# so it requires the template_release version of godot to run. + +add_library( godot-cpp-test SHARED EXCLUDE_FROM_ALL ) + +target_sources( godot-cpp-test + PRIVATE + src/example.cpp + src/example.h + src/register_types.cpp + src/register_types.h + src/tests.h +) -else() +set( TEST_TARGET "template_debug" CACHE STRING "Which godot-cpp::target to link against" ) +set_property( CACHE TEST_TARGET PROPERTY STRINGS "template_debug;template_release;editor" ) - set(GODOT_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,-R,'$$ORIGIN'") +target_link_libraries( godot-cpp-test + PRIVATE + godot-cpp::${TEST_TARGET} ) - set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings") +### Get useful properties of the library +get_target_property( GODOT_PLATFORM godot-cpp::${TEST_TARGET} GODOT_PLATFORM ) +get_target_property( GODOT_TARGET godot-cpp::${TEST_TARGET} GODOT_TARGET ) +get_target_property( GODOT_ARCH godot-cpp::${TEST_TARGET} GODOT_ARCH ) - if(CMAKE_BUILD_TYPE MATCHES Debug) - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0") - else() - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3") - endif(CMAKE_BUILD_TYPE MATCHES Debug) -endif() +set( OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/project/bin/" ) -# 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") -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() +set_target_properties( godot-cpp-test + PROPERTIES + CXX_STANDARD 17 + CXX_EXTENSIONS OFF + CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY} -# Get Sources -file(GLOB_RECURSE SOURCES src/*.c**) -file(GLOB_RECURSE HEADERS include/*.h**) + POSITION_INDEPENDENT_CODE ON + BUILD_RPATH_USE_ORIGIN ON + LINK_SEARCH_START_STATIC ON + LINK_SEARCH_END_STATIC ON -# Define our godot-cpp library -add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS}) + # NOTE: Wrapping the output variables inside a generator expression + # prevents msvc generator from adding addition Config Directories + LIBRARY_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" + RUNTIME_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" + PDB_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" #MSVC Only, ignored on other platforms -target_include_directories(${PROJECT_NAME} SYSTEM - PRIVATE - ${CPP_BINDINGS_PATH}/include - ${CPP_BINDINGS_PATH}/gen/include - ${GODOT_GDEXTENSION_DIR} + PREFIX "lib" + OUTPUT_NAME "gdexample.${GODOT_PLATFORM}.${GODOT_TARGET}.${GODOT_ARCH}" ) -# Create the correct name (godot.os.build_type.system_bits) -# Synchronized with godot-cpp's CMakeLists.txt - -set(BITS 32) -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(BITS 64) -endif(CMAKE_SIZEOF_VOID_P EQUAL 8) - -if(CMAKE_BUILD_TYPE MATCHES Debug) - set(GODOT_CPP_BUILD_TYPE Debug) -else() - set(GODOT_CPP_BUILD_TYPE Release) -endif() - -string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME) -string(TOLOWER ${GODOT_CPP_BUILD_TYPE} BUILD_TYPE) - -if(ANDROID) - # Added the android abi after system name - set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI}) -endif() +if( CMAKE_SYSTEM_NAME STREQUAL Darwin ) + get_target_property( OSX_ARCH godot-cpp::${TEST_TARGET} OSX_ARCHITECTURES ) -if(CMAKE_VERSION VERSION_GREATER "3.13") - target_link_directories(${PROJECT_NAME} - PRIVATE - ${CPP_BINDINGS_PATH}/bin/ - ) + set( OUTPUT_DIR "${OUTPUT_DIR}/libgdexample.macos.${TEST_TARGET}.framework") - target_link_libraries(${PROJECT_NAME} - godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}$<$>:.${BITS}> - ) -else() - target_link_libraries(${PROJECT_NAME} - ${CPP_BINDINGS_PATH}/bin/libgodot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}$<$>:.${BITS}>.a - ) -endif() + set_target_properties( godot-cpp-test + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" + RUNTIME_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" -# Add the compile flags -set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS}) -set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS ${GODOT_LINKER_FLAGS}) + OUTPUT_NAME "gdexample.macos.${TEST_TARGET}" + SUFFIX "" -set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "gdexample") + #macos options + OSX_ARCHITECTURES "${OSX_ARCH}" + ) +endif () From 597055d13cfd8cdac51285ab59c5f7c570b4ee33 Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Sun, 24 Nov 2024 00:06:57 +1030 Subject: [PATCH 04/15] CMake: re-add the godot::cpp alias pointing to template_debug So that builds that relied on the alias already wont break. --- cmake/godotcpp.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/godotcpp.cmake b/cmake/godotcpp.cmake index 736d1e3e..c6ba53a3 100644 --- a/cmake/godotcpp.cmake +++ b/cmake/godotcpp.cmake @@ -293,4 +293,8 @@ function( godotcpp_generate ) endforeach () + # Added for backwards compatibility with prior cmake solution so that builds dont immediately break + # from a missing target. + add_library( godot::cpp ALIAS template_debug ) + endfunction() From ac466e47664fee8e08191a8243e005915ae6f154 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Tue, 26 Nov 2024 01:49:30 -0800 Subject: [PATCH 05/15] Add `print_line` for compatibility with engine modules --- include/godot_cpp/core/class_db.hpp | 1 + include/godot_cpp/core/print_string.hpp | 75 +++++++++++++++++++++++++ src/core/print_string.cpp | 39 +++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 include/godot_cpp/core/print_string.hpp create mode 100644 src/core/print_string.cpp diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 6edb3244..865deb81 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -37,6 +37,7 @@ #include #include #include +#include #include diff --git a/include/godot_cpp/core/print_string.hpp b/include/godot_cpp/core/print_string.hpp new file mode 100644 index 00000000..3d70c796 --- /dev/null +++ b/include/godot_cpp/core/print_string.hpp @@ -0,0 +1,75 @@ +/**************************************************************************/ +/* print_string.hpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef GODOT_PRINT_STRING_HPP +#define GODOT_PRINT_STRING_HPP + +#include + +namespace godot { +inline void print_error(const Variant &p_variant) { + UtilityFunctions::printerr(p_variant); +} + +inline void print_line(const Variant &p_variant) { + UtilityFunctions::print(p_variant); +} + +inline void print_line_rich(const Variant &p_variant) { + UtilityFunctions::print_rich(p_variant); +} + +template +void print_error(const Variant &p_variant, Args... p_args) { + UtilityFunctions::printerr(p_variant, p_args...); +} + +template +void print_line(const Variant &p_variant, Args... p_args) { + UtilityFunctions::print(p_variant, p_args...); +} + +template +void print_line_rich(const Variant &p_variant, Args... p_args) { + UtilityFunctions::print_rich(p_variant, p_args...); +} + +bool is_print_verbose_enabled(); + +// Checking the condition before evaluating the text to be printed avoids processing unless it actually has to be printed, saving some CPU usage. +#define print_verbose(m_variant) \ + { \ + if (is_print_verbose_enabled()) { \ + print_line(m_variant); \ + } \ + } +} // namespace godot + +#endif // GODOT_PRINT_STRING_HPP diff --git a/src/core/print_string.cpp b/src/core/print_string.cpp new file mode 100644 index 00000000..1170137d --- /dev/null +++ b/src/core/print_string.cpp @@ -0,0 +1,39 @@ +/**************************************************************************/ +/* print_string.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include + +#include + +namespace godot { +bool is_print_verbose_enabled() { + return OS::get_singleton()->is_stdout_verbose(); +} +} // namespace godot From f174b4a445f54d559d6329a86707c46ba81a67b8 Mon Sep 17 00:00:00 2001 From: Lukas Tenbrink Date: Tue, 26 Nov 2024 21:39:49 +0100 Subject: [PATCH 06/15] Update gdextension_interface.h. Add metadata to GetTypeInfo of char16_t and char32_t. --- gdextension/gdextension_interface.h | 25 ++++++++++++++++++++++++- include/godot_cpp/core/type_info.hpp | 4 ++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h index 9f5ef728..8268afc3 100644 --- a/gdextension/gdextension_interface.h +++ b/gdextension/gdextension_interface.h @@ -198,6 +198,7 @@ typedef struct { typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr); typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr); +typedef void *(*GDExtensionVariantGetInternalPtrFunc)(GDExtensionVariantPtr); typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result); typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count); typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args); @@ -420,7 +421,9 @@ typedef enum { GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT, - GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE + GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE, + GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR16, + GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32, } GDExtensionClassMethodArgumentMetadata; typedef void (*GDExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error); @@ -1311,6 +1314,9 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasKey)(GDExtensionConstVar * * Gets the object instance ID from a variant of type GDEXTENSION_VARIANT_TYPE_OBJECT. * + * If the variant isn't of type GDEXTENSION_VARIANT_TYPE_OBJECT, then zero will be returned. + * The instance ID will be returned even if the object is no longer valid - use `object_get_instance_by_id()` to check if the object is still valid. + * * @param p_self A pointer to the Variant. * * @return The instance ID for the contained object. @@ -1378,6 +1384,23 @@ typedef GDExtensionVariantFromTypeConstructorFunc (*GDExtensionInterfaceGetVaria */ typedef GDExtensionTypeFromVariantConstructorFunc (*GDExtensionInterfaceGetVariantToTypeConstructor)(GDExtensionVariantType p_type); +/** + * @name variant_get_ptr_internal_getter + * @since 4.4 + * + * Provides a function pointer for retrieving a pointer to a variant's internal value. + * Access to a variant's internal value can be used to modify it in-place, or to retrieve its value without the overhead of variant conversion functions. + * It is recommended to cache the getter for all variant types in a function table to avoid retrieval overhead upon use. + * + * @note Each function assumes the variant's type has already been determined and matches the function. + * Invoking the function with a variant of a mismatched type has undefined behavior, and may lead to a segmentation fault. + * + * @param p_type The Variant type. + * + * @return A pointer to a type-specific function that returns a pointer to the internal value of a variant. Check the implementation of this function (gdextension_variant_get_ptr_internal_getter) for pointee type info of each variant type. + */ +typedef GDExtensionVariantGetInternalPtrFunc (*GDExtensionInterfaceGetVariantGetInternalPtrFunc)(GDExtensionVariantType p_type); + /** * @name variant_get_ptr_operator_evaluator * @since 4.1 diff --git a/include/godot_cpp/core/type_info.hpp b/include/godot_cpp/core/type_info.hpp index d847598a..ebdad7b2 100644 --- a/include/godot_cpp/core/type_info.hpp +++ b/include/godot_cpp/core/type_info.hpp @@ -149,8 +149,8 @@ MAKE_TYPE_INFO_WITH_META(uint32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_MET MAKE_TYPE_INFO_WITH_META(int32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32) MAKE_TYPE_INFO_WITH_META(uint64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64) MAKE_TYPE_INFO_WITH_META(int64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64) -MAKE_TYPE_INFO(char16_t, GDEXTENSION_VARIANT_TYPE_INT) -MAKE_TYPE_INFO(char32_t, GDEXTENSION_VARIANT_TYPE_INT) +MAKE_TYPE_INFO_WITH_META(char16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR16) +MAKE_TYPE_INFO_WITH_META(char32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32) MAKE_TYPE_INFO_WITH_META(float, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT) MAKE_TYPE_INFO_WITH_META(double, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE) From b7dbd26d8f8b5d8220f1791096213a67443a842d Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Thu, 28 Nov 2024 08:55:00 +1030 Subject: [PATCH 07/15] Align MSVC runtime (MD[d], MT) options to engine #1647 Engine has an option to link to MDd debug_crt add flag to SCons options Add flag to CMAKE options --- cmake/windows.cmake | 15 +++++---------- tools/windows.py | 11 ++++++++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cmake/windows.cmake b/cmake/windows.cmake index c46519e8..bf17f74f 100644 --- a/cmake/windows.cmake +++ b/cmake/windows.cmake @@ -11,10 +11,8 @@ function( windows_options ) option( GODOT_USE_STATIC_CPP "Link MinGW/MSVC C++ runtime libraries statically" ON ) - # The below scons variables are controlled via toolchain files instead - # "mingw_prefix" "MinGW prefix" - # "use_llvm" "Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag)" - # "use_mingw" "Use the MinGW compiler instead of MSVC - only effective on Windows" + option( GODOT_DEBUG_CRT "Compile with MSVC's debug CRT (/MDd)" OFF ) + endfunction() function( windows_generate TARGET_NAME ) @@ -23,10 +21,13 @@ function( windows_generate TARGET_NAME ) set( NOT_MSVC "$" ) set( STATIC_CPP "$") set( DISABLE_EXCEPTIONS "$") + set( DEBUG_CRT "$" ) set_target_properties( ${TARGET_NAME} PROPERTIES PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>" + INTERFACE_MSVC_RUNTIME_LIBRARY + "$>" ) target_compile_definitions( ${TARGET_NAME} @@ -38,12 +39,6 @@ function( windows_generate TARGET_NAME ) > ) - target_compile_options( ${TARGET_NAME} - PUBLIC - $<${IS_MSVC}: - $$<${IS_DEV}:d> # Link microsoft runtime - > - ) target_link_options( ${TARGET_NAME} PUBLIC diff --git a/tools/windows.py b/tools/windows.py index 490b9f71..f66bce42 100644 --- a/tools/windows.py +++ b/tools/windows.py @@ -78,6 +78,7 @@ def options(opts): opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler 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("debug_crt", "Compile with MSVC's debug CRT (/MDd)", 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) @@ -117,10 +118,14 @@ def generate(env): env["CC"] = "clang-cl" env["CXX"] = "clang-cl" - if env["use_static_cpp"]: - env.Append(CCFLAGS=["/MT"]) + if env["debug_crt"]: + # Always use dynamic runtime, static debug CRT breaks thread_local. + env.AppendUnique(CCFLAGS=["/MDd"]) else: - env.Append(CCFLAGS=["/MD"]) + if env["use_static_cpp"]: + env.AppendUnique(CCFLAGS=["/MT"]) + else: + env.AppendUnique(CCFLAGS=["/MD"]) if env["silence_msvc"] and not env.GetOption("clean"): silence_msvc(env) From daef7d48ea1d73cc1463dbe6efce4b59bf8d3c2c Mon Sep 17 00:00:00 2001 From: Lukas Tenbrink Date: Tue, 26 Nov 2024 23:35:31 +0100 Subject: [PATCH 08/15] Add variant_internal.hpp. This module contains VariantInternalType, VariantInternal, VariantGetInternalPtr, VariantInternalAccessor and VariantDefaultInitializer, allowing to access and manipulate Variant's internal values. --- include/godot_cpp/godot.hpp | 1 + include/godot_cpp/variant/variant.hpp | 1 + .../godot_cpp/variant/variant_internal.hpp | 510 ++++++++++++++++++ src/godot.cpp | 2 + src/variant/variant.cpp | 2 + src/variant/variant_internal.cpp | 43 ++ test/project/main.gd | 3 + test/src/example.cpp | 10 + test/src/example.h | 3 + 9 files changed, 575 insertions(+) create mode 100644 include/godot_cpp/variant/variant_internal.hpp create mode 100644 src/variant/variant_internal.cpp diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index 39a5f05d..40693aa7 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -88,6 +88,7 @@ extern "C" GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_c extern "C" GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict; extern "C" GDExtensionInterfaceGetVariantFromTypeConstructor gdextension_interface_get_variant_from_type_constructor; extern "C" GDExtensionInterfaceGetVariantToTypeConstructor gdextension_interface_get_variant_to_type_constructor; +extern "C" GDExtensionInterfaceGetVariantGetInternalPtrFunc gdextension_interface_variant_get_ptr_internal_getter; extern "C" GDExtensionInterfaceVariantGetPtrOperatorEvaluator gdextension_interface_variant_get_ptr_operator_evaluator; extern "C" GDExtensionInterfaceVariantGetPtrBuiltinMethod gdextension_interface_variant_get_ptr_builtin_method; extern "C" GDExtensionInterfaceVariantGetPtrConstructor gdextension_interface_variant_get_ptr_constructor; diff --git a/include/godot_cpp/variant/variant.hpp b/include/godot_cpp/variant/variant.hpp index 4c5f206a..f6b70523 100644 --- a/include/godot_cpp/variant/variant.hpp +++ b/include/godot_cpp/variant/variant.hpp @@ -49,6 +49,7 @@ class Variant { friend class GDExtensionBinding; friend class MethodBind; + friend class VariantInternal; static void init_bindings(); diff --git a/include/godot_cpp/variant/variant_internal.hpp b/include/godot_cpp/variant/variant_internal.hpp new file mode 100644 index 00000000..56b73038 --- /dev/null +++ b/include/godot_cpp/variant/variant_internal.hpp @@ -0,0 +1,510 @@ +/**************************************************************************/ +/* variant_internal.hpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef GODOT_VARIANT_INTERNAL_HPP +#define GODOT_VARIANT_INTERNAL_HPP + +#include +#include +#include + +namespace godot { +// For use when you want to access the internal pointer of a Variant directly. +// Use with caution. You need to be sure that the type is correct. + +namespace internal { +template +struct VariantInternalType {}; + +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::BOOL; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::INT; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::FLOAT; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::STRING; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::VECTOR2; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::VECTOR2I; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::RECT2; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::RECT2I; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::VECTOR3; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::VECTOR3I; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::TRANSFORM2D; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::VECTOR4; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::VECTOR4I; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PLANE; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::QUATERNION; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::AABB; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::BASIS; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::TRANSFORM3D; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PROJECTION; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::COLOR; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::STRING_NAME; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::NODE_PATH; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::RID; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::OBJECT; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::CALLABLE; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::SIGNAL; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::DICTIONARY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_BYTE_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_INT32_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_INT64_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_FLOAT32_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_FLOAT64_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_STRING_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_VECTOR2_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_VECTOR3_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_COLOR_ARRAY; +}; +template <> +struct VariantInternalType { + static constexpr Variant::Type type = Variant::PACKED_VECTOR4_ARRAY; +}; +} //namespace internal + +class VariantInternal { + friend class Variant; + + static GDExtensionVariantGetInternalPtrFunc get_internal_func[Variant::VARIANT_MAX]; + + static void init_bindings(); + +public: + template + _FORCE_INLINE_ static T *get_internal_value(Variant *v) { + return static_cast(get_internal_func[internal::VariantInternalType::type](v)); + } + + template + _FORCE_INLINE_ static const T *get_internal_value(const Variant *v) { + return static_cast(get_internal_func[internal::VariantInternalType::type](const_cast(v))); + } + + // Atomic types. + _FORCE_INLINE_ static bool *get_bool(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static int64_t *get_int(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const int64_t *get_int(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static double *get_float(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const double *get_float(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static String *get_string(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const String *get_string(const Variant *v) { return get_internal_value(v); } + + // Math types. + _FORCE_INLINE_ static Vector2 *get_vector2(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Vector2 *get_vector2(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Vector2i *get_vector2i(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Vector2i *get_vector2i(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Rect2 *get_rect2(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Rect2 *get_rect2(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Rect2i *get_rect2i(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Rect2i *get_rect2i(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Vector3 *get_vector3(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Vector3 *get_vector3(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Vector3i *get_vector3i(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Vector3i *get_vector3i(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Vector4 *get_vector4(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Vector4 *get_vector4(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Vector4i *get_vector4i(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Vector4i *get_vector4i(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Transform2D *get_transform2d(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Plane *get_plane(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Quaternion *get_quaternion(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Quaternion *get_quaternion(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static AABB *get_aabb(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const AABB *get_aabb(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Basis *get_basis(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Transform3D *get_transform(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Transform3D *get_transform(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Projection *get_projection(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Projection *get_projection(const Variant *v) { return get_internal_value(v); } + + // Misc types. + _FORCE_INLINE_ static Color *get_color(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Color *get_color(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static StringName *get_string_name(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const StringName *get_string_name(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static NodePath *get_node_path(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const NodePath *get_node_path(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static RID *get_rid(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const RID *get_rid(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Callable *get_callable(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Callable *get_callable(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Signal *get_signal(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Signal *get_signal(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Dictionary *get_dictionary(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static Array *get_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Array *get_array(const Variant *v) { return get_internal_value(v); } + + // Typed arrays. + _FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedByteArray *get_byte_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedInt32Array *get_int32_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedInt32Array *get_int32_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedInt64Array *get_int64_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedInt64Array *get_int64_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedFloat32Array *get_float32_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedFloat32Array *get_float32_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedFloat64Array *get_float64_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedFloat64Array *get_float64_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedStringArray *get_string_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedStringArray *get_string_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedVector2Array *get_vector2_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedVector2Array *get_vector2_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedVector3Array *get_vector3_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedVector3Array *get_vector3_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedColorArray *get_color_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedColorArray *get_color_array(const Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static PackedVector4Array *get_vector4_array(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const PackedVector4Array *get_vector4_array(const Variant *v) { return get_internal_value(v); } + + _FORCE_INLINE_ static Object **get_object(Variant *v) { return get_internal_value(v); } + _FORCE_INLINE_ static const Object **get_object(const Variant *v) { return (const Object **)get_internal_value(v); } + + _FORCE_INLINE_ static void *get_opaque_pointer(Variant *v) { + switch (v->get_type()) { + case Variant::NIL: + return nullptr; + case Variant::BOOL: + return get_bool(v); + case Variant::INT: + return get_int(v); + case Variant::FLOAT: + return get_float(v); + case Variant::STRING: + return get_string(v); + case Variant::VECTOR2: + return get_vector2(v); + case Variant::VECTOR2I: + return get_vector2i(v); + case Variant::VECTOR3: + return get_vector3(v); + case Variant::VECTOR3I: + return get_vector3i(v); + case Variant::VECTOR4: + return get_vector4(v); + case Variant::VECTOR4I: + return get_vector4i(v); + case Variant::RECT2: + return get_rect2(v); + case Variant::RECT2I: + return get_rect2i(v); + case Variant::TRANSFORM3D: + return get_transform(v); + case Variant::PROJECTION: + return get_projection(v); + case Variant::TRANSFORM2D: + return get_transform2d(v); + case Variant::QUATERNION: + return get_quaternion(v); + case Variant::PLANE: + return get_plane(v); + case Variant::BASIS: + return get_basis(v); + case Variant::AABB: + return get_aabb(v); + case Variant::COLOR: + return get_color(v); + case Variant::STRING_NAME: + return get_string_name(v); + case Variant::NODE_PATH: + return get_node_path(v); + case Variant::RID: + return get_rid(v); + case Variant::CALLABLE: + return get_callable(v); + case Variant::SIGNAL: + return get_signal(v); + case Variant::DICTIONARY: + return get_dictionary(v); + case Variant::ARRAY: + return get_array(v); + case Variant::PACKED_BYTE_ARRAY: + return get_byte_array(v); + case Variant::PACKED_INT32_ARRAY: + return get_int32_array(v); + case Variant::PACKED_INT64_ARRAY: + return get_int64_array(v); + case Variant::PACKED_FLOAT32_ARRAY: + return get_float32_array(v); + case Variant::PACKED_FLOAT64_ARRAY: + return get_float64_array(v); + case Variant::PACKED_STRING_ARRAY: + return get_string_array(v); + case Variant::PACKED_VECTOR2_ARRAY: + return get_vector2_array(v); + case Variant::PACKED_VECTOR3_ARRAY: + return get_vector3_array(v); + case Variant::PACKED_COLOR_ARRAY: + return get_color_array(v); + case Variant::PACKED_VECTOR4_ARRAY: + return get_vector4_array(v); + case Variant::OBJECT: + return get_object(v); + case Variant::VARIANT_MAX: + ERR_FAIL_V(nullptr); + } + ERR_FAIL_V(nullptr); + } + + _FORCE_INLINE_ static const void *get_opaque_pointer(const Variant *v) { + switch (v->get_type()) { + case Variant::NIL: + return nullptr; + case Variant::BOOL: + return get_bool(v); + case Variant::INT: + return get_int(v); + case Variant::FLOAT: + return get_float(v); + case Variant::STRING: + return get_string(v); + case Variant::VECTOR2: + return get_vector2(v); + case Variant::VECTOR2I: + return get_vector2i(v); + case Variant::VECTOR3: + return get_vector3(v); + case Variant::VECTOR3I: + return get_vector3i(v); + case Variant::VECTOR4: + return get_vector4(v); + case Variant::VECTOR4I: + return get_vector4i(v); + case Variant::RECT2: + return get_rect2(v); + case Variant::RECT2I: + return get_rect2i(v); + case Variant::TRANSFORM3D: + return get_transform(v); + case Variant::PROJECTION: + return get_projection(v); + case Variant::TRANSFORM2D: + return get_transform2d(v); + case Variant::QUATERNION: + return get_quaternion(v); + case Variant::PLANE: + return get_plane(v); + case Variant::BASIS: + return get_basis(v); + case Variant::AABB: + return get_aabb(v); + case Variant::COLOR: + return get_color(v); + case Variant::STRING_NAME: + return get_string_name(v); + case Variant::NODE_PATH: + return get_node_path(v); + case Variant::RID: + return get_rid(v); + case Variant::CALLABLE: + return get_callable(v); + case Variant::SIGNAL: + return get_signal(v); + case Variant::DICTIONARY: + return get_dictionary(v); + case Variant::ARRAY: + return get_array(v); + case Variant::PACKED_BYTE_ARRAY: + return get_byte_array(v); + case Variant::PACKED_INT32_ARRAY: + return get_int32_array(v); + case Variant::PACKED_INT64_ARRAY: + return get_int64_array(v); + case Variant::PACKED_FLOAT32_ARRAY: + return get_float32_array(v); + case Variant::PACKED_FLOAT64_ARRAY: + return get_float64_array(v); + case Variant::PACKED_STRING_ARRAY: + return get_string_array(v); + case Variant::PACKED_VECTOR2_ARRAY: + return get_vector2_array(v); + case Variant::PACKED_VECTOR3_ARRAY: + return get_vector3_array(v); + case Variant::PACKED_COLOR_ARRAY: + return get_color_array(v); + case Variant::PACKED_VECTOR4_ARRAY: + return get_vector4_array(v); + case Variant::OBJECT: + return get_object(v); + case Variant::VARIANT_MAX: + ERR_FAIL_V(nullptr); + } + ERR_FAIL_V(nullptr); + } +}; + +template +struct VariantGetInternalPtr { + static internal::VariantInternalType *get_ptr(Variant *v) { return VariantInternal::get_internal_value(v); } + static const internal::VariantInternalType *get_ptr(const Variant *v) { return VariantInternal::get_internal_value(v); } +}; + +template +struct can_set_variant_internal_value { + static const bool value = true; +}; + +template <> +struct can_set_variant_internal_value { + static const bool value = false; +}; + +template +struct VariantInternalAccessor { + static _FORCE_INLINE_ const T &get(const Variant *v) { return *VariantInternal::get_internal_value(v); } + + // Enable set() only for those types where we can set (all but Object *). + template ::value>> + static _FORCE_INLINE_ void set(Variant *v, const internal::VariantInternalType &p_value) { + *VariantInternal::get_internal_value(v) = p_value; + } +}; + +template ::value>> +struct VariantDefaultInitializer { + static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_internal_value(v) = T(); } +}; + +} // namespace godot + +#endif // GODOT_VARIANT_INTERNAL_HPP diff --git a/src/godot.cpp b/src/godot.cpp index fe75e6e9..31a64c46 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -94,6 +94,7 @@ GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict = nullptr; GDExtensionInterfaceGetVariantFromTypeConstructor gdextension_interface_get_variant_from_type_constructor = nullptr; GDExtensionInterfaceGetVariantToTypeConstructor gdextension_interface_get_variant_to_type_constructor = nullptr; +GDExtensionInterfaceGetVariantGetInternalPtrFunc gdextension_interface_variant_get_ptr_internal_getter = nullptr; GDExtensionInterfaceVariantGetPtrOperatorEvaluator gdextension_interface_variant_get_ptr_operator_evaluator = nullptr; GDExtensionInterfaceVariantGetPtrBuiltinMethod gdextension_interface_variant_get_ptr_builtin_method = nullptr; GDExtensionInterfaceVariantGetPtrConstructor gdextension_interface_variant_get_ptr_constructor = nullptr; @@ -375,6 +376,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge LOAD_PROC_ADDRESS(variant_can_convert_strict, GDExtensionInterfaceVariantCanConvertStrict); LOAD_PROC_ADDRESS(get_variant_from_type_constructor, GDExtensionInterfaceGetVariantFromTypeConstructor); LOAD_PROC_ADDRESS(get_variant_to_type_constructor, GDExtensionInterfaceGetVariantToTypeConstructor); + LOAD_PROC_ADDRESS(variant_get_ptr_internal_getter, GDExtensionInterfaceGetVariantGetInternalPtrFunc); LOAD_PROC_ADDRESS(variant_get_ptr_operator_evaluator, GDExtensionInterfaceVariantGetPtrOperatorEvaluator); LOAD_PROC_ADDRESS(variant_get_ptr_builtin_method, GDExtensionInterfaceVariantGetPtrBuiltinMethod); LOAD_PROC_ADDRESS(variant_get_ptr_constructor, GDExtensionInterfaceVariantGetPtrConstructor); diff --git a/src/variant/variant.cpp b/src/variant/variant.cpp index 1f57d48a..cf8323ab 100644 --- a/src/variant/variant.cpp +++ b/src/variant/variant.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -49,6 +50,7 @@ void Variant::init_bindings() { from_type_constructor[i] = internal::gdextension_interface_get_variant_from_type_constructor((GDExtensionVariantType)i); to_type_constructor[i] = internal::gdextension_interface_get_variant_to_type_constructor((GDExtensionVariantType)i); } + VariantInternal::init_bindings(); StringName::init_bindings(); String::init_bindings(); diff --git a/src/variant/variant_internal.cpp b/src/variant/variant_internal.cpp new file mode 100644 index 00000000..fbfd1cfb --- /dev/null +++ b/src/variant/variant_internal.cpp @@ -0,0 +1,43 @@ +/**************************************************************************/ +/* variant_internal.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include + +namespace godot { + +GDExtensionVariantGetInternalPtrFunc VariantInternal::get_internal_func[Variant::VARIANT_MAX]{}; + +void VariantInternal::init_bindings() { + for (int i = 1; i < Variant::VARIANT_MAX; i++) { + get_internal_func[i] = internal::gdextension_interface_variant_get_ptr_internal_getter((GDExtensionVariantType)i); + } +} + +} // namespace godot diff --git a/test/project/main.gd b/test/project/main.gd index e5a3b95c..b69ad75a 100644 --- a/test/project/main.gd +++ b/test/project/main.gd @@ -271,6 +271,9 @@ func _ready(): # Test that we can access an engine singleton. assert_equal(example.test_use_engine_singleton(), OS.get_name()) + assert_equal(example.test_get_internal(1), 1) + assert_equal(example.test_get_internal(true), -1) + # Test that notifications happen on both parent and child classes. var example_child = $ExampleChild assert_equal(example_child.get_value1(), 11) diff --git a/test/src/example.cpp b/test/src/example.cpp index 22739b29..4bd3d974 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -243,6 +243,8 @@ void Example::_bind_methods() { ClassDB::bind_method(D_METHOD("callable_bind"), &Example::callable_bind); ClassDB::bind_method(D_METHOD("test_post_initialize"), &Example::test_post_initialize); + ClassDB::bind_method(D_METHOD("test_get_internal", "a"), &Example::test_get_internal); + GDVIRTUAL_BIND(_do_something_virtual, "name", "value"); ClassDB::bind_method(D_METHOD("test_virtual_implemented_in_script"), &Example::test_virtual_implemented_in_script); GDVIRTUAL_BIND(_do_something_virtual_with_control, "control"); @@ -741,6 +743,14 @@ String Example::test_library_path() { return library_path; } +int64_t Example::test_get_internal(const Variant &p_input) const { + if (p_input.get_type() != Variant::INT) { + return -1; + } + + return *VariantInternal::get_int(&p_input); +} + void ExampleRuntime::_bind_methods() { ClassDB::bind_method(D_METHOD("set_prop_value", "value"), &ExampleRuntime::set_prop_value); ClassDB::bind_method(D_METHOD("get_prop_value"), &ExampleRuntime::get_prop_value); diff --git a/test/src/example.h b/test/src/example.h index a7ae54c0..cd5e9f84 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -185,6 +186,8 @@ class Example : public Control { bool test_post_initialize() const; + int64_t test_get_internal(const Variant &p_input) const; + // Static method. static int test_static(int p_a, int p_b); static void test_static2(); From 732df06a8145a8912b1e5afd26d68d36be756f00 Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Sat, 30 Nov 2024 12:19:41 +1030 Subject: [PATCH 09/15] CMake: Fix selection of MSVC Runtime compile flags My last attempt at solving this was not correct. I have left lots of comments in the source detailing the issue as it will effect consumers. --- cmake/windows.cmake | 50 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/cmake/windows.cmake b/cmake/windows.cmake index bf17f74f..c209bdee 100644 --- a/cmake/windows.cmake +++ b/cmake/windows.cmake @@ -5,8 +5,50 @@ Windows This file contains functions for options and configuration for targeting the Windows platform +MSVC Runtime Selection +---------------------- + +There are two main ways to set the msvc runtime library; +Using ``target_compile_options()`` to add the flags +or using the ``CMAKE_MSVC_RUNTIME_LIBRARY`` property_ abstraction, introduced +in CMake version 3.15 with the policy CMP0091_ to remove the flags from +``CMAKE__FLAGS_``. + +Default: ``CMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded$<$:Debug>DLL"`` + +This initializes each target's ``MSVC_RUNTIME_LIBRARY`` property at the time of +target creation. + +This creates a conundrum for us, the ``CMAKE_MSVC_RUNTIME_LIBRARY`` needs to be +correct at the time the target is created, but we have no control over the +consumers CMake scripts, and the per-target ``MSVC_RUNTIME_LIBRARY`` property +is not transient. + +We need ``CMAKE_MSVC_RUNTIME_LIBRARY`` to be ``"$<1:>"`` to ensure it +will not add any flags. And then use ``target_compile_options()`` so that our +flags will propagate to consumers. + +In the interests of playing nicely we detect whether we are being consumed +and notify the consumer that we are setting ``CMAKE_MSVC_RUNTIME_LIBRARY``, +that dependent targets rely on it, and point them to these comments as to why. + +.. _CMP0091:https://cmake.org/cmake/help/latest/policy/CMP0091.html +.. _property:https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html +.. https://discourse.cmake.org/t/mt-staticrelease-doesnt-match-value-md-dynamicrelease/5428/4 + ]=======================================================================] +if( PROJECT_NAME ) # we are not the top level if this is true + if( DEFINED CMAKE_MSVC_RUNTIME_LIBRARY ) + # Warning that we are clobbering the variable. + message( WARNING "setting CMAKE_MSVC_RUNTIME_LIBRARY to \"$<1:>\"") + else( ) + # Notification that we are setting the variable + message( STATUS "setting CMAKE_MSVC_RUNTIME_LIBRARY to \"$<1:>\"") + endif() +endif() +set( CMAKE_MSVC_RUNTIME_LIBRARY "$<1:>" CACHE INTERNAL "Select the MSVC runtime library for use by compilers targeting the MSVC ABI." ) +#[============================[ Windows Options ]============================] function( windows_options ) option( GODOT_USE_STATIC_CPP "Link MinGW/MSVC C++ runtime libraries statically" ON ) @@ -15,6 +57,7 @@ function( windows_options ) endfunction() +#[===========================[ Target Generation ]===========================] function( windows_generate TARGET_NAME ) set( IS_MSVC "$" ) set( IS_CLANG "$,$>" ) @@ -26,8 +69,6 @@ function( windows_generate TARGET_NAME ) set_target_properties( ${TARGET_NAME} PROPERTIES PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>" - INTERFACE_MSVC_RUNTIME_LIBRARY - "$>" ) target_compile_definitions( ${TARGET_NAME} @@ -39,6 +80,11 @@ function( windows_generate TARGET_NAME ) > ) + target_compile_options( ${TARGET_NAME} + PUBLIC + $<${IS_MSVC}:$>> + ) + target_link_options( ${TARGET_NAME} PUBLIC From 9df3a66a88e5eb47781ce83ec490d23c7fc20b70 Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Thu, 28 Nov 2024 23:39:32 +1030 Subject: [PATCH 10/15] Replace empty EXCLUDE variable with EXCLUDE_FROM_ALL This was a mistake left over from the modernise PR --- cmake/godotcpp.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/godotcpp.cmake b/cmake/godotcpp.cmake index c6ba53a3..13f1bfdb 100644 --- a/cmake/godotcpp.cmake +++ b/cmake/godotcpp.cmake @@ -240,7 +240,7 @@ function( godotcpp_generate ) set( HOT_RELOAD "$,$>" ) # the godot-cpp.* library targets - add_library( ${TARGET_NAME} STATIC ${EXCLUDE} ) + add_library( ${TARGET_NAME} STATIC EXCLUDE_FROM_ALL ) add_library( godot-cpp::${TARGET_NAME} ALIAS ${TARGET_NAME} ) file( GLOB_RECURSE GODOTCPP_SOURCES LIST_DIRECTORIES NO CONFIGURE_DEPENDS src/*.cpp ) From 542ab19a21535e489ab0b69cbdcd7e1e44f3febc Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Tue, 26 Nov 2024 19:44:37 +1030 Subject: [PATCH 11/15] CMake: Handle GODOT_DEV_BUILD flag correctly .dev is added to output artifacts Warn users for specifying dev_build and Release build config Update documentation with deviations to SCons Update debug_symbols handling, its rolled into build config Cleanup helper variables and comments --- CMakeLists.txt | 52 ++------------------- cmake/common_compiler_flags.cmake | 28 ++++-------- cmake/godotcpp.cmake | 76 +++++++++++++++++++++---------- cmake/windows.cmake | 4 -- doc/cmake.rst | 14 ++++++ test/CMakeLists.txt | 5 +- 6 files changed, 85 insertions(+), 94 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 926946d9..fb59a999 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,12 @@ CMAKE_PROJECT__INCLUDE which was introduced in version 3.17 Scons Compatibility ------------------- +There is an understandable conflict between build systems as they define +similar concepts in different ways. When there isn't a 1:1 relationship, +compromises need to be made to resolve those differences. + As we are attempting to maintain feature parity, and ease of maintenance, these -CMake scripts are built to resemble the SCons build system. +CMake scripts are built to resemble the SCons build system wherever possible. The file structure and file content are made to match, if not in content then in spirit. The closer the two build systems look the easier they will be to @@ -30,58 +34,12 @@ function is run. cpp_tool = Tool("godotcpp", toolpath=["tools"]) cpp_tool.options(opts, env) - The CMake equivalent is below. ]=======================================================================] include( cmake/godotcpp.cmake ) godotcpp_options() -#[=======================================================================[.rst: - -Configurations --------------- - -There are two build main configurations, 'Debug' and 'Release', these are not -related to godot's DEBUG_FEATURES flag. Build configurations change the default -compiler and linker flags present when building the library, things like debug -symbols, optimization. - -The Scons build scripts don't have this concept, you can think of it like the -SCons solution has a single default configuration. In both cases overriding the -defaults is controlled by options on the command line, or in preset files. - -Because of this added configuration and that it can be undefined, it becomes -important to set a default, considering the SCons solution that does not enable -debug symbols by default, it seemed appropriate to set the default to 'Release' -if unspecified. This can always be overridden like below. - -.. highlight:: shell - - cmake -DCMAKE_BUILD_TYPE:STRING=Debug - -.. caution:: - -A complication arises from `Multi-Config Generators`_ that cannot have -their configuration set at configure time. This means that the configuration -must be set on the build command. This is especially important for Visual -Studio Generators which default to 'Debug' - -.. highlight:: shell - - cmake --build . --config Release - -.. _Multi-Config Generators:https://cmake.org/cmake/help/latest/prop_gbl/GENERATOR_IS_MULTI_CONFIG.html -]=======================================================================] -get_property( IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) -if( NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE ) - if( GODOT_DEV_BUILD ) - set( CMAKE_BUILD_TYPE Debug ) - else () - set( CMAKE_BUILD_TYPE Release ) - endif () -endif () - #[[ Python is required for code generation ]] find_package(Python3 3.4 REQUIRED) # pathlib should be present diff --git a/cmake/common_compiler_flags.cmake b/cmake/common_compiler_flags.cmake index 1b185fe2..4d1bdb95 100644 --- a/cmake/common_compiler_flags.cmake +++ b/cmake/common_compiler_flags.cmake @@ -7,7 +7,11 @@ flags like optimization levels, warnings, and features. For platform specific flags look to each of the ``cmake/.cmake`` files. ]=======================================================================] -#Generator Expression Helpers + +#[[ Compiler Configuration, not to be confused with build targets ]] +set( DEBUG_SYMBOLS "$,$>" ) + +#[[ Compiler Identification ]] set( IS_CLANG "$" ) set( IS_APPLECLANG "$" ) set( IS_GNU "$" ) @@ -20,16 +24,7 @@ set( GNU_GT_V11 "$,11>" ) set( GNU_LT_V11 "$,11>" ) set( GNU_GE_V12 "$,12>" ) -set( HOT_RELOAD-UNSET "$") - -set( DISABLE_EXCEPTIONS "$") - - function( common_compiler_flags TARGET_NAME ) - set( IS_RELEASE "$") - set( DEBUG_FEATURES "$,$>" ) - set( HOT_RELOAD "$,$>" ) - set( DEBUG_SYMBOLS "$" ) target_compile_features(${TARGET_NAME} PUBLIC @@ -44,24 +39,19 @@ function( common_compiler_flags TARGET_NAME ) $<${DISABLE_EXCEPTIONS}: $<${NOT_MSVC}:-fno-exceptions> > - $<$: - $<${IS_MSVC}:/EHsc> - > # Enabling Debug Symbols $<${DEBUG_SYMBOLS}: - $<${IS_MSVC}: /Zi /FS> - # Adding dwarf-4 explicitly makes stacktraces work with clang builds, # otherwise addr2line doesn't understand them. $<${NOT_MSVC}: -gdwarf-4 - $ + $ > > - $<${IS_DEV}: - $<${NOT_MSVC}:-fno-omit-frame-pointer -O0 -g> + $<${IS_DEV_BUILD}: + $<${NOT_MSVC}:-fno-omit-frame-pointer -O0> > $<${HOT_RELOAD}: @@ -137,6 +127,8 @@ function( common_compiler_flags TARGET_NAME ) # features $<${DEBUG_FEATURES}:DEBUG_ENABLED DEBUG_METHODS_ENABLED> + $<${IS_DEV_BUILD}:DEV_ENABLED> + $<${HOT_RELOAD}:HOT_RELOAD_ENABLED> $<$:REAL_T_IS_DOUBLE> diff --git a/cmake/godotcpp.cmake b/cmake/godotcpp.cmake index 13f1bfdb..9bad5ae0 100644 --- a/cmake/godotcpp.cmake +++ b/cmake/godotcpp.cmake @@ -2,6 +2,19 @@ godotcpp.cmake -------------- +As godot-cpp is a C++ project, there are no C files, and detection of a C +compiler is unnecessary. When CMake performs the configure process, if a +C compiler is specified, like in a toolchain, or from an IDE, then it will +print a warning stating that the CMAKE_C_COMPILER compiler is unused. +This if statement simply silences that warning. +]=======================================================================] +if( CMAKE_C_COMPILER ) +endif () + +#[=======================================================================[.rst: +Include Platform Files +---------------------- + Because these files are included into the top level CMakelists.txt before the project directive, it means that @@ -18,10 +31,7 @@ include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos.cmake) include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/web.cmake) include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows.cmake) -#Silence warning from unused CMAKE_C_COMPILER from toolchain -if( CMAKE_C_COMPILER ) -endif () - +# Detect number of processors include(ProcessorCount) ProcessorCount(PROC_MAX) message( "Auto-detected ${PROC_MAX} CPU cores available for build parallelism." ) @@ -99,8 +109,7 @@ function( godotcpp_options ) #TODO threads #TODO compiledb #TODO compiledb_file - - #NOTE: build_profile's equivalent in cmake is CMakePresets.json + #TODO build_profile set(GODOT_USE_HOT_RELOAD "" CACHE BOOL "Enable the extra accounting required to support hot reload. (ON|OFF)") @@ -114,17 +123,26 @@ function( godotcpp_options ) set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" ) #TODO optimize - #TODO debug_symbols - option( GODOT_DEBUG_SYMBOLS "" OFF ) + option( GODOT_DEV_BUILD "Developer build with dev-only debugging code (DEV_ENABLED)" OFF ) + #[[ debug_symbols + Debug symbols are enabled by using the Debug or RelWithDebInfo build configurations. + Single Config Generator is set at configure time + + cmake ../ -DCMAKE_BUILD_TYPE=Debug + + Multi-Config Generator is set at build time + + cmake --build . --config Debug + + ]] + # FIXME These options are not present in SCons, and perhaps should be added there. option( GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." OFF ) 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. + #[[ Target Platform Options ]] android_options() ios_options() linux_options() @@ -136,7 +154,6 @@ endfunction() # Function to configure and generate the targets function( godotcpp_generate ) #[[ Multi-Threaded MSVC Compilation - When using the MSVC compiler the build command -j only specifies parallel jobs or targets, and not multi-threaded compilation To speed up compile times on msvc, the /MP flag can be set. But we need to set it @@ -157,13 +174,11 @@ function( godotcpp_generate ) #[[ GODOT_SYMBOL_VISIBLITY To match the SCons options, the allowed values are "auto", "visible", and "hidden" - This effects the compiler flag -fvisibility=[default|internal|hidden|protected] - The corresponding CMake option CXX_VISIBILITY_PRESET accepts the compiler values. + This effects the compiler flag_ -fvisibility=[default|internal|hidden|protected] + The corresponding target option CXX_VISIBILITY_PRESET accepts the compiler values. TODO: It is probably worth a pull request which changes both to use the compiler values - https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fvisibility - - This performs the necessary conversion + .. _flag:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fvisibility ]] if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" ) set( GODOT_SYMBOL_VISIBILITY "default" ) @@ -230,14 +245,29 @@ function( godotcpp_generate ) godot_arch_map( SYSTEM_ARCH ${CMAKE_SYSTEM_PROCESSOR} ) endif() + # Transform options into generator expressions + set( HOT_RELOAD-UNSET "$") + + set( DISABLE_EXCEPTIONS "$") + + # GODOT_DEV_BUILD + set( RELEASE_TYPES "Release;MinSizeRel") + get_property( IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) + if( IS_MULTI_CONFIG ) + message( NOTICE "=> Default build type is Debug. For other build types add --config to build command") + elseif( GODOT_DEV_BUILD AND CMAKE_BUILD_TYPE IN_LIST RELEASE_TYPES ) + message( WARNING "=> GODOT_DEV_BUILD implies a Debug-like build but CMAKE_BUILD_TYPE is '${CMAKE_BUILD_TYPE}'") + endif () + set( IS_DEV_BUILD "$") + # The .dev portion of the name if GODOT_DEV_BUILD is true. + set( DEV_TAG "$<${IS_DEV_BUILD}:.dev>" ) + ### Define our godot-cpp library targets foreach ( TARGET_NAME template_debug template_release editor ) - # Useful genex snippits used in subsequent genex's - set( IS_RELEASE "$") - set( IS_DEV "$") - set( DEBUG_FEATURES "$,$>" ) - set( HOT_RELOAD "$,$>" ) + # Generator Expressions that rely on the target + set( DEBUG_FEATURES "$>" ) + set( HOT_RELOAD "$>" ) # the godot-cpp.* library targets add_library( ${TARGET_NAME} STATIC EXCLUDE_FROM_ALL ) @@ -268,7 +298,7 @@ function( godotcpp_generate ) BUILD_RPATH_USE_ORIGIN ON PREFIX lib - OUTPUT_NAME "${PROJECT_NAME}.${SYSTEM_NAME}.${TARGET_NAME}.${SYSTEM_ARCH}" + OUTPUT_NAME "${PROJECT_NAME}.${SYSTEM_NAME}.${TARGET_NAME}${DEV_TAG}.${SYSTEM_ARCH}" ARCHIVE_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/bin>" # Things that are handy to know for dependent targets diff --git a/cmake/windows.cmake b/cmake/windows.cmake index c209bdee..fd07bd18 100644 --- a/cmake/windows.cmake +++ b/cmake/windows.cmake @@ -59,11 +59,7 @@ endfunction() #[===========================[ Target Generation ]===========================] function( windows_generate TARGET_NAME ) - set( IS_MSVC "$" ) - set( IS_CLANG "$,$>" ) - set( NOT_MSVC "$" ) set( STATIC_CPP "$") - set( DISABLE_EXCEPTIONS "$") set( DEBUG_CRT "$" ) set_target_properties( ${TARGET_NAME} diff --git a/doc/cmake.rst b/doc/cmake.rst index d47dadd8..f604e78a 100644 --- a/doc/cmake.rst +++ b/doc/cmake.rst @@ -24,6 +24,20 @@ Configuration examples are listed at the bottom of the page. .. _godot-cpp-template: https://github.com/godotengine/godot-cpp-template +SCons Deviations +---------------- + +Not everything from SCons can be perfectly representable in CMake, here are +the notable differences. + +- debug_symbols + No longer has an explicit option, and is enabled via Debug-like CMake + build configurations; Debug, RelWithDebInfo. + +- dev_build + Does not define NDEBUG when disabled, NDEBUG is set via Release-like + CMake build configurations; Release, MinSizeRel. + Basic walkthrough ----------------- diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ab7397fa..12e44f16 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -26,6 +26,7 @@ get_target_property( GODOT_TARGET godot-cpp::${TEST_TARGET} GODOT_TARGET ) get_target_property( GODOT_ARCH godot-cpp::${TEST_TARGET} GODOT_ARCH ) set( OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/project/bin/" ) +set( DEV_TAG "$<$:.dev>" ) set_target_properties( godot-cpp-test PROPERTIES @@ -45,7 +46,7 @@ set_target_properties( godot-cpp-test PDB_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" #MSVC Only, ignored on other platforms PREFIX "lib" - OUTPUT_NAME "gdexample.${GODOT_PLATFORM}.${GODOT_TARGET}.${GODOT_ARCH}" + OUTPUT_NAME "gdexample.${GODOT_PLATFORM}.${GODOT_TARGET}${DEV_TAG}.${GODOT_ARCH}" ) if( CMAKE_SYSTEM_NAME STREQUAL Darwin ) @@ -58,7 +59,7 @@ if( CMAKE_SYSTEM_NAME STREQUAL Darwin ) LIBRARY_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" RUNTIME_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" - OUTPUT_NAME "gdexample.macos.${TEST_TARGET}" + OUTPUT_NAME "gdexample.macos.${TEST_TARGET}${DEV_TAG}" SUFFIX "" #macos options From ef9778a392fb6c9f49a13da55f7c5dcca8d2b5ed Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Thu, 5 Dec 2024 09:35:32 +1030 Subject: [PATCH 12/15] CMake: Enable using clang-cl on windows detect clang with MSVC frontend using CMAKE_CXX_COMPILER_FRONTEND_VARIANT --- CMakeLists.txt | 1 + cmake/common_compiler_flags.cmake | 29 +++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb59a999..fa2f1cc9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ project( godot-cpp HOMEPAGE_URL "https://github.com/godotengine/godot-cpp" LANGUAGES CXX) +compiler_detection() godotcpp_generate() # Test Example diff --git a/cmake/common_compiler_flags.cmake b/cmake/common_compiler_flags.cmake index 4d1bdb95..ac3f4490 100644 --- a/cmake/common_compiler_flags.cmake +++ b/cmake/common_compiler_flags.cmake @@ -2,9 +2,10 @@ Common Compiler Flags --------------------- -This file contains a single function to configure platform agnostic compiler -flags like optimization levels, warnings, and features. For platform specific -flags look to each of the ``cmake/.cmake`` files. +This file contains host platform toolchain and target platform agnostic +configuration. It includes flags like optimization levels, warnings, and +features. For target platform specific flags look to each of the +``cmake/.cmake`` files. ]=======================================================================] @@ -24,6 +25,25 @@ set( GNU_GT_V11 "$,11>" ) set( GNU_LT_V11 "$,11>" ) set( GNU_GE_V12 "$,12>" ) +#[[ Check for clang-cl with MSVC frontend +The compiler is tested and set when the project command is called. +The variable CXX_COMPILER_FRONTEND_VARIANT was introduced in 3.14 +The generator expression $ wasn't introduced +until CMake 3.30 so we can't use it yet. + +So to support clang downloaded from llvm.org which uses the MSVC frontend +by default, we need to test for it. ]] +function( compiler_detection ) + if( ${CMAKE_CXX_COMPILER_ID} STREQUAL Clang ) + if( ${CMAKE_CXX_COMPILER_FRONTEND_VARIANT} STREQUAL MSVC ) + message( "Using clang-cl" ) + set( IS_CLANG "0" PARENT_SCOPE ) + set( IS_MSVC "1" PARENT_SCOPE ) + set( NOT_MSVC "0" PARENT_SCOPE ) + endif () + endif () +endfunction( ) + function( common_compiler_flags TARGET_NAME ) target_compile_features(${TARGET_NAME} @@ -60,7 +80,8 @@ function( common_compiler_flags TARGET_NAME ) # MSVC only $<${IS_MSVC}: - "/MP ${PROC_N}" + # /MP isn't valid for clang-cl with msvc frontend + $<$:/MP${PROC_N}> /W4 # Disable warnings which we don't plan to fix. From 9943675dcbfb1df48b74d2405b910371ff0d1ec3 Mon Sep 17 00:00:00 2001 From: Lukas Tenbrink Date: Wed, 27 Nov 2024 00:24:02 +0100 Subject: [PATCH 13/15] Add a separate setup-godot-cpp github action. --- .github/actions/setup-godot-cpp/action.yml | 62 ++++++++++++++++++++++ .github/workflows/ci.yml | 31 ++--------- 2 files changed, 66 insertions(+), 27 deletions(-) create mode 100644 .github/actions/setup-godot-cpp/action.yml diff --git a/.github/actions/setup-godot-cpp/action.yml b/.github/actions/setup-godot-cpp/action.yml new file mode 100644 index 00000000..287fb238 --- /dev/null +++ b/.github/actions/setup-godot-cpp/action.yml @@ -0,0 +1,62 @@ +name: Setup godot-cpp +description: Setup build dependencies for godot-cpp. + +inputs: + platform: + required: true + description: Target platform. + em-version: + default: 3.1.62 + description: Emscripten version. + windows-compiler: + required: true + description: The compiler toolchain to use on Windows ('mingw' or 'msvc'). + type: choice + options: + - mingw + - msvc + default: mingw + mingw-version: + default: 12.2.0 + description: MinGW version. + ndk-version: + default: r23c + description: Android NDK version. + scons-version: + default: 4.4.0 + description: SCons version. + +runs: + using: composite + steps: + - name: Setup Python (for SCons) + uses: actions/setup-python@v5 + with: + python-version: 3.x + + - name: Setup Android dependencies + if: inputs.platform == 'android' + uses: nttld/setup-ndk@v1 + with: + ndk-version: ${{ inputs.ndk-version }} + link-to-sdk: true + + - name: Setup Web dependencies + if: inputs.platform == 'web' + uses: mymindstorm/setup-emsdk@v14 + with: + version: ${{ inputs.em-version }} + no-cache: true + + - name: Setup MinGW for Windows/MinGW build + if: inputs.platform == 'windows' && inputs.windows-compiler == 'mingw' + uses: egor-tensin/setup-mingw@v2 + with: + version: ${{ inputs.mingw-version }} + + - name: Setup SCons + shell: bash + run: | + python -c "import sys; print(sys.version)" + python -m pip install scons==${{ inputs.scons-version }} + scons --version diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33b2450d..6580de90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,34 +108,11 @@ jobs: cache-name: ${{ matrix.cache-name }} continue-on-error: true - - name: Set up Python (for SCons) - uses: actions/setup-python@v5 + - name: Setup godot-cpp + uses: ./.github/actions/setup-godot-cpp with: - python-version: 3.x - - - name: Android dependencies - if: matrix.platform == 'android' - uses: nttld/setup-ndk@v1 - with: - ndk-version: r23c - link-to-sdk: true - - - name: Web dependencies - if: matrix.platform == 'web' - uses: mymindstorm/setup-emsdk@v14 - with: - version: ${{ env.EM_VERSION }} - no-cache: true - - - name: Setup MinGW for Windows/MinGW build - if: matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' - uses: egor-tensin/setup-mingw@v2 - with: - version: 12.2.0 - - - name: Install scons - run: | - python -m pip install scons==4.0.0 + platform: ${{ matrix.platform }} + windows-compiler: ${{ contains(matrix.flags, 'use_mingw=yes') && 'mingw' || 'msvc' }} - name: Generate godot-cpp sources only run: | From 47d9cb9bed021662ec8f5b8f34db1ff4b507a68a Mon Sep 17 00:00:00 2001 From: David Snopek Date: Mon, 9 Dec 2024 11:33:57 -0600 Subject: [PATCH 14/15] Fix `print_verbose()` macro conflicting with `UtilityFunctions::print_verbose()` --- include/godot_cpp/core/print_string.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/godot_cpp/core/print_string.hpp b/include/godot_cpp/core/print_string.hpp index 3d70c796..61f4330c 100644 --- a/include/godot_cpp/core/print_string.hpp +++ b/include/godot_cpp/core/print_string.hpp @@ -61,15 +61,13 @@ void print_line_rich(const Variant &p_variant, Args... p_args) { UtilityFunctions::print_rich(p_variant, p_args...); } +template +void print_verbose(const Variant &p_variant, Args... p_args) { + UtilityFunctions::print_verbose(p_variant, p_args...); +} + bool is_print_verbose_enabled(); -// Checking the condition before evaluating the text to be printed avoids processing unless it actually has to be printed, saving some CPU usage. -#define print_verbose(m_variant) \ - { \ - if (is_print_verbose_enabled()) { \ - print_line(m_variant); \ - } \ - } } // namespace godot #endif // GODOT_PRINT_STRING_HPP From 2fd3a805052e31581cc8875b42d4b4ebd9ece90e Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Sat, 12 Oct 2024 02:17:42 +0200 Subject: [PATCH 15/15] Add icon path to class creation info --- gdextension/gdextension_interface.h | 1 + include/godot_cpp/core/class_db.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h index 8268afc3..68c39587 100644 --- a/gdextension/gdextension_interface.h +++ b/gdextension/gdextension_interface.h @@ -368,6 +368,7 @@ typedef struct { GDExtensionBool is_abstract; GDExtensionBool is_exposed; GDExtensionBool is_runtime; + GDExtensionConstStringPtr icon_path; GDExtensionClassSet set_func; GDExtensionClassGet get_func; GDExtensionClassGetPropertyList get_property_list_func; diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 865deb81..402f7e08 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -251,6 +251,7 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) { is_abstract, // GDExtensionBool is_abstract; p_exposed, // GDExtensionBool is_exposed; p_runtime, // GDExtensionBool is_runtime; + nullptr, // GDExtensionConstStringPtr icon_path; T::set_bind, // GDExtensionClassSet set_func; T::get_bind, // GDExtensionClassGet get_func; T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;