I’m trying to build a DLL for Python, which uses Qt5 libraries; the below example defines a function, and mostly everything works – except I cannot make the method QString::toLocal8Bit available to Python.
My platform info:
$ for ic in "$(cmd //c ver)" "uname -s" "python3 --version" "g++ --version"; do echo "$ic:" $(echo "$(${ic})" | head -1); done 2>/dev/null
Microsoft Windows [Version 10.0.19045.4355]:
uname -s: MINGW64_NT-10.0-19045
python3 --version: Python 3.11.9
g++ --version: g++.exe (Rev6, Built by MSYS2 project) 13.2.0
$ python3 -c 'from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR; print("Qt: v", QT_VERSION_STR, "tPyQt: v", PYQT_VERSION_STR)'
Qt: v 5.15.12 PyQt: v 5.15.10
Here is QtTestLib.cpp
#include <pybind11/pybind11.h> // pacman -S mingw-w64-x86_64-pybind11
#include <QStringList>
#include <iostream>
QString myStringTesterFunc(const QString &inString, bool specProcess)
{
QString ret_str = "Result: ";
ret_str.append(QString("%1").arg(inString));
ret_str.append(QString("%1").arg(" - "));
if (specProcess)
{
ret_str.append(QString("%1").arg("Special"));
}
else
{
ret_str.append(QString("%1").arg("Regular"));
}
return ret_str;
}
namespace py = pybind11;
// "The module name (example) is given as the first macro argument (it should not be in quotes)."
PYBIND11_MODULE(QtTestLib, m) {
m.doc() = "pybind11 example module (myStringTesterFunc)"; // optional module docstring
m.def("myStringTesterFunc", &myStringTesterFunc, "A function that tests QString");
py::class_<QString>(m, "QString")
.def(py::init<const char*>())
//.def("toLocal8Bit", &QString::toLocal8Bit)
;
}
Compile with:
g++ -g -Wall -Wextra -O -pedantic -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) QtTestLib.cpp -o QtTestLib$(python3-config --extension-suffix) -I/mingw64/include/QtCore -I/mingw64/include/python3.11 $(python3-config --ldflags) /mingw64/bin/Qt5Core.dll $(python3-config --libs)
This compiles fine, for me a QtTestLib.cp311-mingw_x86_64.pyd
file gets generated.
And here is QtTestLib.py
:
import QtTestLib
print(QtTestLib.myStringTesterFunc)
print(QtTestLib.QString)
qstringret = QtTestLib.myStringTesterFunc(QtTestLib.QString("Hello world"), True)
print(qstringret)
print(qstringret.toLocal8Bit())
And when I run the Python script, I get:
$ python3 QtTestLib.py
<built-in method myStringTesterFunc of PyCapsule object at 0x000001fbd1539d70>
<class 'QtTestLib.QString'>
<QtTestLib.QString object at 0x000001fbd15818b0>
Traceback (most recent call last):
File "C:/msys64/tmp/QtTestLib.py", line 18, in <module>
print(qstringret.toLocal8Bit())
^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'QtTestLib.QString' object has no attribute 'toLocal8Bit'
We can see there is a returned object; however the .cpp code as posted does not “export” toLocal8Bit, so no surprise Python sees “object has no attribute”.
So now, uncomment this line in the .cpp code:
.def("toLocal8Bit", &QString::toLocal8Bit)
and try to recompile with g++ again — I get:
$ g++ -g -Wall -Wextra -O -pedantic -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) QtTestLib.cpp -o QtTestLib$(python3-config --extension-suffix) -I/mingw64/include/QtCore -I/mingw64/include/python3.11 $(python3-config --ldflags) /mingw64/bin/Qt5Core.dll $(python3-config --libs)
QtTestLib.cpp: In function 'void pybind11_init_QtTestLib(pybind11::module_&)':
QtTestLib.cpp:54:9: error: no matching function for call to 'pybind11::class_<QString>::def(const char [12], <unresolved overloaded function type>)'
52 | py::class_<QString>(m, "QString")
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 | .def(py::init<const char*>())
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 | .def("toLocal8Bit", &QString::toLocal8Bit)
| ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from QtTestLib.cpp:21:
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1574:13: note: candidate: 'template<class Func, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::de (const char*, Func&&, const Extra& ...) [with Extra = Func; type_ = QString; options = {}]'
1574 | class_ &def(const char *name_, Func &&f, const Extra &...extra) {
| ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1574:13: note: template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note: couldn't deduce template parameter 'Func'
52 | py::class_<QString>(m, "QString")
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 | .def(py::init<const char*>())
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 | .def("toLocal8Bit", &QString::toLocal8Bit)
| ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1599:13: note: candidate: 'template<class T, class ... Extra, typename stC::enable_if<T::op_enable_if_hook, int>::type <anonymous> > pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const T&, const Extra& ...) [with Extra = T; typename stC::enable_if<T::op_enable_if_hook, int>::type <anonymous> = {Extra ...}; type_ = QString; options = {}]'
1599 | class_ &def(const T &op, const Extra &...extra) {
| ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1599:13: note: template argument deduction/substitution faileC:
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1598:95: error: 'op_enable_if_hook' is not a member of 'char [12]'
1598 | template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0>
| ^
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1611:13: note: candidate: 'template<class ... Args, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const pybind11::detail::initimpl::constructor<Args ...>&, const Extra& ...) [with Args = {Args ...}; Extra = {Extra ...}; type_ = QString; options = {}]'
1611 | class_ &def(const detail::initimpl::constructor<Args...> &init, const Extra &...extra) {
| ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1611:13: note: template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note: mismatched types 'const pybind11::detail::initimpl::constructor<Args ...>' and 'const char [12]'
52 | py::class_<QString>(m, "QString")
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 | .def(py::init<const char*>())
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 | .def("toLocal8Bit", &QString::toLocal8Bit)
| ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1618:13: note: candidate: 'template<class ... Args, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const pybind11::detail::initimpl::alias_constructor<Args ...>&, const Extra& ...) [with Args = {Args ...}; Extra = {Extra ...}; type_ = QString; options = {}]'
1618 | class_ &def(const detail::initimpl::alias_constructor<Args...> &init, const Extra &...extra) {
| ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1618:13: note: template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note: mismatched types 'const pybind11::detail::initimpl::alias_constructor<Args ...>' and 'const char [12]'
52 | py::class_<QString>(m, "QString")
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 | .def(py::init<const char*>())
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 | .def("toLocal8Bit", &QString::toLocal8Bit)
| ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1625:13: note: candidate: 'template<class ... Args, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(pybind11::detail::initimpl::factory<Args ...>&&, const Extra& ...) [with Args = {Args ...}; Extra = {Extra ...}; type_ = QString; options = {}]'
1625 | class_ &def(detail::initimpl::factory<Args...> &&init, const Extra &...extra) {
| ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1625:13: note: template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note: mismatched types 'pybind11::detail::initimpl::factory<Args ...>' and 'const char [12]'
52 | py::class_<QString>(m, "QString")
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 | .def(py::init<const char*>())
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 | .def("toLocal8Bit", &QString::toLocal8Bit)
| ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1631:13: note: candidate: 'template<class ... Args, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(pybind11::detail::initimpl::pickle_factory<Args ...>&&, const Extra& ...) [with Args = {Args ...}; Extra = {Extra ...}; type_ = QString; options = {}]'
1631 | class_ &def(detail::initimpl::pickle_factory<Args...> &&pf, const Extra &...extra) {
| ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1631:13: note: template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note: mismatched types 'pybind11::detail::initimpl::pickle_factory<Args ...>' and 'const char [12]'
52 | py::class_<QString>(m, "QString")
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53 | .def(py::init<const char*>())
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54 | .def("toLocal8Bit", &QString::toLocal8Bit)
| ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, why does this error occur, and how can I fix it, so I have QString.toLocal8Bit available in Python?