1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CヘッダからPython向けバインディングを自動生成してDLLから関数を呼び出す方法

Last updated at Posted at 2022-09-10

この記事は?

C向けSDKが手元にあるけど柔軟にインタプリタ型言語のPythonでチクチク触りたい人向に刺さると思われる記事です。

時間がない人向け

ctypeslib2をインストールすると付属するclang2pyを使用すると簡単にできる

  1. pip install ctypeslib2
  2. clang2py header.h -o out.py
  3. (Windowsのみ)生成されたコードを編集し、DLLとリンク

確認のためCソースから自作してPythonから呼んでみる

XとYの値を持つPOINT型を含んだヘッダファイルを作ります。
C言語側のお仕事はprint_position()POINTの属性を出力すること。
DLL化するために__declspec(dllexport)を使用します。

point.h
#ifndef POINT_H
#define POINT_H

typedef struct Point {
    int x;
    int y;
} Point;

__declspec(dllexport) void print_position(Point *);

#endif

point.c
#include "point.h"
#include <stdio.h>

void print_position(Point *point) { printf("X:%d, Y:%d", point->x, point->y); }

動的ライブラリを作る

cl -LD .\point.c

この地点でdllとlibが生成されれば成功。

clang2pyでcヘッダを変換

pip install ctypeslib2
clang2py.exe .\point.h > point.py 

生成されたバインディングにDLLを紐づける

生成結果には以下のような行があるはずです。

point.py
# libraries['FIXME_STUB'] explanation
# As you did not list (-l libraryname.so) a library that exports this function
# This is a non-working stub instead. 
# You can either re-run clan2py with -l /path/to/library.so
# Or manually fix this by comment the ctypes.CDLL loading
_libraries = {}
_libraries['FIXME_STUB'] = FunctionFactoryStub() #  ctypes.CDLL('FIXME_STUB')

これをこう書き換えます。

point.py
# libraries['FIXME_STUB'] explanation
# As you did not list (-l libraryname.so) a library that exports this function
# This is a non-working stub instead. 
# You can either re-run clan2py with -l /path/to/library.so
# Or manually fix this by comment the ctypes.CDLL loading
_libraries = {}
_libraries['FIXME_STUB'] = ctypes.WinDLL(r'path\to\point.dll')

dllが一つならばリンクするキーはFIXME_STUBのままでいい気もします。 linuxならclang2pyの-lオプションで自動でやってくれるかもしれないです。

pythonから呼び出してみる

構造体を作ってprint_positionに参照渡しする。

main.py
import ctypes
import point

p = point.Point()
p.x = 100
p.y = 200
point.print_position(ctypes.byref(p))

成功例

成功していればcのソースに従ってX,Yのポイントが出力されます。
image.png

感想

フィールドが補完されないのがちょっとつらいです。
あとメモリダンプをデバッガから確認しづらいのも苦しいです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?