Embedding Python3 in Qt 5 - python

I would like to embed Python interpreter 3.4 into a Qt 5.2.1 application (64-bit).
However I'm having build issues, I mean when I include Python header in the main.cpp it compiles fine.
#include <python.h>
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
but when I put it anywhere else (after Qt headers)
//
// embedpytest.cpp
//
#include <QLibrary>
#include <python.h>
EmbedPyTest::EmbedPyTest()
{
}
I get compile errors:
C:\Python34\include\object.h:435: error: C2059: syntax error : ';'
C:\Python34\include\object.h:435: error: C2238: unexpected token(s) preceding ';'
It's very similar problem to this one, but the solution is not working
Embedding Python in Qt 5
Anyone knows how to solve this issue ? or suggest some clean workaround so that python.h and Qt5
can live together happily ever after ?

Another way to avoid the conflict regarding 'slots', without the need for deactivating the keywords signals/slots/emit (which may be undesirable for large Qt projects), is to locally "park" the offending keyword while Python.h is included, and then reassign it. To achieve this, replace every occurrence of #include "Python.h" by the following block:
#pragma push_macro("slots")
#undef slots
#include "Python.h"
#pragma pop_macro("slots")
Or, more conveniently, put the above code in its own header, e.g. Python_wrapper.h, and replace all occurrences of #include "Python.h" by #include "Python_wrapper.h".

The offending line is this:
PyType_Slot *slots; /* terminated by slot==0. */
The problem is that with this line, "slots" is a keyword by default in Qt. In order to use that variable name in other projects, you will need to use this in your project file:
CONFIG += no_keywords
For details, see the documentation:
Using Qt with 3rd Party Signals and Slots
It is possible to use Qt with a 3rd party signal/slot mechanism. You can even use both mechanisms in the same project. Just add the following line to your qmake project (.pro) file.
CONFIG += no_keywords
It tells Qt not to define the moc keywords signals, slots, and emit, because these names will be used by a 3rd party library, e.g. Boost. Then to continue using Qt signals and slots with the no_keywords flag, simply replace all uses of the Qt moc keywords in your sources with the corresponding Qt macros Q_SIGNALS (or Q_SIGNAL), Q_SLOTS (or Q_SLOT), and Q_EMIT.

Related

Recursive Include of Python.h causing compilation error [duplicate]

I would like to embed Python interpreter 3.4 into a Qt 5.2.1 application (64-bit).
However I'm having build issues, I mean when I include Python header in the main.cpp it compiles fine.
#include <python.h>
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
but when I put it anywhere else (after Qt headers)
//
// embedpytest.cpp
//
#include <QLibrary>
#include <python.h>
EmbedPyTest::EmbedPyTest()
{
}
I get compile errors:
C:\Python34\include\object.h:435: error: C2059: syntax error : ';'
C:\Python34\include\object.h:435: error: C2238: unexpected token(s) preceding ';'
It's very similar problem to this one, but the solution is not working
Embedding Python in Qt 5
Anyone knows how to solve this issue ? or suggest some clean workaround so that python.h and Qt5
can live together happily ever after ?
Another way to avoid the conflict regarding 'slots', without the need for deactivating the keywords signals/slots/emit (which may be undesirable for large Qt projects), is to locally "park" the offending keyword while Python.h is included, and then reassign it. To achieve this, replace every occurrence of #include "Python.h" by the following block:
#pragma push_macro("slots")
#undef slots
#include "Python.h"
#pragma pop_macro("slots")
Or, more conveniently, put the above code in its own header, e.g. Python_wrapper.h, and replace all occurrences of #include "Python.h" by #include "Python_wrapper.h".
The offending line is this:
PyType_Slot *slots; /* terminated by slot==0. */
The problem is that with this line, "slots" is a keyword by default in Qt. In order to use that variable name in other projects, you will need to use this in your project file:
CONFIG += no_keywords
For details, see the documentation:
Using Qt with 3rd Party Signals and Slots
It is possible to use Qt with a 3rd party signal/slot mechanism. You can even use both mechanisms in the same project. Just add the following line to your qmake project (.pro) file.
CONFIG += no_keywords
It tells Qt not to define the moc keywords signals, slots, and emit, because these names will be used by a 3rd party library, e.g. Boost. Then to continue using Qt signals and slots with the no_keywords flag, simply replace all uses of the Qt moc keywords in your sources with the corresponding Qt macros Q_SIGNALS (or Q_SIGNAL), Q_SLOTS (or Q_SLOT), and Q_EMIT.

The correct CMakeLists.txt file to call a MAXON libarary in a Python script using pybind11

I'm very new to the whole CMake. Following this and this posts, now I want to call a MAXON function inside Python, using pybind11. What I have done so far:
The library can be downloaded from this page (direct download link).
wget https://www.maxongroup.com/medias/sys_master/root/8837358518302/EPOS-Linux-Library-En.zip
unzip:
unzip EPOS-Linux-Library-En.zip
make the install shell script executable and run it:
chmod +x ./install.sh
sudo ./install.sh
Then going to the example folder:
cd /opt/EposCmdLib_6.6.1.0/examples/HelloEposCmd/
Now combining the CMakeLists.txt files from here:
# CMakeLists.txt
cmake_minimum_required(VERSION 2.8.12)
project (HelloEposCmd)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
find_package(pybind11 REQUIRED)
pybind11_add_module(${PROJECT_NAME} HelloEposCmd.cpp)
add_executable(${PROJECT_NAME} HelloEposCmd.cpp)
target_link_libraries(${PROJECT_NAME} -lEposCmd)
and the HelloEposCmd.cpp this line is added right after other header files:
#include <pybind11/pybind11.h>
the main function is renamed to:
int run(int argc, char** argv)
and the pybind11 syntax to add the module is written at the end:
PYBIND11_MODULE(HelloEposCmd, m) {
m.def("run", &run, "runs the HelloEposCmd");
}
However, When I run the cmake . I get the error:
CMake Error at CMakeLists.txt:13 (add_executable):
add_executable can not create target "HelloEposCmd" because another target with the same name already exists. The existing target is a module library created in source directory "/opt/EposCmdLib_6.6.1.0/examples/HelloEposCmd" See documentation for policy CMP0002 for more details.
...
I was wondering if you could be kind to help me get the right CMakeList.txt file. Ideally, I should be able to call the compiled module in python:
# HelloEposCmd.py
import HelloEposCmd
HelloEposCmd.run()
Thanks for your support in advance.
pybind11_add_module already creates a target for you. So you don't need add_executable anymore. Just remove that line and when you will build you will get a library with the name HelloEposCmd
add_executable is needed if you are building an executable (.exe), which I believe is not what you want.
Documenation of pybind11 says.
This function behaves very much like CMake’s builtin add_library (in fact, it’s a wrapper function around that command).
Thanks to abhilb post and his kind followup in the comments I was able to figure the problem out. well, at least find a temporary workaround:
According to this post, the last two lines of the CMakeLists.txt file should change to
# this line can be removed
# add_executable(${PROJECT_NAME} HelloEposCmd.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE -lEposCmd)
and then because according to this post pybind11 doesn't support double pointers we change the run function to:
int run() {
int argc = 1;
char* argv[] = {"./HelloEposCmd"};
...
}
which I suppose to be a horrible workaround (inspired by information from this page). Now running cmake ., make and python3 HelloEposCmd.py should work properly (except a small c++ warning!).
P.S.1. Maybe someone could use std::vector<std::string> as suggested here. This idea was proposed here and there are already some answers worth investigating.
P.S.2. Following this discussion, another workaround could be something like:
#include <stdio.h>
#include <stdlib.h>
void myFunc(int argc, char* argv[]) {
for (int i = 0; i < argc; ++i) {
printf("%s\n", argv[i]);
}
}
int run(int argc, long* argv_) {
char** argv = (char**)malloc(argc * sizeof(char*));
for (int i = 0; i < argc; ++i) {
argv[i] = (char*)(argv_[i]);
}
myFunc(argc, argv);
free(argv);
return 0;
}

Python newbie: old C++ code for interfacing with Python uses deprecated boost/python/numeric.hpp instead of NumPy. How to update?

I'm using Python 2.7.10 on a Mac (10.12.6). Apologies in advance for any silly comments: I am a Python newbie and also am not that experienced with C++.
I need to compile an old C++-based code that interfaces with Python. A couple of the .cpp files use the deprecated "boost/python/numeric.hpp" as an include and for making arrays:
#include <boost/python/numeric.hpp>
const py::numeric::array& X
I have spent a couple of days now on trying to figure out how to deal with this, but just can't turn up any documentation that makes sense as a newbie. I would be very grateful if someone would please point me in the right direction. One thing I did come across was this post:
how to return numpy.array from boost::python?
where one suggestion involves using
#include <numpy/ndarrayobject.h>
However, I just cannot figure out how to use it to translate my old code.
Thank you for any help.
Edit in response to sehe:
The code is too large to post in its entirety, but the errors all seem to be related to:
#include <boost/python/numeric.hpp>
I'm pretty sure I need to use:
#include <numpy/ndarrayobject.h>
However, I can't figure out how to change the code that refers to the arrays.
This seems like such a simple thing, but I haven't been able to find any documentation. Below are specific examples of where the deprecated code is an issue (please let me know if I can make this more understandable)
In the main() file "PyMain.cpp":
// Include from Boost
#include <boost/python.hpp>
namespace py = boost::python;
// Other includes for the code PyCalculator
# XXX...
# XXX...
BOOST_PYTHON_MODULE(PyCalculator)
{
// Set numpy as the numeric::array engine
py::numeric::array::set_module_and_type("numpy", "ndarray");
XXX // (Other non-problematic code
}
Here's an example of another file, "Auxiliary .cpp"
The error shown in the terminal is:
PyAux.cpp: fatal error:
'boost/python/numeric.hpp' file not found
#include "PyAux.hpp"
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <Python.h>
#include <numpy/ndarrayobject.h>
// Boost includes
#include <boost/python.hpp>
#include <boost/python/numeric.hpp>
#include <boost/python/slice.hpp>
#include <boost/smart_ptr.hpp>
namespace py = boost::python;
// Other includes
#include <PyAux/Math/Other/Core>
namespace PyCalculator {
... XXX
// There are functions like:
static auto initializeWithArray(const py::numeric::array& array) -> boost::shared_ptr<VectorType>
{ //...XXX
const py::numeric::array& X
}
}
The solution is to comment out:
//#include <boost/python/numeric.hp
and replace it with:
#include <boost/python/numpy.hpp>

Wrapper DLL for Python: "fatal error LNK1127: library is corrupt"

Brief description
I have a DLL programmed in ADA with GNAT. I want to compile with MSVC another DLL in C as a wrapper to the ADA_DLL in order to use it with Python.
I have compiled the ada_DLL, then I have generated the .lib file according to gnat documentation about MSVC. And finally I tried to compile the C_DLL with Visual-Studio, getting the error:
libmath.lib : fatal error LNK1127: library is corrupt
Update: In the case of compiling with gcc as suggested by #Brian, I get the following output:
>"C:\GNAT\2015\bin\gcc.exe" -c -IC:\Python27\include -o libmath_c.o libmath_c.c
>"C:\GNAT\2015\bin\gcc.exe" -shared -LC:\Python27\libs -L./ -l libmath -o DIVISION_CPP.pyd libmath_c.o -lpython27
.//libmath.lib: error adding symbols: Malformed archive
collect2.exe: error: ld returned 1 exit status
Things I tried & more data:
I have tried importing the ADA_DLL directly with ctypes in Python and it works, so I believe that the ADA_DLL is correctly compiled. Also, forgetting about the C_DLL is not really an option.
I did a small example with a division example module. My .def file looks something like:
; dlltool -z libmath.def --export-all-symbols libmath.dll
EXPORTS
[...]
div # 259
[...]
The libmath_c.c:
#include "libmath_c.h"
PyObject* _wrap_DIVISION(PyObject *self, PyObject *args){
div(10, 2);
return Py_None;
}
__declspec(dllexport) void __cdecl initDIVISION_CPP(void){
Py_InitModule("DIVISION_CPP", LIB_METHODS_methods);
}
The libmath_c.h:
#include <windows.h>
#include <stdio.h>
#include <Python.h>
PyObject* _wrap_DIVISION(PyObject *self, PyObject *args);
static PyMethodDef LIB_METHODS_methods[] = {
{ "CPP_DIVISION", _wrap_DIVISION, METH_VARARGS },
{NULL, NULL, 0, NULL} //Added as indicated by #Brian. Thanks!
};
__declspec(dllexport) void __cdecl initDIVISION_CPP(void);
Any idea of what is happening? Any help would be really appreciated. Thanks!
Preamble: Apologies if this turns out to be a non-answer; I want to be able to come back to this and find the links again, and comments tend to rot...
First, gcc (in the version matching Gnat) may work as an alternative C compiler, and if it does, it may eliminate difficulties with incompatible library versions.
GCC can be used for building Windows DLLs so the result should be usable from other Windows executables.
Following comments; gcc does appear to allow compilation, but the result is not currently usable from Python - here, my Python knowledge is shallow, and we don't have an MCVE, so this is speculative:
This Q&A addresses the same error message between Python and pure C, with no Ada, suggesting this error may not be specific to C-wrapped Ada.
You have already bypassed the asker's specific error,
static PyMethodDef* _npfindmethods = { ... };
which was using a pointer; you are (correctly according to the answer) statically allocating an array. However, the accepted answer terminates the list of methods
static PyMethodDef _npfindmethods[] = {
{"add", py_add, METH_VARARGS, py_add_doc},
{NULL, NULL, 0, NULL}
};
with a NULL method; your example does not:
static PyMethodDef LIB_METHODS_methods[] = {
{ "CPP_DIVISION", _wrap_DIVISION, METH_VARARGS }
};
So my hypothesis is that when you run setup() on this module, it finds CPP_DIVISION successfully, then in the absence of a NULL method it runs off into the weeds, producing the same symptoms despite the difference in cause.
I could test this hypothesis using the MCVE in that question by deleting the NULL method; however I don't have a Windows system handy, only Linux.
Alternatively, I see no reason for a C layer. If there isn't one, this Q&A addresses direct interaction between Python and Ada with no C layer, though it appears to use a different method, getattr() to import the external method. Might be an alternative?
Finally I managed to compile with gcc+gnat but not with MSVC+gnat.
With gcc+gnat, I was getting .//libmath.lib: error adding symbols: Malformed archive. The solution consists on using libmath.dll instead of building the .lib from the .dll.
So, in summary:
If you have a .dll generated by gnat, use it with gcc. You don't need to build a .lib.
If you have a .lib (for example python27.lib) or a .dll not generated by gnat, convert it to a .a using a tool like "pexport" (DO NOT USE SED!).
If you really need to compile using the MSVC... I'm sorry, I could not manage to make it work. Your princess is in another castle.

How to prevent <Python.h> of Python 2.7 from including <inttypes.h> in a Python wrapper generated by SWIG?

I am developing a C++ library in which SWIG is used to generate its Python wrapper. Some of my C++ files use <inittypes.h> to call PRId64 and other macros in sprintf.
I was able to compile my library with Python 2.6 and GCC 4.4.7 on Scientific Linux 6 (RHEL6 clone), but Python 2.7 and GCC 4.8.2 on Scientific Linux 7 (RHEL7 clone) generated many errors like below.
/home/oxon/libTARGET/inc/target/T2EvalBoard.h:562:145: warning: too many arguments for format [-Wformat-extra-args]
In file included from /home/oxon/libTARGET_build/src/targetPYTHON_wrap.cxx:3117:0:
/home/oxon/libTARGET/inc/target/BaseCameraModule.h: In member function ‘virtual void TARGET::BaseCameraModule::ReceiveEvent(uint32_t&, uint8_t**)’:
/home/oxon/libTARGET/inc/target/BaseCameraModule.h:211:66: error: expected ‘)’ before ‘PRIu32’
sprintf(str, "Cannot read event data. Requested length is %" PRIu32 " bytes, but only %" PRId64 " bytes were read.", length, fBytesReturned);
I know that I have to add the following lines in header files first in order to use PRId64 and other.
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
But targetPYTHON_wrap.cxx, which is a source file generated by SWIG, includes <Python.h> in the beginning of the file, and so the above lines are ignored. Indeed, the following code cannot be compiled, because <Python.h> includes <inttypes.h> in it.
#include <Python.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>
int main()
{
printf("Output: " PRIu32 "\n", 100);
return 0;
}
How do I use PRId64 and other macros with <Python.h> and SWIG?
In SWIG, the following adds lines to the very top of the SWIG wrapper, so it will be defined before Python.h:
%begin %{
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
%}
I added -D__STDC_FORMAT_MACROS in CXX_FLAGS, but looking for a better solution if exists.

Categories