Einbetten / Einfügen von Python.h in C ++ [Vollständige Anleitung] (Python 3.9) (Windows) (Qt 5.15) [Duplikat]

Dec 07 2020

Beim Versuch, ein Python-Skript in mein Qt C ++ - Programm einzubetten, treten beim Versuch, Python.h einzuschließen, mehrere Probleme auf. Die folgenden Funktionen möchte ich bereitstellen:

  • Schließen Sie python.h ein
  • Führen Sie Python-Strings aus
  • Führen Sie Python-Skripte aus
  • Führen Sie Python-Skripte mit Argumenten aus
  • Es sollte auch funktionieren, wenn Python nicht auf dem bereitgestellten Computer installiert ist

Deshalb habe ich im Internet nach einer Lösung gesucht. Und fand viele Fragen und Blogs, aber nicht haben sie alle meine Probleme abgedeckt und es dauerte immer noch mehrere Stunden und viel Frust. Deshalb muss ich einen StackOverflow-Eintrag mit meiner vollständigen Lösung aufschreiben, damit er Ihnen helfen und Ihre Arbeit beschleunigen kann :)

Antworten

3 Olgidos Dec 07 2020 at 22:01

(Diese Antwort und alle ihre Codebeispiele funktionieren auch in einer Nicht-Qt-Umgebung. Nur 2. und 4. sind Qt-spezifisch.)

  1. Laden Sie Python herunter und installieren Sie es https://www.python.org/downloads/release
  2. Ändern Sie die .pro-Datei Ihres Projekts und fügen Sie die folgenden Zeilen hinzu (bearbeiten Sie sie für Ihren korrekten Python-Pfad):
INCLUDEPATH = "C:\Users\Public\AppData\Local\Programs\Python\Python39\include" 
LIBS += -L"C:\Users\Public\AppData\Local\Programs\Python\Python39\libs" -l"python39"
  1. Beispiel 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();
}
  1. Wann immer Sie #include <Python.h> verwenden, verwenden Sie stattdessen den folgenden Code. (Die Slots von Python stehen ansonsten in Konflikt mit den Qt-Slots
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")
  1. Fügen Sie nach dem Kompilieren die Ordner python3.dll, python39.dll sowie die Ordner DLLs und Lib Python zu Ihrem Kompilierungsordner hinzu. Sie finden sie im Stammverzeichnis Ihrer Python-Installation. Auf diese Weise können Sie den eingebetteten C ++ - Code auch dann ausführen, wenn Python nicht installiert ist.

Mit diesen Schritten konnte ich Python in Qt mit dem 64-Bit-MinGW- und MSVC-Compiler zum Laufen bringen. Nur die MSVC im Debug-Modus hat noch ein Problem.

DES WEITEREN:

Wenn Sie Argumente an das Python-Skript übergeben möchten, benötigen Sie die folgende Funktion (sie kann einfach in Ihren Code kopiert werden):

/*!
 * \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;
}

Um diese Funktion zu verwenden, rufen Sie sie folgendermaßen auf (zum Beispiel in Ihrer Hauptfunktion):

    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);

Zusammen mit dem Skript test.py im Testordner:

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)

Sie erhalten folgende Ausgabe:

My command line args are Progamm and Hello