動機
ふと思い立った。簡単なサンプルを書いたつもりだったけど、思わぬところでちょっとはまったからメモ。
方法
サンプルコード
基本的にはこちらの写経。
Cのラッパを書いたのは2度目だけど、前回はバインディング部分はほとんど書いてなかったし、そもそもMacではなかったんで今回は新鮮。コードは上記サイトがなくなった時のために写させてもらいます。
- test.c
#include <stdio.h> int add(int x, int y) { return x + y; } void out(const char* address, const char* name) { printf("こんちはー、おいどんは%sの%sです。\n", address, name); }
- testWrapper.c
#include "Python.h" extern int add(int x, int y); extern void out(const char* address, const char* name); PyObject* test_add(PyObject* self, PyObject* args) { int x, y, g; if (!PyArg_ParseTuple(args, "ii", &x, &y)) return NULL; g = add(x, y); return Py_BuildValue("i", g); } PyObject* test_out(PyObject* self, PyObject* args, PyObject* kw) { const char* address = NULL; const char* name = NULL; static char* argnames[] = {"args", "name", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kw, "|ss", argnames, &address, &name)) return NULL; out(address, name); return Py_BuildValue(""); } static PyMethodDef testmethods[] = { {"add", test_add, METH_VARARGS}, {"out", test_out, METH_VARARGS | METH_KEYWORDS}, {NULL}, }; void inittest() { Py_InitModule("test", testmethods); }
コンパイル(モジュール作成)
これをコンパイル。ここで若干はまった。まずは通常のLinux等の場合。
gcc -fpic -o test.o -c test.c gcc -fpic -I/usr/lib/python2.5 -o testWrapper.o -c testWrapper.c gcc -share test.o testWrapper.o -o testmodule.so
Mac OS X 10.4を使っていますが、執筆時の環境ではgccは4.0.1です。上のコンパイルを行おうとすると、
$ gcc -fpic -o test.o -c test.c test.c:1: warning: -fpic is not supported; -fPIC assumed
でまず警告がでます。これは-fPICになおします。あとPython.hの場所はMacPortsで入れたので当然上記と異なります。さらに最後モジュールを作成するところでは、こんな感じで失敗します。
$ gcc -share test.o testWrapper.o -o testmodule.so i686-apple-darwin8-gcc-4.0.1: unrecognized option '-share' /usr/libexec/gcc/i686-apple-darwin8/4.0.1/ld: Undefined symbols: _main _PyArg_ParseTuple _PyArg_ParseTupleAndKeywords _Py_BuildValue _Py_InitModule4 collect2: ld returned 1 exit status
これは原因が2つあって、「オプションが間違っていること」と「定義を見に行けてない」ことがそれです。前者に関してはここが参考になります。
Macではgccの-sharedオプションは-bundleにしてください。さらにこれだけではまだ/opt/local/lib/python2.5/lib-dynloadにあるダイナミックライブラリを見に行けてないので、"-undefined dynamic_lookup"オプションをつけます。
それがこれ。
gcc -fPIC -o test.o -c test.c gcc -fPIC -I/opt/local/include/python2.5 -o testWrapper.o -c testWrapper.c gcc -undefined dynamic_lookup -bundle test.o testWrapper.o -o testmodule.so
テスト
これでモジュールが作成されます。あとはちゃんと使えるのかテスト。
$ python Python 2.5.2 (r252:60911, Dec 13 2008, 22:26:36) [GCC 4.0.1 (Apple Computer, Inc. build 5370)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import test >>> test.add(4, 5) 9 >>> test.out("Japan", "ymotongpoo") こんちはー、おいどんはJapanのymotongpooです。