Python.hをC ++に埋め込む/含める[フルガイド](Python 3.9)(Windows)(Qt 5.15)[複製]

Dec 07 2020

PythonスクリプトをQtC ++プログラムに埋め込もうとしたときに、Python.hをインクルードしようとすると、複数の問題が発生しました。以下の機能を提供したいと思います。

  • python.hを含める
  • Python文字列を実行する
  • Pythonスクリプトを実行する
  • 引数を使用してPythonスクリプトを実行する
  • デプロイされたマシンにPythonがインストールされていない場合にも機能するはずです

そのため、私は解決策を見つけるためにインターネットを検索しました。そして、たくさんの質問やブログを見つけましたが、それらが私のすべての問題をカバーしておらず、それでも私は数時間と多くの欲求不満を要しました。そのため、完全なソリューションでStackOverflowエントリを書き留めておく必要があります。そうすれば、すべての作業が役立ち、加速する可能性があります:)

回答

3 Olgidos Dec 07 2020 at 22:01

(この回答とそのすべてのコード例は、Qt以外の環境でも機能します。2。と4のみがQt固有です)

  1. Pythonをダウンロードしてインストールする https://www.python.org/downloads/release
  2. プロジェクトの.proファイルを変更し、次の行を追加します(正しい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. 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. #include <Python.h>を使用する場合は常に、代わりに次のコードを使用してください。(PythonのスロットはQtスロットと競合します
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")
  1. コンパイル後、python3.dll、python39.dll、およびDLLとLibPythonフォルダーをコンパイルフォルダーに追加します。それらは、Pythonインストールのルートディレクトリにあります。これにより、Pythonがインストールされていない場合でも、埋め込みC ++コードを実行できます。

これらの手順により、64ビットのMinGWおよびMSVCコンパイラを使用してQtでPythonを実行することができました。デバッグモードのMSVCだけがまだ問題を抱えていました。

さらに:

Pythonスクリプトに引数を渡したい場合は、次の関数が必要です(コードに簡単にコピーして貼り付けることができます)。

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

この関数を使用するには、次のように呼び出します(たとえば、メインで)。

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

テストフォルダー内のtest.pyスクリプトと一緒に:

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)

次の出力が得られます。

My command line args are Progamm and Hello