Skip to content

Commit

Permalink
Update SConstruct and AddingProperties section
Browse files Browse the repository at this point in the history
  • Loading branch information
paddy-exe committed Dec 5, 2022
1 parent 22dd882 commit 9e94d48
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 135 deletions.
118 changes: 23 additions & 95 deletions tutorials/scripting/gdextension/files/cpp_example/SConstruct
Original file line number Diff line number Diff line change
@@ -1,41 +1,8 @@
#!python
#!/usr/bin/env python
import os
import sys

opts = Variables([], ARGUMENTS)

# Gets the standard flags CC, CCX, etc.
env = DefaultEnvironment()

# Define our options
opts.Add(EnumVariable('target', "Compilation target", 'debug', ['d', 'debug', 'r', 'release']))
opts.Add(EnumVariable('platform', "Compilation platform", '', ['', 'windows', 'linuxbsd', 'linux', 'osx']))
opts.Add(EnumVariable('p', "Compilation target, alias for 'platform'", '', ['', 'windows', 'linuxbsd', 'linux', 'osx']))
opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no'))
opts.Add(PathVariable('target_path', 'The path where the lib is installed.', 'demo/bin/'))
opts.Add(PathVariable('target_name', 'The library name.', 'libgdexample', PathVariable.PathAccept))

# Local dependency paths, adapt them to your setup
godot_headers_path = "godot-cpp/godot-headers/"
cpp_bindings_path = "godot-cpp/"
cpp_library = "libgodot-cpp"

# only support 64 at this time..
bits = 64

# Updates the environment with the option variables.
opts.Update(env)

# Process some arguments
if env['use_llvm']:
env['CC'] = 'clang'
env['CXX'] = 'clang++'

if env['p'] != '':
env['platform'] = env['p']

if env['platform'] == '':
print("No valid target platform selected.")
quit()
env = SConscript("godot-cpp/SConstruct")

# For the reference:
# - CCFLAGS are compilation flags shared between C and C++
Expand All @@ -45,65 +12,26 @@ if env['platform'] == '':
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags

# Check our platform specifics
if env['platform'] == "osx":
env['target_path'] += 'osx/'
cpp_library += '.osx'
env.Append(CCFLAGS=['-arch', 'x86_64'])
env.Append(CXXFLAGS=['-std=c++17'])
env.Append(LINKFLAGS=['-arch', 'x86_64'])
if env['target'] in ('debug', 'd'):
env.Append(CCFLAGS=['-g', '-O2'])
else:
env.Append(CCFLAGS=['-g', '-O3'])

elif env['platform'] in ('linuxbsd', 'linux'):
env['target_path'] += 'linuxbsd/'
cpp_library += '.linux'
env.Append(CCFLAGS=['-fPIC'])
env.Append(CXXFLAGS=['-std=c++17'])
if env['target'] in ('debug', 'd'):
env.Append(CCFLAGS=['-g3', '-Og'])
else:
env.Append(CCFLAGS=['-g', '-O3'])

elif env['platform'] == "windows":
env['target_path'] += 'win64/'
cpp_library += '.windows'
# This makes sure to keep the session environment variables on windows,
# that way you can run scons in a vs 2017 prompt and it will find all the required tools
env.Append(ENV=os.environ)

env.Append(CPPDEFINES=['WIN32', '_WIN32', '_WINDOWS', '_CRT_SECURE_NO_WARNINGS'])
env.Append(CCFLAGS=['-W3', '-GR'])
env.Append(CXXFLAGS='/std:c++17')
if env['target'] in ('debug', 'd'):
env.Append(CPPDEFINES=['_DEBUG'])
env.Append(CCFLAGS=['-EHsc', '-MDd', '-ZI'])
env.Append(LINKFLAGS=['-DEBUG'])
else:
env.Append(CPPDEFINES=['NDEBUG'])
env.Append(CCFLAGS=['-O2', '-EHsc', '-MD'])

if env['target'] in ('debug', 'd'):
cpp_library += '.debug'
else:
cpp_library += '.release'

cpp_library += '.' + str(bits)

# make sure our binding library is properly includes
env.Append(CPPPATH=['.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/'])
env.Append(LIBPATH=[cpp_bindings_path + 'bin/'])
env.Append(LIBS=[cpp_library])

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

library = env.SharedLibrary(target=env['target_path'] + env['target_name'] , source=sources)
env.Append(CPPPATH=["src/"])
sources = Glob("src/*.cpp")

if env["platform"] == "macos":
library = env.SharedLibrary(
"demo/bin/osx/libgdexample.{}.framework".format(
env["platform"],
),
source=sources,
)
elif env["platform"] == "windows":
library = env.SharedLibrary(
"demo/bin/win64/libgdexample.{}.{}{}".format(env["platform"], env["arch"], env["SHLIBSUFFIX"]),
source=sources,
)
else:
library = env.SharedLibrary(
"demo/bin/linux/libgdexample.{}.{}{}".format(env["platform"], env["arch"], env["SHLIBSUFFIX"]),
source=sources,
)

Default(library)

# Generates help for the -h scons option.
Help(opts.GenerateHelpText(env))
74 changes: 34 additions & 40 deletions tutorials/scripting/gdextension/gdextension_cpp_example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ GDExtension node we'll be creating. We will name it ``gdexample.h``:
namespace godot {

class GDExample : public Sprite2D {
GD_CLASS(GDExample, Sprite2D)
GDCLASS(GDExample, Sprite2D)

private:
float time_passed;
Expand Down Expand Up @@ -370,7 +370,6 @@ also result in *just* that file being exported when you export the project,
which means the data pack won't contain libraries that are incompatible with the
target platform.

TODO: check if dependencies section is supported
Finally, the ``dependencies`` section allows you to name additional dynamic
libraries that should be included as well. This is important when your GDExtension
plugin implements someone else's library and requires you to supply a
Expand All @@ -394,40 +393,41 @@ Adding properties
-----------------

GDScript allows you to add properties to your script using the ``export``
keyword. In GDExtension you have to register the properties and there are two ways
of doing this. You can either bind directly to a member or use a setter and
getter function.
keyword. In GDExtension you have to register the properties with a getter and
sett function or directly implement the ``_get_property_list``, ``_get`` and
``_set`` methods of an object (but that goes far beyond the scope of this
tutorial.

.. note::

There is a third option, just like in GDScript you can directly implement the
``_get_property_list``, ``_get`` and ``_set`` methods of an object but that
goes far beyond the scope of this tutorial.

We'll examine both starting with the direct bind. Lets add a property that
allows us to control the amplitude of our wave.
Lets add a property that allows us to control the amplitude of our wave.

In our ``gdexample.h`` file we simply need to add a member variable like so:
In our ``gdexample.h`` file we need to add a member variable and getter and setter
functions:

.. code-block:: C++

...
private:
float time_passed;
float amplitude;

public:
void set_amplitude(const float amplitude);
float get_amplitude() const;
...

In our ``gdexample.cpp`` file we need to make a number of changes, we will only
show the methods we end up changing, don't remove the lines we're omitting:

.. code-block:: C++

void GDExample::_register_methods() {
register_method("_process", &GDExample::_process);
register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
void GDExample::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_amplitude"), &GDExample::get_amplitude);
ClassDB::bind_method(D_METHOD("set_amplitude", "p_amplitude"), &GDExample::set_amplitude);

ClassDB::add_property("GDExample", PropertyInfo(Variant::FLOAT, "amplitude"), "set_amplitude", "get_amplitude");
}

void GDExample::_init() {
void GDExample::GDExample() {
// initialize any variables here
time_passed = 0.0;
amplitude = 10.0;
Expand All @@ -444,21 +444,19 @@ show the methods we end up changing, don't remove the lines we're omitting:
set_position(new_position);
}

void GDExample::set_amplitude(const float p_amplitude) {
amplitude = p_amplitude;
}

float GDExample::get_amplitude() const {
return amplitude;
}

Once you compile the module with these changes in place, you will see that a
property has been added to our interface. You can now change this property and
when you run your project, you will see that our Godot icon travels along a
larger figure.

.. note::

The ``reloadable`` property in the ``gdexample.gdnlib`` file must be set to
``true`` for the Godot editor to automatically pick up the newly added
property.

However, this setting should be used with care, especially when tool classes
are used, as the editor might hold objects then that have script instances
attached to them that are managed by a GDExtension library.

Let's do the same but for the speed of our animation and use a setter and getter
function. Our ``gdexample.h`` header file again only needs a few more lines of
code:
Expand All @@ -479,13 +477,13 @@ showing the methods that have changed so don't remove anything we're omitting:

.. code-block:: C++

void GDExample::_register_methods() {
register_method("_process", &GDExample::_process);
register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
register_property<GDExample, float>("speed", &GDExample::set_speed, &GDExample::get_speed, 1.0);
void GDExample::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_speed"), &GDExample::get_speed);
ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &GDExample::set_speed);
ClassDB::add_property("GDExample", PropertyInfo(Variant::FLOAT, "speed"), "set_speed", "get_speed");
}

void GDExample::_init() {
void GDExample::GDExample() {
// initialize any variables here
time_passed = 0.0;
amplitude = 10.0;
Expand All @@ -507,7 +505,7 @@ showing the methods that have changed so don't remove anything we're omitting:
speed = p_speed;
}

float GDExample::get_speed() {
float GDExample::get_speed() const {
return speed;
}

Expand All @@ -524,14 +522,10 @@ need to make additional choices based on the state of your object.
.. note::

For simplicity, we've left out the optional parameters in the
register_property<class, type> method call. These parameters are
``rpc_mode``, ``usage``, ``hint`` and ``hint_string``. These can be used to
add_property() method call. These parameters are
``hint``, ``hint_string``, ``usage`` and ``class_name``. These can be used to
further configure how properties are displayed and set on the Godot side.

Modern C++ compilers are able to infer the class and variable type and allow
you to omit the ``<GDExample, float>`` part of our ``register_property``
method. We've had mixed experiences with this however.

Signals
-------

Expand Down

0 comments on commit 9e94d48

Please sign in to comment.