ブログ

割とコンピュータよりの情報をお届けします。

C言語からPythonの関数呼び出し4

久しぶりの「C言語からPythonの関数呼び出し」記事として,WinPythonとVisual Studio 2017でPython embeddable用の実行ファイルを作るということを再検討していた.

まず,Python側のコードの例は以下のようにした.
今回もlistを引数としてPythonに渡して,listを返り値としてもらうという例になっている.

# -*- coding: utf-8 -*-

def SampleFunc1(t, f):
    output = [10, 9, 7, 5, 3, 1];
    return output

C(C++)言語側のコードは以下のようにした.

#include <stdio.h>
#include <windows.h>

#define _USE_MATH_DEFINES
#include <cmath>
#ifdef _DEBUG
#undef _DEBUG
#include <Python.h>
#define _DEBUG
#else
#include <Python.h>
#endif

int main()
{
    char Path[MAX_PATH + 1];
    char Dir[MAX_PATH + 1 + 32];
    char drive[MAX_PATH + 1]
        , dir[MAX_PATH + 1]
        , fname[MAX_PATH + 1]
        , ext[MAX_PATH + 1];
    if (0 != GetModuleFileNameA(NULL, Path, MAX_PATH)) {
        _splitpath_s(Path, drive, dir, fname, ext);

        int j = 0;
        for (int i = 0; i < MAX_PATH + 1; i++) {
            Dir[j] = dir[i];
            j++;
            if (dir[i] == '\\') {
                Dir[j] = dir[i];
                j++;
            }
            else if (dir[i] == '\0') {
                break;
            }
        }
        sprintf_s(dir, "%s%s", drive, Dir);
        printf("ディレクトリ パス : %s\n", dir);
    }
    char buf1[2000];
    sprintf_s(buf1, "import sys\r\nsys.path.append('%s')\r\nprint(sys.path)\r\n", dir);
    // 実行ファイルと同じフォルダにあるpyモジュールも使いたいので,前回より少し手を加えた.

    PyObject *pName, *pModule, *pFunc;
    PyObject *pArgs, *pArg, *pArg2, *pValue, *pValue2;

    Py_Initialize();
    PyRun_SimpleString(buf1);
    pName = PyUnicode_DecodeFSDefault("SampleFunc");

    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, "SampleFunc1");

        if (pFunc && PyCallable_Check(pFunc)) {
            pArgs = PyTuple_New(2); // 関数fncの引数の数を引数にする

            pArg = PyList_New(1000);
            pArg2 = PyList_New(1000);
            for (int i = 0; i < 1000; i++) {
                double value = sin(2.0 * M_PI * 0.01 * 1.0 * i);
                pValue = PyFloat_FromDouble(value);
                pValue2 = PyFloat_FromDouble(2.0);
                if (!pValue) {
                    Py_DECREF(pArgs);
                    Py_DECREF(pArg);
                    Py_DECREF(pArg2);
                    Py_DECREF(pModule);
                    return 1;
                }
                PyList_SetItem(pArg, i, pValue);
                PyList_SetItem(pArg2, i, pValue2);
            }
            if (PyTuple_SetItem(pArgs, 0, pArg2) != 0)
                return 1;
            if (PyTuple_SetItem(pArgs, 1, pArg) != 0)
                return 1;

            pValue = PyObject_CallObject(pFunc, pArgs);
            Py_DECREF(pArgs);
            if (pValue != NULL) {
                //printf("%d\n", PyList_CheckExact(pValue));
                Py_ssize_t len = PyList_Size(pValue);

                for (int i = 0; i < len; i++) {
                    //printf("%I32d ", PyFloat_Check(PyList_GetItem(pValue, i)));
                    printf("%.4g\n", PyFloat_AsDouble(PyList_GetItem(pValue, i)));
                }
                //printf("return: %s\n", (char*)PyUnicode_DATA(pValue));
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr, "Call failed\n");
                return 1;
            }
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function\n");
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load module\n");
        return 1;
    }
    if (Py_FinalizeEx() < 0) {
        return 120;
    }
    return 0;
}

プロジェクトのプロパティを次のように設定しておくとF5キーでデバッグがかかるようになる.
(Python部分はデバッグできない) 「ビルド後のイベント」のコマンドライン
copy .\*.py $(TargetDir)

「デバッグ」の「環境」にPython Embeddableのインストールパスを設定する.例えば
PATH="$(Path)C:\python-3.7.2.post1-embed-amd64\;"

なお,[C/C++]の[追加インクルードディレクトリ]にはWinPythonのインストールパスを設定する.例えば
C:\WPy-3710Zero\python-3.7.1.amd64\include
[リンカー]の[追加のライブラリディレクトリ]には 例えば
C:\WPy-3710Zero\python-3.7.1.amd64\include
[リンカー]の[追加の依存ファイル]には
python3.lib
を設定する.

 

なお途中にでている「手を加えた」としている部分は次の記事ですこし考え直した.

2019/02/02 コンピュータ   TakeMe
タグ:Python
< 前の記事     一覧へ     後の記事 >

コメント送信フォーム


※ Eメールは公開されません
Loading...
 画像の文字を入力してください