
C言語で書いた関数をPython のモジュールとしてimportするよ!
はじめに
私はずっとC言語を使っていたのですが、Pythonは非常に便利ですよね!感動しました!
しかし、ずっとCで書いてきたので、Cの関数をPython で使えないか調べてみました。
詳しいことは知らずに実行だけしたいかたはこちらへ
環境と制約
・CentOS
・gcc:g++ ではできませんでした。また、c++だと上手くいきませんでした。
・python3系:python2系だとラッパーの記述が変わります。
・Python.h:ないときはsudo yum install python3-devel で入るらしいがやったことないです。
手順
手順は大まかに以下となります。
- C言語で書いた関数を用意する
- 上記の関数とPythonを結びつけるラッパーを作る
- コンパイルする
- 完成!
C 言語で書いた関数を用意する
まず、C 言語で書かれた関数を用意します。サンプル(c_file.c)を下に置いておきます。
#include <stdio.h>
int func1(int x, int y){
return x + y;
}
void func2(char* s, char* t){
printf("%s %s\n", s, t);
}
上記の関数とPythonを結びつけるラッパーを作る
ラッパーを作ります。下記にサンプルコード(wrap_file.c)を置いておきます。
// /usr/include/下にPython.h があるので探してください。
#include "/usr/include/python3.6m/Python.h"
// c_file.c で定義した関数を使用します。
extern int func1(x,y);
// Pythonのオブジェクトを作成しています。おまじないです。
PyObject* f_func1(PyObject* self, PyObject* args)
{
// ローカル変数定義
int x; // func1のxの型
int y; // func1のyの型
int result; // funct1の戻り値の型
// "ii" はx と yの型をpythonの型に変換したものです。x, yがint型なので ii、他の型は下の表を参照。
if (!PyArg_ParseTuple(args, "ii", &x, &y))
return NULL;
// c_file.c の関数を実行
result = func1(x, y);
// 結果を返す。ここで、"i"はresult の型です。下の表を参照。
return Py_BuildValue("i", result);
}
// 上記とほぼ一緒なので割愛します。
extern void func2(adrs,name);
PyObject* f_func2(PyObject* self, PyObject* args)
{
char* adrs;
char* name;
if (!PyArg_ParseTuple(args, "ss", &adrs, &name))
return NULL;
func2(adrs,name);
return Py_BuildValue("");
}
// おまじないです。{Pythonで使う名前, このファイルで定義されている名前,METH_VARARGS}
static PyMethodDef methods[] = {
{"func1", f_func1, METH_VARARGS},
{"func2", f_func2, METH_VARARGS},
{NULL}
};
// おまじない。
static struct PyModuleDef module_name =
{
PyModuleDef_HEAD_INIT,
"module_name", // Python でimport する名前。import module_name になる。
"",
-1,
methods
};
// おまじない。
PyMODINIT_FUNC PyInit_module_name(void) // PyInit_<Python でimportする名前。>
{
return PyModule_Create(&module_name); // Python でimportする名前。
}
C言語 | Python |
int | i |
double | d |
char | c |
char* | s |
コンパイルする
つづいてコンパイルしていきます。
c_file.c とwrap_file.c をそれぞれコンパイルして、c_file.o と wrap_file.o を作成します。
gcc -fPIC -Wall -c -o c_file.o c_file.c
gcc -fPIC -Wall -c -o wrap_file.o wrap_file.c
作成したc_file.o と wrap_file.o から、module_name.so を作成します。
gcc -fPIC -Wall -shared -o module_name.so c_file.o wrap_file.o
module_name.so をpython からimportします。
import module_name
でインポートできます。
完成
実際にPythonで実行してみましょう!

実行できました!
まとめ
C言語で作成した関数をPython で実行してみました。ラッパーを作るのが面倒に思ったと思います。
なので、ラッパを自動で作成するスクリプトを作成しました。
簡単にできるのでぜひ使ってみてください。
補足資料
gcc
通常、gcc main.c をすると、
-> プリプロセッサ:コンパイルの準備。#define とかを処理する。
-> コンパイル:オブジェクトファイルに変換される。.o ファイル
-> リンク:ほかにもコンパイルされているファイルがあれば連結する。
-> 実行ファイル:a.out いつもの ./a.out するやつ。
という順番で実行ファイルが作成されます。
gcc のオプション
-fPIC
Position Independent Code でコンパイルする。
-Wall
Warning all:警告をすべて有効化する
-o <ファイル名>
<ファイル名>のファイルができる。つけないとデフォルトのa.out になる。
-c
オブジェクトファイルを作る。.o のファイル。
gcc ではなくg++でコンパイルしてみる
g++ でコンパイルすると
error: invalid conversion from ‘PyObject* ()(PyObject, PyObject, PyObject)…
というエラーが出ます。
コンバージョンできないらしいですが、詳しくはわかりません。
gcc でコンパイルしましょう。
その他
Python.h が見つからないとき
sudo find / -name “Python.h”
でPython.h が見つかります。なかったら
sudo yum install python3-devel
でPython.hが入るらしいですが、よくわかりません。
コメント