diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89258520..9b0a5396 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,8 @@ on: [push, pull_request] env: # Only used for the cache key. Increment version to force clean build. GODOT_BASE_BRANCH: master + # Used to select the version of Godot to run the tests with. + GODOT_TEST_VERSION: 4.1.4-stable concurrency: group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}} @@ -153,7 +155,7 @@ jobs: - name: Download latest Godot artifacts uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9 - if: ${{ matrix.run-tests }} + if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }} with: repo: godotengine/godot branch: master @@ -166,15 +168,28 @@ jobs: ensure_latest: true path: godot-artifacts + - name: Prepare Godot artifacts for testing + if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION == 'master' }} + run: | + chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono + echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV + + - name: Download requested Godot version for testing + if: ${{ matrix.run-tests && env.GODOT_TEST_VERSION != 'master' }} + run: | + wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip + unzip -a Godot.zip + chmod +x "Godot_v${GODOT_TEST_VERSION}_linux.x86_64" + echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV + - name: Run tests if: ${{ matrix.run-tests }} run: | - chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono - ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono --headless --version + $GODOT --headless --version cd test # Need to run the editor so .godot is generated... but it crashes! Ignore that :-) - (cd project && (timeout 10 ../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true)) - GODOT=../godot-artifacts/godot.linuxbsd.editor.x86_64.mono ./run-tests.sh + (cd project && (timeout 30 $GODOT --editor --headless --quit >/dev/null 2>&1 || true)) + ./run-tests.sh - name: Upload artifact uses: actions/upload-artifact@v3 diff --git a/binding_generator.py b/binding_generator.py index 20fd283b..e5ebad3f 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -1470,13 +1470,16 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append("\t \\") for method in class_api["methods"]: - # ClassDBSingleton shouldn't have any static or vararg methods, but if some appear later, lets skip them. - if vararg: - continue + # ClassDBSingleton shouldn't have any static methods, but if some appear later, lets skip them. if "is_static" in method and method["is_static"]: continue - method_signature = "\tstatic " + vararg = "is_vararg" in method and method["is_vararg"] + if vararg: + method_signature = "\ttemplate static " + else: + method_signature = "\tstatic " + return_type = None if "return_type" in method: return_type = correct_type(method["return_type"].replace("ClassDBSingleton", "ClassDB"), None, False) @@ -1498,7 +1501,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us method_arguments = method["arguments"] method_signature += make_function_parameters( - method_arguments, include_default=True, for_builtin=True, is_vararg=False + method_arguments, include_default=True, for_builtin=True, is_vararg=vararg ) method_signature += ") { \\" @@ -1512,6 +1515,8 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us method_body += f"({return_type})" method_body += f'ClassDBSingleton::get_singleton()->{method["name"]}(' method_body += ", ".join(map(lambda x: escape_identifier(x["name"]), method_arguments)) + if vararg: + method_body += ", args..." method_body += "); \\" result.append(method_body) @@ -2126,9 +2131,9 @@ def make_varargs_template(function_data, static=False): args_array = f"\t\tstd::array variant_args {{ " for argument in method_arguments: if argument["type"] == "Variant": - args_array += argument["name"] + args_array += escape_identifier(argument["name"]) else: - args_array += f'Variant({argument["name"]})' + args_array += f'Variant({escape_identifier(argument["name"])})' args_array += ", " args_array += "Variant(args)... };" @@ -2305,6 +2310,7 @@ def correct_default_value(value, type_name): "null": "nullptr", '""': "String()", '&""': "StringName()", + '^""': "NodePath()", "[]": "Array()", "{}": "Dictionary()", "Transform2D(1, 0, 0, 1, 0, 0)": "Transform2D()", # Default transform. @@ -2316,6 +2322,10 @@ def correct_default_value(value, type_name): return f"{type_name}()" if value.startswith("Array["): return f"{{}}" + if value.startswith("&"): + return value[1::] + if value.startswith("^"): + return value[1::] return value diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 752c4390..988d4d1d 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -286,9 +286,9 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p return bind; } -#define GDREGISTER_CLASS(m_class) ClassDB::register_class(); -#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class(true); -#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class(); +#define GDREGISTER_CLASS(m_class) ::godot::ClassDB::register_class(); +#define GDREGISTER_VIRTUAL_CLASS(m_class) ::godot::ClassDB::register_class(true); +#define GDREGISTER_ABSTRACT_CLASS(m_class) ::godot::ClassDB::register_abstract_class(); } // namespace godot diff --git a/src/core/class_db.cpp b/src/core/class_db.cpp index 702df993..8d490433 100644 --- a/src/core/class_db.cpp +++ b/src/core/class_db.cpp @@ -360,6 +360,7 @@ void ClassDB::initialize(GDExtensionInitializationLevel p_level) { } void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) { + std::set to_erase; for (std::vector::reverse_iterator i = class_register_order.rbegin(); i != class_register_order.rend(); ++i) { const StringName &name = *i; const ClassInfo &cl = classes[name]; @@ -370,9 +371,20 @@ void ClassDB::deinitialize(GDExtensionInitializationLevel p_level) { internal::gdextension_interface_classdb_unregister_extension_class(internal::library, name._native_ptr()); - for (auto method : cl.method_map) { + for (const std::pair &method : cl.method_map) { memdelete(method.second); } + + classes.erase(name); + to_erase.insert(name); + } + + { + // The following is equivalent to c++20 `std::erase_if(class_register_order, [&](const StringName& name){ return to_erase.contains(name); });` + std::vector::iterator it = std::remove_if(class_register_order.begin(), class_register_order.end(), [&](const StringName &p_name) { + return to_erase.count(p_name) > 0; + }); + class_register_order.erase(it, class_register_order.end()); } } diff --git a/src/core/object.cpp b/src/core/object.cpp index d2e10ffb..410daf85 100644 --- a/src/core/object.cpp +++ b/src/core/object.cpp @@ -75,7 +75,7 @@ MethodInfo::operator Dictionary() const { dict["name"] = name; dict["args"] = internal::convert_property_list(arguments); Array da; - for (int i = 0; i < default_arguments.size(); i++) { + for (size_t i = 0; i < default_arguments.size(); i++) { da.push_back(default_arguments[i]); } dict["default_args"] = da; diff --git a/tools/common_compiler_flags.py b/tools/common_compiler_flags.py index 437f256b..838dbcf0 100644 --- a/tools/common_compiler_flags.py +++ b/tools/common_compiler_flags.py @@ -39,6 +39,14 @@ def generate(env): elif env.get("is_msvc", False): env.Append(CXXFLAGS=["/EHsc"]) + if not env.get("is_msvc", False): + if env["symbols_visibility"] == "visible": + env.Append(CCFLAGS=["-fvisibility=default"]) + env.Append(LINKFLAGS=["-fvisibility=default"]) + elif env["symbols_visibility"] == "hidden": + env.Append(CCFLAGS=["-fvisibility=hidden"]) + env.Append(LINKFLAGS=["-fvisibility=hidden"]) + # Set optimize and debug_symbols flags. # "custom" means do nothing and let users set their own optimization flags. if env.get("is_msvc", False): diff --git a/tools/godotcpp.py b/tools/godotcpp.py index 92ad7aeb..adfd4975 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -291,6 +291,15 @@ def options(opts, env): ) ) + opts.Add( + EnumVariable( + key="symbols_visibility", + help="Symbols visibility on GNU platforms. Use 'auto' to apply the default value.", + default=env.get("symbols_visibility", "hidden"), + allowed_values=["auto", "visible", "hidden"], + ) + ) + opts.Add( EnumVariable( "optimize",