Osadź / dołącz Python.h do C ++ [Pełny przewodnik] (Python 3.9) (Windows) (Qt 5.15) [duplikat]

Dec 07 2020

Kiedy próbowałem osadzić skrypt w języku Python w moim programie Qt C ++, napotykam wiele problemów podczas próby dołączenia Python.h. Następujące funkcje, które chciałbym zapewnić:

  • Dołącz python.h
  • Wykonaj ciągi Pythona
  • Wykonaj skrypty w języku Python
  • Wykonuj skrypty w języku Python z argumentami
  • Powinien również działać, gdy Python nie jest zainstalowany na wdrożonej maszynie

Dlatego szukałem w Internecie rozwiązania. Znalazłem wiele pytań i blogów, ale żadne z nich nie obejmowało wszystkich moich problemów, a mimo to zajęło mi to wiele godzin i dużo frustracji. Dlatego muszę napisać wpis StackOverflow z moim pełnym rozwiązaniem, aby pomóc i przyspieszyć całą twoją pracę :)

Odpowiedzi

3 Olgidos Dec 07 2020 at 22:01

(Ta odpowiedź i wszystkie jej przykłady kodu działają również w środowisku innym niż Qt. Tylko 2. i 4. są specyficzne dla Qt)

  1. Pobierz i zainstaluj Python https://www.python.org/downloads/release
  2. Zmień plik .pro swojego projektu i dodaj następujące wiersze (edytuj, aby uzyskać poprawną ścieżkę do języka Python):
INCLUDEPATH = "C:\Users\Public\AppData\Local\Programs\Python\Python39\include" 
LIBS += -L"C:\Users\Public\AppData\Local\Programs\Python\Python39\libs" -l"python39"
  1. Przykładowy kod main.cpp:
#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. Ilekroć #include <Python.h> zamiast tego użyj następującego kodu. (W przeciwnym razie automaty z Pythona będą w konflikcie z gniazdami Qt
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")
  1. Po skompilowaniu dodaj python3.dll, python39.dll, a także foldery DLL i Lib Python do folderu kompilacji. Możesz je znaleźć w katalogu głównym instalacji Pythona. Umożliwi to uruchomienie osadzonego kodu C ++ nawet wtedy, gdy Python nie jest zainstalowany.

Dzięki tym krokom udało mi się uruchomić Pythona w Qt z 64-bitowym kompilatorem MinGW i MSVC. Tylko MSVC w trybie debugowania nadal miał problem.

DALEJ:

Jeśli chcesz przekazać argumenty do skryptu Pythona, potrzebujesz następującej funkcji (można ją łatwo skopiować i wkleić do kodu):

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

Aby użyć tej funkcji, nazwij ją w ten sposób (na przykład w swoim głównym):

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

Razem ze skryptem test.py w folderze testowym:

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)

otrzymasz następujący wynik:

My command line args are Progamm and Hello