aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/doc/examples/samplebinding.rst
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/doc/examples/samplebinding.rst')
-rw-r--r--sources/shiboken2/doc/examples/samplebinding.rst246
1 files changed, 246 insertions, 0 deletions
diff --git a/sources/shiboken2/doc/examples/samplebinding.rst b/sources/shiboken2/doc/examples/samplebinding.rst
new file mode 100644
index 000000000..a53b32bac
--- /dev/null
+++ b/sources/shiboken2/doc/examples/samplebinding.rst
@@ -0,0 +1,246 @@
+SampleBinding Example
+***********************
+
+This example showcases how you can use Shiboken to generate CPython-based
+binding code for a C++ library. The C++ library is called :code:`Universe`,
+with two classes: :code:`Icecream` and :code:`Truck`. Ice-creams are
+characterized by their flavor, and :code:`Truck` serves as a vehicle of
+:code:`Icecream` distribution for kids in a neighborhood.
+
+First, let's look at the definition of the two classes:
+
+.. code-block:: cpp
+ :caption: icecream.h
+
+ class Icecream
+ {
+ public:
+ Icecream(const std::string &flavor);
+ virtual Icecream *clone();
+ virtual ~Icecream();
+ virtual const std::string getFlavor();
+
+ private:
+ std::string m_flavor;
+ };
+
+.. code-block:: cpp
+ :caption: truck.h
+
+ class Truck {
+ public:
+ Truck(bool leaveOnDestruction = false);
+ Truck(const Truck &other);
+ Truck& operator=(const Truck &other);
+ ~Truck();
+
+ void addIcecreamFlavor(Icecream *icecream);
+ void printAvailableFlavors() const;
+
+ bool deliver() const;
+ void arrive() const;
+ void leave() const;
+
+ void setLeaveOnDestruction(bool value);
+ void setArrivalMessage(const std::string &message);
+
+ private:
+ void clearFlavors();
+
+ bool m_leaveOnDestruction = false;
+ std::string m_arrivalMessage = "A new icecream truck has arrived!\n";
+ std::vector m_flavors;
+ };
+
+Here's a summary of what's included in the :code:`Universe` library:
+
+* The :code:`Icecream` polymorphic type, which is intended to be overridden.
+* The :code:`Icecream::getFlavor()` method returns the flavor depending on the
+ actual derived type.
+* The :code:`Truck` value type that contains pointers, hence the copy
+ constructor.
+* :code:`Truck` stores the :code:`Icecream` objects in a vector, which can be
+ modified via :code:`Truck::addIcecreamFlavor()`.
+* The :code:`Truck’s` arrival message can be customized using its
+ :code:`setArrivalMessage()` method.
+* The :code:`Truck::deliver()` method tells us if the ice-cream delivery was
+ successful.
+
+Shiboken typesystem
+====================
+
+Now that the library definitions are in place, the Shiboken generator needs a
+header file that includes the types we are interested in:
+
+.. code-block:: cpp
+ :caption: bindings.h
+
+ #ifndef BINDINGS_H
+ #define BINDINGS_H
+ #include "icecream.h"
+ #include "truck.h"
+ #endif // BINDINGS_H
+
+In addition, Shiboken also requires an XML-based typesystem file that defines the
+relationship between C++ and Python types:
+
+.. code-block:: xml
+ :caption: bindings.xml
+
+ <?xml version="1.0"?>
+ <typesystem package="Universe">
+ <primitive-type name="bool"/>
+ <primitive-type name="std::string"/>
+ <object-type name="Icecream">
+ <modify-function signature="clone()">
+ <modify-argument index="0">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+ <value-type name="Truck">
+ <modify-function signature="addIcecreamFlavor(Icecream*)">
+ <modify-argument index="1">
+ <define-ownership owner="c++"/>
+ </modify-argument>
+ </modify-function>
+ </value-type>
+ </typesystem>
+
+One important thing to notice here is that we declare :code:`"bool"` and
+:code:`"std::string"` as primitive types. These types are used by some of the
+C++ methods as parameters or return types, so Shiboken must know about them.
+Then, Shiboken can generate relevant conversion code between C++ and Python, although
+most C++ primitive types are handled by Shiboken without additional code.
+
+Next, we declare the two aforementioned classes. One of them as an
+“object-type” and the other as a “value-type”. The main difference is that
+object-types are passed around in generated code as pointers, whereas
+value-types are copied (value semantics).
+
+By specifying the names of these classes in the typesystem file, Shiboken
+automatically tries to generate bindings for all methods of those
+classes. You need not mention all the methods manually in the XML file, unless
+you want to modify them.
+
+Object ownership rules
+=======================
+
+Shiboken doesn't know if Python or C++ are responsible for freeing the C++ objects that were
+allocated in the Python code, and assuming this might lead to errors.
+There can be cases where Python should release the C++ memory when the reference count of the
+Python object becomes zero, but it should never delete the underlying C++ object just from
+assuming that it will not be deleted by underlying C++ library, or if it's maybe parented to
+another object (like QWidgets).
+
+In our case, the :code:`clone()` method is only called inside the C++ library,
+and we assume that the C++ code takes care of releasing the cloned object.
+
+As for :code:`addIcecreamFlavor()`, we know that a :code:`Truck` owns the
+:code:`Icecream` object, and will remove it once the :code:`Truck` is
+destroyed. That's why the ownership is set to “c++” in the typesystem file,
+so that the C++ objects are not deleted when the corresponding Python names
+go out of scope.
+
+Build
+=====
+
+To build the :code:`Universe` custom library and then generate bindings for it,
+use the :file:`CMakeLists.txt` file provided with the example. Later, you can reuse
+the file for your own libraries with minor changes.
+
+Now, run the :command:`"cmake ."` command from the prompt to configure the
+project and build with the toolchain of your choice; we recommend the
+‘(N)Makefiles’ generator.
+
+As a result, you end up with two shared libraries:
+:file:`libuniverse.(so/dylib/dll)` and :file:`Universe.(so/pyd)`. The former is
+the custom C++ library, and the latter is the Python module to import in your
+Python script.
+
+For more details about these platforms, see the :file:`README.md` file.
+
+Use the Python module
+=====================
+
+The following script uses the :code:`Universe` module, derives a few types from
+:code:`Icecream`, implements virtual methods, instantiates objects, and much more:
+
+.. code-block:: python
+ :caption: main.py
+
+ from Universe import Icecream, Truck
+
+ class VanillaChocolateIcecream(Icecream):
+ def __init__(self, flavor=""):
+ super(VanillaChocolateIcecream, self).__init__(flavor)
+
+ def clone(self):
+ return VanillaChocolateIcecream(self.getFlavor())
+
+ def getFlavor(self):
+ return "vanilla sprinked with chocolate"
+
+ class VanillaChocolateCherryIcecream(VanillaChocolateIcecream):
+ def __init__(self, flavor=""):
+ super(VanillaChocolateIcecream, self).__init__(flavor)
+
+ def clone(self):
+ return VanillaChocolateCherryIcecream(self.getFlavor())
+
+ def getFlavor(self):
+ base_flavor = super(VanillaChocolateCherryIcecream, self).getFlavor()
+ return base_flavor + " and a cherry"
+
+ if __name__ == '__main__':
+ leave_on_destruction = True
+ truck = Truck(leave_on_destruction)
+
+ flavors = ["vanilla", "chocolate", "strawberry"]
+ for f in flavors:
+ icecream = Icecream(f)
+ truck.addIcecreamFlavor(icecream)
+
+ truck.addIcecreamFlavor(VanillaChocolateIcecream())
+ truck.addIcecreamFlavor(VanillaChocolateCherryIcecream())
+
+ truck.arrive()
+ truck.printAvailableFlavors()
+ result = truck.deliver()
+
+ if result:
+ print("All the kids got some icecream!")
+ else:
+ print("Aww, someone didn't get the flavor they wanted...")
+
+ if not result:
+ special_truck = Truck(truck)
+ del truck
+
+ print("")
+ special_truck.setArrivalMessage("A new SPECIAL icecream truck has arrived!\n")
+ special_truck.arrive()
+ special_truck.addIcecreamFlavor(Icecream("SPECIAL *magical* icecream"))
+ special_truck.printAvailableFlavors()
+ special_truck.deliver()
+ print("Now everyone got the flavor they wanted!")
+ special_truck.leave()
+
+After importing the classes from the :code:`Universe` module, it derives two
+types from :code:`Icecream` for different “flavors”. It then creates a
+:code:`truck` to deliver some regular flavored Icecreams and two special ones.
+
+If the delivery fails, a new :code:`truck` is created with the old flavors
+copied over, and a new *magical* flavor that will surely satisfy all customers.
+
+Try running it to see if the ice creams are delivered.
+
+.. note::
+ You can find the sources for this example under
+ :file:`<PYTHON_ENV_ROOT>/site-packages/lib/PySide2/examples/samplebinding`.
+
+Refer to the following topics for detailed information about using Shiboken:
+ * :doc:`Type System Variables <../typesystem_variables>`
+ * :doc:`User Defined Type Conversion <../typesystem_converters>`
+ * :doc:`Object ownership <../typesystem_ownership>`
+ * :doc:`Considerations and Frequently Asked Questions <../considerations>`