Skip to content

Cherry-picks for the godot-cpp 4.4 branch - 1st batch #1745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ jobs:
run: |
mkdir cmake-build
cd cmake-build
cmake ../ -DGODOTCPP_ENABLE_TESTING=YES
cmake --build . --verbose -j $(nproc) -t godot-cpp.test.template_release --config Release
cmake ../ -DGODOTCPP_ENABLE_TESTING=YES -DGODOTCPP_TARGET=template_release
cmake --build . --verbose -j $(nproc) --target godot-cpp-test --config Release

windows-msvc-cmake:
name: 🏁 Build (Windows, MSVC, CMake)
Expand All @@ -218,5 +218,5 @@ jobs:
run: |
mkdir cmake-build
cd cmake-build
cmake ../ -DGODOTCPP_ENABLE_TESTING=YES
cmake --build . --verbose -t godot-cpp.test.template_release --config Release
cmake ../ -DGODOTCPP_ENABLE_TESTING=YES -DGODOTCPP_TARGET=template_release
cmake --build . --verbose --target godot-cpp-test --config Release
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ repos:
- id: codespell
additional_dependencies: [tomli]

- repo: https://github.com/BlankSpruce/gersemi
rev: 0.18.2
hooks:
- id: gersemi
args: ["-i", "--no-warn-about-unknown-commands", "-l", "120"]

- repo: local
hooks:
- id: copyright-headers
Expand Down
42 changes: 27 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ 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
For more information check cmake/emsdkHack.cmake

SCons Compatibility
-------------------

There is an understandable conflict between build systems as they define
Expand All @@ -18,6 +20,9 @@ compromises need to be made to resolve those differences.

As we are attempting to maintain feature parity, and ease of maintenance, these
CMake scripts are built to resemble the SCons build system wherever possible.
Where they are not, we will attempt to document common difference in
doc/cmake.rst and platform specific differences in their respective
cmake/<platform>.cmake file.

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
Expand All @@ -26,8 +31,7 @@ maintain.
Where the SCons additional scripts in the tools directory, The CMake scripts
are in the cmake directory.

For example, the tools/godotcpp.py is sourced into SCons, and the 'options'
function is run.
For example; the tools/godotcpp.py is matched by the cmake/godotcpp.cmake file

.. highlight:: python

Expand All @@ -36,27 +40,35 @@ function is run.

The CMake equivalent is below.
]=======================================================================]

include( cmake/godotcpp.cmake )
include(cmake/godotcpp.cmake)

godotcpp_options()

#[[ People are compiling godot by itself and expecting template_debug
Replace this with PROJECT_IS_TOP_LEVEL, <PROJECT-NAME>_IS_TOP_LEVEL when minimum reaches 3.21
]]
if(NOT PROJECT_NAME)
set(GODOTCPP_IS_TOP_LEVEL ON)
endif()

# 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)
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
)

compiler_detection()
godotcpp_generate()

# Conditionally enable the godot-cpp.test.<target> integration testing targets
if( GODOTCPP_ENABLE_TESTING )
add_subdirectory( test )
if(GODOTCPP_ENABLE_TESTING)
add_subdirectory(test)
endif()

# If this is the top level CMakeLists.txt, Generators which honor the
# USE_FOLDERS flag will organize godot-cpp targets under the subfolder
# 'godot-cpp'. This is enable by default from CMake version 3.26
#[[ If this is the top level CMakeLists.txt, Generators which honor the
USE_FOLDERS flag will organize godot-cpp targets under a subfolder named
'godot-cpp'. This is enable by default from CMake version 3.26 ]]
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
11 changes: 8 additions & 3 deletions binding_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,19 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision=
api = {}
with open(api_filepath, encoding="utf-8") as api_file:
api = json.load(api_file)
_generate_bindings(api, use_template_get_node, bits, precision, output_dir)
_generate_bindings(api, api_filepath, use_template_get_node, bits, precision, output_dir)


def _generate_bindings(api, use_template_get_node, bits="64", precision="single", output_dir="."):
def _generate_bindings(api, api_filepath, use_template_get_node, bits="64", precision="single", output_dir="."):
if "precision" in api["header"] and precision != api["header"]["precision"]:
raise Exception(
f"Cannot do a precision={precision} build using '{api_filepath}' which was generated by Godot built with precision={api['header']['precision']}"
)

target_dir = Path(output_dir) / "gen"

shutil.rmtree(target_dir, ignore_errors=True)
target_dir.mkdir(parents=True)
target_dir.mkdir(parents=True, exist_ok=True)

real_t = "double" if precision == "double" else "float"
print("Built-in type config: " + real_t + "_" + bits)
Expand Down
153 changes: 80 additions & 73 deletions cmake/GodotCPPModule.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,144 +26,151 @@ The build_profile.py has a __main__ and is used as a tool
Its usage is listed as:
$ python build_profile.py BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]
]]
function( build_profile_generate_trimmed_api BUILD_PROFILE INPUT_JSON OUTPUT_JSON )
function(build_profile_generate_trimmed_api BUILD_PROFILE INPUT_JSON OUTPUT_JSON)
execute_process(
COMMAND "${Python3_EXECUTABLE}"
"${godot-cpp_SOURCE_DIR}/build_profile.py"
"${BUILD_PROFILE}"
"${INPUT_JSON}"
"${OUTPUT_JSON}"
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
COMMAND
"${Python3_EXECUTABLE}" "${godot-cpp_SOURCE_DIR}/build_profile.py" "${BUILD_PROFILE}" "${INPUT_JSON}"
"${OUTPUT_JSON}"
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
)
endfunction( )

endfunction()

#[[ Generate File List

Use the binding_generator.py Python script to determine the list of files that
will be passed to the code generator using extension_api.json.
NOTE: This happens for every configure.]]
function( binding_generator_get_file_list OUT_VAR_NAME API_FILEPATH OUTPUT_DIR )

function(binding_generator_get_file_list OUT_VAR_NAME API_FILEPATH OUTPUT_DIR)
# This code snippet will be squashed into a single line
# The two strings make this a list, in CMake lists are semicolon delimited strings.
set( PYTHON_SCRIPT
"from binding_generator import print_file_list"
"print_file_list( api_filepath='${API_FILEPATH}',
set(PYTHON_SCRIPT
"from binding_generator import print_file_list"
"print_file_list( api_filepath='${API_FILEPATH}',
output_dir='${OUTPUT_DIR}',
headers=True,
sources=True)")
message( DEBUG "Python:\n${PYTHON_SCRIPT}" )
sources=True)"
)
message(DEBUG "Python:\n${PYTHON_SCRIPT}")

# Strip newlines and whitespace to make it a one-liner.
string( REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}" )
string(REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}")

execute_process( COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
execute_process(
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
)

# Debug output
message( DEBUG "FileList-Begin" )
foreach( PATH ${GENERATED_FILES_LIST} )
message( DEBUG ${PATH} )
message(DEBUG "FileList-Begin")
foreach(PATH ${GENERATED_FILES_LIST})
message(DEBUG ${PATH})
endforeach()

# Error out if the file list generator returned no files.
list( LENGTH GENERATED_FILES_LIST LIST_LENGTH )
if( NOT LIST_LENGTH GREATER 0 )
message( FATAL_ERROR "File List Generation Failed")
list(LENGTH GENERATED_FILES_LIST LIST_LENGTH)
if(NOT LIST_LENGTH GREATER 0)
message(FATAL_ERROR "File List Generation Failed")
endif()
message( STATUS "There are ${LIST_LENGTH} Files to generate" )

set( ${OUT_VAR_NAME} ${GENERATED_FILES_LIST} PARENT_SCOPE )
endfunction( )
message(STATUS "There are ${LIST_LENGTH} Files to generate")

set(${OUT_VAR_NAME} ${GENERATED_FILES_LIST} PARENT_SCOPE)
endfunction()

#[[ Generate Bindings

Using the generated file list, use the binding_generator.py to generate the
godot-cpp bindings. This will run at build time only if there are files
missing. ]]
function( binding_generator_generate_bindings API_FILE USE_TEMPLATE_GET_NODE, BITS, PRECISION, OUTPUT_DIR )
function(
binding_generator_generate_bindings
API_FILE
USE_TEMPLATE_GET_NODE,
BITS,
PRECISION,
OUTPUT_DIR
)
# This code snippet will be squashed into a single line
set( PYTHON_SCRIPT
"from binding_generator import generate_bindings"
"generate_bindings(
set(PYTHON_SCRIPT
"from binding_generator import generate_bindings"
"generate_bindings(
api_filepath='${API_FILE}',
use_template_get_node='${USE_TEMPLATE_GET_NODE}',
bits='${BITS}',
precision='${PRECISION}',
output_dir='${OUTPUT_DIR}')")
output_dir='${OUTPUT_DIR}')"
)

message( DEBUG "Python:\n${PYTHON_SCRIPT}" )
message(DEBUG "Python:\n${PYTHON_SCRIPT}")

# Strip newlines and whitespace to make it a one-liner.
string( REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}" )

add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
VERBATIM
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
MAIN_DEPENDENCY ${GODOTCPP_GDEXTENSION_API_FILE}
DEPENDS ${godot-cpp_SOURCE_DIR}/binding_generator.py
COMMENT "Generating bindings"
string(REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}")

add_custom_command(
OUTPUT ${GENERATED_FILES_LIST}
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
VERBATIM
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
MAIN_DEPENDENCY ${GODOTCPP_GDEXTENSION_API_FILE}
DEPENDS ${godot-cpp_SOURCE_DIR}/binding_generator.py
COMMENT "Generating bindings"
)
endfunction( )
add_custom_target(generate_bindings DEPENDS ${GENERATED_FILES_LIST})
set_target_properties(generate_bindings PROPERTIES FOLDER "godot-cpp")
endfunction()

#[[ Generate doc_data.cpp
The documentation displayed in the Godot editor is compiled into the extension.
It takes a list of XML source files, and transforms them into a cpp file that
is added to the sources list.]]
function( generate_doc_source OUTPUT_PATH SOURCES )
function(generate_doc_source OUTPUT_PATH SOURCES)
# Transform SOURCES CMake LIST
# quote each path with ''
# join with , to transform into a python list minus the surrounding []
set( PYTHON_LIST "${SOURCES}")
list( TRANSFORM PYTHON_LIST REPLACE "(.*\.xml)" "'\\1'" )
list( JOIN PYTHON_LIST "," PYTHON_LIST )
set(PYTHON_LIST "${SOURCES}")
list(TRANSFORM PYTHON_LIST REPLACE "(.*\.xml)" "'\\1'")
list(JOIN PYTHON_LIST "," PYTHON_LIST)

get_filename_component(OUTPUT_DIR "${OUTPUT_PATH}" DIRECTORY)
file(MAKE_DIRECTORY ${OUTPUT_DIR} )
file(MAKE_DIRECTORY ${OUTPUT_DIR})

# Python one-liner to run our command
# lists in CMake are just strings delimited by ';', so this works.
set( PYTHON_SCRIPT "from doc_source_generator import generate_doc_source"
"generate_doc_source( '${OUTPUT_PATH}', [${PYTHON_LIST}] )" )

add_custom_command( OUTPUT "${OUTPUT_PATH}"
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
VERBATIM
WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
DEPENDS
set(PYTHON_SCRIPT
"from doc_source_generator import generate_doc_source"
"generate_doc_source( '${OUTPUT_PATH}', [${PYTHON_LIST}] )"
)

add_custom_command(
OUTPUT "${OUTPUT_PATH}"
COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}"
VERBATIM
WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}"
DEPENDS #
"${godot-cpp_SOURCE_DIR}/doc_source_generator.py"
"${SOURCES}"
COMMENT "Generating: ${OUTPUT_PATH}"
COMMENT "Generating: ${OUTPUT_PATH}"
)
add_custom_target(generate_doc_source DEPENDS "${OUTPUT_PATH}")
set_target_properties(generate_doc_source PROPERTIES FOLDER "godot-cpp")
endfunction()

#[[ target_doc_sources
A simpler interface to add xml files as doc source to a output target.
TARGET: The gdexension library target
SOURCES: a list of xml files to use for source generation and inclusion.
This function also adds a doc_gen target to test source generation.]]
function( target_doc_sources TARGET SOURCES )
SOURCES: a list of xml files to use for source generation and inclusion.]]
function(target_doc_sources TARGET SOURCES)
# set the generated file name
set( DOC_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen/doc_source.cpp" )
set(DOC_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen/doc_source.cpp")

# Create the file generation target, this won't be triggered unless a target
# that depends on DOC_SOURCE_FILE is built
generate_doc_source( "${DOC_SOURCE_FILE}" ${SOURCES} )

# Add DOC_SOURCE_FILE as a dependency to TARGET
target_sources( ${TARGET} PRIVATE "${DOC_SOURCE_FILE}" )
target_sources(${TARGET} PRIVATE "${DOC_SOURCE_FILE}")

# Create a dummy target that depends on the source so that users can
# test the file generation task.
if( TARGET doc_gen )
else()
add_custom_target( doc_gen )
endif()
target_sources( doc_gen PRIVATE "${DOC_SOURCE_FILE}" )
# Without adding this dependency to the doc_source_generator, XCode will complain.
add_dependencies(${TARGET} generate_doc_source)
endfunction()
25 changes: 17 additions & 8 deletions cmake/android.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,25 @@ Android platforms.
There is further information and examples in the doc/cmake.rst file.

]=======================================================================]
function( android_options )
# Android Options

#[============================[ Android Options ]============================]
function(android_options)
#[[ Options from SCons

The options below are managed by CMake toolchain files, doc.cmake.rst has
more information

android_api_level : Target Android API level.
Default = 21

ANDROID_HOME : Path to your Android SDK installation.
Default = os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT")
]]
endfunction()

function( android_generate )
target_compile_definitions(${TARGET_NAME}
PUBLIC
ANDROID_ENABLED
UNIX_ENABLED
)
#[===========================[ Target Generation ]===========================]
function(android_generate)
target_compile_definitions(godot-cpp PUBLIC ANDROID_ENABLED UNIX_ENABLED)

common_compiler_flags()
endfunction()
Loading