ずっとWindowsでやってきたので今度はUbuntuで同じことをする。
Ubuntuの場合はdllではなくsoファイルという事になるが、手順などは変わらない。
sysconfig.get_config_varsで各パスを見つける。.aはwindowsの.libに該当。
一覧を出すと長いので引数に値名を入れて必要なものだけ見つける
# where-is-pyh.py import sysconfig import pprint pprint.pprint(sysconfig.get_config_vars('LIBDIR')) # .a ファイルの場所 pprint.pprint(sysconfig.get_config_vars('LIBRARY')) # .a ファイルの名前 pprint.pprint(sysconfig.get_config_vars('INCLUDEPY')) # python.h の場所
Windows版と動的リンクライブラリの設定が若干違う(というかない)が基本的には同じ。DllMainなどは不要なのでその分コードは短い。
// mymod.hpp // このプロジェクトのビルド結果を「sopy.so」とする。 #include <Python.h> // この関数をPython側から呼び出したいとする。 PyObject * hello_in_c(PyObject*); // 第一引数はPython側のself用。 // 関数へアクセスする方法一覧 static PyMethodDef method_list[] = { // Pythonで使用する関数名 , C++内で使用する関数名 , 引数の個数に関するフラグ , docstring { "hello_on_python", (PyCFunction)hello_in_c, METH_VARARGS , nullptr }, // ... 公開したい関数の個数分だけ記述する // 配列の最後は全てNULLの要素を入れておく { nullptr, nullptr, 0, nullptr } }; // モジュールを定義する構造体 static PyModuleDef module_def = { PyModuleDef_HEAD_INIT, "sopy", // モジュール名 "Example of pyhton wrapper", // モジュール説明 0, method_list // Structure that defines the methods of the module }; // 関数名はPyInit_ + soファイル名 PyMODINIT_FUNC PyInit_sopy() { return PyModule_Create(&module_def); }
// mymod.cpp #include "mymod.hpp" PyObject* hello_in_c(PyObject*) { printf("hello world from C"); return Py_None; }
最初のステップでsysconfigで見つけたパスとライブラリ名をそれぞれ指定する。
$ g++ mymod.cpp -shared -fPIC -o sopy.so -I/home/myname/anaconda3/envs/BindTest/include/python3.9 -L/home/myname/anaconda3/envs/BindTest/lib -lpython3.9
import sopy sopy.hello_on_python()