私は次の設定をしています:
- Python バインディングを備えた GDAL ライブラリ (SWIG)
- グルーコード (Python)
- ctypes と連動する AC ライブラリ
Dataset
SWIGオブジェクトの基になるデータセット ポインター/ハンドルを C ライブラリに渡したいです。このポインターを取得するにはどうすればよいですか?
C ライブラリと SWIG のインターフェイスを取りたくありません。
実際には非常に簡単でした。私のソリューションが移植可能であることを願っています。私のC関数の定義は次のようになります。
int myfunc(GDALDatasetH ds);
次に、私のctypes
定義は次のようになります。
_lib = C.LibraryLoader(C.CDLL).LoadLibrary(lib_path)
_myfunc = _lib.myfunc
_myfunc.argtypes = [C.c_void_p]
_myfunc.restype = C.POINTER(C.c_char)
そして私はC関数を次のように呼び出すことができます:
ds = gdal.Open(path)
...
_myfunc(C.c_void_p(long(ds.this)))
この問題に対する ctypes アプローチに関する私の留保は、ds オブジェクトの参照カウントが自動的にインクリメントされず、スコープ外に出た場合に不適切なポインターになることです。
より良いアプローチは、データ参照カウンターを管理する C python 拡張モジュールを定義することです。
オブジェクトを保持するために static PyObject * を使用していますが、明らかに実際の実装ではよりインテリジェントに格納されます。
static PyObject * ds;
PyObject* GiveDsToC(PyObject * self, PyObject * args)
{
PyObject * pThis=NULL;
unsigned long addr;
if(!PyArg_ParseTuple(args, "O", &ds))
return NULL;
/* Ensure the interpreter keeps ds around while we have it */
Py_INCREF(ds);
pThis = PyObject_GetAttrString(ds, "this"); // new reference
addr = PyLong_AsLong(pThis); // convert using __int__ method
Py_DECREF(pThis); // Release the object back
CallSomeCFunction(addr);
Py_RETURN_NONE;
}
void FinishedWithDS(void)
{
// Lock the GIL and decrement the reference counter
PyGILState_STATE state = PyGILState_Ensure();
Py_DECREF(ds);
PyGILState_Release(state);
}