スポンサーリンク

Ubuntu + g++ + Python/C APIでPythonからCを呼び出す

ずっと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 の場所
['/home/myname/anaconda3/envs/BindTest/include/python3.9']
['/home/myname/anaconda3/envs/BindTest/lib']
['libpython3.9.a']

C++のプログラムを書く

Windows版と動的リンクライブラリの設定が若干違う(というかない)が基本的には同じ。DllMainなどは不要なのでその分コードは短い。

mymod.hpp

// 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

// 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()

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: