PythonからC言語で書いた関数を呼び出すには、CPythonにCのコードを追加する。 具体的には以下の公式記事を参考にすればいい:
- 1. C や C++ による Python の拡張 — Python 3.12.5 ドキュメント
- 1. Extending Python with C or C++ — Python 3.12.5 documentation
しかし、微妙に詰まった点があったのでここでは具体的なステップで拡張の書き方を紹介する。
1. 関数を書く
まずは関数の中身を書く
// 以下の2行は必ず必要 #define PY_SSIZE_T_CLEAN #include <Python.h> static PyObject* spam_system(PyObject* self, PyObject* args) { const char* command; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; sts = system(command); return PyLong_FromLong(sts); }
この部分は、PythonのAPIを使うこと以外は比較的素直に書ける。
2. 関数を登録情報を書く
インタプリタがアクセスできるように、関数の情報を"メソッドテーブル"に書く必要がある。
static PyMethodDef SpamMethods[] = { // METH_VARARGS: C関数が使う呼び出し規約をインタプリタに教える // METH_VAARGS もしくは METH_VAARGS | METH_KEYWORDS {"system", spam_system, METH_VARARGS, "Execute a shell command."}, {NULL, NULL, 0, NULL} };
基本的には、名前、関数、呼び出し規約、説明(任意) を入れれば良い。 最後の行は番兵として必要なだけらしい。
3. モジュール定義の構造体を作る
以下のようにモジュール定義用の構造体を作り、メソッドテーブルを参照させる:
static struct PyModuleDef spammodule = { PyModuleDef_HEAD_INIT, "spam", NULL, -1, SpamMethods };
4. Pythonインタプリタの初期化時にモジュールを登録する
インタプリタの初期化時に、モジュールを登録する。
PyMODINIT_FUNC PyInit_spam(void) { return PyModule_Create(&spammodule); }
上記までのプログラムをspammodule.c
のファイルとして保存しておく。
5. CPythonのコンパイルとリンク
ここがさらにトリッキーで、CPythonのModule/
ディレクトリに上記のプログラムを入れる必要がある。
具体的には、以下のようにコンパイルする:
git clone --depth 1 https://github.com/python/cpython.git cp spammodule.c cpython/Modules/ vim Modules/setup.local
setup.local
は以下のような新しいモジュールの説明を書く:
spam spammodule.o
このファイルはPythonのコンパイル時に自動で見つけてくれる。
そしてコンパイルする:
cd cpython ./configure --prefix=`pwd`/built make -j 4 make install
6. 新しいモジュールを試す
ここまで行けば、あとは単純に試せる
$ cpython/built/bin/python3 Python 3.14.0a0 on linux Type "help", "copyright", "credits" or "license" for more information. >>> import spam >>> spam.system("echo hi") hi 0