From 2de650b82a45e295ac4fafbc509074aa253041b9 Mon Sep 17 00:00:00 2001 From: Samuel Nicholas Date: Thu, 19 Sep 2024 08:11:03 +0930 Subject: [PATCH] Re-Structure cmake solution to be closer to the scons solution. This is just a single step, re-arranging the code without actually changing its functionality. new docs/cmake.md moved the block of comments from the start of the CMakeLists.txt into the cmake.md file and converted content to markdown. new cmake/godotcpp.cmake Moved all exposed options into a new function godotcpp_options() Moved configuration and generation code into godotcpp_generate() To get all the options into the godotcpp_options() I changed the logic of GODOT_USE_HOT_RELOAD which I believe is a closer match to scons, that if the options is not set, and the build type is not release, then it defaults to ON. I msvc builds require the default flags to be modified or it will throw errors. I have added the links to articles in the commit, but its about removing the runtime error checks /RTC1 from the CMAKE_CXX_FLAGS_DEBUG variable. This needs to happen before the files are included. https://stackoverflow.com/questions/74426638/how-to-remove-rtc1-from-specific-target-or-file-in-cmake https://discourse.cmake.org/t/how-do-i-remove-compile-options-from-target/5965 Renamed GodotCompilerWarnings.cmake to common_compiler_flags.cmake to match scons Included files explicitly by path, as we dont need to append to the CMAKE_MODULES_PATH which effects the whole build tree. This prevents consumers of the library from clobbering the names of the cmake include files and breaking the build. (cherry picked from commit 2402a044ebc2189f6c725b9a64c66c9bc2e5c616) --- CMakeLists.txt | 254 ++---------------- ...ings.cmake => common_compiler_flags.cmake} | 0 cmake/godotcpp.cmake | 240 +++++++++++++++++ doc/cmake.md | 57 ++++ 4 files changed, 312 insertions(+), 239 deletions(-) rename cmake/{GodotCompilerWarnings.cmake => common_compiler_flags.cmake} (100%) create mode 100644 cmake/godotcpp.cmake create mode 100644 doc/cmake.md diff --git a/CMakeLists.txt b/CMakeLists.txt index d0a6547d..ff77368b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,248 +1,24 @@ -# cmake arguments -# CMAKE_BUILD_TYPE: Compilation target (Debug or Release defaults to Debug) -# -# godot-cpp cmake arguments -# GODOT_GDEXTENSION_DIR: Path to the directory containing GDExtension interface header and API JSON file -# GODOT_SYSTEM_HEADERS: Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one. -# GODOT_WARNING_AS_ERROR: Treat any warnings as errors -# GODOT_USE_HOT_RELOAD: Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds. -# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) -# GODOT_PRECISION: Floating-point precision level ("single", "double") -# -# Android cmake arguments -# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake) -# ANDROID_NDK: The path to the android ndk root folder -# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9) -# ANDROID_PLATFORM: The android platform version (android-23) -# More info here: https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html -# -# Examples -# -# Builds a debug version: -# cmake . -# cmake --build . -# -# Builds a release version with clang -# CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" . -# cmake --build . -# -# Builds an android armeabi-v7a debug version: -# cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \ -# -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug . -# cmake --build . -# -# Protip -# Generate the buildfiles in a sub directory to not clutter the root directory with build files: -# mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build . -# -# Ensure that you avoid exposing godot-cpp symbols - this might lead to hard to debug errors if you ever load multiple -# plugins using difference godot-cpp versions. Use visibility hidden whenever possible: -# set_target_properties( PROPERTIES CXX_VISIBILITY_PRESET hidden) -# -# Todo -# Test build for Windows, Mac and mingw. - cmake_minimum_required(VERSION 3.13) project(godot-cpp LANGUAGES CXX) -option(GODOT_GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node. (ON|OFF)" ON) -option(GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." ON) -option(GODOT_WARNING_AS_ERROR "Treat warnings as errors" OFF) - -set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING "Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)") -set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" ) - -# CXX_VISIBILITY_PRESET supported values are: default, hidden, protected, and internal -# which is inline with the gcc -fvisibility= -# https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html -# To match the scons options we need to change the text to match the -fvisibility flag -# it is probably worth another PR which changes both to use the flag options -if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" ) - set( GODOT_SYMBOL_VISIBILITY "default" ) +# Configure CMake +# https://discourse.cmake.org/t/how-do-i-remove-compile-options-from-target/5965 +# https://stackoverflow.com/questions/74426638/how-to-remove-rtc1-from-specific-target-or-file-in-cmake +if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) + if(NOT CMAKE_BUILD_TYPE MATCHES Debug) + STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + endif () endif () -# Add path to modules -list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) +include( ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake ) -# Set some helper variables for readability -set( compiler_is_clang "$,$>" ) -set( compiler_is_gnu "$" ) -set( compiler_is_msvc "$" ) +# I know this doesn't look like a typical CMakeLists.txt, but as we are +# attempting mostly feature parity with SCons, and easy maintenance, the closer +# the two build systems look the easier they will be to keep in lockstep. -# Default build type is Debug in the SConstruct -if("${CMAKE_BUILD_TYPE}" STREQUAL "") - set(CMAKE_BUILD_TYPE Debug) -endif() +# The typical target definitions are in ${PROJECT_SOURCE_DIR}/cmake/godotcpp.cmake -# Hot reload is enabled by default in Debug-builds -if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - option(GODOT_USE_HOT_RELOAD "Enable the extra accounting required to support hot reload. (ON|OFF)" ON) -else() - option(GODOT_USE_HOT_RELOAD "Enable the extra accounting required to support hot reload. (ON|OFF)" OFF) -endif() +godotcpp_options() -if(NOT DEFINED BITS) - set(BITS 32) - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(BITS 64) - endif(CMAKE_SIZEOF_VOID_P EQUAL 8) -endif() - -# Input from user for GDExtension interface header and the API JSON file -set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH - "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" ) -set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH - "Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) ( /path/to/custom_api_file )") - -set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json") -if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override. - set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}") -endif() - -set(GODOT_PRECISION "single" CACHE STRING "Set the floating-point precision level (single|double)") -if ("${GODOT_PRECISION}" STREQUAL "double") - add_definitions(-DREAL_T_IS_DOUBLE) -endif() - -set( GODOT_COMPILE_FLAGS ) - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # using Visual Studio C++ - set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP - - if(CMAKE_BUILD_TYPE MATCHES Debug) - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi - else() - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy - STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) - endif(CMAKE_BUILD_TYPE MATCHES Debug) - - add_definitions(-DNOMINMAX) -else() # GCC/Clang - if(CMAKE_BUILD_TYPE MATCHES Debug) - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g") - else() - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3") - endif(CMAKE_BUILD_TYPE MATCHES Debug) -endif() - -# Disable exception handling. Godot doesn't use exceptions anywhere, and this -# saves around 20% of binary size and very significant build time (GH-80513). -option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON ) -if (GODOT_DISABLE_EXCEPTIONS) - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0") - else() - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions") - endif() -else() - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc") - endif() -endif() - -# Generate source from the bindings file -find_package(Python3 3.4 REQUIRED) # pathlib should be present -if(GODOT_GENERATE_TEMPLATE_GET_NODE) - set(GENERATE_BINDING_PARAMETERS "True") -else() - set(GENERATE_BINDING_PARAMETERS "False") -endif() - -execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE GENERATED_FILES_LIST - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -add_custom_command(OUTPUT ${GENERATED_FILES_LIST} - COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${GODOT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")" - VERBATIM - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py - COMMENT "Generating bindings" -) - -# Get Sources -file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**) -file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**) - -# Define our godot-cpp library -add_library(${PROJECT_NAME} STATIC - ${SOURCES} - ${HEADERS} - ${GENERATED_FILES_LIST} -) -add_library(godot::cpp ALIAS ${PROJECT_NAME}) - -include(GodotCompilerWarnings) - -target_compile_features(${PROJECT_NAME} - PRIVATE - cxx_std_17 -) - -if(GODOT_USE_HOT_RELOAD) - target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED) - target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>) -endif() - -target_compile_definitions(${PROJECT_NAME} PUBLIC - $<$: - DEBUG_ENABLED - DEBUG_METHODS_ENABLED - > - $<${compiler_is_msvc}: - TYPED_METHOD_BIND - > -) - -target_link_options(${PROJECT_NAME} PRIVATE - $<$: - -static-libgcc - -static-libstdc++ - -Wl,-R,'$$ORIGIN' - > -) - -# Optionally mark headers as SYSTEM -set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "") -if (GODOT_SYSTEM_HEADERS) - set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) -endif () - -target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC - include - ${CMAKE_CURRENT_BINARY_DIR}/gen/include - ${GODOT_GDEXTENSION_DIR} -) - -# Add the compile flags -set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS}) - -# Create the correct name (godot.os.build_type.system_bits) -string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME) -string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE) - -if(ANDROID) - # Added the android abi after system name - set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI}) - - # Android does not have the bits at the end if you look at the main godot repo build - set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}") -else() - set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}") -endif() - -set_target_properties(${PROJECT_NAME} - PROPERTIES - CXX_EXTENSIONS OFF - POSITION_INDEPENDENT_CODE ON - CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY} - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" - OUTPUT_NAME "${OUTPUT_NAME}" -) +godotcpp_generate() diff --git a/cmake/GodotCompilerWarnings.cmake b/cmake/common_compiler_flags.cmake similarity index 100% rename from cmake/GodotCompilerWarnings.cmake rename to cmake/common_compiler_flags.cmake diff --git a/cmake/godotcpp.cmake b/cmake/godotcpp.cmake new file mode 100644 index 00000000..a5c66779 --- /dev/null +++ b/cmake/godotcpp.cmake @@ -0,0 +1,240 @@ +function( godotcpp_options ) + + #TODO platform + #TODO target + + # Input from user for GDExtension interface header and the API JSON file + set(GODOT_GDEXTENSION_DIR "gdextension" CACHE PATH + "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" ) + set(GODOT_CUSTOM_API_FILE "" CACHE FILEPATH + "Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) ( /path/to/custom_api_file )") + + #TODO generate_bindings + + option(GODOT_GENERATE_TEMPLATE_GET_NODE + "Generate a template version of the Node class's get_node. (ON|OFF)" ON) + + #TODO build_library + + set(GODOT_PRECISION "single" CACHE STRING + "Set the floating-point precision level (single|double)") + + #TODO arch + #TODO threads + #TODO compiledb + #TODO compiledb_file + #TODO build_profile aka cmake preset + + set(GODOT_USE_HOT_RELOAD "" CACHE BOOL + "Enable the extra accounting required to support hot reload. (ON|OFF)") + + option(GODOT_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON ) + + set( GODOT_SYMBOL_VISIBILITY "hidden" CACHE STRING + "Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)") + set_property( CACHE GODOT_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" ) + + #TODO optimize + #TODO debug_symbols + #TODO dev_build + + # FIXME These options are not present in SCons, and perhaps should be added there. + option(GODOT_SYSTEM_HEADERS "Expose headers as SYSTEM." ON) + option(GODOT_WARNING_AS_ERROR "Treat warnings as errors" OFF) + + # Run options commands on the following to populate cache for all platforms. + # This type of thing is typically done conditionally + # But as scons shows all options so shall we. + #TODO ios_options() + #TODO linux_options() + #TODO macos_options() + #TODO web_options() + #TODO windows_options() +endfunction() + + +function( godotcpp_generate ) + # Set some helper variables for readability + set( compiler_is_clang "$,$>" ) + set( compiler_is_gnu "$" ) + set( compiler_is_msvc "$" ) + + # CXX_VISIBILITY_PRESET supported values are: default, hidden, protected, and internal + # which is inline with the gcc -fvisibility= + # https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html + # To match the scons options we need to change the text to match the -fvisibility flag + # it is probably worth another PR which changes both to use the flag options + if( ${GODOT_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOT_SYMBOL_VISIBILITY} STREQUAL "visible" ) + set( GODOT_SYMBOL_VISIBILITY "default" ) + endif () + + # Default build type is Debug in the SConstruct + if("${CMAKE_BUILD_TYPE}" STREQUAL "") + set(CMAKE_BUILD_TYPE Debug) + endif() + + # Hot reload is enabled by default in Debug-builds + if( GODOT_USE_HOT_RELOAD STREQUAL "" AND NOT CMAKE_BUILD_TYPE STREQUAL "Release") + set(GODOT_USE_HOT_RELOAD ON) + endif() + + if(NOT DEFINED BITS) + set(BITS 32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BITS 64) + endif(CMAKE_SIZEOF_VOID_P EQUAL 8) + endif() + + + set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json") + if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override. + set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}") + endif() + + if ("${GODOT_PRECISION}" STREQUAL "double") + add_definitions(-DREAL_T_IS_DOUBLE) + endif() + + set( GODOT_COMPILE_FLAGS ) + + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # using Visual Studio C++ + set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP + + if(CMAKE_BUILD_TYPE MATCHES Debug) + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi + else() + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy + endif(CMAKE_BUILD_TYPE MATCHES Debug) + + add_definitions(-DNOMINMAX) + else() # GCC/Clang + if(CMAKE_BUILD_TYPE MATCHES Debug) + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g") + else() + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3") + endif(CMAKE_BUILD_TYPE MATCHES Debug) + endif() + + # Disable exception handling. Godot doesn't use exceptions anywhere, and this + # saves around 20% of binary size and very significant build time (GH-80513). + if (GODOT_DISABLE_EXCEPTIONS) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0") + else() + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions") + endif() + else() + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc") + endif() + endif() + + # Generate source from the bindings file + find_package(Python3 3.4 REQUIRED) # pathlib should be present + if(GODOT_GENERATE_TEMPLATE_GET_NODE) + set(GENERATE_BINDING_PARAMETERS "True") + else() + set(GENERATE_BINDING_PARAMETERS "False") + endif() + + execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE GENERATED_FILES_LIST + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + add_custom_command(OUTPUT ${GENERATED_FILES_LIST} + COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${GODOT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")" + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py + COMMENT "Generating bindings" + ) + + # Get Sources + # As this cmake file was added using 'include(godotcpp)' from the root CMakeLists.txt, + # the ${CMAKE_CURRENT_SOURCE_DIR} is still the root dir. + file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**) + file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**) + + # Define our godot-cpp library + add_library(${PROJECT_NAME} STATIC + ${SOURCES} + ${HEADERS} + ${GENERATED_FILES_LIST} + ) + add_library(godot::cpp ALIAS ${PROJECT_NAME}) + + include(${PROJECT_SOURCE_DIR}/cmake/common_compiler_flags.cmake) + + target_compile_features(${PROJECT_NAME} + PRIVATE + cxx_std_17 + ) + + if(GODOT_USE_HOT_RELOAD) + target_compile_definitions(${PROJECT_NAME} PUBLIC HOT_RELOAD_ENABLED) + target_compile_options(${PROJECT_NAME} PUBLIC $<${compiler_is_gnu}:-fno-gnu-unique>) + endif() + + target_compile_definitions(${PROJECT_NAME} PUBLIC + $<$: + DEBUG_ENABLED + DEBUG_METHODS_ENABLED + > + $<${compiler_is_msvc}: + TYPED_METHOD_BIND + > + ) + + target_link_options(${PROJECT_NAME} PRIVATE + $<$: + -static-libgcc + -static-libstdc++ + -Wl,-R,'$$ORIGIN' + > + ) + + # Optionally mark headers as SYSTEM + set(GODOT_SYSTEM_HEADERS_ATTRIBUTE "") + if (GODOT_SYSTEM_HEADERS) + set(GODOT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) + endif () + + target_include_directories(${PROJECT_NAME} ${GODOT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC + include + ${CMAKE_CURRENT_BINARY_DIR}/gen/include + ${GODOT_GDEXTENSION_DIR} + ) + + # Add the compile flags + set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS}) + + # Create the correct name (godot.os.build_type.system_bits) + string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME) + string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE) + + if(ANDROID) + # Added the android abi after system name + set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI}) + + # Android does not have the bits at the end if you look at the main godot repo build + set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}") + else() + set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}") + endif() + + set_target_properties(${PROJECT_NAME} + PROPERTIES + CXX_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ON + CXX_VISIBILITY_PRESET ${GODOT_SYMBOL_VISIBILITY} + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" + OUTPUT_NAME "${OUTPUT_NAME}" + ) + +endfunction() diff --git a/doc/cmake.md b/doc/cmake.md new file mode 100644 index 00000000..3dd77f58 --- /dev/null +++ b/doc/cmake.md @@ -0,0 +1,57 @@ +## CMake + +### cmake arguments + +`CMAKE_BUILD_TYPE`: Compilation target (Debug or Release defaults to Debug) + +### godot-cpp cmake arguments +- `GODOT_GDEXTENSION_DIR`: Path to the directory containing GDExtension interface header and API JSON file +- `GODOT_SYSTEM_HEADERS`: Mark the header files as SYSTEM. This may be useful to suppress warnings in projects including this one. +- `GODOT_WARNING_AS_ERROR`: Treat any warnings as errors +- `GODOT_USE_HOT_RELOAD`: Build with hot reload support. Defaults to YES for Debug-builds and NO for Release-builds. +- `GODOT_CUSTOM_API_FILE`: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`) +- `GODOT_PRECISION`: Floating-point precision level ("single", "double") + +### Android cmake arguments +- `CMAKE_TOOLCHAIN_FILE`: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake) +- `ANDROID_NDK`: The path to the android ndk root folder +- `ANDROID_TOOLCHAIN_NAME`: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9) +- `ANDROID_PLATFORM`: The android platform version (android-23) + +- More info [here](https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html) + +## Examples +```shell +Builds a debug version: +cmake . +cmake --build . +``` +Builds a release version with clang + +```shell +CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" . +cmake --build . +``` +Builds an android armeabi-v7a debug version: + +``` shell +cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \ + -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug . +cmake --build . +``` + +## Protip +Generate the buildfiles in a sub directory to not clutter the root directory with build files: + +```shell +mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build . +``` + +Ensure that you avoid exposing godot-cpp symbols - this might lead to hard to debug errors if you ever load multiple +plugins using difference godot-cpp versions. Use visibility hidden whenever possible: +```cmake +set_target_properties( PROPERTIES CXX_VISIBILITY_PRESET hidden) +``` + +## Todo +Test build for Windows, Mac and mingw.