aboutsummaryrefslogtreecommitdiffstats
path: root/examples/samplebinding/doc
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-12-07 15:21:37 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2021-12-08 12:12:16 +0100
commitf029a27152cf7c7a741ce03a6f91be71729093ca (patch)
tree06fab915acc36e5598f3b6469706a03d16453d0a /examples/samplebinding/doc
parentf3972822d254ad20b8e9582f89fe8e30ce931f5c (diff)
Document the scriptableapplication, samplebinding examples
Add a dummy .pyproject file into the doc directory for the example gallery script to collect it. Convert the .md files to .rst files for the documentation. Pick-to: 6.2 Change-Id: I87ea5b980d3d2177a7851f71462ca0b0bd0eba7e Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'examples/samplebinding/doc')
-rw-r--r--examples/samplebinding/doc/samplebinding.pyproject10
-rw-r--r--examples/samplebinding/doc/samplebinding.rst273
2 files changed, 283 insertions, 0 deletions
diff --git a/examples/samplebinding/doc/samplebinding.pyproject b/examples/samplebinding/doc/samplebinding.pyproject
new file mode 100644
index 000000000..82c485a09
--- /dev/null
+++ b/examples/samplebinding/doc/samplebinding.pyproject
@@ -0,0 +1,10 @@
+{
+ "files": ["../bindings.h",
+ "../icecream.cpp",
+ "../icecream.h",
+ "../macros.h",
+ "../main.py",
+ "../truck.cpp",
+ "../truck.h",
+ "../CMakeLists.txt"]
+}
diff --git a/examples/samplebinding/doc/samplebinding.rst b/examples/samplebinding/doc/samplebinding.rst
new file mode 100644
index 000000000..af2e917dc
--- /dev/null
+++ b/examples/samplebinding/doc/samplebinding.rst
@@ -0,0 +1,273 @@
+Sample Bindings Example
+=======================
+
+This example showcases how to generate Python bindings for a
+non-Qt C++ library.
+
+The example defines a CMake project that builds two libraries:
+
+* ``libuniverse`` - a sample library with two C++ classes.
+
+* ``Universe`` - the generated Python extension module that contains
+ bindings to the library above.
+
+The project file is structured in such a way that a user can copy-paste
+in into their own project, and be able to build it with a minimal amount
+of modifications.
+
+Description
++++++++++++
+
+The libuniverse library declares two classes: ``Icecream`` and ``Truck``.
+
+``Icecream`` objects have a flavor, and an accessor for returning the
+flavor.
+
+``Truck`` instances store a vector of ``Icecream`` objects, and have various
+methods for adding new flavors, printing available flavors, delivering
+icecream, etc.
+
+From a C++ perspective, ``Icecream`` instances are treated as
+*object types* (pointer semantics) because the class declares virtual
+methods.
+
+In contrast ``Truck`` does not define virtual methods and is treated as
+a *value type* (copy semantics).
+
+Because ``Truck`` is a value type and it stores a vector of ``Icecream``
+pointers, the rule of three has to be taken into account (implement the
+copy constructor, assignment operator, destructor).
+
+And due to ``Icecream`` objects being copyable, the type has to define an
+implementation of the ``clone()`` method, to avoid type slicing issues.
+
+Both of these types and their methods will be exposed to Python by
+generating CPython code. The code is generated by ``shiboken`` and
+placed in separate ``.cpp`` files named after each C++ type. The code is
+then compiled and linked into a shared library. The shared library is a
+CPython extension module, which is loaded by the Python interpreter.
+
+Beacuse the C++ language has different semantics to Python, shiboken
+needs help in figuring out how to generate the bindings code. This is
+done by specifying a special XML file called a typesystem file.
+
+In the typesystem file you specify things like:
+
+ * which C++ primitive types should have bindings (int, bool, float)
+
+ * which C++ classes should have bindings (Icecream) and what kind of
+ semantics (value / object)
+
+ * Ownership rules (who deletes the C++ objects, C++ or Python)
+
+ * Code injection (for various special cases that shiboken doesn't know
+ about)
+
+ * Package name (name of package as imported from Python)
+
+In this example we declare ``bool`` and ``std::string`` as primitive types,
+``Icecream`` as an object type, ``Truck`` as a value type,
+and the ``clone()`` and ``addIcecreamFlavor(Icecream*)`` need additional
+info about who owns the parameter objects when passing them across
+language boundaries (in this case C++ will delete the objects).
+
+The ``Truck`` has getters and setters for the string ``arrivalMessage``.
+In the type system file, we declare this to be a property in Python:
+
+.. code-block:: xml
+
+ <property type="std::string" name="arrivalMessage" get="getArrivalMessage" set="setArrivalMessage"/>
+
+
+It can then be used in a more pythonic way:
+
+.. code-block:: python
+
+ special_truck.arrivalMessage = "A new SPECIAL icecream truck has arrived!\n"
+
+After shiboken generates the C++ code and CMake makes an extension
+module from the code, the types can be accessed in Python simply by
+importing them using the original C++ names.
+
+.. code-block:: python
+
+ from Universe import Icecream, Truck
+
+
+Constructing C++ wrapped objects is the same as in Python
+
+.. code-block:: python
+
+ icecream = Icecream("vanilla")
+ truck = Truck()
+
+
+And actual C++ constructors are mapped to the Python `__init__` method.
+
+.. code-block:: python
+
+ class VanillaChocolateIcecream(Icecream):
+ def __init__(self, flavor=""):
+ super().__init__(flavor)
+
+
+C++ methods can be accessed as regular Python methods using the C++
+names
+
+.. code-block:: python
+
+ truck.addIcecreamFlavor(icecream)
+
+Inheritance works as with regular Python classes, and virtual C++
+methods can be overridden simply by definining a method with the same
+name as in the C++ class.
+
+.. code-block:: python
+
+ class VanillaChocolateIcecream(Icecream):
+ # ...
+ def getFlavor(self):
+ return "vanilla sprinked with chocolate"
+
+
+The ``main.py`` script demonstrates usages of these types.
+
+The CMake project file contains many comments explaining all the build
+rules for those interested in the build process.
+
+Building the project
+++++++++++++++++++++
+
+This example can only be built using ``CMake``.
+The following requirements need to be met:
+
+* A PySide package is installed into the current active Python
+ environment (system or virtualenv)
+
+* A new enough version of CMake (3.1+).
+
+* ninja
+
+For Windows you will also need:
+
+* a Visual Studio environment to be active in your terminal
+
+* Correct visual studio architecture chosen (32 vs 64 bit)
+
+* Make sure that your Python intepreter and bindings project build
+ configuration is the same (all Release, which is more likely,
+ or all Debug).
+
+The build uses the ``pyside_config.py`` file to configure the project
+using the current PySide/Shiboken installation.
+
+Using CMake
+===========
+
+You can build and run this example by executing the following commands
+(slightly adapted to your file system layout) in a terminal:
+
+macOS/Linux:
+
+.. code-block:: bash
+
+ cd ~/pyside-setup/examples/samplebinding
+
+On Windows:
+
+.. code-block:: bash
+
+ cd C:\pyside-setup\examples\samplebinding
+
+.. code-block:: bash
+
+ mkdir build
+ cd build
+ mkdir build
+ cd build
+ cmake -H.. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release
+ ninja
+ ninja install
+ cd ..
+
+The final example can then be run by:
+
+.. code-block:: bash
+
+ python main.py
+
+Windows troubleshooting
++++++++++++++++++++++++
+
+It is possible that ``CMake`` can pick up the wrong compiler
+for a different architecture, but it can be addressed explicitly
+by setting the ``CC`` environment variable:
+
+.. code-block:: bash
+
+ set CC=cl
+
+or by using the -G option:
+
+.. code-block:: bash
+
+ cmake -H.. -B. -G "Visual Studio 14 Win64"
+
+If the ``-G "Visual Studio 14 Win64"`` option is used, a ``sln`` file
+will be generated, and can be used with ``MSBuild``
+instead of ``nmake/jom``.
+The easiest way to both build and install in this case, is to use
+the cmake executable:
+
+.. code-block:: bash
+
+ cmake --build . --target install --config Release
+
+Note that using the ``"NMake Makefiles JOM"`` generator is preferred to
+the MSBuild one, because the MSBuild one generates configs for both
+Debug and Release, and this might lead to building errors if you
+accidentally build the wrong config at least once.
+
+Virtualenv Support
+++++++++++++++++++
+
+If the python application is started from a terminal with an activated
+python virtual environment, that environment's packages will be used for
+the python module import process.
+In this case, make sure that the bindings were built while the
+``virtualenv`` was active, so that the build system picks up the correct
+python shared library and PySide6 / shiboken package.
+
+Linux Shared Libraries Notes
+++++++++++++++++++++++++++++
+
+For this example's purpose, we link against the absolute path of the
+dependent shared library ``libshiboken`` because the
+installation of the library is done via a wheel, and there is
+no clean solution to include symbolic links in a wheel package
+(so that passing -lshiboken to the linker would work).
+
+Windows Notes
++++++++++++++
+
+The build config of the bindings (Debug or Release) should match
+the PySide build config, otherwise the application will not properly
+work.
+
+In practice this means the only supported configurations are:
+
+#. release config build of the bindings +
+ PySide ``setup.py`` without ``--debug`` flag + ``python.exe`` for the
+ PySide build process + ``python36.dll`` for the linked in shared
+ library.
+
+#. debug config build of the application +
+ PySide ``setup.py`` *with* ``--debug`` flag + ``python_d.exe`` for the
+ PySide build process + ``python36_d.dll`` for the linked in shared
+ library.
+
+This is necessary because all the shared libraries in question have to
+link to the same C++ runtime library (``msvcrt.dll`` or ``msvcrtd.dll``).
+To make the example as self-contained as possible, the shared libraries
+in use (``pyside6.dll``, ``shiboken6.dll``) are hard-linked into the build
+folder of the application.