This guide specifically shows how to get a Windows 10 x64 OS compiled for a Windows x64 Debug dynamic library and integrate it into a Godot project.
To begin, make sure you are running the appropriate command line tool as an administrator.
Create a SimpleLibrary directory and enter it. This is where our Godot and GDNative projects will exist. For later use, we will also create subdirectories for libraries (lib) and source code (src).
Once inside, we get a copy of each necessary repository for C++ NativeScript bindings generation and enter into the cpp_bindings
directory.
mkdir SimpleLibrary
cd SimpleLibrary
mkdir lib
mkdir src
git clone https://github.com/GodotNativeTools/cpp_bindings
git clone https://github.com/GodotNativeTools/godot_headers
cd cpp_bindings
Run the following scons
command, where godotbinpath points to the relative location of your godot installation and headers points to the godot_headers directory you just installed.
scons godotbinpath="..\..\godot\bin\godot.windows.tools.64.exe" headers="..\godot_headers" p=windows generate_bindings=yes
Note that on Windows, godotbinpath
MUST use backslashes ('\'), otherwise you will receive an error telling you that '..' is not a command. This is because the app at godotbinpath is executed and cmd.exe uses forward slashes ('/') for command options instead of the bash-like dash ('-'), so it thinks you are running...
.. /.. /.. /godot .....etc. (as if these were each options for a '..' command, e.g.)
.. -.. -.. -godot .....
Also note that if you encounter a bug saying "fatal error", something about AABB not finding stuff, you can try deleting and re-cloning thr cpp_bindings repository (worked for me the first time around).
You should see it generate several files. After a few minutes, it will conclude with "scons: done building targets".
Now it will have generated a static library file (.lib) for cpp_bindings that we must copy into our lib\ directory.
copy bin\cpp_bindings.windows.64.lib ..\lib\
Because there doesn't seem to be a vsproj=yes
command that works anymore to build a vsproject for us, we'll need to make it ourselves.
Create a Visual Studio project. The name should be SimpleLibrary and it should NOT create a directory (uncheck the box). You'll want to select the SimpleLibrary directory as the location to put the project. Choose the Win32 Desktop Wizard template. Select options for both a dynamic library (.dll) and an empty project.
Afterwards, things should look like this:
SimpleLibrary -cpp_bindings -godot_headers -lib -SimpleLibrary --.vs --SimpleLibrary.sln --SimpleLibrary.vcxproj --SimpleLibrary.vcsproj.filters -src
In Visual Studio, we will need to configure a few things. Make sure you have a debug, x64 configuration for the solution. The options are located in the toolbar at the top left, just before the "Local Windows Debugger" button with the green play icon.
Then go to "Project > SimpleLibrary Properties..." to open the project properties.
(note that for the next step, for things that involve paths, it's advised that you use the "..." button on new entries to create records)
Ensure that you are on the x64 Debug configurations at tge top (or just do all platforms) and make the following changes...
- VC++ Directories > Include Directories. Add 'SimpleLibrary\cpp_bindings\include', 'SimpleLibrary\cpp_bindings\include\core', and 'SimpleLibrary\godot_headers' to the list.
- VC++ Directories > Library Directories. Add 'SimpleLibrary\lib'.
- VC++ Directories > Source Directories. Add 'SimpleLibrary\src'.
- C/C++ > Linker > System. Subsystem = "Console (/SUBSYSTEM:CONSOLE)"
- C/C++ > Linker > Input. Add "cpp_bindings.windows.64.lib" (without quotes) to the Additional Dependencies parameter.
Click Apply and then Save to close the window.
Under Source Files in the Solution Explorer of Visual Studio, create a pair of new items: an init.cpp
file and a SimpleClass.cpp
file in SimpleLibrary\src.
SimpleClass.cpp should be...
//SimpleClass.cpp
#include <core/Godot.hpp>
#include <Reference.hpp>
using namespace godot;
class SimpleClass : public GodotScript<Reference> {
GODOT_CLASS(SimpleClass);
public:
SimpleClass() { }
void test_void_method() {
Godot::print("This is test");
}
Variant method(Variant arg) {
Variant ret;
ret = arg;
return ret;
}
static void _register_methods() {
register_method("method", &SimpleClass::method);
/**
* How to register exports like gdscript
* export var _name = "SimpleClass"
**/
register_property((char *)"base/name", &SimpleClass::_name, String("SimpleClass"));
/** For registering signal **/
// register_signal<SimpleClass>("signal_name");
}
String _name;
};
and init.cpp should be...
#include "SimpleClass.cpp"
/** GDNative Initialize **/
extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o)
{
godot::Godot::gdnative_init(o);
}
/** GDNative Terminate **/
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o)
{
godot::Godot::gdnative_terminate(o);
}
/** NativeScript Initialize **/
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle)
{
godot::Godot::nativescript_init(handle);
godot::register_class<SimpleClass>();
}
Now build Visual Studio (make sure you have it set to Debug x64! If you did not do this at the beginning of the process, all of the project properties will have been assigned to the wrong configuration and you will need to redo them all!)
If all goes well, the solution should build successfully.
Next step, create a Godot project folder in the main SimpleLibrary directory (where lib and src are located). You will start to see Godot import all of the obj files you've generated.
EDIT: Godot will now only allow you to create a project in an empty directory, so instead, create a directory, make the project, and then cut/paste the files into the SimpleLibrary directory.
Using a text editor (because Godot does not yet have a button somewhere to do this), create a .gdnlib file with the following:
[general]
symbol_prefix="godot_"
singleton=false
load_once=true
[entry]
Windows.64=<YOUR DLL PATH HERE>
[dependencies]
Windows.64=[ ]
Note: .gdnlib
as a filetype is currently being used in place of a GDNativeLibrary.tres type, but at this time, the editor only knows how to create the .tres
version, even if it can respond to and edit both of them. I do not know if they will eventually be converted back into .tres
for consistency's sake or if they will add support for creating .gdnlib
files directly from the editor.
Note: As an example, the value I had for my <YOUR DLL PATH HERE> was "SimpleLibrary/x64/Debug/SimpleLibrary.dll".
Create a gdnlibs
folder (not important, just for organizational purposes) in your project and save the file in there with the name simple_class.gdnlib
. You may need to rename the file from .gdnlib.txt
to just .gdnlib
depending on which text editor you used.
If you want to be EXTRA sure that you got this step right (recommended), then in your Godot project, open the .gdnlib
file. It will have a GUI editor that pops up in the bottom panel.
Find "Windows" in the list, click the folder icon on the 64
row, and select your .dll
file. This allows Godot to know where your .dll
exists.
Go to the Script Editor. In its toolbar, select File > New to create a new script. Set the type of the script to NativeScript.
Because our SimpleClass
demo type inherits from GodotScript<Reference>
, you should type "Reference" in the text box labeled "Inherits".
Specify the name of the class ("SimpleClass" - this must match the contents of the GODOT_CLASS macro in SimpleClass.cpp
) and give it a filename of simple_class.gdns
.
Once the script has been created, check the Inspector. It will have a null GDNativeLibrary field.
Click the arrow and pick Load
to load your .gdnlib
file as its GDNativeLibrary for the .gdns
file.
This will ensure that the engine's Script object will know which .dll
(depending on the platform) to look at when accessing "SimpleClass" properties and methods.
Now, VERY IMPORTANT: click the save icon in the Inspector. If you do not do this, the changed GDNativeLibrary setting on the NativeScript resource will only exist on the NativeScript resource instance in the Inspector rather than in the .gdns
file in the file system. Because you load scripts via the file at the path, you won't actually get a NativeScript that is pointing to the GDNativeLibrary unless you do this.
Finally, create a new scene. Add a node of type Node with a built-in GDScript with the following code:
extends Node
func _ready():
var simple = preload("simple_class.gdns").new()
print(simple.method("Hello World from NativeScript!"))
Save the scene (name doesn't matter) and run it. When the game loads, you should see our string printed to the console. We passed it to a NativeScript class, which passed it along to the native implementation (done in C++, but it doesn't really know that, nor does it care), and C++ returned that value as a Variant
for GDScript to catch, convert to a String
, and print.
add reloadable=true to the .gdnlib file as the project gives me errors without it