以前MIDIハッカソンで、「PythonはC/C++とお話できます!」的な話を聞いていて、ずっと気になっていたのでちょっと試すだけ試してみた。PythonからCプログラムを呼び出す | 象歩を参考に、そのまま動かすところまでやってみた。CもPythonも未経験だけど、可能性広げる意味で。。
コンパイルのところでちょっと詰まったのでメモっておく。
環境
ソースを用意する
先ほどの記事を参考に、 hello.c
と helloWrapper.c
を用意する。「1.ソースコード」の節と「2.wraper コード」の節のソースコードをそれぞれそのままコピペでOK。
コンパイル
コンパイルに使用するコマンドは、参考記事では下記のようになってる。
gcc -fpic -o hello.o -c hello.c gcc -fpic -I/usr/include/python -o helloWrapper.o -c helloWrapper.c gcc -shared hello.o helloWrapper.o -o hellomodule.so
しかし、homebrewでインストールしたpythonでは /usr/include/python
にヘッダファイルがあるわけではないので、そのままでは動かない。
$ gcc -fpic -I/usr/include/python -o helloWrapper.o -c helloWrapper.c helloWrapper.c:2:10: fatal error: 'Python.h' file not found #include "Python.h" ^ 1 error generated. $ ls /usr/include/python ls: /usr/include/python: No such file or directory
この辺を解決しなきゃ。。
hello.c
のコンパイル
とりあえず一行目は動くので、動かして hello.o
を作る。warning出るけど…
$ gcc -fpic -o hello.o -c hello.c hello.c:9:2: warning: implicitly declaring library function 'printf' with type 'int (const char *, ...)' printf("こんにちは、私は %s の %s です。\n", adrs, name); ^ hello.c:9:2: note: include the header <stdio.h> or explicitly provide a declaration for 'printf' 1 warning generated. $ ls hello.c hello.o helloWrapper.c
helloWrapper.c
のコンパイル
続けて、 helloWrapper.c
のコンパイル。Python.h
をインクルードしているので、これがあるパスを見つけて、 -I
の後に記述しなくちゃいけない。
で、ググってたら、python-config --prefix
というコマンドがある のを見つけたので実行してみると、ビンゴっぽかった。
$ python-config --prefix /usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7 $ ls `python-config --prefix` Headers@ Python* Resources/ bin/ include/ lib/
Headers内に Python.h
があったので helloWrapper.c
のコンパイルは下記のコマンドでいけた。
$ gcc -fpic -I`python-config --prefix`/Headers -o helloWrapper.o -c helloWrapper.c helloWrapper.c:31:10: warning: incompatible pointer types initializing 'PyCFunction' (aka 'PyObject *(*)(PyObject *, PyObject *)') with an expression of type 'PyObject *(PyObject *, PyObject *, PyObject *)' [-Wincompatible-pointer-types] {"out", hello_out, METH_VARARGS | METH_KEYWORDS}, ^~~~~~~~~ 1 warning generated. $ ls hello.c hello.o helloWrapper.c helloWrapper.o
hellomodule.so
の作成
最後、 hellomodule.so
共有モジュールの作成。これもさっきのパスにヒントがあって、 -L
オプションには、lib
ディレクトリを指定すれば良いようだった。
-l
のオプションですごく迷ったのだけど、 compilation - C can't compile - symbol(s) not found for architecture x86_64 - Stack Overflow とか見ると、静的ライブラリlibimplementations.a
の場合は-limplementations
という指定にしていた。
libディレクトリには、libpython2.7.dylib
というファイル名があったので、-lpython2.7
かなと思って下記のコマンドを発行。
$ gcc -L`python-config --prefix`/lib -lpython2.7 -shared hello.o helloWrapper.o -o hellomodule.so $ ls hello.c hello.o helloWrapper.c helloWrapper.o hellomodule.so*
いけた。ここまでで材料が揃った。
実行する
$ python Python 2.7.10 (default, Jul 13 2015, 12:05:58) [GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import hello >>> hello.add(2, 3) 5 >>> hello.out("大原", "麗子") こんにちは、私は 大原 の 麗子 です。 >>> quit()
おおー!
今度はnode.jsのネイティブバインディングやってみたいですね!