diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9f5db7878..96699f5029 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -208,30 +208,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 @@ -246,15 +222,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 ../ + cmake --build . --verbose -j $(nproc) -t godot-cpp-test windows-msvc-cmake: name: 🏁 Build (Windows, MSVC, CMake) @@ -265,12 +238,36 @@ 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 ../ + cmake --build . --verbose -t godot-cpp-test --config Release + +# - name: Download latest Godot artifacts +# uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9 +# with: +# repo: godotengine/godot +# branch: master +# event: push +# workflow: windows_builds.yml +# workflow_conclusion: success +# name: windows-x86_64-msvc +# search_artifacts: true +# check_artifacts: true +# ensure_latest: true +# path: godot-artifacts + +# FIXME Error: no matching workflow run found with any artifacts? + +# - name: Run tests +# run: | +# # Run the test project +# $godot="./godot-artifacts/godot.windows.editor.x86_64.exe" +# &$godot -e --path test\project\ --headless --quit *>$null +# $godot_tr = C:\build\godot\msvc.master\bin\godot.windows.template_release.x86_64.exe +# $godot_tr --path ..\test\project\ --headless --quit +# $output=&$godot --path test\project\ --headless --quit *>&1 | Out-String +# !$output.Contains("==== TESTS FINISHED ====") +# $output.Contains("******** FAILED ********") diff --git a/.gitignore b/.gitignore index ee9a3f756b..6119b62531 100644 --- a/.gitignore +++ b/.gitignore @@ -199,3 +199,6 @@ venv # Clion Configuration .idea/ cmake-build-* + +# CMake related +CMakeUserPresets.json diff --git a/CMakeLists.txt b/CMakeLists.txt index ff77368ba6..cf0e8668c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,50 @@ 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}) + +# As we are attempting to maintain feature parity, and ease of maintenance, +# these CMake scripts are built to resemble the structure of the SCons build system. +# The closer the two build systems look the easier they will be to maintain. + +# include pulls in the code from godotcpp.cmake +# the equivalent in scons: +# cpp_tool = Tool("godotcpp", toolpath=["tools"]) +include( cmake/godotcpp.cmake ) + +godotcpp_options() + +# godot-cpp targets three main configurations, editor, template_release and template_debug. +# These are all built in "Release" mode unless GODOT_DEV_BUILD is enabled, then the build type is "Debug". +# WARNING: If using Visual Studio Generators the build type is 'Debug' unless specified on the command line like so: +# cmake --build . --config Release +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 () -include( ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake ) +# Get Python +find_package(Python3 3.4 REQUIRED) # pathlib should be present -# 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. +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) -# The typical target definitions are in ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake -godotcpp_options() +# 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 0000000000..1d6826ae03 --- /dev/null +++ b/cmake/android.cmake @@ -0,0 +1,14 @@ +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 94556415b1..2d22f04ed1 100644 --- a/cmake/common_compiler_flags.cmake +++ b/cmake/common_compiler_flags.cmake @@ -1,94 +1,180 @@ -# 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() +#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> + > + + # TODO Set optimize + # "custom" means do nothing and let users set their own optimization flags. + #if env.get("is_msvc", False): + #if env["optimize"] == "speed": + #env.Append(CCFLAGS=["/O2"]) + #env.Append(LINKFLAGS=["/OPT:REF"]) + #elif env["optimize"] == "speed_trace": + #env.Append(CCFLAGS=["/O2"]) + #env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"]) + #elif env["optimize"] == "size": + #env.Append(CCFLAGS=["/O1"]) + #env.Append(LINKFLAGS=["/OPT:REF"]) + #elif env["optimize"] == "debug" or env["optimize"] == "none": + #env.Append(CCFLAGS=["/Od"]) + #else: + #if env["optimize"] == "speed": + #env.Append(CCFLAGS=["-O3"]) + ## `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces. + #elif env["optimize"] == "speed_trace": + #env.Append(CCFLAGS=["-O2"]) + #elif env["optimize"] == "size": + #env.Append(CCFLAGS=["-Os"]) + #elif env["optimize"] == "debug": + #env.Append(CCFLAGS=["-Og"]) + #elif env["optimize"] == "none": + #env.Append(CCFLAGS=["-O0"]) + + # 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/godotcpp.cmake b/cmake/godotcpp.cmake index a5c6677964..bafce5ae99 100644 --- a/cmake/godotcpp.cmake +++ b/cmake/godotcpp.cmake @@ -1,13 +1,36 @@ -function( godotcpp_options ) +#Silence warning from unused CMAKE_C_COMPILER from toolchain +if( CMAKE_C_COMPILER ) +endif () + +# Detect processor count so we can use it in msvc builds +include(ProcessorCount) +ProcessorCount(PROC_N) +message( "Auto-detected ${PROC_N} CPU cores available for build parallelism." ) + +set( PLATFORM_LIST linux macos windows android ios web ) +set( ARCH_LIST universal x86_32 x86_64 arm32 arm64 rv64 ppc32 ppc64 wasm32 ) + +set( ARCH_ALIAS w64 amd64 armv7 armv8 arm64v8 aarch64 rv riscv riscv64 ppcle ppc ppc64le ) +set( ARCH_ALIAS_VALUE x86_64 x86_64 arm32 arm64 arm64 arm64 rv64 rv64 rv64 ppc32 ppc32 ppc64 ) + +# include lists of sources and generic configure function +include( cmake/sources.cmake ) +include( cmake/common_compiler_flags.cmake) +include( cmake/android.cmake) +include( cmake/ios.cmake) +include( cmake/linux.cmake) +include( cmake/macos.cmake) +include( cmake/web.cmake) +include( cmake/windows.cmake) - #TODO platform - #TODO target +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 +42,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,29 +66,27 @@ 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) + 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. - #TODO ios_options() - #TODO linux_options() - #TODO macos_options() - #TODO web_options() - #TODO windows_options() + android_options() + ios_options() + linux_options() + macos_options() + web_options() + windows_options() endfunction() function( godotcpp_generate ) - # Set some helper variables for readability - set( compiler_is_clang "$,$>" ) - set( compiler_is_gnu "$" ) - set( compiler_is_msvc "$" ) - + ### Configure variables # 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 @@ -68,16 +96,13 @@ function( godotcpp_generate ) 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 +110,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 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 +137,90 @@ 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> ) - - # Optionally mark headers as SYSTEM - set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "") - if (GODOT_SYSTEM_HEADERS) - set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) + string(REPLACE ";" "" SYSTEM_NAME "${SYSTEM_NAME}") + + ### Derive SYSTEM_ARCH + # from the toolchain first + if (NOT GODOT_ARCH) + set( SYSTEM_PROCESSOR "$") + set( ARCH_IN_LIST "$" ) + set( ARCH_INDEX "$") + set( SYSTEM_ARCH "$>") + else () + # override from manually specified GODOT_ARCH variable + set(SYSTEM_ARCH ${GODOT_ARCH}) endif () - target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC - include - ${CMAKE_CURRENT_BINARY_DIR}/gen/include - ${GODOT_GDEXTENSION_DIR} - ) - - # Add the compile flags - set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS}) - - # Create the correct name (godot.os.build_type.system_bits) - string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME) - string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE) - - if(ANDROID) - # Added the android abi after system name - set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI}) - - # Android does not have the bits at the end if you look at the main godot repo build - set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}") - else() - set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}") - endif() - - set_target_properties(${PROJECT_NAME} - PROPERTIES - CXX_EXTENSIONS OFF - POSITION_INDEPENDENT_CODE ON - CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY} - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - OUTPUT_NAME "${OUTPUT_NAME}" - ) + ### 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 ) + add_library( godot-cpp::${TARGET_NAME} ALIAS ${TARGET_NAME} ) + + target_sources( ${TARGET_NAME} + PRIVATE + ${GODOTCPP_SOURCES} + ${GENERATED_FILES_LIST} + ${GODOTCPP_HEADERS} + ) + + 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_SOURCE_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 0000000000..a689f506ba --- /dev/null +++ b/cmake/ios.cmake @@ -0,0 +1,14 @@ +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 0000000000..ea94a1c2a5 --- /dev/null +++ b/cmake/linux.cmake @@ -0,0 +1,14 @@ +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 0000000000..b60bb3584e --- /dev/null +++ b/cmake/macos.cmake @@ -0,0 +1,38 @@ +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/sources.cmake b/cmake/sources.cmake new file mode 100644 index 0000000000..26d607293d --- /dev/null +++ b/cmake/sources.cmake @@ -0,0 +1,98 @@ +# Globbing is a source of bugs, sources are named explicitly here. +# TODO look into file sets. +set( GODOTCPP_SOURCES + src/godot.cpp + src/classes/editor_plugin_registration.cpp + src/classes/low_level.cpp + src/classes/wrapped.cpp + src/core/class_db.cpp + src/core/error_macros.cpp + src/core/memory.cpp + src/core/method_bind.cpp + src/core/object.cpp + src/variant/aabb.cpp + src/variant/basis.cpp + src/variant/callable_custom.cpp + src/variant/callable_method_pointer.cpp + src/variant/char_string.cpp + src/variant/color.cpp + src/variant/packed_arrays.cpp + src/variant/plane.cpp + src/variant/projection.cpp + src/variant/quaternion.cpp + src/variant/rect2.cpp + src/variant/rect2i.cpp + src/variant/transform2d.cpp + src/variant/transform3d.cpp + src/variant/variant.cpp + src/variant/vector2.cpp + src/variant/vector2i.cpp + src/variant/vector3.cpp + src/variant/vector3i.cpp + src/variant/vector4.cpp + src/variant/vector4i.cpp +) +set( GODOTCPP_HEADERS + include/godot_cpp/godot.hpp + include/godot_cpp/classes/editor_plugin_registration.hpp + include/godot_cpp/classes/ref.hpp + include/godot_cpp/classes/wrapped.hpp + include/godot_cpp/core/binder_common.hpp + include/godot_cpp/core/builtin_ptrcall.hpp + include/godot_cpp/core/class_db.hpp + include/godot_cpp/core/defs.hpp + include/godot_cpp/core/engine_ptrcall.hpp + include/godot_cpp/core/error_macros.hpp + include/godot_cpp/core/math.hpp + include/godot_cpp/core/memory.hpp + include/godot_cpp/core/method_bind.hpp + include/godot_cpp/core/method_ptrcall.hpp + include/godot_cpp/core/mutex_lock.hpp + include/godot_cpp/core/object.hpp + include/godot_cpp/core/object_id.hpp + include/godot_cpp/core/property_info.hpp + include/godot_cpp/core/type_info.hpp + include/godot_cpp/templates/cowdata.hpp + include/godot_cpp/templates/hash_map.hpp + include/godot_cpp/templates/hash_set.hpp + include/godot_cpp/templates/hashfuncs.hpp + include/godot_cpp/templates/list.hpp + include/godot_cpp/templates/local_vector.hpp + include/godot_cpp/templates/pair.hpp + include/godot_cpp/templates/rb_map.hpp + include/godot_cpp/templates/rb_set.hpp + include/godot_cpp/templates/rid_owner.hpp + include/godot_cpp/templates/safe_refcount.hpp + include/godot_cpp/templates/search_array.hpp + include/godot_cpp/templates/self_list.hpp + include/godot_cpp/templates/sort_array.hpp + include/godot_cpp/templates/spin_lock.hpp + include/godot_cpp/templates/thread_work_pool.hpp + include/godot_cpp/templates/vector.hpp + include/godot_cpp/templates/vmap.hpp + include/godot_cpp/templates/vset.hpp + include/godot_cpp/variant/aabb.hpp + include/godot_cpp/variant/array_helpers.hpp + include/godot_cpp/variant/basis.hpp + include/godot_cpp/variant/callable_custom.hpp + include/godot_cpp/variant/callable_method_pointer.hpp + include/godot_cpp/variant/char_string.hpp + include/godot_cpp/variant/char_utils.hpp + include/godot_cpp/variant/color.hpp + include/godot_cpp/variant/color_names.inc.hpp + include/godot_cpp/variant/plane.hpp + include/godot_cpp/variant/projection.hpp + include/godot_cpp/variant/quaternion.hpp + include/godot_cpp/variant/rect2.hpp + include/godot_cpp/variant/rect2i.hpp + include/godot_cpp/variant/transform2d.hpp + include/godot_cpp/variant/transform3d.hpp + include/godot_cpp/variant/typed_array.hpp + include/godot_cpp/variant/variant.hpp + include/godot_cpp/variant/vector2.hpp + include/godot_cpp/variant/vector2i.hpp + include/godot_cpp/variant/vector3.hpp + include/godot_cpp/variant/vector3i.hpp + include/godot_cpp/variant/vector4.hpp + include/godot_cpp/variant/vector4i.hpp +) diff --git a/cmake/web.cmake b/cmake/web.cmake new file mode 100644 index 0000000000..a9939ba19c --- /dev/null +++ b/cmake/web.cmake @@ -0,0 +1,7 @@ +function( web_options ) + # web options +endfunction() + +function( web_generate TARGET_NAME ) + common_compiler_flags( ${TARGET_NAME} ) +endfunction() diff --git a/cmake/windows.cmake b/cmake/windows.cmake new file mode 100644 index 0000000000..0ba382334c --- /dev/null +++ b/cmake/windows.cmake @@ -0,0 +1,54 @@ +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 index 3dd77f58f6..ac4a700402 100644 --- a/doc/cmake.md +++ b/doc/cmake.md @@ -1,57 +1,261 @@ -## CMake +# CMake -### cmake arguments +> **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](https://github.com/IvanInventor/godot-cpp/tree/cmake-rewrite) | [Vorlac's godot-roguelite Project](https://github.com/vorlac/godot-roguelite) -`CMAKE_BUILD_TYPE`: Compilation target (Debug or Release defaults to Debug) +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](https://github.com/godotengine/godot-cpp-template) for a practical example on how to consume the godot-cpp library as part of a Godot extension. -### 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") +[Configuration examples](#Examples) are listed at the bottom of the page. -### 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) +## Clone the git repository -- More info [here](https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html) +```shell +> git clone https://github.com/godotengine/godot-cpp.git +Cloning into 'godot-cpp'... +... +> cd godot-cpp +``` + +## 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. +```shell +> mkdir cmake-build +> cd cmake-build +``` + +## Configure the build +Cmake isn't a build tool, it's a build tool generator, which means it generates the build scripts/files that will end up compiling your code. +To see the list of generators run `cmake --help` + +The current working directory is the build directory that was created in the previous step. + +Configure and generate Ninja build files. +Review [build-configurations](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations) for more information. + +```shell +> cmake ../ -G "Ninja" +``` + +To list the available options cmake use the `-L[AH]` option. `A` is for advanced, and `H` is for help strings. +```shell +> cmake ../ -LH +``` + +Specify options on the command line + +Review [setting-build-variables](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#setting-build-variables) for more information. + +```shell +> cmake ../ -DGODOT_USE_HOT_RELOAD:BOOL=ON -DGODOT_PRECISION:STRING=double -DCMAKE_BUILD_TYPE:STRING=Debug +``` + +### A non-exhaustive list of options +``` +// 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 +``` + +## Building + +Building the default `all` target, this will build `editor`, `template_debug` and `template_release` targets. +```shell +> cmake --build . +``` + +To build only a single target, specify it like so: + +```shell +> cmake --build . -t template_release +``` + +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. + +```shell +> cmake --build . -t template_release --config Release +``` ## Examples + +#### Building using Microsoft Visual Studio +So long as cmake is installed from the cmake [downloads page](https://cmake.org/download/) and in the PATH, and Microsoft Visual Studio is installed with c++ support, cmake will detect the msvc compiler. + +Assuming the current working directory is the godot-cpp project root: +```shell +> mkdir build-msvc +> cd build-msvc +> cmake ../ +> cmake --build . -t godot-cpp-test --config Release +``` + +#### Building godot-cpp-test with debug symbols using msys2/clang64 and "Ninja" generator +Assumes the ming-w64-clang-x86_64-toolchain is installed + +Using the msys2/clang64 shell ```shell -Builds a debug version: -cmake . -cmake --build . +> mkdir build-clang +> cd build-clang +> cmake ../ -G"Ninja" -DCMAKE_BUILD_TYPE:STRING=Debug +> cmake --build . -t godot-cpp-test ``` -Builds a release version with clang + +#### Building godot-cpp-test with debug symbols using msys2/clang64 and "Ninja Multi-Config" generator +Assumes the ming-w64-clang-x86_64-toolchain is installed + +Using the msys2/clang64 shell +```shell +> mkdir build-clang +> cd build-clang +> cmake ../ -G"Ninja Multi-Config" +> cmake --build . -t godot-cpp-test --config Debug +``` + + +### Emscripten to web-assembly +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 + +```shell +> 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 +From what I can tell, there are two directions you can go + +Use the `CMAKE_ANDROID_*` variables specified on the commandline or in your own toolchain file as listed in the [cmake-toolchains](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android-with-the-ndk) documentation. + +Or use the `$ANDROID_HOME/ndk//build/cmake/android.toolchain.cmake` toolchain 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`) + + +Using your own toolchain file as described in the cmake documentation ```shell -CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" . -cmake --build . +> mkdir build-android +> cd build-android +> cmake ../ --toolchain my_toolchain.cmake +> cmake --build . -t template_release ``` -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 . +Doing the equivalent on just using the command line + +```shell +> 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 ``` -## Protip -Generate the buildfiles in a sub directory to not clutter the root directory with build files: +Using the toolchain file from the Android ndk +Defaults to minimum supported version( android-16 in my case) and armv7-a. ```shell -mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build . +> mkdir build-android +> cd build-android +> cmake ../ --toolchain $ANDROID_HOME/ndk//build/cmake/android.toolchain.cmake +> cmake --build . -t template_release + ``` -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) +Specify Android platform and ABI + +```shell +> 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 ``` -## Todo -Test build for Windows, Mac and mingw. +## 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](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 + x86_64-linux + +### Mac +Host System: `Mac Mini Apple M2 Sequoia 15.0.1` + +### Windows +OS Name: Microsoft Windows 11 Home +OS Version: 10.0.22631 N/A Build 22631 +Processor(s): AMD Ryzen 7 6800HS Creator Edition + +#### [Microsoft Visual Studio 17 2022](https://visualstudio.microsoft.com/vs/) + x86_64-w64 + +#### [LLVM](https://llvm.org/) + Host: x86_64-pc-windows-msvc + +#### [AndroidSDK](https://developer.android.com/studio/#command-tools) + armv7-none-linux-androideabi16 + +#### [Emscripten](https://emscripten.org/) + 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/) + + Env: ucrt64 + Compiler: gcc version 14.2.0 (Rev1, Built by MSYS2 project) + Host: x86_64-w64-mingw32 + Target: x86_64-w64-mingw32 + + Env: clang64 + Compiler: clang version 18.1.8 + Host: x86_64-w64-windows-gnu + 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) + gcc - x86_64-w64-mingw32-ucrt +##### [Jetbrains-CLion](https://www.jetbrains.com/clion/) + x86_64-w64-mingw32-msvcrt diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f1c4c0d7e2..8e66196c1c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,144 +1,63 @@ -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() - -else() +# 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 +) - set(GODOT_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,-R,'$$ORIGIN'") +target_link_libraries( godot-cpp-test + PRIVATE + godot-cpp::template_release ) - set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings") +### Get useful properties of the library +get_target_property( GODOT_PLATFORM godot-cpp::template_release GODOT_PLATFORM ) +get_target_property( GODOT_TARGET godot-cpp::template_release GODOT_TARGET ) +get_target_property( GODOT_ARCH godot-cpp::template_release 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::template_release 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.template_release.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.template_release" + SUFFIX "" -set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "gdexample") + #macos options + OSX_ARCHITECTURES "${OSX_ARCH}" + ) +endif ()