I want to start working on my own windows software. I know python and I am learning c++. How can I create windows software with the frontend written in c++ and the backend in python?
I know this is possible because blender is written in c++ and python aswell
You can embed Python into C++.
Documentation
The simplest form of embedding Python is the use of the very high level interface. This interface is intended to execute a Python script without needing to interact with the application directly. This can for example be used to perform some operation on a file.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
if (Py_FinalizeEx() < 0) {
exit(120);
}
PyMem_RawFree(program);
return 0;
}
Related
I have a problem with the functional feature of Pybind11 when I use it with a for-loop with OpenMP. I've done some research and my problem sounds pretty similar to the one in this Pull Request from 2 years ago, but although this PR is closed and the issue seems to be fixed I still have this issue. A code example I created will hopefully explain my problem better:
b.h
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <omp.h>
namespace py = pybind11;
class B {
public:
B(int n, const int& initial_value);
void map(const std::function<int(int)> &f);
private:
int n;
int* elements;
};
b.cpp
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include "b.h"
namespace py = pybind11;
B::B(int n, const int& v)
: n(n) {
elements = new int[n];
#pragma omp parallel for
for (int i = 0; i < n; i++) {
elements[i] = v;
}
}
void B::map(const std::function<int(int)> &f) {
#pragma omp parallel for
for (int i = 0; i < n; i++) {
elements[i] = f(elements[i]);
}
}
PYBIND11_MODULE(m, handle) {
handle.doc() = "Example Module";
py::class_<B>(handle, "B")
.def(py::init<int, int>())
.def("map", &B::map)
;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.4...3.18)
project(example)
find_package(OpenMP)
add_subdirectory(pybind11)
pybind11_add_module(m b.cpp)
if(OpenMP_CXX_FOUND)
target_link_libraries(m PUBLIC OpenMP::OpenMP_CXX)
else()
message( FATAL_ERROR "Your compiler does not support OpenMP" )
endif()
test.py
from build.m import *
def test(i):
return i * 20
b = B(2, 2)
b.map(test)
I basically have an array where I want to apply a Python function to every element using a for-loop. I know that it is an issue with functional and OpenMP specifically because in other parts of my project I am using OpenMP successfully and functional is also working if I am not using OpenMP.
Edit: It freezes at the map function and has to be terminated. I am using Ubuntu 21.10, Python 3.9, GCC 11.2.0, OpenMP 4.5, and the newest version of the pybind11 repo.
You're likely experiencing a deadlock between OpenMP's scheduler and Python's GIL (Global Interpreter Lock).
I suggest attaching gdb to your process and looking at where the threads are to verify that's really the problem.
IMHO mixing Python functions and OpenMP like that is asking for trouble. If you want multi-threading of Python functions you can use multiprocessing.pool.ThreadPool. But unless your functions release the GIL most of the time you won't benefit from multi-threading.
This question already has answers here:
how can i include python.h in QMake
(1 answer)
Embedding python 3.4 into C++ Qt Application?
(4 answers)
Closed 2 years ago.
When I was trying to embed a Python script into my Qt C++ program, I run into multiple problems when trying to include Python.h.
The following features, I would like to provide:
Include python.h
Execute Python Strings
Execute Python Scripts
Execute Python Scripts with Arguments
It should also work when Python is not installed on the deployed machine
Therefore I searched around the Internet to try to find a solution. And found a lot of Questions and Blogs, but non have them covered all my Problems and it still took me multiple hours and a lot of frustration.
That's why I have to write down a StackOverflow entry with my full solution so it might help and might accelerate all your work :)
(This answer and all its code examples work also in a non-Qt environment. Only 2. and 4. are Qt specific)
Download and install Python https://www.python.org/downloads/release
Alter the .pro file of your project and add the following lines (edit for your correct python path):
INCLUDEPATH = "C:\Users\Public\AppData\Local\Programs\Python\Python39\include"
LIBS += -L"C:\Users\Public\AppData\Local\Programs\Python\Python39\libs" -l"python39"
Example main.cpp code:
#include <QCoreApplication>
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")
/*!
* \brief runPy can execut a Python string
* \param string (Python code)
*/
static void runPy(const char* string){
Py_Initialize();
PyRun_SimpleString(string);
Py_Finalize();
}
/*!
* \brief runPyScript executs a Python script
* \param file (the path of the script)
*/
static void runPyScript(const char* file){
FILE* fp;
Py_Initialize();
fp = _Py_fopen(file, "r");
PyRun_SimpleFile(fp, file);
Py_Finalize();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
runPy("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
//uncomment the following line to run a script
//runPyScript("test/decode.py");
return a.exec();
}
Whenever you #include <Python.h> use the following code instead. (The Slots from Python will otherwise conflict with the Qt Slots
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")
After compiling, add the python3.dll, python39.dll, as well as the DLLs and Lib Python folders to your compilation folder. You can find them in the root directory of your Python installation. This will allow you to run the embedded c++ code even when python is not installed.
With these steps, I was able to get python running in Qt with the 64 bit MinGW and MSVC compiler. Only the MSVC in debug mode got still a problem.
FURTHER:
If you want to pass arguments to the python script, you need the following function (It can be easy copy-pasted into your code):
/*!
* \brief runPyScriptArgs executs a Python script and passes arguments
* \param file (the path of the script)
* \param argc amount of arguments
* \param argv array of arguments with size of argc
*/
static void runPyScriptArgs(const char* file, int argc, char *argv[]){
FILE* fp;
wchar_t** wargv = new wchar_t*[argc];
for(int i = 0; i < argc; i++)
{
wargv[i] = Py_DecodeLocale(argv[i], nullptr);
if(wargv[i] == nullptr)
{
return;
}
}
Py_SetProgramName(wargv[0]);
Py_Initialize();
PySys_SetArgv(argc, wargv);
fp = _Py_fopen(file, "r");
PyRun_SimpleFile(fp, file);
Py_Finalize();
for(int i = 0; i < argc; i++)
{
PyMem_RawFree(wargv[i]);
wargv[i] = nullptr;
}
delete[] wargv;
wargv = nullptr;
}
To use this function, call it like this (For example in your main):
int py_argc = 2;
char* py_argv[py_argc];
py_argv[0] = "Progamm";
py_argv[1] = "Hello";
runPyScriptArgs("test/test.py", py_argc, py_argv);
Together with the test.py script in the test folder:
import sys
if len(sys.argv) != 2:
sys.exit("Not enough args")
ca_one = str(sys.argv[0])
ca_two = str(sys.argv[1])
print ("My command line args are " + ca_one + " and " + ca_two)
you get the following output:
My command line args are Progamm and Hello
I read usb camera as cv2.VideoCapture() function and showing frames. I need to some c++ application read frames from python application.
How can i make this ?
Steps:
Read camera with python from usb camera.
Show frames cv2.imshow("usb_cam_frame", frame).
Run c++ application.
Transfer frames to c++ application. ???
Show same frames with c++ application.
You can use embedding python in C++ and call python function in a C++ program. Put the python module and define a dict in this module that contain data of frame in file for example test.py.
#include <Python.h>
int main(int argc, char *argv[])
{
Py_Initialize();
pName = PyString_FromString("test.py");
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, "frame");
if (PyCallable_Check(pFunc))
{
PyObject_CallObject(pFunc, NULL);
}
else
{
PyErr_Print();
}
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
I'd like to re-use a Python script that makes use of matplotlib in interactive mode by embedding a call to it from a C application -- what do I need to do in order to get interactive mode in an embedded Python script working?
I set up an extremely simple example using PyRun_SimpleString(); it works when interactive mode is turned off, but when interactive mode is on the plot window only shows up for a brief interval right before the application ends
#include <Python.h>
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime,sleep\n"
"import matplotlib.pyplot as plt\n"
"import matplotlib\n"
"print(matplotlib.get_backend())\n"
"plt.ion()\n"
"plt.plot([1,2,3,4,3,5,7])\n"
"sleep(5)\n");
Py_Finalize();
PyMem_RawFree(program);
return 0;
}
The backend used by matplotlib is Qt4Agg. When I execute the lines above in the Python interpreter, it behaves as I'd expect. If I change the plt.ion() to a plt.ioff() and put in a plt.show() after the plt.plot() call, I also see the plot.
I'm assuming when you say, "[w]hen I execute the lines above in the Python interpreter, it behaves as I'd expect," you're referring to running it within the Python command line/REPL. The right way to test one to one behavior with embedded Python would be to instead place your in a python script and then try running it with python script.py.
You'll notice that within a script your code gives a similar problem. I think the trick is to use plt.pause(5) instead of sleep(5), this allows the event loop for the plot GUI to fire and actually draw the window properly (https://stackoverflow.com/a/35119003/11365663).
For REPLs, matplotlib has some extra magic so that the details of the event loop are hidden from you.
This worked for me:
#include <Python.h>
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime,sleep\n"
"import matplotlib.pyplot as plt\n"
"import matplotlib\n"
"print(matplotlib.get_backend())\n"
"plt.ion()\n"
"plt.plot([1,2,3,4,3,5,7])\n"
"plt.pause(5)\n");
Py_Finalize();
PyMem_RawFree(program);
return 0;
}
I have a simple python script that uses a c/c++ library with ctypes. My c++ library also contains a main method, so I can compile it without the -shared flag and it can be excecuted and it runs without issues.
However, when I run the same code from a python script using ctypes, a part of the c++ program is excecuted (I can tell that from the cout calls). Then the entire application, including the python script, termiantes (I can tell that from the missing cout and print calls). There is no error message, no segfault, no python stacktrace.
My question is: How can I debug this? What are possible reasons for this to happen?
Here is part of the code, however, since there is no error message, I don't know which code is relevant.
import ctypes
interface = ctypes.CDLL("apprunner.so")
interface.start()
print "complete"
.
#include "../../app/ShaderApp.cpp"
#include <iostream>
#include "TestApp.cpp"
TestApp* app = 0;
extern "C" void start() {
app = new TestApp();
cout << "Running from library" << endl;
app->run();
}
int main( int argc, const char* argv[]) {
cout << "Running from excecutable" << endl;
start();
}
Typically you begin from a small mock-up library that just lets you test the function calls from python. When this is ready (all the debug prints are ok) you proceed further. In your example, comment out #include "testapp.cpp" and get the prints to cout working.