[Interest] My first Shiboken6-based C++ lib bindings
Filippo Rusconi
listes.rusconi at laposte.net
Mon Nov 21 17:59:40 CET 2022
Greetings,
in my desperate :-) quest for a flexible solution to provide scripting to my
Qt6-based C++ project, I am now contemplating Python also. I had tried months
ago to build PySide on my Debian box, but never succeeded.
I tried now again (see [ Procedure ] below) and I can actually build the
shiboken6 generator:
% lls pyside6/pyside-setup/build/testenv/build/shiboken6/generator/shiboken6
-rwxr-xr-x 1 rusconi rusconi 2856416 Nov 17 16:08 pyside6/pyside-setup/build/testenv/build/shiboken6/generator/shiboken6
That was a wonderful start!
And then, I couldn't believe it :-)
--- Build completed (1167s)
(Note that the build fails with CMake but is sucessful with SetupTools -- as
described in an issue that I posted some days ago)
I could run the tetrix.py program (although the doc is erroneous on the location
of the file).
So, now that I actually could build PySide6, comes the actual work.
1. I could build and use the scriptableapplication example.
2. I "transferred" the samplebinding example to my use case, that I describe
below:
The library (Qt6-based) for which I want to develop bindings is named
libpappsomspp and is entirely contained in the "pappso" namespace.
I decided to start with the most simple component: the pappso::DataPoint struct.
The datapoint.h file contains omitted QDataStream stuff, which requires Qt6Core.
namespace pappso
{
struct PMSPP_LIB_DECL DataPoint
{
pappso_double x = -1;
pappso_double y = 0;
DataPoint();
DataPoint(const DataPoint &other);
DataPoint(pappso_double x, pappso_double y);
DataPoint(std::pair<pappso_double, pappso_double> pair);
DataPoint(const QString &text);
// For debugging purposes.
//~DataPoint();
DataPointCstSPtr makeDataPointCstSPtr() const;
void initialize(pappso_double x, pappso_double y);
void initialize(const DataPoint &other);
bool initialize(const QString &text);
void reset();
void incrementX(pappso_double value);
void incrementY(pappso_double value);
bool operator==(const DataPoint &other) const;
DataPoint &operator=(const DataPoint &other);
bool isValid() const;
QString toString() const;
QString toString(int decimals) const;
};
} // namespace pappso
that implements just this: (x,y).
The typesystem file (copied and modified from the sample binding example) is:
<?xml version="1.0"?>
<typesystem package="PyPappsomspp">
<primitive-type name="bool"/>
<primitive-type name="std::string"/>
<load-typesystem name="typesystem_core.xml" generate="no"/>
<namespace-type name="pappso">
<object-type name="DataPoint">
</object-type>
</namespace-type>
</typesystem>
The project builds, but I have to problems, a series of build warnings and the
fact that upon loading of the generated Python module in Python there is a
missing reference.
First the build warnings:
-------------------------
[ 98%] Building CXX object pybind/CMakeFiles/PyPappsomspp.dir/PyPappsomspp/pypappsomspp_module_wrapper.cpp.o
cd /home/rusconi/devel/pappsomspp/build-area/unix/pybind && /usr/lib/ccache/c++ -DPyPappsomspp_EXPORTS -DQT_CORE_LIB -DQT_NO_DEBUG -DQT_NO_DEBUG_OUTPUT -DQT_NO_KEYWORDS -I/home/rusconi/devel/pappsomspp/build-area/unix -I/home/rusconi/devel/pappsomspp/development -I/home/rusconi/devel/pappsomspp/development/src/pappsomspp -I/usr/include/python3.10 -I/home/rusconi/devel/small-pyside6/lib/python3.10/site-packages/shiboken6_generator/include -I/home/rusconi/devel/small-pyside6/lib/python3.10/site-packages/PySide6/include -I/home/rusconi/devel/small-pyside6/lib/python3.10/site-packages/PySide6/include/QtCore -isystem /usr/include/x86_64-linux-gnu/qt6/QtCore -isystem /usr/include/x86_64-linux-gnu/qt6 -isystem /usr/lib/x86_64-linux-gnu/qt6/mkspecs/linux-g++ -O3 -DNDEBUG -fPIC -Wno-unknown-pragmas -Wall -Wextra -fPIC -fPIC -std=gnu++17 -MD -MT pybind/CMakeFiles/PyPappsomspp.dir/PyPappsomspp/pypappsomspp_module_wrapper.cpp.o -MF CMakeFiles/PyPappsomspp.dir/PyPappsomspp/pypappsomspp_module_wrapper.cpp.o.d -o CMakeFiles/PyPappsomspp.dir/PyPappsomspp/pypappsomspp_module_wrapper.cpp.o -c /home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:22:1: warning: missing initializer for member ‘PyMethodDef::ml_meth’ [-Wmissing-field-initializers]
22 | };
| ^
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:22:1: warning: missing initializer for member ‘PyMethodDef::ml_flags’ [-Wmissing-field-initializers]
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:22:1: warning: missing initializer for member ‘PyMethodDef::ml_doc’ [-Wmissing-field-initializers]
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:116:15: warning: cast between incompatible function types from ‘PyObject* (*)(PyObject*)’ {aka ‘_object* (*)(_object*)’} to ‘PyCFunction’ {aka ‘_object* (*)(_object*, _object*)’} [-Wcast-function-type]
116 | {"clear", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::clear), METH_NOARGS, "clear"},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:117:18: warning: cast between incompatible function types from ‘PyObject* (*)(PyObject*)’ {aka ‘_object* (*)(_object*)’} to ‘PyCFunction’ {aka ‘_object* (*)(_object*, _object*)’} [-Wcast-function-type]
117 | {"pop_back", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::pop_back), METH_NOARGS, "pop_back"},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:118:20: warning: cast between incompatible function types from ‘PyObject* (*)(PyObject*)’ {aka ‘_object* (*)(_object*)’} to ‘PyCFunction’ {aka ‘_object* (*)(_object*, _object*)’} [-Wcast-function-type]
118 | {"removeLast", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::pop_back), METH_NOARGS, "removeLast"},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:121:19: warning: cast between incompatible function types from ‘PyObject* (*)(PyObject*)’ {aka ‘_object* (*)(_object*)’} to ‘PyCFunction’ {aka ‘_object* (*)(_object*, _object*)’} [-Wcast-function-type]
121 | {"pop_front", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::pop_front), METH_NOARGS, "pop_front"},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:122:21: warning: cast between incompatible function types from ‘PyObject* (*)(PyObject*)’ {aka ‘_object* (*)(_object*)’} to ‘PyCFunction’ {aka ‘_object* (*)(_object*, _object*)’} [-Wcast-function-type]
122 | {"removeFirst", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::pop_front), METH_O, "removeFirst"},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:124:18: warning: cast between incompatible function types from ‘PyObject* (*)(PyObject*)’ {aka ‘_object* (*)(_object*)’} to ‘PyCFunction’ {aka ‘_object* (*)(_object*, _object*)’} [-Wcast-function-type]
124 | {"capacity", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::capacity), METH_NOARGS, "capacity"},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:125:14: warning: cast between incompatible function types from ‘PyObject* (*)(PyObject*)’ {aka ‘_object* (*)(_object*)’} to ‘PyCFunction’ {aka ‘_object* (*)(_object*, _object*)’} [-Wcast-function-type]
125 | {"data", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::data), METH_NOARGS, "data"},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/rusconi/devel/pappsomspp/build-area/unix/pybind/PyPappsomspp/pypappsomspp_module_wrapper.cpp:126:19: warning: cast between incompatible function types from ‘PyObject* (*)(PyObject*)’ {aka ‘_object* (*)(_object*)’} to ‘PyCFunction’ {aka ‘_object* (*)(_object*, _object*)’} [-Wcast-function-type]
126 | {"constData", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::constData), METH_NOARGS, "constData"},
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These warnings seem related to this generated code:
pypappsomspp_module_wrapper.cpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
static PyMethodDef QIntList_methods[] = {
{"push_back", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::push_back), METH_O, "push_back"},
{"append", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::push_back), METH_O, "append"},
{"clear", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::clear), METH_NOARGS, "clear"},
{"pop_back", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::pop_back), METH_NOARGS, "pop_back"},
{"removeLast", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::pop_back), METH_NOARGS, "removeLast"},
{"push_front", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::push_front), METH_O, "push_front"},
{"prepend", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::push_front), METH_O, "prepend"},
{"pop_front", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::pop_front), METH_NOARGS, "pop_front"},
{"removeFirst", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::pop_front), METH_O, "removeFirst"},
{"reserve", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::reserve), METH_O, "reserve"},
{"capacity", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::capacity), METH_NOARGS, "capacity"},
{"data", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::data), METH_NOARGS, "data"},
{"constData", reinterpret_cast<PyCFunction>(ShibokenSequenceContainerPrivate<QList<int >>::constData), METH_NOARGS, "constData"},
{nullptr, nullptr, 0, nullptr} // Sentinel
};
Given my total newbie'ness in the field, I cannot tell if these warnings are
serious or not (not even what they actually mean).
Now, for the import error:
I chdir to the directory where the module library PyPappsomspp.so is generated
and I start a python interpreter. When I try to import the module, like this:
(ins)>>> import PyPappsomspp
I get the following error:
ImportError: <dir>/PyPappsomspp.so: undefined symbol: _Z35init_PyPappsomspppappsoStaticFieldsv
Demangled, this yields function: init_PyPappsomspppappsoStaticFields()
I suspect that this function name can be deconstructed like so:
init_<PythonModuleName><namespace>StaticFields().
Has anyone an idea of what error I am doing here or any idea how to explore
where that error and the compilation warnings come from? I feel like I am not
very far from heaven here :-)
Thanks for reading!
Sincerely,
Filippo
--
⢀⣴⠾⠻⢶⣦⠀ Filippo Rusconi, PhD
⣾⠁⢠⠒⠀⣿⡁ Research scientist at CNRS
⢿⡄⠘⠷⠚⠋⠀ Debian Developer
⠈⠳⣄⠀⠀⠀⠀ http://msxpertsuite.org
http://www.debian.org
More information about the Interest
mailing list