Предоставить непрозрачный тип для Python с помощью Swig
Я пытаюсь обернуть непрозрачный тип в C, используя SWIG, но я не могу понять, как это сделать. У меня есть три файла, перечисленные ниже:
simplelib.c:
#include <assert.h>
#include <stdlib.h>
#include "simplelib.h"
struct _simplelib_my_type {
double x;
double y;
};
simplelib_MyType *
simplelib_mytype_create(double x, double y)
{
simplelib_MyType *mt = NULL;
if (mt = calloc(1, sizeof(*mt))) {
mt->x;
mt->y;
}
return mt;
}
void
simplelib_mytype_destroy(simplelib_MyType *mt)
{
if (mt) {
free(mt);
mt = NULL;
}
}
int
simplelib_mytype_calc(const simplelib_MyType *mt, double z, double *res)
{
int ok = 0;
assert(mt);
if (z != 0.0) {
*res = mt->x * mt->y / z;
ok = 1;
}
return ok;
}
simplelib.h:
#ifndef SIMPLELIB_H
#define SIMPLELIB_H
typedef struct _simplelib_my_type simplelib_MyType;
simplelib_MyType *simplelib_mytype_create(double x, double y);
void simplelib_mytype_destroy(simplelib_MyType *mt);
int simplelib_mytype_calc(const simplelib_MyType *mt, double z, double *res);
#endif // SIMPLELIB_H
и мой интерфейсный файл simplelibswig.i:
%module simplelibswig
%{
extern "C" {
#include "simplelib.h"
}
%}
%include "simplelib.h"
Я строю все, используя CMake, используя этот CMakeLists.txt:
project(simplelib)
cmake_minimum_required(VERSION 2.8)
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
find_package(PythonLibs)
include_directories(${PYTHON_INCLUDE_PATH})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
SET(CMAKE_SWIG_FLAGS "")
SET_SOURCE_FILES_PROPERTIES(simplelibswig.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(simplelibswig.i PROPERTIES SWIG_FLAGS "-includeall")
add_library(${PROJECT_NAME}
simplelib.h
simplelib.c
)
swig_add_module(simplelibswig python simplelibswig.i)
swig_link_libraries(simplelibswig ${PYTHON_LIBRARIES} ${PROJECT_NAME})
Теперь, что я хотел бы сделать, это 1) переименовать непрозрачный тип из simplelib_MyType в MyType 2) представить тип с помощью конструктора / деструктора / метода с использованием%extend
Проблема в том, что вышеописанное не раскрывает тип во встроенном модуле python. Я ожидаю, что файл интерфейса предоставит typedef как класс с именем typedefed, но этого не происходит. Таким образом, я не могу перейти к пункту 1 и 2 выше. Что я делаю неправильно?
С наилучшими пожеланиями, Рикард
1 ответ
Swig нуждается в определении вашего непрозрачного типа, чтобы он мог быть открыт и расширен. Даже неточный сделает:
%module simplelibswig
%{
extern "C" {
struct _simplelib_my_type { int _unused; };
#include "simplelib.h"
}
%}
struct _simplelib_my_type { int _unused; };
%include "simplelib.h"
Чтобы SWIG также управлял памятью непрозрачного объекта, функции, которые его создают и уничтожают, должны быть помечены так:
%newobject simplelib_mytype_create;
%delobject simplelib_mytype_destroy;
%include "simplelib.h"
Теперь, если вызов кода Python simplelib_mytype_create
возвращаемое значение будет принадлежать Python вместо кода C, и будет освобождено, когда все ссылки будут уничтожены. Но если simplelib_mytype_destroy
При вызове функции Python будет знать, что объект уже освобожден, и не будет освобождать его снова.
Вы можете %extend
а также %rename
тип сейчас тоже:
%module simplelibswig
%{
struct _simplelib_my_type { int _unused; };
#include "simplelib.h"
%}
%rename(opaque) _simplelib_my_type;
struct _simplelib_my_type { int _unused; };
%newobject simplelib_mytype_create;
%delobject simplelib_mytype_destroy;
%include "simplelib.h"
%extend _simplelib_my_type {
_simplelib_my_type(double a,double b) { return simplelib_mytype_create(a,b); }
%apply double *OUTPUT { double* res };
int calc(double z, double *res) { return simplelib_mytype_calc($self,z,res); }
~_simplelib_my_type() { simplelib_mytype_destroy($self); }
}
Выход
>>> import simplelibswig
>>> simplelibswig.opaque(1.2,3.4)
<simplelibswig.opaque; proxy of <Swig Object of type 'simplelib_MyType *' at 0x0000000002872DE0> >
>>> a=simplelibswig.opaque(1.2,3.4)
>>> a.calc(3.4)
[1, 1.2]
>>> a.calc(1.2)
[1, 3.4000000000000004]