Issue compiling GDExtension(C++) with simple Godot::String getter

Godot Version

4.1.4

Issue

I am trying to create a GDExtension Node which internally works with a String that can be modified with an added property from the editor. While other extensions work fine, my current extension does not even compile when binding only a simple getter.
I tried using the types String and StringName as in the end I want to define an input action. Both types caused the same compile error which you can see below. When commenting out all method bindings, the code compiles.

Question

Does anyone know how String and StringName work for GDExtensions and how they can be used in the code below?

Compile Error

scons -Q
cl /Fosrc\DefaultExit.obj /c src\DefaultExit.cpp /TP /std:c++17 /EHsc /nologo “/IC:\GodotExtensions\godot-cpp\gdextension” “/IC:\GodotExtensions\godot-cpp\include” “/IC:\GodotExtensions\godot-cpp\gen\include” “/IC:\GodotExtensions\godot-cpp\gen\include\core” /Isrc
DefaultExit.cpp
C:\GodotExtensions\godot-cpp\include\godot_cpp/core/method_bind.hpp(591): error C2440:
“reinterpret_cast”: “R (__cdecl godot::DefaultExit::* )(void) const” cannot be converted to “R (__cdecl godot::_gde_UnexistingClass::* )(void) const”
with
[
R=godot::StringName
]
C:\GodotExtensions\godot-cpp\include\godot_cpp/core/method_bind.hpp(591): note: Pointers to elements have different representations; conversion not possible
C:\GodotExtensions\godot-cpp\include\godot_cpp/core/method_bind.hpp(591): note: The template instantiation context (oldest first) is
src\DefaultExit.cpp(12): note: See reference to the currently compiled instantiation “godot::MethodBind godot::ClassDB::bind_method<godot::MethodDefinition,godot::StringName(__cdecl godot::DefaultExit:: )(void) const,>(N,M)” of the function template.
with
[
N=godot::MethodDefinition,
M=godot::StringName (__cdecl godot::DefaultExit::* )(void) const
]
C:\GodotExtensions\godot-cpp\include\godot_cpp/core/class_db.hpp(241): note: See reference to the currently compiled instantiation “godot::MethodBind godot::create_method_bindgodot::DefaultExit,godot::StringName,(R (__cdecl godot::DefaultExit:: )(void) const)” of the function template.
with
[
R=godot::StringName
]
C:\GodotExtensions\godot-cpp\include\godot_cpp/core/method_bind.hpp(591): error C2512:
“godot::MethodBindTRC::MethodBindTRC”: No suitable default constructor available
with
[
R=godot::StringName
]
C:\GodotExtensions\godot-cpp\include\godot_cpp/core/method_bind.hpp(591): note: when adjusting the argument list “()”
scons: *** [src\DefaultExit.obj] Error 2

Code

DefaultExit.h

#ifndef DEFAULTEXIT
#define DEFAULTEXIT

#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/classes/input_event.hpp>
#include <godot_cpp/variant/string_name.hpp>


namespace godot{
    class DefaultExit : public Node{
        GDCLASS(DefaultExit, Node)
    
        private:
            StringName exit_string;

        protected:
            static void _bind_methods();

        public:
            DefaultExit();
            ~DefaultExit();

            StringName get_ExitString() const;
            void set_ExitString(const StringName strg);

            void _input(const Ref<InputEvent> &event);
    };
}

#endif

DefaultExit.cpp

#include "DefaultExit.h"

#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/scene_tree.hpp>



using namespace godot;

void DefaultExit::_bind_methods(){
    ClassDB::bind_method(D_METHOD("get_exit_string"), &DefaultExit::get_ExitString);
	//ClassDB::bind_method(D_METHOD("set_exit_string", "exit_string"), &DefaultExit::set_ExitString);
	//ClassDB::add_property("DefaultExit",PropertyInfo(Variant::STRING, "Exit Action"), "set_exit_string", "get_exit_string");
    
}

DefaultExit::DefaultExit(){
    this->exit_string = "exit";
}

DefaultExit::~DefaultExit(){
}

StringName DefaultExit::get_ExitString() const{
    return exit_string;
}

void DefaultExit::set_ExitString(const StringName strg){
    this->exit_string = strg;
}

void DefaultExit::_input(const Ref<InputEvent> &event){
    if (!Engine::get_singleton()->is_editor_hint()) {
        if (event->is_action_pressed(exit_string)) {
            get_tree()->quit();
        }
    }
}

Just copied your code and it compiles with 4.1 bindings without problems.
It not used right now, but AFAIK must be
set_ExitString(const StringName& strg)

Not sure, do you use template?
you must have also register_types.h and register_types.cpp and inside

	ClassDB::register_class<DefaultExit>();

Thank you for your replies.

It appears the problem is my custom SConstruct file since I could compile my code as well using a default one. My problem with this is that it is linked to the SConstruct file of the bindings. Whenever I create another extension directory and use it, all bindings have to be rebuild.

Is there a way to use an independent SConstruct file which just links to already build bindings?

Custom SConstruct file likely causing problems:

#!/usr/bin/env python
import os
import sys

env = Environment()



library_title = "DefaultExit"
bindings_dir = "../../"

#For reference:
#- CCFLAGS are compilation flags shared between C and C++
#- CFLAGS are for C-specific compilation flags
#- CXXFLAGS are for C++-specific compilation flags
#- CPPFLAGS are for pre-processor flags
#- CPPDEFINES are for pre-processor defines
#- LINKFLAGS are for linking flags

# tweak this if you want to use different folders, or more folders, to store your source code in.

env["platform"] = "windows"  #  "linux" or "macos" 
env["suffix"] = ".dll"  # ".so" for Linux ", .dll" for Windows or ".dylib" for macOS

env.Append(CPPPATH=[f"{bindings_dir}godot-cpp/gdextension/"])
env.Append(CPPPATH=[f"{bindings_dir}godot-cpp/include/"])
env.Append(CPPPATH=[f"{bindings_dir}godot-cpp/gen/include/"])
env.Append(CPPPATH=[f"{bindings_dir}godot-cpp/gen/include/core"])

env.Append(LIBPATH=[f"{bindings_dir}godot-cpp/bin"])
env.Append(LIBS=["libgodot-cpp.windows.template_debug.x86_64"])

if env["platform"] == "windows":
    env.Append(CXXFLAGS=["/std:c++17", "/EHsc"])
else:
    env.Append(CXXFLAGS=["-std=c++17"])


env.Append(CPPPATH=["src/"])
sources = Glob("src/*.cpp")


if env["platform"] == "macos":
    library = env.SharedLibrary(
        "../../demoproject/bin/HelloWorld.{}.{}.framework/{}/{}.{}.{}".format(library_title, library_title,
            env["platform"], env["target"], env["platform"], env["target"]
        ),
        source=sources,
    )
else:
    library = env.SharedLibrary(
        "../../demoproject/bin/{}/{}{}{}".format(library_title, library_title, env["suffix"], env["SHLIBSUFFIX"]),
        source=sources,
    )

Default(library)

Working SConstruct file with dependency to the bindings SConstruct file:

#!/usr/bin/env python
import os
import sys

env = SConscript("../../godot-cpp/SConstruct")

#For reference:
#- CCFLAGS are compilation flags shared between C and C++
#- CFLAGS are for C-specific compilation flags
#- CXXFLAGS are for C++-specific compilation flags
#- CPPFLAGS are for pre-processor flags
#- CPPDEFINES are for pre-processor defines
#- LINKFLAGS are for linking flags

# tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPPATH=["src/"])
sources = Glob("src/*.cpp")

if env["platform"] == "macos":
    library = env.SharedLibrary(
        "../../demoproject/bin/HelloWorld.{}.{}.framework/helloWorld.{}.{}".format(
            env["platform"], env["target"], env["platform"], env["target"]
        ),
        source=sources,
    )
else:
    library = env.SharedLibrary(
        "../../demoproject/bin/HelloWorld{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
        source=sources,
    )

Default(library)

Yes I have done that. The compiler outputs an error regarding the _binding_methods() which AFAIK it only does when the class registered correctly and it can reach its implementation.

1 Like

Grats. Im not a C++ programmer, don’t know scons but confused there are no this files in your output after cl
If you also start your way, can offer to look into this folder. It literally very similar how gd extention made, except not all parent class virtual methods available for overriding like in this modules.