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

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

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

##pythonのバージョン
python2と3では，想像していた以上に違うかったのでそれぞれの作成方法を載せる．
なお，c言語の関数に違いはない．

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

##サンプルプログラム
・C言語の関数

```cpp
#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

```cpp
#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

```cpp
#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つであるが他の場合は，
引数がない場合

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

引数が2つ

```cpp
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](https://qiita-image-store.s3.amazonaws.com/0/176010/89cfbe51-efac-3fcb-0654-b8e0ab073d6a.jpeg)


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で別ファイルで作ること自体が稀有だと思う（笑）

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