PythonからCプログラムを呼び出してみた

こんにちは。ハロです。

Python修行中の身になってしばらくたち、ふだん書くコードはほとんどPythonになりました。でも、例えばデバイスの制御などで、どうしてもC/C++でプログラミングしないといけない場面はまだあります。

今回は、PythonからCプログラムを呼び出すことができたので、それについてシェアします。

Pythonから呼び出せるCプログラムの作り方

PythonからCプログラムを呼び出すためには、Pythonのモジュールとして扱える形でCプログラムを作る必要があります。

Python公式ドキュメントに CやC++によるPythonの拡張 というページがあるので、ここに書かれているコードを参考にして作りましょう。手順はこんな感じです。

まずは、今回の作業用にディレクトリを作ってそこへ移動します。

~ $ mkdir call-cfunction-example
~ $ cd call-cfunction-example

それから、Cのコードを書きます。今回は「引数nを与えて、その回数分hello!と出力する」プログラムにしてみました。

~/call-cfunction-example $ vim hello.c

ソースファイルはこちら

#include <Python.h>

static PyObject* hello_say(PyObject* self, PyObject* args) {
  int n;

  if (!PyArg_ParseTuple(args, "i", &n)) {
    return NULL;
  }

  for (int i = 0; i < n; i++) {
    printf("hello!\n");
  }

  Py_RETURN_NONE;
}

static PyMethodDef hello_module_methods[] = {
  { "say",  hello_say, METH_VARARGS, "" },
  { NULL, NULL, 0, NULL }
};

static struct PyModuleDef hello_module_definition = {
  PyModuleDef_HEAD_INIT, "hello", "", -1, hello_module_methods
};

PyMODINIT_FUNC PyInit_hello(void) {
  return PyModule_Create(&hello_module_definition);
}

helloモジュールにsay関数があって、sayに引数nを渡すと、n回だけhello!と出力できるようになっています。機能の割にソースファイルが複雑に見えますね。

最初はややこしく感じると思いますが、落ち着いてシンボルの対応を見れば、そこまで難しくないはず。

まあでも、どうしても難しい時は、思い切って「おまじない」ということにしても良いかも知れません。

ビルドと実行

Cのコードが書けたら、Pythonから呼び出せるモジュールにするため、ビルド用のファイルsetup.pyを書きます。

~/call-cfunction-example $ vim setup.py

ビルド用ファイル

from distutils.core import setup, Extension


setup(
    name='hello',
    ext_modules=[
        Extension('hello', ['hello.c'])
    ],
)

これで準備完了です。Cプログラムをビルドして、Pythonで呼び出せるモジュールにします。

~/call-cfunction-example $ python3 setup.py build_ext -i

実は最初のビルド時、Python.hのインクルードに失敗するエラーが出ました。これはpython3-devパッケージがインストールされていなかったためで、もしこれがインストールされていない場合は、次のようにあらかじめインストールしておきましょう。

~/call-cfunction-example $ sudo apt -y install python3-dev

最後にPythonインタプリタから実行できることを確認します。

~/call-cfunction-example $ python3
Python 3.6.9 (default, Oct  8 2020, 12:12:24) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import hello
>>> hello.say(4)
hello!
hello!
hello!
hello!
>>> 

無事に、helloモジュールのsayメソッドを呼び出すことができました。

実際には、setup.pyにインクルードディレクトリ、ライブラリディレクトリ、ライブラリファイル、オブジェクトファイルなどの記述が追加で必要になるかも知れません。そんな時はPython公式ドキュメントの APIリファレンス が参考になると思います。

感想

Pythonのモジュールとして扱える形でCプログラムを作るため、Cプログラム側がちょっと複雑になりますね。個人的には、少し大変だけど、かなり役立つ機能だなと思いました。

プログラミングって、間口は広くなって敷居も低くなったけど、奥はどんどん深くなっている気がします。むむむ。

またね。

この記事を書いた人

ハロ

ハロ

学究の兎です。コンピュータサイエンス全般が好きで、ある時はハンダごてを握って電子回路を作ってみたり、またある時は新しいプログラミング言語を覚えて嬉々としてキーボードを叩いていたりします。