を作ろうかなとふと思った。
ggると、
#include "Python.h"
らしい。なるほど!
g++ -c main.cpp main.cpp:1:20: fatal error: Python.h: そのようなファイルやディレクトリはありません #include "Python.h" ^
想定内!(゜∀ ゜)
gcc - fatal error: Python.h: No such file or directory - Stack Overflowを参考に、Ubuntu14.04LTSにて
$ sudo apt-get install python-dev
よし!まだエラーが出るぞ!さきほどの海外フォーラムをもっと読んでみる。
# find /usr/include/python2.7 -name "Python.h" /usr/include/python2.7/Python.h
うん。これだゎ。incude pathsを通せばコンパイルが通るようになった。さてこっから面倒くさいので先人の知恵に頼るということで、親切なページをggる。
http://qiita.com/mtwtk_man/items/9d3db89dc4efe4697b5dを参考にしよう。
ちょっとついでに、zshのカラーもいじっておく...。
autoload -U colors colors PROMPT="${fg[cyan]}%n@%m:%d%# ${reset_color}"
で
# grep -n -e "Py.*Def" **/*.*
する。struct PyModuleDefが見えてないんだよねぇ...。
Oops... これ、ひょっとしてpython v3用か?
Migrating C extensions — Supporting Python 3: An in-depth guideに素敵なことが書いてある気がするのだが。
$ python --version Python 2.7.6
うーん。
Pythonを高速化しよう! - gumi Engineer’s Blogとかc/c++をラップしてpythonで使えるように - Python | Welcome to undergroundがv2用だな。
文字列の扱いはhttp://qiita.com/mtwtk_man/items/9d3db89dc4efe4697b5d、数値の扱いはPythonからCプログラムを呼び出す | 象歩とかを参考にして...。
メモリ管理とか、本当はC/APIで文字列操作をして色々ハマったこと - YAMAGUCHI::weblogとか参考にしてPyMem_Mallocとか使うのかもしれないけど、面倒なので一旦見なかったことに(汗)
戻り値の生成はhttp://docs.python.jp/2.5/ext/buildValue.htmlでも参考に。pythonのバージョンが古そうだが、流石にこんなとこは共通だと信じたいので気にしない方向で。
文字列の連結は面倒くさいのでSTLを使うことにして...。
[Makefile]
TARGET=samplemodule01.so CXXFLAGS += -I/usr/include/python2.7 LFLAGS += -lpython2.7 OBJS = samplemodule01.o ################################################################################ .PHONY: all all: $(TARGET) $(TARGET): $(OBJS) $(CXX) -Wall -shared -o $(TARGET) $(OBJS) $(LFLAGS) .cpp.o: $(CXX) -Wall -fpic $(CXXFLAGS) -c $< .PHONY: clean clean: rm -rf $(TARGET) $(OBJS)
と
#include <Python.h> #include <string> static PyObject* add_triple(PyObject *self, PyObject *args) { int i1, i2, i3; const char *s1, *s2, *s3; if ( PyArg_ParseTuple(args, "iii", &i1, &i2, &i3) ) { return Py_BuildValue("i", i1 + i2 + i3); } else if ( PyArg_ParseTuple(args, "sss", &s1, &s2, &s3) ) { std::string st1(s1), st2(s2), st3(s3); return Py_BuildValue("s", (st1 + st2 + st3).c_str()); } return NULL; } static PyMethodDef samplemodule01_methods[] = { {"add_triple", add_triple, METH_VARARGS, "add triple objects"}, {NULL, NULL, 0, NULL} }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef samplemodule01_module = { PyModuleDef_HEAD_INIT, "samplemodule01", "sample extension module", -1, samplemodule01_methods }; #endif /* PY_MAJOR_VERSION >= 3 */ PyMODINIT_FUNC #if PY_MAJOR_VERSION >= 3 PyInit_samplemodule01(void) { return PyModule_Create(&samplemodule01_module); } #else /* ! PY_MAJOR_VERSION >= 3 */ initsamplemodule01(void) { Py_InitModule3("samplemodule01", samplemodule01_methods, "sample extension module"); } #endif /* ! PY_MAJOR_VERSION >= 3*/
とかをビルドしてみる。v3用には確認していない!
モジュールの仕様はsamplemodule01.add_triple()に3つの数値あるいは3つの文字列を与えると型の意味に応じた加算を行って返すっちゅー意味の分からないもんだが、ま、サンプルなんで。
ビルドしたらsamplemodule01.soができた。
- fPICはたまに?見るけど、実はよく知らない。Linux の共有ライブラリを作るとき PIC でコンパイルするのはなぜか - bkブログでも読むことにしてお茶を濁して先にいく(汗)
テストするために、pythonスクリプトを書く。
[test.py]
#! /usr/bin/env python # -*- coding: utf-8 -*- import samplemodule01 if __name__ == "__main__" : v = samplemodule01.add_triple(2, 3, 5) print("2+3+5=%d" % (v)) v = samplemodule01.add_triple("YOU", "は", "SHOCK") print("%s 愛で空が 落ちてくる" % (v))
さて、試験運転。
$ ./tesy.py 2+3+5=10 YOUはSHOCK 愛で空が 落ちてくる
ふむ。"You are shocked"でないらしいのでこれでいいのだ。shockには名詞形もあるらしいので「お前はショックだ」ってことなんだろうか。Google翻訳で「youはshock」と入れたら「あなたはショックをは」と返ってきたをは。