Browse Source

Merge pull request #1598 from enetheru/modernise

Modernise existing cmake options
David Snopek 8 months ago
parent
commit
a42b3634d2
15 changed files with 1153 additions and 496 deletions
  1. 8 38
      .github/workflows/ci.yml
  2. 4 1
      .gitignore
  3. 91 17
      CMakeLists.txt
  4. 41 0
      cmake/android.cmake
  5. 161 93
      cmake/common_compiler_flags.cmake
  6. 40 0
      cmake/emsdkHack.cmake
  7. 216 160
      cmake/godotcpp.cmake
  8. 22 0
      cmake/ios.cmake
  9. 22 0
      cmake/linux.cmake
  10. 59 0
      cmake/macos.cmake
  11. 42 0
      cmake/web.cmake
  12. 63 0
      cmake/windows.cmake
  13. 0 57
      doc/cmake.md
  14. 331 0
      doc/cmake.rst
  15. 53 130
      test/CMakeLists.txt

+ 8 - 38
.github/workflows/ci.yml

@@ -207,30 +207,6 @@ jobs:
           path: ${{ matrix.artifact-path }}
           path: ${{ matrix.artifact-path }}
           if-no-files-found: error
           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:
   linux-cmake-ninja:
     name: 🐧 Build (Linux, GCC, CMake Ninja)
     name: 🐧 Build (Linux, GCC, CMake Ninja)
     runs-on: ubuntu-22.04
     runs-on: ubuntu-22.04
@@ -245,15 +221,12 @@ jobs:
           sudo apt-get update -qq
           sudo apt-get update -qq
           sudo apt-get install -qqq build-essential pkg-config cmake ninja-build
           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
       - name: Build test GDExtension library
         run: |
         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:
   windows-msvc-cmake:
     name: 🏁 Build (Windows, MSVC, CMake)
     name: 🏁 Build (Windows, MSVC, CMake)
@@ -264,12 +237,9 @@ jobs:
         with:
         with:
           submodules: recursive
           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
       - name: Build test GDExtension library
         run: |
         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

+ 4 - 1
.gitignore

@@ -198,4 +198,7 @@ venv
 
 
 # Clion Configuration
 # Clion Configuration
 .idea/
 .idea/
-cmake-build-*
+cmake-build*/
+
+# CMake related
+CMakeUserPresets.json

+ 91 - 17
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_<PROJECT-NAME>_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()
 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 <source> -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()
 godotcpp_generate()
+
+# Test Example
+add_subdirectory( test )

+ 41 - 0
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()

+ 161 - 93
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 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>" )
-set( compiler_greater_than_or_equal_v9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>" )
-set( compiler_greater_than_or_equal_v11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>" )
-set( compiler_less_than_v11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>" )
-set( compiler_greater_than_or_equal_v12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,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
-    $<$<OR:${compiler_is_clang},${compiler_is_gnu}>:
-        -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
-    >
-    $<$<AND:${compiler_is_gnu},${compiler_less_than_v8}>:
-        # Bogus warning fixed in 8+.
-        -Wno-strict-overflow
-    >
-    $<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v9}>:
-        -Wattribute-alias=2
-    >
-    $<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v11}>:
-        # Broke on MethodBind templates before GCC 11.
-        -Wlogical-op
-    >
-    $<$<AND:${compiler_is_gnu},${compiler_less_than_v11}>:
-        # Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it.
-        -Wno-type-limits
-    >
-    $<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v12}>:
-        # 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>
-                $<$<OR:${compiler_is_clang},${compiler_is_gnu}>:-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/<platform>.cmake`` files.
+
+]=======================================================================]
+#Generator Expression Helpers
+set( IS_CLANG "$<CXX_COMPILER_ID:Clang>" )
+set( IS_APPLECLANG "$<CXX_COMPILER_ID:AppleClang>" )
+set( IS_GNU "$<CXX_COMPILER_ID:GNU>" )
+set( IS_MSVC "$<CXX_COMPILER_ID:MSVC>" )
+set( NOT_MSVC "$<NOT:$<CXX_COMPILER_ID:MSVC>>" )
+
+set( GNU_LT_V8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>" )
+set( GNU_GE_V9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>" )
+set( GNU_GT_V11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>" )
+set( GNU_LT_V11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>" )
+set( GNU_GE_V12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>" )
+
+set( HOT_RELOAD-UNSET "$<STREQUAL:${GODOT_USE_HOT_RELOAD},>")
+
+set( DISABLE_EXCEPTIONS "$<BOOL:${GODOT_DISABLE_EXCEPTIONS}>")
+
+
+function( common_compiler_flags TARGET_NAME )
+    set( IS_RELEASE "$<STREQUAL:${TARGET_NAME},template_release>")
+    set( DEBUG_FEATURES "$<OR:$<STREQUAL:${TARGET_NAME},template_debug>,$<STREQUAL:${TARGET_NAME},editor>>" )
+    set( HOT_RELOAD "$<IF:${HOT_RELOAD-UNSET},$<NOT:${IS_RELEASE}>,$<BOOL:${GODOT_USE_HOT_RELOAD}>>" )
+    set( DEBUG_SYMBOLS "$<BOOL:${GODOT_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>
+            >
+            $<$<NOT:${DISABLE_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
+                    $<IF:${IS_DEV},-g3,-g2>
+                >
+            >
+
+            $<${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
+        $<$<OR:${IS_CLANG},${IS_GNU}>:
+            -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>
+
+            $<$<STREQUAL:${GODOT_PRECISION},double>: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>>
+            $<$<NOT:${DEBUG_SYMBOLS}>:
+                $<${IS_GNU}:-s>
+                $<${IS_CLANG}:-s>
+                $<${IS_APPLECLANG}:-Wl,-S -Wl,-x -Wl,-dead_strip>
+            >
+    )
+
+endfunction()

+ 40 - 0
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_<projectName>_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 ()

+ 216 - 160
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
     # Input from user for GDExtension interface header and the API JSON file
     set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH
     set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH
             "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" )
             "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" )
     set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH
     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
     #TODO generate_bindings
 
 
@@ -19,15 +91,22 @@ function( godotcpp_options )
     set(GODOT_PRECISION "single" CACHE STRING
     set(GODOT_PRECISION "single" CACHE STRING
             "Set the floating-point precision level (single|double)")
             "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 threads
     #TODO compiledb
     #TODO compiledb
     #TODO compiledb_file
     #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
     set(GODOT_USE_HOT_RELOAD "" CACHE BOOL
             "Enable the extra accounting required to support hot reload. (ON|OFF)")
             "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 )
     option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON )
 
 
     set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING
     set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING
@@ -36,48 +115,67 @@ function( godotcpp_options )
 
 
     #TODO optimize
     #TODO optimize
     #TODO debug_symbols
     #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.
     # 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()
 endfunction()
 
 
-
+# Function to configure and generate the targets
 function( godotcpp_generate )
 function( godotcpp_generate )
-    # Set some helper variables for readability
-    set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
-    set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
-    set( compiler_is_msvc "$<CXX_COMPILER_ID: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 <n> only specifies
+    parallel jobs or targets, and not multi-threaded compilation To speed up
+    compile times on msvc, the /MP <n> 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 <n> or --parallel <n> 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" )
     if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" )
         set( GODOT_SYMBOL_VISIBILITY "default" )
         set( GODOT_SYMBOL_VISIBILITY "default" )
     endif ()
     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)
     if(NOT DEFINED BITS)
         set(BITS 32)
         set(BITS 32)
         if(CMAKE_SIZEOF_VOID_P EQUAL 8)
         if(CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -85,67 +183,26 @@ function( godotcpp_generate )
         endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
         endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
     endif()
     endif()
 
 
-
     set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json")
     set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json")
     if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "")  # User-defined override.
     if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "")  # User-defined override.
         set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}")
         set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}")
     endif()
     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)
     if(GODOT_GENERATE_TEMPLATE_GET_NODE)
         set(GENERATE_BINDING_PARAMETERS "True")
         set(GENERATE_BINDING_PARAMETERS "True")
     else()
     else()
         set(GENERATE_BINDING_PARAMETERS "False")
         set(GENERATE_BINDING_PARAMETERS "False")
     endif()
     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}
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
             OUTPUT_VARIABLE GENERATED_FILES_LIST
             OUTPUT_VARIABLE GENERATED_FILES_LIST
             OUTPUT_STRIP_TRAILING_WHITESPACE
             OUTPUT_STRIP_TRAILING_WHITESPACE
     )
     )
 
 
     add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
     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
             VERBATIM
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
             MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
             MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
@@ -153,88 +210,87 @@ function( godotcpp_generate )
             COMMENT "Generating bindings"
             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
-            $<$<CONFIG:Debug>:
-            DEBUG_ENABLED
-            DEBUG_METHODS_ENABLED
-            >
-            $<${compiler_is_msvc}:
-            TYPED_METHOD_BIND
-            >
-    )
-
-    target_link_options(${PROJECT_NAME} PRIVATE
-            $<$<NOT:${compiler_is_msvc}>:
-            -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
+            $<$<PLATFORM_ID:Android>:android.${ANDROID_ABI}>
+            $<$<PLATFORM_ID:iOS>:ios>
+            $<$<PLATFORM_ID:Linux>:linux>
+            $<$<PLATFORM_ID:Darwin>:macos>
+            $<$<PLATFORM_ID:Emscripten>:web>
+            $<$<PLATFORM_ID:Windows>:windows>
+            $<$<PLATFORM_ID:Msys>: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()
     else()
-        set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
+        godot_arch_map( SYSTEM_ARCH ${CMAKE_SYSTEM_PROCESSOR} )
     endif()
     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 "$<STREQUAL:${TARGET_NAME},template_release>")
+        set( IS_DEV "$<BOOL:${GODOT_DEV_BUILD}>")
+        set( DEBUG_FEATURES "$<OR:$<STREQUAL:${TARGET_NAME},template_debug>,$<STREQUAL:${TARGET_NAME},editor>>" )
+        set( HOT_RELOAD "$<IF:${HOT_RELOAD-UNSET},$<NOT:${IS_RELEASE}>,$<BOOL:${GODOT_USE_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()
 endfunction()

+ 22 - 0
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()

+ 22 - 0
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()

+ 59 - 0
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()

+ 42 - 0
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()

+ 63 - 0
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 "$<CXX_COMPILER_ID:MSVC>" )
+    set( IS_CLANG "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
+    set( NOT_MSVC "$<NOT:${IS_MSVC}>" )
+    set( STATIC_CPP "$<BOOL:${GODOT_USE_STATIC_CPP}>")
+    set( DISABLE_EXCEPTIONS "$<BOOL:${GODOT_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}:
+                $<IF:${STATIC_CPP},/MT,/MD>$<${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()

+ 0 - 57
doc/cmake.md

@@ -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(<all-my-plugin-related-targets> PROPERTIES CXX_VISIBILITY_PRESET hidden)
-```
-
-## Todo
-Test build for Windows, Mac and mingw.

+ 331 - 0
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 <godot-cpp source folder>
+    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 ``<version>`` is whatever
+ndk version you have installed ( tested with `23.2.8568313`) and ``<platform>``
+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=<platform> \
+            -DCMAKE_ANDROID_ARCH_ABI=<arch> \
+            -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/<version>/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/<version>/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 ``<arch>[sub][-vendor][-OS][-env]``
+
+* `osdev.org <https://wiki.osdev.org/Target_Triplet>`_
+* `stack overflow <https://stackoverflow.com/questions/13819857/does-a-list-of-all-known-target-triplets-in-use-exist>`_
+* `LLVM <https://llvm.org/doxygen/classllvm_1_1Triple.html>`_
+* `clang target triple <https://clang.llvm.org/docs/CrossCompilation.html#target-triple>`_
+* `vcpkg <https://learn.microsoft.com/en-us/vcpkg/concepts/triplets>`_
+* `wasm32-unknown-emscripten <https://blog.therocode.net/2020/10/a-guide-to-rust-sdl2-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 <https://visualstudio.microsoft.com/vs/>`_
+    :Target: x86_64-w64
+
+`LLVM <https://llvm.org/>`_
+    :Target: x86_64-pc-windows-msvc
+
+`AndroidSDK <https://developer.android.com/studio/#command-tools>`_
+    armv7-none-linux-androideabi16
+
+`Emscripten <https://emscripten.org/>`_
+    :Compiler: Emscripten
+    :Target: wasm32-unknown-emscripten
+
+`MinGW-w64 <https://www.mingw-w64.org/>`_ based toolchains
+
+    `MSYS2 <https://www.msys2.org/>`_
+        Necessary reading about MSYS2 `environments <https://www.msys2.org/docs/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 <https://github.com/mstorsjo/llvm-mingw/releases>`_
+
+    `MinGW-W64-builds <https://github.com/niXman/mingw-builds-binaries/releases>`_
+        :Compiler: gcc
+        :Target: x86_64-w64-mingw32-ucrt
+
+    `Jetbrains-CLion <https://www.jetbrains.com/clion/>`_
+        :Target: x86_64-w64-mingw32-msvcrt

+ 53 - 130
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}$<$<NOT:$<PLATFORM_ID:Android>>:.${BITS}>
-	)
-else()
-	target_link_libraries(${PROJECT_NAME}
-			${CPP_BINDINGS_PATH}/bin/libgodot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}$<$<NOT:$<PLATFORM_ID:Android>>:.${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 ()