LoginSignup
19
24

More than 5 years have passed since last update.

Pythonからc言語を呼び出す(python.h)

Last updated at Posted at 2018-03-06

はじめに

半か月ほど前にpython.hのラッパモジュールについてまとめてたファイルが出てきたので,投稿しておく
ちなみに,raspberry pi3用に作成したものです.

方法

C言語にはpython.hというヘッダがあり,これを使うことにより実装が可能になる.
プログラムは,c言語で関数を作成し,python wrapperというラッパモジュールによりpythonで関数を呼び出す.

pythonのバージョン

python2と3では,想像していた以上に違うかったのでそれぞれの作成方法を載せる.
なお,c言語の関数に違いはない.

サンプルプログラムについて

サンプルプログラムを見ても,「ん?なにこれ?」ってなると思います...なりました笑
筆者が理解したことは出来るだけ最後に追記として書き残しておきますので,サンプルプログラムを見た後で気になれば見ていただければと思います.
あと,今回の環境はraspberry pi3.関数とラッパモジュールは別ファイルです.(同ファイルの方が楽で簡単です)

サンプルプログラム

・C言語の関数

#include <iostream>

void numPrint(int num){
    std::cout << num << std::endl
}

コンパイル
$ g++ -Wall -pthread -fpic -o intPrint.o -c intPrint.cpp -lpigpiod_if2 -lrt

・Python2.7

#include <Python.h>

extern void numPrint(int num);

PyObject *numPrint(PyObject* self, PyObject* args){
    int num;

    if(!PyArg_ParseTuple(args, "i", &num)) return NULL;
    numPrint(num);
    return Py_Buildvalue("");
}

static PyMethodDef numPrintmethods[]={
    {"numPrint",numPrint ,METH_VARARGS},
    {NULL,NULL,0},
};

PyMODINIT_FUNC initPWM(void){
    Py_InitModule("numPrint",numPrintmethods);
}

コンパイル
$ g++ -fpic -I/usr/include/python2.7 -o intPrintWrapper.o -c intPrintWrapper.cpp -lpigpiod_if2 -lrt
$ g++ -shared intPrint.o intPrintWrapper.o -o intPrintmodule.so -lpigpiod_if2 –lrt

・Python3.4

#include <Python.h>
#include <cstdio>

extern void numPrint(int num);

PyObject *numPrint(PyObject* self, PyObject* args){
    int num;

    if(!PyArg_ParseTuple(args, "i", &num)) return NULL;
    numPrint(num);
    return Py_Buildvalue("");
}

static PyMethodDef numPrintmethods[]={
    {"numPrint",numPrint ,METH_VARARGS ,NULL},
    {NULL,NULL, 0, NULL},
};

static PyModuleDef numPrintmodule = {
    PyModuleDef_HEAD_INIT,
    "numPrint",
    NULL,
    -1,
    numPrintmethods
};

PyMODINIT_FUNC PyInit_numPrint(void){
    return PyModule_Create(&numPrintmodule);
}

コンパイル
$ arm-linux-gnueabihf-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.4m -c intPrintWrapper.cpp -o intPrintWrapper.o
$ arm-linux-gnueabihf-g++ -pthread -shared intPrint.o -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,relro -g -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 intPrintWrapper.o -o intPrint.cpython-34m.so -lpigpiod_if2 -lrt
(※不要なものもあると思います・ファイル名,フォルダの場所に気をつけてください)

追記

○追記
・簡易目次
PyObjectについて/PyModuleDefについて/モジュールを他の場所でも使えるようにする/同ファイル内での実装/クラスでの実装/

●PyObjectについて
PyObjectはpythonのバージョンで変化はない(と思う)

・本稿では引数1つであるが他の場合は,
引数がない場合

PyObject *numPrint(PyObject* self, PyObject* args){
    numPrint();
    return Py_Buildvalue("");
}

引数が2つ

PyObject *numPrint(PyObject* self, PyObject* args){
    int num, num2;

    if(!PyArg_ParseTuple(args, "ii", &num, &num2)) return NULL;
    numPrint(num, num2);
    return Py_Buildvalue("");
}

となる.

・引数について
20180306_1.JPG

if(!PyArg_ParseTuple(args, “ii”, &num, &num2)) return NULL;
の”ii”は,c言語で言うint型の引数が2つある状態.

・戻り値について
戻り値をreturnで返すことは出来る.

●モジュールを他の場所でも使えるようにする(フォルダ移動)
$ sudo mv intPrint.cpython-34m.so /usr/local/lib/python3.4/dist-packages/ intPrint.cpython-34m.so

●同ファイル内での実装
出来る.やってはいない.

●クラスでの実装
出来る.やってはいない.

おわりに

自身がラッパモジュールを調べているときに,別ファイルで作成しているのを見つけれなかったので,投稿しています.
そもそも,python.hで別ファイルで作ること自体が稀有だと思う(笑)

最後に,ここまで読んでいただきありがとうございます.少しでも誰かの役に立てれば幸いです.

19
24
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
24