From 0a40640a1882dceb34f601dc818cd64c29612672 Mon Sep 17 00:00:00 2001 From: Venugopal Shivashankar Date: Wed, 14 Nov 2018 15:04:00 +0100 Subject: Doc: Add an index page for Shiboken Also document the samplebinding example. Change-Id: I2ee1fa6049ae672f5ab46df4d1eba411e69dc3c7 Reviewed-by: Paul Wicking Reviewed-by: Friedemann Kleint --- sources/pyside2/doc/index.rst | 3 +- sources/shiboken2/doc/conf.py.in | 4 +- sources/shiboken2/doc/contents.rst | 4 +- sources/shiboken2/doc/images/icecream.png | Bin 0 -> 4272 bytes .../doc/images/qtforpython-underthehood.png | Bin 0 -> 19144 bytes sources/shiboken2/doc/index.rst | 28 +++ sources/shiboken2/doc/samplebinding.rst | 247 +++++++++++++++++++++ 7 files changed, 280 insertions(+), 6 deletions(-) create mode 100644 sources/shiboken2/doc/images/icecream.png create mode 100644 sources/shiboken2/doc/images/qtforpython-underthehood.png create mode 100644 sources/shiboken2/doc/index.rst create mode 100644 sources/shiboken2/doc/samplebinding.rst (limited to 'sources') diff --git a/sources/pyside2/doc/index.rst b/sources/pyside2/doc/index.rst index fa1daec00..27fefeb16 100644 --- a/sources/pyside2/doc/index.rst +++ b/sources/pyside2/doc/index.rst @@ -102,8 +102,7 @@ Qt Modules Provides classes to create and use state machines from SCXML files. |project| also comes with the -:doc:`Shiboken2 ` generator that outputs C++ code -for CPython extensions. +:doc:`Shiboken2 ` CPython binding code generator. .. toctree:: :maxdepth: 2 diff --git a/sources/shiboken2/doc/conf.py.in b/sources/shiboken2/doc/conf.py.in index 3ca8ac573..d3aa95c0b 100644 --- a/sources/shiboken2/doc/conf.py.in +++ b/sources/shiboken2/doc/conf.py.in @@ -39,7 +39,7 @@ source_suffix = '.rst' source_encoding = 'utf-8' # The master toctree document. -#master_doc = 'contents' +master_doc = 'index' # General information about the project. project = u'Shiboken' @@ -137,7 +137,7 @@ html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_themes'] # Additional templates that should be rendered to pages, maps page names to # template names. -html_additional_pages = { 'index' : 'index.html'} +#html_additional_pages = { 'index' : 'index.html'} # If false, no module index is generated. html_use_modindex = False diff --git a/sources/shiboken2/doc/contents.rst b/sources/shiboken2/doc/contents.rst index 24adb1c68..a0b40effb 100644 --- a/sources/shiboken2/doc/contents.rst +++ b/sources/shiboken2/doc/contents.rst @@ -1,11 +1,10 @@ Table of contents ***************** .. toctree:: - :numbered: :maxdepth: 3 - faq.rst overview.rst + samplebinding.rst commandlineoptions.rst projectfile.rst typesystemvariables.rst @@ -15,3 +14,4 @@ Table of contents ownership.rst wordsofadvice.rst shibokenmodule.rst + faq.rst diff --git a/sources/shiboken2/doc/images/icecream.png b/sources/shiboken2/doc/images/icecream.png new file mode 100644 index 000000000..41d1a25fa Binary files /dev/null and b/sources/shiboken2/doc/images/icecream.png differ diff --git a/sources/shiboken2/doc/images/qtforpython-underthehood.png b/sources/shiboken2/doc/images/qtforpython-underthehood.png new file mode 100644 index 000000000..64e30b1c5 Binary files /dev/null and b/sources/shiboken2/doc/images/qtforpython-underthehood.png differ diff --git a/sources/shiboken2/doc/index.rst b/sources/shiboken2/doc/index.rst new file mode 100644 index 000000000..4cc5b204e --- /dev/null +++ b/sources/shiboken2/doc/index.rst @@ -0,0 +1,28 @@ +Shiboken the Binding Generator +******************************* + +Shiboken is the CPython-based binding code generator for C or C++ libraries. +It uses an ApiExtractor library to parse the C or C++ headers and get the +type information, using Clang. The library can also be used to parse non-Qt +projects. The following diagram summarizes Shiboken's role in the PySide +project. + +.. image:: images/qtforpython-underthehood.png + +A typesystem file (XML) is used to specify the types to be exposed to Python +and to apply modifications to properly represent and manipulate the types in +the Python World. For example, you can remove and add methods to certain types, +and also modify the arguments of each method. Such actions are inevitable to +properly handle the data structures or types. + +The final outcome of this process is a set of wrappers written in CPython, +which can be used as a module in your python code. + +Refer to the following topics for more information and examples: + +.. toctree:: + :maxdepth: 1 + + overview + samplebinding + contents diff --git a/sources/shiboken2/doc/samplebinding.rst b/sources/shiboken2/doc/samplebinding.rst new file mode 100644 index 000000000..2e0311092 --- /dev/null +++ b/sources/shiboken2/doc/samplebinding.rst @@ -0,0 +1,247 @@ +SampleBinding Example +*********************** + +The example showcases how you can generate CPython-based binding code for a +C++ library using Shiboken. The C++ library is called Universe, +with two classes: Icecream and Truck. Icecreams are characterized +by their flavor, and Truck serves as a vehicle of Icecream distribution for +kids in a neighborhood. + +First, let's look at the definition of the two classes: +.. code-block:: + :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; + }; + +and then truck.h: +.. code-block:: c++ + :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 is a summary of what the Universe library includes: + +* The Icecream polymorphic type, which is intended to be overridden. +* The getFlavor() method returns the flavor depending on the actual derived + type. +* The Truck value type that contains owned pointers, hence the copy + constructor. +* Truck stores the Icecream objects in a vector, which can be modified via + addIcecreamFlavor(). +* The Truck’s arrival message can be customized using setArrivalMessage(). +* The deliver() method tells us if the ice cream delivery was successful. + +Shiboken typesystem +==================== + +Now that the library definitions are in place, Shiboken generator needs a header +file that includes the types we are interested in: + +.. code-block:: c + :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:: + :caption: bindings.xml + + + + + + + + + + + + + + + + + + + + + +The first important thing to notice here is that we declare "bool" and +"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. +It can then 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 cannot magically know who is responsible for freeing the C++ objects +allocated in the Python code. It can guess, but it’s not always correct. There +can be cases where Python should release the C++ memory when the ref count +of the Python object becomes zero. It should never delete the C++ object assuming +that it will not be deleted by the C++ library or maybe it’s 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 Truck owns the Icecream +object, and will remove it once the 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. + +Building +========= + +To build the Universe custom library and then generate bindings for it, use +the :file:`CMakeLists.txt` file provided with the example. You can reuse the +file for your own libraries with minor changes. + +Now, run the command :command:`cmake .` from the prompt to configure the +project and build with the toolchain of your choice (we recommend the +‘(N)Makefiles’ generator though). + +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 that can be +imported in your Python script. + +Refer to the :file:`README.md` file for more details about the Windows-specific +build instructions. + +Using the Python module +======================== + +The following script uses the Universe module, derives a few types from +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 Universe module, it derives two types from +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 truck is created with the old flavors copied over, +and a new *magical* flavor that will surely satisfy all customers. + +The script above shows how to derive from C++ types, override virtual methods, +create and destroy objects, and more. Try running it to see if the ice creams +are delivered. + +.. note:: + You can find the sources for this example under + :file:`/site-packages/lib/PySide2/examples/samplebinding`. + +Refer to the following topics for detailed information about using Shiboken: + * :doc:`Shiboken module ` + * :doc:`Type System Variables ` + * :doc:`User Defined Type Conversion ` + * :doc:`Object ownership ` + * :doc:`Frequently Asked Questions ` -- cgit v1.2.3