Гэта мая калекцыя SWIG typemap FAQ для Python і Perl5. Tcl частка будзе прадастаўлена пазней. Версія SWIG заснаваны на 1.3a5. Усе крэдыты павінны пайсці на аўтараў у SWIG спіс рассылкі. Прамая любыя вашы пытанні аб гэтым часта задаюць пытанні pinhong@eecs.berkeley.edu. [Апошняе абнаўленне 06/06, 2001]
[Адказ] У прынцыпе, вы можаце праверыць яго з SWIG кіраўніцтва карыстальніка. Вось некаторыя з іх:
[Python]
| Python -> C/C++, %typemap(python,in) | |
|---|---|
| char * |
%typemap(python,in) char * {
if (!PyString_Check($source)) {
PyErr_SetString(PyExc_TypeError,not a string);
return NULL;
}
$target = PyString_AsString($source);
}
|
| int, short, long |
%typemap(python,in) int,short,long {
if (!PyInt_Check($source)) {
PyErr_SetString(PyExc_TypeError,"not an integer);
return NULL;
}
$target = ($type) PyInt_AsLong($source);
}
|
| float, double |
%typemap(python,in) float,double {
if (!PyFloat_Check($source)) {
PyErr_SetString(PyExc_TypeError,not a float);
return NULL;
}
$target = ($type) PyFloat_AsDouble($source);
}
|
| FILE * |
%typemap(python,in) FILE * {
if (!PyFile_Check($source)) {
PyErr_SetString(PyExc_TypeError,not a file);
return NULL;
}
$target = PyFile_AsFile($source);
}
|
| C/C++ -> Python, %typemap(python,out) | |
|---|---|
| char * |
%typemap(python,out) char *,const char *{
$target = Py_BuildValue("s", ($type) $source);
}
або
%typemap(python,out) char *,const char *{
$target=Py_BuildValue("s#",($type)$source,length);
}
|
| int, short |
%typemap(python,out) int, short {
$target = Py_BuildValue("i", ($type) $source);
}
|
| long |
%typemap(python,out) long {
$target = Py_BuildValue("l", ($type) $source);
}
|
| float, double |
%typemap(python,out) float, double {
$target = PyBuild_Value("d",($type) $source);
}
|
| FILE * |
%typemap(python,out) FILE * {
$target = PyFile_FromFile($source);
}
|
| Perl -> C/C++, %typemap(perl5,in) | |||
|---|---|---|---|
| char * |
%typemap(perl5,in) char * {
$target = SvPV($source,PL_na);
}
або
%typemap(perl5,in) char * {
$target = SvPV($source,length);
}
| ||
| int, short, long |
%typemap(perl5,in) int,short,long {
$target = ($type) SvIV($source);
}
| ||
| двайны |
%typemap(perl5,in) float, double {
$target = ($type) SvNV($source);
}
|
| C/C++ -> Perl, %typemap(perl5,out) | |
|---|---|
| char * |
%typemap(perl5,out) char * {
$target = sv_newmortal();
sv_setpv($target,$source);
//sv_setpvn($target,$source,length);
argvi++;
}
|
| int, short, long |
%typemap(perl5,out) int,short,long {
$target = sv_newmortal();
sv_setiv($target,(IV) $source);
argvi++;
}
|
| float,double |
%typemap(perl5,out) float, double {
$target = sv_newmortal();
sv_setiv($target,(double) $source);
argvi++;
}
|
typedef internal_foo_struct foo; foo *foo_new(void); void foo_destroy(foo *f); int foo_connect(foo *f); int foo_do_something(foo *f, int n); int foo_disconnect(foo *f);Я хацеў бы карту ў аб'ект у глыток-выхад мовах.
[Адказ] вызначыць яго ў SWIG файл інтэрфэйсу наступным чынам:
class foo {
public:
%addmethods {
foo() {
return foo_new();
}
~foo() {
foo_destroy(self);
}
int connect() {
return foo_connect(self);
}
int do_something(int n) {
return foo_do_something(self, n);
}
// etc...
}
};
Абавязкова выкарыстоўвайце-C + + сьцяг пры выкліку глыток. Калі ў вас ёсць канструктар, як
foo *new_foo(int n);Вам не трэба абгарнуць яго з іншай абалонкай, таму addmethods павінны быць:
%addmethods foo{
foo(int n);
}
tw_createDialogue(20,20, 2,2, 0, "NULL", "NULL");
[Адказ] Выкарыстоўвайце наступны элемент мовы для прадстаўлення NULL:
[Адказ] наступны код з SWIG1.1p5 прыкладаў.
%typemap(python,in) char ** {
/* Check if is a list */
if (PyList_Check($source)) {
int size = PyList_Size($source);
int i = 0;
$target = (char **) malloc((size+1)*sizeof(char *));
for (i = 0; i < size; i++) {
PyObject *o = PyList_GetItem($source,i);
if (PyString_Check(o))
$target[i] = PyString_AsString(PyList_GetItem($source,i));
else {
PyErr_SetString(PyExc_TypeError,"list must contain strings");
free($target);
return NULL;
}
}
$target[i] = 0;
} else {
PyErr_SetString(PyExc_TypeError,"not a list");
return NULL;
}
}
%typemap(python,freearg) char ** {
free((char *) $source);
}
%typemap(python,out) char ** {
int len,i;
len = 0;
while ($source[len]) len++;
$target = PyList_New(len);
for (i = 0; i < len; i++) {
PyList_SetItem($target,i,PyString_FromString($source[i]));
}
}
[Perl]
%typemap(perl5,in) char ** {
AV *tempav;
I32 len;
int i;
SV **tv;
if (!SvROK($source))
croak("$source is not an array.");
if (SvTYPE(SvRV($source)) != SVt_PVAV)
croak("$source is not an array.");
tempav = (AV*)SvRV($source);
len = av_len(tempav);
$target = (char **) malloc((len+2)*sizeof(char *));
for (i = 0; i <= len; i++) {
tv = av_fetch(tempav, i, 0);
$target[i] = (char *) SvPV(*tv,PL_na);
}
$target[i] = 0;
};
// This cleans up our char ** array after the function call
%typemap(perl5,freearg) char ** {
free($source);
}
// Creates a new Perl array and places a char ** into it
%typemap(perl5,out) char ** {
AV *myav;
SV **svs;
int i = 0,len = 0;
/* Figure out how many elements we have */
while ($source[len])
len++;
svs = (SV **) malloc(len*sizeof(SV *));
for (i = 0; i < len ; i++) {
svs[i] = sv_newmortal();
sv_setpv((SV*)svs[i],$source[i]);
};
myav = av_make(len,svs);
for (i = 0; i < len; i++) {
/* SvREFCNT_dec(svs[i]); */
}
free(svs);
$target = newRV_noinc((SV*)myav);
sv_2mortal($target);
argvi++; /* This is critical! */
}
Калі вы не жадаеце спасылку масіва, паспрабуйце наступнае:
%typemap(perl5,out) char ** {
int i = 0;
while ($source[i]) {
if(i+1>items){ EXTEND(sp,1);}
ST(argvi+i) = sv_newmortal();
sv_setpv((SV *)ST(argvi+i),$source[i]);
i++;
}
argvi+=i;
}
typedef struct
{
unsigned int Offset;
int Range;
int Pattern[12];
} TriggerStructure;
Ёсць шмат структур, як гэта ў гэтым API. Праблема ў тым, масіў цэлых лікаў (ці імкнецца, або без знака і г.д.) Як вы ведаеце, SWIG проста робіць толькі для чытання доступу для іх. Я прачытаў дакументацыю, але існуе вельмі мала пра гэта, нягледзячы на ??тое, "звычайнай з'явай". Тое, што я хацеў бы зрабіць з боку Python заключаецца ў наступным:
ts = TriggerStructure() ts.Pattern = [1, 2, 45, 54, 7, 8, 6, 7, 1, 10, 11, 12]Але код абалонкі заўсёды здаецца, што для стварэння SWIG аб'екта паказальнік на яго
[Адказ] SWIG1.3a5 генеруе да memberin typemap паказальнік выкліку пераўтварэнні, які правярае уваход для правільнага тыпу дадзеных і абмежаванняў, як вы можаце напісаць typemaps, напрыклад,
if ((SWIG_ConvertPtr(argo1,(void **) &arg1,SWIGTYPE_p_int,1)) == -1) return NULL;На самай справе, $ крыніца ў typemap павінна быць "argo1" для гнуткасці, а не "arg1". Вось Perl скрыпт для каментавання гэтага паказальніка пераўтварэнні.
#!/usr/bin/env perl -i.bak
while(<>){
if(/"OO:(\w+?)_(\w+?)_(set|get)"/o){
print;
$_ = <>;
print;
$conv=<>;
$_=<>;
if(/^\s*\{\s*$/o){
print "/* $conv*/\n";
}else{
print $conv;
}
}
print;
}
Цяпер вы можаце напісаць пару typemaps:
%typemap(python, memberin) int [ANY]{
// source should be argo1
if (PyList_Check(argo1)) {
int size = PyList_Size(argo1);
int i = 0;
for(i=0;i<size;i++){
PyObject *o = PyList_GetItem(argo1,i);
if (PyInt_Check(o)){
$target[i] = (int)PyInt_AsLong(o);
}else{
PyErr_SetString(PyExc_TypeError,"List must contain integers");
return NULL;
}
}
for(i=size;i<$dim0;i++) $target[i]=0;
}
}
%typemap(python, out) int* TriggerStructure_Pattern_get{
int len,i;
len = 12;
$target = PyList_New(len);
for (i = 0; i < len; i++) {
PyList_SetItem($target,i,PyInt_FromLong((long)$source[i]));
}
}
Яны павінны служыць таму, што вам трэба. Не забудзьцеся запусціць скрыпт на Perl вышэй на выхадзе SWIG '* _wrap.c "закаментаваць залішнія пераўтварэнні паказальніка. Калі вы хочаце атрымаць доступ да асобных элементаў ў шаблоне, скажам, напрыклад,
ts = TriggerStructure() ts.Pattern = [1, 2, 45, 54, 7, 8, 6, 7, 1, 10, 11, 12] ts.Pattern[2]=22 print ts.Pattern[11]Вы можаце зрабіць наступнае:
%inline %{
struct TSPattern{
int *trig;
int __getitem__(int i){
if(i>12){
PyErr_SetString(PyExc_IndexError,"Index is out of range");
return 0;
}
return trig[i];
}
void __setitem__(int i,int x){
if(i>12){
PyErr_SetString(PyExc_IndexError,"Index is out of range");
return;
}
trig[i]=x;
}
};
%}
%typemap(python, memberin) TSPattern *{
// source should be argo1
int *tgt=(int*)$target;
if (PyList_Check(argo1)) {
int size = PyList_Size(argo1);
int i = 0;
for(i=0;i<size;i++){
PyObject *o = PyList_GetItem(argo1,i);
if (PyInt_Check(o)){
tgt[i] = (int)PyInt_AsLong(o);
}else{
PyErr_SetString(PyExc_TypeError,"List must contain integers");
return NULL;
}
}
for(i=size;i<12;i++) tgt[i]=0;
}
}
%typemap(python, out) TSPattern *{
static TSPattern t;
t.trig=(int*)$source;
$target=SWIG_NewPointerObj((void *)&t, SWIGTYPE_p_TSPattern);
}
typedef struct
{
unsigned int Offset;
int Range;
TSPattern *Pattern; // Note a type change here
} TriggerStructure;
%{ typedef struct {...} TriggerStructure;...%}
Мы выкарыстоўваем метады ў SWIG1.1 кіраўнік кіраўніцтва карыстальніка. 9. Недахопам для кода вышэй занадта шмат "вымярэнне" жорсткага кадавання. [Perl5] Для Perl, выкажам здагадку, што мы C структуры, як:
typedef struct _myStruct {
...
int myIntArray[4];
} myStruct
Выкарыстоўвайце наступную пару typemaps:
%typemap(perl5,out) int* myStruct_myIntArray_get{
AV *myav;
SV **svs;
if ($source) {
svs = (SV **) malloc(4*sizeof(SV *));
svs[0] = sv_newmortal();
sv_setiv((SV*) svs[0],$source[0]);
svs[1] = sv_newmortal();
sv_setiv((SV*) svs[1],$source[1]);
svs[2] = sv_newmortal();
sv_setiv((SV*) svs[2],$source[2]);
svs[3] = sv_newmortal();
sv_setiv((SV*) svs[3],$source[3]);
myav = av_make(4,svs);
free(svs);
$target = newRV_noinc((SV*)myav);
sv_2mortal($target);
argvi++;
}
}
%typemap(perl5,memberin) int myIntArray[ANY]{
AV *tempav;
int i;
SV **tv;
/* NOTE source = ST(1) */
if (!SvROK(ST(1)))
croak("input is not an array.");
if (SvTYPE(SvRV(ST(1))) != SVt_PVAV)
croak("input is not an array.");
tempav = (AV*)SvRV(ST(1));
for (i = 0; i < $dim0; i++) {
tv = av_fetch(tempav, i, 0);
$target[i] = (int) SvIV(*tv);
}
}
І, на жаль, вам неабходна змяніць "myModule_wrap.c", выкарыстоўваючы наступны сцэнар, каб выдаліць SWIG праверыць тыпу.
#!/usr/bin/env perl -i.bak
# mark_pl_tcheck.pl
$field=shift @ARGV;
while(<>){
if(/^\s*XS.+?${field}_set/o){
print;
while(<>){
if(/SWIG_ConvertPtr\(ST\(1\)/o){
while(<>){ last if /^\s*\}/;}
last;
}
print;
}
next;
}
print;
}
Запусціць пад UNIX:
unix> perl mark_pl_tcheck.pl myIntArray myModule_wrap.cЗрабіць і кампіляцыі *. C, і вы можаце праверыць яго
$myStructPtr = getMyStructPtr();
$myStructPtr->{myIntArray} = [ 1, 2, 3, 4]; # <-- not (1,2,3,4)!
print $myStructPtr->{myIntArray}[2];
Звярніце ўвагу, што
$myStructPtr->{myIntArray}[2]=99; # Any number
does NOT work. That is to say, the individual element can not be
left-hand-side.
It is possible to make it work. It is just tricky.
const emt_parameters *GetParameters(string element);
[Адказ] Вы заўсёды павінны праверыць, як радок будзе апрацавана. Калі C / C + + выклік будзе набыць (ўласная) гэтую радок, вы павінны выкарыстоўваць наступны код.
%typemap(python,in) string *, string&, string {
if (PyString_Check($source)) {
$target = new string(PyString_AsString($source),
PyString_Size($source));
}else{
PyErr_SetString(PyExc_TypeError,"not a string type");
return NULL;
}
}
%typemap(perl5,in) string *, string&, string {
$target=new string((char*)SvPV($source, PL_na));
}
// if the C/C++ does not acquire the string, you have to
// add this freearg typemap.
%typemap(python, freearg) string*, string&, string {
delete $source;
}
%typemap(perl5, freearg) string*, string&, string {
delete $source;
}
Калі вы ўпэўненыя, C / C + + функцыі не будуць набываць гэтую радок, вы можаце зрабіць наступнае, каб пазбегнуць выдзялення памяці (па "новай"):
%typemap(python,in) string*, string&, string{
if (PyString_Check($source)) {
static string tmp_string(NULL,0);
tmp_string=string(PyString_AsString($source),
PyString_Size($source));
$target=&tmp_string;
}else{
PyErr_SetString(PyExc_TypeError,"not a string type");
return NULL;
}
}
%typemap(perl5,in) string*, string&, string{
static string tmp_string(NULL,0);
tmp_string=string((char*)SvPV($source, PL_na));
$target=&tmp_string;
}
typemaps String з прасцей:
%typemap(python,out) string*, string&{
$target = Py_BuildValue("s#",$source->c_str(),$source->size());
}
%typemap(python,out) string {
$target = Py_BuildValue("s#",$source->c_str(),$source->size());
delete $source;
}
%typemap(perl5,out) string*, string&{
sv_setpv($target,$source->c_str());
}
%typemap(perl5,out) string {
sv_setpv($target,$source->c_str());
delete $source;
}
%module example
%inline %{
char *ret_null(){
return (char*)NULL;
}
%}
Я атрымаў дамп.
[Адказ] З дапамогай гэтай typemap, яно павінна быць у парадку
%typemap(python,out) char *{
$target=Py_BuildValue("s",$source);
}
bool Read(istream & infile); bool Write(ostream & ofile);Любая спроба выкарыстоўваць гэтыя функцыі спарадзіла тую ж памылку:
TypeError: Type error. Expected _p_istream
[Адказ] фокус у тым, каб зрабіць SWIG лічаць геат з'яўляецца вытворным ад IStream. Вам не трэба нічога казаць у рэальным C + + кода. Паспрабуйце гэта:
%module istream
%{
#include <iostream.h>
#include <fstream.h>
%}
class istream{ };
class ifstream:public istream{
public:
ifstream(const char *fn);
~ifstream();
};
Праверце гэта:
from istream import *
ifs=ifstream("test.txt")
Read(ifs)
[Адказ] Калі вы дазволіце, каб змяніць your_module_wrap.c, вы можаце выкарыстоўваць наступныя Perl скрыпт:
#!/usr/bin/perl
$fromType=shift @ARGV;
$toType=shift @ARGV;
while(<>){
if(/^static\s+swig_type_info\s+_swigt__p_$toType\[\]/o){
print << "END";
static void *_p_${fromType}To_p_${toType}(void *x) {
return (void *)(($toType *) (($fromType *) x));
}
END
s/("$toType\s*\*"\}),/$1,{"_p_$fromType",_p_${fromType}To_p_${toType}},/o;
}
print;
}
Выкарыстайце наступную каманду, каб зрабіць Foo сумяшчальны з несапраўднымі.
perl type_conv.pl void Foo your_module_wrap.c > new_wrap.cШто яна робіць гэта, каб ўставіць запіс тыпу пераўтварэнні ў SWIG тыпу праверкі сістэмы, каб пазбегнуць праблемы вы атрымалі.
[Адказ] На самай справе, вам не патрэбныя ніякія typemap для несапраўдным * у typemap. SWIG не выконвае праверку тыпаў у дадзеным выпадку.
Пры выкарыстанні '* несапраўднымі ", як выхад, вы павінны воблачнасць яго тып дадзеных вам трэба. Праверыць гэта FAQ.
[Адказ] Выкарыстоўвайце наступны код:
[Python]
def ptrcast(t,ptr):
import re
if type(t)!=type(""):
if len(t.__bases__)==1:
t=t.__bases__[0].__name__
else: t=t.__name__
if hasattr(ptr,"this"):
ptr=ptr.this
return re.sub(r"(_p)+_\w+$","_p_"+t,ptr)
Скажам, напрыклад, калі вы атрымалі "_101d68_p_Foo" паказальнік, вы можаце больш кінуў яго па:
a_Bar_ptr=ptrcast(Bar,'_101d68_p_Foo')Для цені аб'екта, вы можаце зрабіць наступнае:
a_Bar_obj=BarPtr(ptrcast(Bar,'_101d68_p_Foo'))
[Perl5]
bless $ptr,"NewClass";Калі вы выкарыстоўваеце цені аб'екта, вам трэба зрабіць,
bless $ptr,"NewClass";
bless tied{%{$ptr}},"NewClass";
>>> v = myVector() >>> # fill v with some values >>> w = map(lambda x:x+1, v)апошняя каманда не працуе, як чакалася, а менавіта, карту () не выяўляе канцы майго кантэйнера і ўваходзіць у бясконцы цыкл.
[Адказ] Вы можаце павысіць IndexError калі кантэйнер доступ па-за дыяпазону. Як правіла, вы можаце напісаць такі код:
class MySeq{
int _len;
AnItem *arr;
public:
...
%addmethods {
int __len__(){ return _len;}
AnItem* __getitem__(int i){
if (i < 0 || i >= _len) {
PyErr_SetString(PyExc_IndexError, "array index out of range");
return NULL;
}
return arr[i];
}
void __setitem__(int i, AnItem *p){ arr[i]=p;}
}
};
Існуе больш зручны спосаб гэта зрабіць. Вы можаце знайсці яго ў SWIG Кіраўніцтва карыстальніка Кіраўнік 9. Больш шырокае прыклад можна знайсці тут [Адказ]
%pragma(python) code="python source code"Дадае "Python зыходным кодам" бліжэй да пачатку. Ру файл.
%pragma(python) include="filename"Дадае змесціва файла ў канец. Ру файл. Гэта робіцца дакладна таксама для Perl.
%pragma(perl5) code="perl source code" %pragma(perl5) include="filename"Звярніце ўвагу, што SWIG можа ўключаць у сябе дадатковы код толькі перад кодам SWIG згенэраваная за '*. вечара. Калі вам неабходна ўставіць яго ў рэшце рэшт, вы павінны відавочна аб'яднання дадатковы код для вашага '*.pm'.
%pragma(python) addtomethod="methodName:python source code"Дадае "Python зыходны код" да канца метад пад назвай "имяМетода" у цяперашняе вызначэнне класа. Двукоссі тэкст можа займаць некалькі радкоў, але вы павінны пераканацца, што вы атрымліваеце права водступу.
%pragma(python) addtoclass="python source code"Дадае "Python зыходны код" у канцы вызначэння класа для бягучага класа. Двукоссі тэкст можа займаць некалькі радкоў, але вы павінны пераканацца, што вы атрымліваеце права водступу. Першыя два прагм былі ў SWIG на працягу доўгага часу. Апошнія два былі прадстаўлены мне і Дэвід дадаў іх у адным з паведамленні 1.1p5 рэлізаў, так што вы можаце выкарыстоўваць іх, калі вы ўсё яшчэ карыстаецеся канчатковага 1.1-883 рэлізе. Я havn't праверылі ўсе жа, калі яны ўсё яшчэ працуюць у 1.3aX...
[Адказ] Вы можаце напісаць свой ??уласны деструктор ў C + +, Python і зрабіць выклік __del__ з іншым метадам класа.
%pragma(python) include="new__del__.py"А ў "new__del__.py", вы павінны мець
class Foo(Foo): ... def __del__(self,myClassc=myClassc): if self.thisown == 1 : myClassc.my_delete_Foo(self)
//file truc.h
class truc
{...
void mymethod(int, int);
void mymethod(float);
}
SWIG дасць памылку, як гэта:
Line 17. Function truc_mymethod (member mymethod) multiply defined (2nd definition ignored).
[Адказ] Вам неабходна пазначыць іншае імя для іх выкарыстання ў Python. Напрыклад,
class truc
{...
%name(mymethod_int) void mymethod(int, int);
%name(mymethod_float) void mymethod(float);
}
%pragma(python) include="truc_overloaded.py"
У truc_overloaded.py неабходна ўказаць наступнае:
class truc(truc):
def mythod(self,*args):
if len(args)==2:
val=apply(trucc.mymethod_int,args)
else:
val=apply(trucc.mymethod_float,args)
return val
Вось Perl скрыпт, які аўтаматычна робіць гэта за вас, калі вашы перагружаныя інтэрфейсы адрозніваюцца толькі колькасцю аргументаў:
#!/usr/bin/env perl
$ifile=shift @ARGV;
open(F,"swig -python -shadow -c++ $ifile 2>&1 |");
$errCount=0;
while(<F>){
if(/multiply defined /o){
/Line (\d+)\s*\.\s*(\w+)\s+(\S+)/o;
$n=$1;
$md{$n}=[$2,$3,0];
if(/\(member /o){
$md{$n}[2]=1;
}
}
}
close(F);
open(IFILE,$ifile);
unshift @line,"";
while(<IFILE>){
#$line[$num]="%name(${name}__L$num) ".$line[$num];
if(/%module\s+(\S+)/o){ $mod=$1;}
if(/class\s+(\w+)/o){ $class=$1;}
if(exists $md{$.}){
$s=$_;
if($_ !~ /\)\s*;/o && $_ =~ /\)\s*\{/o){
while(<IFILE>){
$s.=$_;
if(/\)\s*;/o || /\)\s*\{/o){ last;}
}
}
$c=0;
$s =~ s/,/$c++,","/oge;
if($s !~ /\(\s*(void)?\s*\)/m){
$c++;
}
if($md{$.}[2] || $md{$.}[0] =~ /Const/o){
push @{$redef{$class}{$md{$.}[1]}},[$.,$c];
}else{
push @{$redef{""}{$md{$.}[1]}},[$.,$c];
}
$md{$.}[1] =~ s/^new_//o;
print "%name($md{$.}[1]__L$.) $s";
next;
}
print;
}
close(IFILE);
print "%pragma(python) include=\"$mod\_overloaded.py\"\n";
open(F,">${mod}_overloaded.py");
for $cl(keys %redef){
if($cl ne ""){
print F "
class $cl\($cl):\n";
for $f(keys %{$redef{$cl}}){
$el="";
if($f =~ /^new_/o){
$clname="";
print F " def __init__\(self,*args):\n";
}else{
$clname="${cl}_";
print F " def $f\(*args):\n";
}
for $i(@{$redef{$cl}{$f}}){
print F " ${el}if len(args)==$i->[1]:\n";
print F " val = apply(${mod}c.${clname}${f}__L$i->[0],args)\n";
$el="el";
}
print F " else: val = apply(${mod}c.${clname}${f},args)\n";
if($f !~ /^new_/o){ print F " return val\n";}
}
}else{
for $f(keys %{$redef{$cl}}){
$el="";
print F "def $f\(*args):\n";
for $i(@{$redef{$cl}{$f}}){
print F " ${el}if len(args)==$i->[1]:\n";
print F " val = apply(${mod}c.${clname}${f}__L$i->[0],args)\n";
$el="el";
}
print F " else: val = apply(${mod}c.${clname}${f},args)\n";
print F " return val\n";
}
}
}
close(F);
class Foo {
public:
%name (Foo_A) Foo();
%name (Foo_B) Foo(int i);
%name (Foo_C) Foo(float f);
...};
У мове Python, ён павінен быць у стане ідэнтыфікаваць arugments і зрабіць адпаведны канструктар. [Адказ] Я атрымаў складаны метад. Устаўце наступныя радкі ў ваш файл інтэрфэйсу:
%pragma(python) include="override_Foo_init.py"У override_Foo_init.py:
class Foo(Foo): # <=== Tricky here!
def __init__(self,*_args,**_kwargs):
if len(_args)==0:
self.this = apply(Fooc.new_Foo_A,_args,_kwargs)
elif type(_args[0])==type(1):
self.this = apply(Fooc.new_Foo_B,_args,_kwargs)
elif type(_args[0])==type(0.1):
self.this = apply(Fooc.new_Foo_C,_args,_kwargs)
self.thisown = 1
void foo(int *argX, int *argY);% Typemap (Python, у) існуе для абодвух пераменных. Ці ёсць спосаб прымусіць typemap% (у) для argX для выканання перад typemap% (у) для argY? Гэта можа быць карысна, напрыклад, у тых выпадках, калі argY ў 3 элемент масіву, памеры 3D масіва, на які паказвае argX.
[Адказ] Хоць метад ніжэй складана, вы можаце зрабіць гэта шляхам замены функцыі азначэнні ў SWIG і З у два разы, напрыклад,
%{
#define fake_foo(arg1,arg2,arg3) foo(arg3,arg1,arg2)
%}
int fake_foo(char *arg1,char *arg2,char *arg3);
%pragma(python) code="def foo(arg3,arg1,arg2):
return fake_foo(arg1,arg2,arg3)";
fake_foo() is the function prototype seen by SWIG, and
therefore it is converted as expected. However, we call
it by the way it is originally defined i.e. foo().
MsOle * msOleString(char *str, int length);Ён генеруе код наступныя абгорткі 'C':
if(!PyArg_ParseTuple(args,"si:msOleString",&_arg0,&_arg1))Што мне трэба, гэта:
if(!PyArg_ParseTuple(args,"s#:msOleString",&_arg0,&_arg1))Калі б я руку рэдагаваць код абгорткі "З", чым усё добра. Калі я раблю не так, то генеруецца выключэнне, таму што мой _arg0 змяшчае '\ 0' у сярэдзіне буфера.
[Адказ] Паспрабуйце гэта:
%typemap(python,in) char *str{
if (PyString_Check($source)) {
$source=Py_BuildValue("(O)",$source);
if(!PyArg_ParseTuple($source,"s#:msOleString",&$target,&arg1))
return NULL;
}else{
PyErr_SetString(PyExc_TypeError,"not a string type");
return NULL;
}
}
%typemap(python,ignore) int length{
}
void f(double* a, int n)
{
int i;
for(i=0;i<n;i++)
a[i] = double(i)/double(n);
}
з некаторай дапамогай спісу Numpy мне ўдалося атрымаць рабочую інтэрфейсу, такіх як:
>>> import Numeric >>> import NumExt >>> a = Numeric.arange(0.0,10.0) >>> NumExt.f(a,len(a))Я хацеў бы больш элегантным інтэрфейсам, не маючы прадставіць даўжыню масіва:
>>> NumExt.f(a)
[Адказ] фокус у тым, каб стварыць паказальнік на ўваход $ мэты.
%module pass_info
%typemap(python,ignore) int n(int *ptr_n){
ptr_n=&$target;
}
%typemap(python,in) double *a{
int i,size;
*ptr_n=size=PyList_Size($source);
$target=(double *)malloc(sizeof(double)*size);
for(i=0;i<size;i++){
$target[i]=PyFloat_AsDouble(PyList_GetItem($source,i));
}
}
%typemap(python,freearg) double *a{
free($source);
}
%inline %{
#include <stdio.h>
void f(double* a, int n)
{
int i;
for(i=0;i<n;i++)
a[i] = (double)i/(double)n;
}
%}
extern int SmDefineVocab(char *,short,*SM_VOCWORD[],SM_MSG *);SM_VOCWORD чакае масіў паказальнікаў. Што такое typemap для SM_VOCWORD **?
%define array_in(T)
%typemap(python,in) T **{
if(PyList_Check($source)) {
int size = PyList_Size($source);
int i = 0;
$target = (T **) malloc(size*sizeof(T*));
for(i = 0; i < size; i++) {
PyObject *o = PyList_GetItem($source,i);
T *ptr;
if ((SWIG_ConvertPtr(o,(void **) &ptr,
SWIGTYPE_p_##T,1)) == -1) return NULL;
$target[i] = ptr;
}
} else {
PyErr_SetString(PyExc_TypeError,"not a list type");
return NULL;
}
}
%typemap(python,freearg) T **{
free($source);
}
%typemap(perl5,in) T **{
if (!SvROK($source))
croak("$source is not an array.");
if (SvTYPE(SvRV($source)) != SVt_PVAV)
croak("$source is not an array.");
tempav = (AV*)SvRV($source);
len = av_len(tempav);
$target = (T **) malloc(len*sizeof(char *));
for (i = 0; i <= len; i++) {
tv = av_fetch(tempav, i, 0);
T *ptr;
if ((SWIG_ConvertPtr(av,(void **) &ptr,
SWIGTYPE_p_##T,1)) == -1) return NULL;
$target[i] = ptr;
}
}
%typemap(perl5,freearg) T **{
free($source);
}
%enddef
Вы можаце выкарыстоўваць гэтую array_in макрас ў файл інтэрфейсу для стварэння typemap для SM_VOCWORD:
array_in(SM_VOCWORD);
[Адказ] Выкарыстаньне наступныя радкі макраса некалькіх вызначэнне ў SWIG, вы можаце зрабіць гэта вельмі агульны характар:
%define vector_typemap(T)
%typemap(python,out) vector<T *> *, vector<T *> &{
$target = PyList_New(0);
if($source){
for(vector<T *>::iterator i=$source->begin();
i!=$source->end();i++){
PyObject *o=SWIG_NewPointerObj((void *)(*i), SWIGTYPE_p_##T);
PyList_Append($target,o);
Py_XDECREF(o);
}
//delete $source; //depends on your code
}
}
%typemap(perl5,out) vector<T *> *, vector<T *> &{
if($source){
if($source->size()>items){
EXTEND(sp,$source->size()-items);
}
for(vector<T *>::iterator i=$source->begin();
i!=$source->end();i++){
ST(argvi) = sv_newmortal();
SWIG_MakePtr(ST(argvi++), (void *)(*i), SWIGTYPE_p_##T);
}
//delete $source; //depends on your code
}
}
%enddef
Напрыклад, у вас ёсць "Cell" Вектар быць SWIGified. Выкарыстоўвайце наступны код у вашым інтэрфейс файла:
vector_typemap(Cell);Вы можаце праверыць гэта,
swig -E your_interface_file.i
struct rtype { };
int foo(rtype *OUTPUT);
Foo будзе запоўніць змесціва структуры паказалі на выхад. [Адказ]
%include typemaps.i
%define ptr_argout(T)
%typemap(python,argout) T* OUTPUT{
PyObject *o=SWIG_NewPointerObj((void *)$source, SWIGTYPE_p_##T);
$target = l_output_helper($target,o);
}
%typemap(python,ignore) T* OUTPUT{
static T temp;
$target=&temp;
}
%typemap(perl5,argout) T* OUTPUT{
PyObject *o=SWIG_NewPointerObj((void *)$source, SWIGTYPE_p_##T);
$target = l_output_helper($target,o);
}
%typemap(perl5,ignore) T* OUTPUT{
static T temp;
$target=&temp;
}
%enddef
Зараз вы можаце выкарыстаць:
ptr_argout(rtype,OUTPUT); int foo(rtype *OUTPUT);Памятаеце вяртання структура статычнай зменнай тыпу. Вы не можаце трымаць значэння ў папярэдні прызыў.
Акрамя таго, можна вылучыць памяць для яго, напрыклад:
%include typemaps.i
%define ptr_argout(T)
%typemap(python,argout) T* OUTPUT{
PyObject *o=SWIG_NewPointerObj((void *)$source, SWIGTYPE_p_##T);
$target = l_output_helper($target,o);
}
%typemap(python,ignore) T* OUTPUT{
$target=(T*)malloc(sizeof(T));
}
%addmethods T{
~T(){
free(self);
}
}
%enddef
Int khepera_receive_serial (INT max_length, сімвал буфера *);Які выклікае адказвае вылучыць буфер з max_length байт, а функцыя вяртае фактычную даўжыню выкарыстаць. У мове Python, ён павінен у канчатковым выніку выглядае так:
>>> (length, buffer) = khepera_receive_serial( max_length )
[Адказ] Паспрабуйце гэта,
%typemap(python,ignore) char *buffer(char **temp){
temp=&$target;
}
%typemap(python,in) int max_length{
$target=PyInt_AsLong($source);
*temp=(char*)malloc($target);
}
%typemap(python,argout) char *buffer{
PyObject *o;
o = Py_BuildValue("s#",$source,result);
$target = t_output_helper($target, o);
free(*temp);
}
У прынцыпе, мы ствараем знак ** тэмпература ў кропцы назад у рэальны аргумент і вылучыць памяць. Калі мы ведаем max_length, мы размеркавання. * Тэмп гарантыі аргументу паказальнік правільна ўказалі. Для выхаднога буфера, мы ствараем прадстаўленне Python струны з вядомай даўжыні (гэта значыць вынік). Status GetItemAtIndex(int theIndex, Object* &item);якія вяртаюць прыватнасці пункт з спісу. Swig выкідвае паведамленне пра памылку на гэтай канструкцыі ў інтэрфейс файла. Пры выдаленні і дазваляе складанне інтэрфейс, калі я спрабую "пункт" доступ такім чынам, значэнне 'імя' не тое, што з ў спісе.
[Адказ] Вам трэба
shadowClassPtr(Object); // Make a C function ObjectPtr()
obj_argout(Object); // Make %typemap(python,argout) Object *REF_PTR{...}
typedef int Status;
// Notice that you should use Object *REF_PTR, instead of Object* &item!
Status GetItemAtIndex(int theIndex,Object* REF_PTR);
int GetGroupPriority(int32 groupID, uint8& priority);прыярытэт выхадны аргумент, які з'яўляецца тып вызначаецца як непадпісаным знак. З Python, я хацеў бы назваць яго так:
error, priority = classInst.GetGroupPriority(32)
[Адказ] Выкарыстаньне typemaps.i, вы можаце зрабіць гэта наступным
%include typemaps.i
%apply unsigned char* T_OUTPUT{ unit8& OUTPUT};
int GetGroupPriority(int groupID, unit8& OUTPUT);
[Адказ] Глядзіце наступны код:
%{
#define SWIG_module_name "Put_MyModuleName_here"
static PyObject *MyModuleName;
%}
%init %{
MyModuleName=PyImport_ImportModule(SWIG_module_name);
%}
%define shadowClassPtr(T)
%{
static PyObject *T##Ptr_o=NULL;
PyObject *T##Ptr(void *source,int own) {
char cbuf[512];
PyObject *o;
if(T##Ptr_o==NULL)T##Ptr_o=PyObject_GetAttrString(MyModuleName,"T""Ptr");
SWIG_MakePtr(cbuf,(void*)(source),SWIGTYPE_p_##T);
o=PyObject_CallFunction(T##Ptr_o, "(s)",cbuf);
if(own){
PyObject *val = PyInt_FromLong(1L);
PyObject_SetAttrString(o, "thisown", val);
}
return o;
}
%}
%enddef
// Declare a C function FooPtr() here
shadowClassPtr(Foo);
%include typemaps.i
%define obj_argout(T)
%inline %{
typedef T* T##ptr;
%}
%typemap(python,argout) T **, T##ptr &, T* REF_PTR{
PyObject *o=T##Ptr((void*) *$source,1);
$target = t_output_helper($target, o);
}
%typemap(python,ignore) T **,T##ptr &(T *temp){
$target=&temp;
}
%typemap(python,ignore) T* REF_PTR{
}
%typemap(python,argout) T *OUTPUT,T &{
PyObject *o=T##Ptr((void*) $source,1);
$target = t_output_helper($target, o);
}
%typemap(python,ignore) T *OUTPUT, T &{
$target=new T();
}
%enddef
// Define each type of argout typemaps
obj_argout(Foo);
// SWIG does not parse Foo* &p. Workaround is as follows:
void ret_Foo_refptr(Foo *REF_PTR);
%{
void ret_Foo_refptr(Foo *&p){
p=new Foo("Foo returns by ref ptr!");
}
%}
Аднаго паказальніка і заданне амаль так жа, з пункту гледжання typemap код, аднак, двайны падыход паказальнік накладвае адказнасць выдзяленне памяці на C / C + + руціннай сябе. [Perl] Для Perl, вы павінны мець дапаможныя функцыі (напрыклад, FooPtr2Obj) для дасягнення аб'екта shadowinig. SWIG як правіла, дае дабраславеньне скалярнага замест дабраславіў звязаныя хэш. Мы павінны зрабіць гэта ў функцыі Perl памочніка наступным чынам:
// Assume using swig -perl5 -shadow -compat
%define shadowClassPtr(T)
%{
SV* T##Ptr2Obj(void *src){
HV *hv=newHV();
SV *rv;
SV *sv = sv_newmortal();
SWIG_MakePtr(sv, (void *)src, SWIGTYPE_p_##T);
sv_magic((SV*)hv,sv,(int)'P',Nullch,0);
rv=newRV_noinc((SV*)hv);
sv_2mortal(rv);
return sv_bless(rv, SvSTASH(SvRV(sv)));
}
%}
%enddef
// Declare a C function FooPtr2Obj() here
shadowClassPtr(Foo);
%define obj_argout(T)
%inline %{
typedef T* T##ptr;
%}
%typemap(perl5,argout) T**, T##ptr &, T* REF_PTR{
if (argvi >= items) EXTEND(sp,1);
ST(argvi++)=T##Ptr2Obj((void *)*$source); // shadowing
//Uncomment the following two lines if no object shadowing
//ST(argvi) = sv_newmortal();
//SWIG_MakePtr(ST(argvi++), (void *)*$source, SWIGTYPE_p_##T);
}
%typemap(perl5,ignore) T **,T##ptr &(T *temp){
$target=&temp;
}
%typemap(perl5,ignore) T* REF_PTR{
}
%typemap(perl5,argout) T* OUTPUT,T &{
if (argvi >= items) EXTEND(sp,1);
ST(argvi++)=T##Ptr2Obj((void *)$source);
//Uncomment the following two lines if no object shadowing
//ST(argvi) = sv_newmortal();
//SWIG_MakePtr(ST(argvi++), (void *)$source, SWIGTYPE_p_##T);
}
%typemap(perl5,ignore) T *OUTPUT,T &{
$target=new T();
}
%enddef
>>> s = ipol2.Evaluate(3) >>> s '_41071eb8_p_pfQuat' >>> t = pfQuat() >>> t <C pfQuat instance at _41071ee8_p_pfQuat>Так T разглядаецца як праўдзівы напрыклад, S разглядаецца як просты паказальнік. Зараз, калі я называю 'дэль Т', SWIG спароджаных
static PyObject *_wrap_delete_pfQuat(PyObject *self, PyObject *args)называецца. Калі я называю 'дэль S', гэтая функцыя SWIG не называецца. І з верхнім UNIX, я бачу, што ёсць уцечкі мембраны: аб'ект Python PTR, магчыма, выдаленыя, але асноўная C + + аб'ект не з'яўляецца. Як я магу гэта выправіць?
[Адказ] Не забудзьцеся напісаць свой ??прататып функцыі пасля вызначэння класа ў інтэрфейс файла. Я паспрабаваў інтэрфейс файл, напрыклад так:
%module delobj
pfQuat Evaluate();
%inline %{
class pfQuat{
public:
pfQuat(){ }
~pfQuat(){ printf("object deleted in C++(%p)\n",this);}
};
%}
pfQuat Evaluate_OK();
%{
pfQuat Evaluate(){
return *(new pfQuat);
}
pfQuat Evaluate_OK(){
return *(new pfQuat);
}
%}
Вы можаце праверыць гэта з дапамогай скрыпту:
from delobj import * s=Evaluate() print "s=",s del s print "s is not really deleted!" t=Evaluate_OK() print "t=",t del t print "t should be deleted" print "End of test_delobj"Звярніце ўвагу, што "_41071eb8_p_pfQuat" не паказальнік на аб'ект для SWIG, але гэта структура паказальніка, які не мае на ўвазе якога-небудзь выдаліць C + + эксплуатацыі аб'екта, замест гэтага <C pfQuat например, на _41071ee8_p_pfQuat> фактычна раздрукаваны на
pfQuat.__repr__і гэта падказка, што гэтая пераменная Python быў далучаны да аб'екта Python. Праверце розніцу ў фармаце *. ру файл SWIG спароджаны:
Evaluate = delobjc.Evaluate def Evaluate_OK(*args, **kwargs): val = apply(delobjc.Evaluate_OK,args,kwargs) if val: val = pfQuatPtr(val); val.thisown = 1 return val
[Адказ] Праверыць гэтую Пытанні і адказы аб тым, як цень паказальнік на аб'ект. Вось мой прыклад кода:
shadowClassPtr(MyClass);
%define stl_vector_out(MyClass)
%typemap(python,out) vector<MyClass*>*{
$target = PyList_New(0);
if($source){
for(vector<MyClass*>::iterator i=$source->begin();
i!=$source->end();i++){
PyObject *optr=MyClass##Ptr((void*)*i,1);
PyList_Append($target,optr);
Py_XDECREF(optr);
}
// delete $source; // depends on your code
}
}
%enddef
Вы можаце выкарыстоўваць гэты макрас заклікаць да вектар вузла ў модулі test_obj_cast.
stl_vector_out(test_obj_cast,Node);Яшчэ прыклады для сачэння паказальнік даступныя ў гэтым FAQ.
'_41071eb8_p_pfQuat'але што я сапраўды хачу гэта цень паказальніка, скажам, напрыклад,
<C pfQuat instance at _41071ee8_p_pfQuat>.Як я магу цень яго ў C?
[Адказ]
#define new_obj_typecast(MyMod,MyClass,source,target) \
{ \
char cbuf[512]; \
PyObject *val = PyInt_FromLong(1L);\
PyObject *mod=PyImport_ImportModule("MyMod");\
PyObject *func=PyObject_GetAttrString(mod,"MyClass""Ptr");\
SWIG_MakePtr(cbuf,(void*)source,SWIGTYPE_p_##MyClass);\
target=PyObject_CallFunction(func, "(s)",cbuf);\
PyObject_SetAttrString(target, "thisown", val);\
Py_DECREF(func);\
Py_DECREF(mod);\
}
Калі вам не трэба валодаць гэтым аб'ектам, выканайце наступныя дзеянні:
#define new_obj_typecast(MyMod,MyClass,source,target) \
{ \
char cbuf[512]; \
PyObject *mod=PyImport_ImportModule("MyMod");\
PyObject *func=PyObject_GetAttrString(mod,"MyClass""Ptr");\
SWIG_MakePtr(cbuf,(void*)source,SWIGTYPE_p_##MyClass);\
target=PyObject_CallFunction(func, "(s)",cbuf);\
Py_DECREF(func);\
Py_DECREF(mod);\
}
Калі гэтая сачэнне аперацыі здараецца даволі часта, вы можаце зрабіць гэта:
%{
#define SWIG_module_name "Put_MyModuleName_Here"
static PyObject *MyModuleName;
%}
%init %{
MyModuleName=PyImport_ImportModule(SWIG_module_name);
%}
%define shadowClassPtr(T)
%{
static PyObject *T##Ptr_o=NULL;
PyObject *T##Ptr(void *source,int own) {
char cbuf[512];
PyObject *o;
if(T##Ptr_o==NULL)T##Ptr_o=PyObject_GetAttrString(MyModuleName,"T""Ptr");
SWIG_MakePtr(cbuf,(void*)(source),SWIGTYPE_p_##T);
o=PyObject_CallFunction(T##Ptr_o, "(s)",cbuf);
if(own){
PyObject *val = PyInt_FromLong(1L);
PyObject_SetAttrString(o, "thisown", val);
}
return o;
}
%}
%enddef
Калі ў вас ёсць клас Foo, наступны код стварае функцыю C PyObject * FooPtr (крыніца несапраўднымі *, Int ўласныя) ў інтэрфейс файла:
shadowClassPtr(Foo);Ужыванне argout typemap могуць быць:
shadowClassPtr(Foo);
%typemap(python,argout) Foo **{
$target=t_output_helper($target,FooPtr((void*)*$source,1));
}
%typemap(python,ignore) Foo **(Foo *temp){
$target=&temp;
}
// Assume using swig -perl5 -shadow -compat
%define shadowClassPtr(T)
%{
SV* T##Ptr2Obj(void *src){
HV *hv=newHV();
SV *rv;
SV *sv = sv_newmortal();
SWIG_MakePtr(sv, (void *)src, SWIGTYPE_p_##T);
sv_magic((SV*)hv,sv,(int)'P',Nullch,0);
rv=newRV_noinc((SV*)hv);
sv_2mortal(rv);
return sv_bless(rv, SvSTASH(SvRV(sv)));
}
%}
%enddef
// Declare a C function FooPtr2Obj() here
shadowClassPtr(Foo);
int foo(int argc, char **argv);Як я магу абгарнуць яго ў SWIG і зменнай функцыяй аргументу ў інтэрфейсе.
[Адказ] [Python] Вам трэба пару typemaps:
%typemap(python,ignore) char **argv{
int i;
int num_argv=PyTuple_Size(args);
$target=(char**)malloc(num_argv*sizeof(char *));
for(i=0;i<num_argv;i++){
PyObject *o=PyTuple_GetItem(args,i);
if(PyString_Check(o)){
$target[i]=PyString_AsString(o);
/* depending on your need for the following 2 conditions
}else if(PyInt_Check(o)){
char tmp[128];
sprintf(tmp,"%ld",PyInt_AsLong(o));
$target[i]=strdup(tmp);
}else if(PyFloat_Check(o)){
char tmp[128];
sprintf(tmp,"%g",PyFloat_AsDouble(o));
$target[i]=strdup(tmp);
// remember to release memory!
*/
}else
$target[i]="(not char *)";
}
args=Py_BuildValue("(i)",num_argv);
}
%typemap(python,freearg) char **argv{
free($source);
Py_DECREF(args);
}
Цяпер вы можаце выкарыстоўваць
foo("No","matter","how","many","arguments","I","got")
foo("it","is","OK")
%typemap(perl5,in) char **argv {
$target = (char **)
malloc(n_arg*sizeof(char *));
for (; n_arg; --n_arg) {
$target[n_arg-1]=
(char *)SvPV(ST(n_arg-1),PL_na);
}
}
%typemap(perl5,ignore) int argc(int n_arg){
$target=n_arg=items;
items=1;
}
%typemap(perl5,freearg) char **argv {
free($source);
}
[Адказ] Выкарыстаньне наступны сцэнар Perl, вы можаце працаваць з большасцю перагрузкі аператараў кода шляхам дадання "% addmethods" частцы.
#!/usr/bin/env perl
if(scalar @ARGV==0 || $ARGV[0] =~ /^-h/oi){
print STDERR "Usage: perl $0 your_interface_file > new_interface_file\n";
exit;
}
$refgone="&";
if($ARGV[0] eq "-ref"){
$refgone="";
shift @ARGV;
}
%binopmap=(
'<'=>'__lt__', '>'=>'__gt__', '=='=>'__eq__', '!='=>'__ne__',
'<='=>'__le__', '>='=>'__ge__',
'+'=>'__add__', '-'=>'__sub__','*'=>'__mul__', '/'=>'__div__',
'&'=>'__and__', '^'=>'__xor__','|'=>'__or__', '%'=>'__mod__',
'+='=>'__iadd__','-='=>'__isub__','*='=>'__imul__','/='=>'__idiv__',
'&='=>'__iand__','^='=>'__ixor__','|='=>'__ior__','%='=>'__imod__',
'<<'=>'__lshift__','>>'=>'__rshift__',
'[]'=>'__getitem__'
);
%unopmap={ '-' =>'__neg__','+' =>'__pos__'};
$ifile=shift @ARGV;
open(IFILE,$ifile);
$cmtout="//";
while(<IFILE>){
if(m|^\s*//|o){ print; next;}
elsif(/\%inline/o){ $cmtout="";}
elsif(/\%\}/o){ $cmtout="//";}
elsif(/class\s+(\w+)/o){ $class=$1;}
elsif(/\boperator\b\s*[^\w\s]+\s*\(/o){
$s=$_; $h=$_;
if($_ !~ /^(.+?)operator\s*(\W+?)\s*\(/o || !exists $binopmap{$2}){
print STDERR "Operator overloading at Line $. cannot be translated!\n =>$_";
print $_; next;
}
$rettype=$1; $op=$2;
print "$cmtout$_";
if($_ !~ /;/o && $_ !~ /\{/o){
while(<IFILE>){
print "$cmtout$_";
$s.=$_;
if(/;/o){ last;}
}
}elsif($_ =~ /\{/o){
$p=1;
while(<IFILE>){
print "$cmtout$_";
$s.=$_;
s/([\{\}])/if($1 eq "{"){$p++}else{$p--} $1/goe;
if($p==0 && /\}/o){ last;}
}
}
$s=~ /\(\s*(.*)\s*\)/mo;
$param=$1;
if($param =~ s/((const\s+)?\w+\s*[^\w\s]*)\s*\w+$/$1 oprnd2/o){
}elsif($param =~ s/((const\s+)?\w+\s*[^\w\s]*)$/$1 oprnd2/o){ }
if(!exists $addmethods{$class}){
$addmethods{$class}="%addmethods $class\{\n";
}
if($op eq "[]"){
$h =~ s/^(.+?)\s*$refgone\s*operator\s*(\W+?)\s*\((.*)\).*$/$1 $binopmap{$op}\($param){/o;
$addmethods{$class}.=$h." return (*self)[oprnd2];\n }\n";
$rettype =~ s/$refgone//o;
$h =~ s/^.*?__getitem__\s*\(.*?\)/ void __setitem__($param,$rettype _value)/o;
$h.= " (*self)[oprnd2]=_value;\n }\n";
}else{
$h =~ s/^(.+?)operator\s*(\W+?)\s*\((.*)\).*$/$1 $binopmap{$op}\($param){/o;
$h.= " return *self $op oprnd2;\n }\n";
}
$addmethods{$class}.=$h;
next;
}
print;
}
close(IFILE);
print "\n// ----------- Operator overloading code ----------\n";
for $c(keys %addmethods){
print "$addmethods{$c}\n};\n";
}
Выкажам здагадку, у вас ёсць аб'ява класа:
class Foo {
public:
Foo(int _i);
bool operator ==(Foo &y);
Foo& operator +=(Foo &y);
int& operator [](int i);
}
Запуск сцэнарыя, вы атрымаеце:
class Foo {
public:
Foo(int _i);
// bool operator ==(Foo &y);
// Foo& operator +=(Foo &y);
// int& operator [](int i);
}
};
// ----------- Operator overloading code ----------
%addmethods Foo{
bool __eq__(Foo & oprnd2){
return *self == oprnd2;
}
Foo& __iadd__(Foo & oprnd2){
return *self += oprnd2;
}
int __getitem__(int oprnd2){
return (*self)[oprnd2];
}
void __setitem__(int oprnd2, int _value){
(*self)[oprnd2]=_value;
}
};
озЬгеат аднаго і аператара <<(озЬгеат & OS, сопзЬ Foo Foo &);такога аператара "Стрым-выхад?
[Адказ] Выкарыстоўвайце наступны код:
%{
#include <iostream.h>
#define op_lshift(T) \
else if((SWIG_ConvertPtr(din,(void **)&arg,SWIGTYPE_p_##T,1)) != -1)\
return (*self << *(T*)arg)
%}
%typemap(python,in) PyObject*{
$target=$source;
}
class ostream{ };
%addmethods ostream{
ostream& __lshift__(PyObject *din){
void *arg;
if(PyString_Check(din)){
*self << (char*)PyString_AsString(din);
return *self;
}else if(PyInt_Check(din)){
*self << (long)PyInt_AsLong(din);
return *self;
}else if(PyFloat_Check(din)){
*self << (double)PyFloat_AsDouble(din);
return *self; }
op_lshift(MyClass);
op_lshift(MyClass2);
op_lshift(MyClass3);
//...
}
}
%inline %{
ostream* cout_get(){
return &cout;
}
%}
op_lshift () макрас можа быць выкарыстаны для стварэння больш аператар загрузкі. cout_get () выкарыстоўваецца для атрымання "суд" у Python. [Адказ] Калі ў Вас не ўзнікае ніякіх дадзеных поля ў грамадскасці, вы можаце выкарыстоўваць наступны сцэнар Perl (reduceSWIGpm.pl) для спрашчэння сачэння схеме:
#!/usr/bin/env perl -i.bak
while(<>){
if(/^\s*sub\s+new\s*\{/o){
print;
while(<>){
if(/^\s*bless\s+\$self,/){
next;
}elsif(s/\$OWNER\{\$s/\$OWNER\{\$\$s/o){ last;}
print;
}
print;
while(<>){
if(/return/o){ last;}
}
$_=" return \$self;\n";
}elsif(/^\s*my\s+%resulthash;/o){
$_=<>; $_=<>;
$_=" return \$result;\n";
}elsif(/^\s*sub\s+this\s*\{/o){
print;
$_=<>; $_=<>;
$_="\n return \${\$_[0]};\n";
}
if(/^\s*return unless/o && /'HASH'/o){ $_ ="#$_";}
s/(::delete_\w+)\((\S+?)\)/$1\(\$_[0])/o;
s/tied\(%(\S+?)\)/\$$1/og;
print;
}
У Unix, запусціце гэтую
unix< perl reduceSWIGpm.pl MyModule.pmЁн будзе капіяваць арыгінал "*. вечара" на "*. pm.bak і даць вам нешта накшталт гэтага:
package MyClass;
@ISA = qw( t Sclass );
%OWNER = ();
%ITERATORS = ();
sub new {
my $self = shift;
my @args = @_;
$self = tc::new_MyClass(@args);
return undef if (!defined($self));
$OWNER{$$self} = 1;
return $self;
}
sub DESTROY {
# return unless $_[0]-<isa('HASH');
my $self = ${$_[0]};
delete $ITERATORS{$self};
if (exists $OWNER{$self}) {
tc::delete_MyClass($_[0]);
delete $OWNER{$self};
}
}
sub foo {
my @args = @_;
my $result = tc::MyClass_foo(@args);
return undef if (!defined($result));
return $result;
}
sub DISOWN {
my $self = shift;
my $ptr = $$self;
delete $OWNER{$ptr};
};
...
Я правяраў на просты сцэнар, і ён выдатна працуе з SWIG1.3a5. Ён не можа прымяняцца да ўсіх выпадках. Выкарыстоўвайце з асцярогай! [Адказ] Паспрабуйце наступны сцэнар Perl (detectDep.pl), каб выявіць гэтую залежнасць:
#!/usr/bin/env perl
$inc_sys=0;
if($ARGV[0] eq "-s"){
print STDERR "Include system header files...\n";
$inc_sys=1;
}
$args=join(" ",@ARGV);
open(F,"grep '#include' $args|");
while(<F>){
if(/(\S+?):\s*#include\s+"(\S+?)"/o){
$depend{$1}{$2}=1;
}elsif($inc_sys && /(\S+?):\s*#include\s+\<(\S+?)\>/o){
$h=$1; $dep=$2;
$depend{$h}{$dep}=1
}
}
close(F);
for $f(keys %depend){
print_h($f);
}
sub print_h{
my ($h)=@_;
my $d;
if(exists $visited{$h}){
return;
}
$visited{$h}=1;
for $d(keys %{$depend{$h}}){
print_h($d);
}
print "$h\n";
return;
}
Запусціце яго з
find. -name \*.h -print|perl detectDep.pl
http://embedded.eecs.berkeley.edu/Alumni/pinhong/scriptEDA/foo_wrap.c:1415:incompatible types in assignment of 'char *' to 'char[128]'дзе ў мяне ёсць структура дэкларацыі ў '*. я':
#define FSTRING_LEN 128
typedef char fstring[FSTRING_LEN];
struct cli_state
{...
fstring server_type;
..
};
[Адказ] Вам неабходна ўставіць два typemaps:
%typemap(python,memberin) fstring {
strncpy($target,$source,sizeof(fstring));
}
%typemap(python,memberout) fstring {
$target=Py_BuildValue("s#",$source,sizeof(fstring));
}
[Адказ] Я атрымаў інструмент, які генерыраваць код маршалинга аўтаматычна. Скажам, да прыкладу, вы атрымалі вектар структуры для абкручванні:
struct vector{
float x,y;
struct Ptr *ptr;
};
Мой сцэнар будзе генераваць пары typemaps для Вас:
%typemap(python,out) struct vector {
struct vector *arg0 =$source;
PyObject *obj_x,*obj_y,*obj_ptr;
{
float result ;
result = (float ) (arg0->x);
obj_x = PyFloat_FromDouble(result);
}
{
float result ;
result = (float ) (arg0->y);
obj_y = PyFloat_FromDouble(result);
}
{
struct Ptr *result ;
result = (struct Ptr *) (arg0->ptr);
obj_ptr = SWIG_NewPointerObj((void *) result, SWIGTYPE_p_Ptr);
}
resultobj = Py_BuildValue("[OOO]",obj_x,obj_y,obj_ptr);
Py_DECREF(obj_x);
Py_DECREF(obj_y);
Py_DECREF(obj_ptr);
free($source);
}
%typemap(python,in) struct vector {
float arg_x ;
float arg_y ;
struct Ptr *arg_ptr ;
PyObject *obj_ptr;
static struct vector temp;
$target=&temp;
$source=PyList_AsTuple($source);
if(!PyArg_ParseTuple($source,"ffO",&arg_x,&arg_y,&obj_ptr))return NULL;
$target->x = arg_x;
$target->y = arg_y;
if ((SWIG_ConvertPtr(obj_ptr,(void **) &arg_ptr,SWIGTYPE_p_Ptr,1))== -1) return NULL;
$target->ptr = arg_ptr;
}
У цяперашні час, Perl5, Tcl8 і Python падтрымліваюцца, і праца з SWIG1.3a5. Скрыпт будзе спрабаваць ўзламаць код, генераваны SWIG і rearrage іх у "за" і "ў" typemaps. Я пакладу сцэнар у ~ pinhong http://www-cad.eecs.berkeley.edu/ / scriptEDA [Адказ] Я проста рэалізуецца Perl5, Tcl8, і Python падтрымка зваротнага выкліку ў SWIG1.3a5. ( http://www-cad.eecs.berkeley.edu/ ~ pinhong / scriptEDA ) Напрыклад, калі вы атрымалі файл інтэрфэйсу наступным чынам:
%module testcb
%inline %{
int (*C_func)(double a, char *msg);
void exec_callback(){
int ret;
ret=(*C_func)(1.0,"test CB_FUNC OK!");
printf("*C_func return=%d\n",ret);
}
%}
Выкарыстаньне інструмента, вы можаце атрымаць новы файл інтэрфэйсу:
%module testcb
%{
static PyObject* PyCallBack_C_func=0;
int _cbwrap_C_func(double a,char *msg){
PyObject *arglist,*result;
int ret ;
PyObject *arg0, *arg1;
if(!PyCallBack_C_func)return ret;
arg0 = PyFloat_FromDouble(a);
{
arg1=Py_BuildValue("s",msg);
}
result=PyObject_CallFunction(PyCallBack_C_func,"(OO)",arg0,arg1);
{ PyObject *args=Py_BuildValue("(O)",result);
Py_XDECREF(result);
if(!PyArg_ParseTuple(args,"i:CALLBACK",&ret)) return (int) NULL;
Py_XDECREF(args);
}
return ret;
}
%}
%typemap(python,in) PyObject *{ $target=$source;}
%inline %{
void register_C_func(PyObject *pyfunc){
if (!PyCallable_Check(pyfunc)) {
PyErr_SetString(PyExc_TypeError, "Need a callable object!");
return;
}
if(PyCallBack_C_func)Py_DECREF(PyCallBack_C_func);
PyCallBack_C_func=pyfunc;
Py_INCREF(pyfunc);
}
/* For SWIG Type Conversion */
void __null__C_func(int ret, double a,char *msg){}
%}
%{
int (*C_func)(double a, char *msg);
%}
%init %{
C_func=_cbwrap_C_func;
%}
%inline %{
void exec_callback(){
int ret;
ret=(*C_func)(1.0,"test string here");
printf("*C_func return=%d\n",ret);
}
%}
Мы маглі бы праверыць яго на Python па
from testcb import * def plcb(a,b): print "A=",a,"B=",b return 133 register_C_func(plcb) exec_callback()Выхад будзе
*C_func return=133 A=1, B=test string here
[Адказ] Я выкарыстоўваю: SWIG1.3a5 GCC 2.95.2 з-O3 для ўсіх кампіляцыі і Газа дынамічны код аб'екта Вось вынік:
RunTime Memory Usage
Pure C++ 3.69s 6.7M
Perl5.00503 16.74s ~7M
Tcl8.3.2 18.75s ~11M
Python2.0 30.84s ~10M
Бібліятэка аналізатар выкарыстоўваецца для чытання ў файл дадзеных, і дампа ад мовы сцэнарыяў API. Выканання вымяраецца "Час" каманды UNIX, і выкарыстанне памяці прыкладна адлічваецца ад "PS" каманды. Звярніце ўвагу, што гэты метад ўключае ў сябе ўсе накладныя выдаткі. Код выглядае наступным чынам у Python:
#!/usr/bin/env python
from pythongnd import *
import sys
sdf=read_sdf(sys.argv[1])
for i in sdf.all_cells():
for j in i.all_iopaths():
print " (IOPATH",
if j.cond(): print "(COND",j.cond(),
print dump_edge(j.begin()),dump_edge(j.end()),
for t in j.all_triples():
if not t: print "()",
else: print "(%.3f:%.3f:%.3f)" % (t.min(),t.typ(),t.max()),
if j.cond(): sys.stdout.write(")")
sys.stdout.write(")\n")
print " )"
print " )"
Я зрабіў, што няма уцечкі памяці ў працягу гэтага пахавання ў скрыптовых мовах. На самай справе, Tcl кода гэта раздражняе, таму што я відавочна вызваліць памяць, перайменаваць $ VAR {}. Акрамя таго, Tcl, Perl, Python і вельмі падобныя. C + + кода цалкам іншая, паколькі ён цвёрда ў метады аб'екта. Я павінен растлумачыць, што аналізатар з'яўляецца Yacc (з выкарыстаннем зубра) і Лекс (з дапамогай Flex), і ўсе тры пакета выкарыстоўваць той жа сінтаксічны аналізатар C. Фармат дадзеных досыць складаная, якія не могуць быць прыдатныя для кадавання усяго рэгулярнага выказвання ў Perl. Я спрабую выкарыстоўваць byacc для генерацыі кода Perl парсер і бакі закадаваныя рэгулярныя заявы для лексічны аналізатар, які аказваецца дастаткова павольна па параўнанні з версіяй C.
Адным з важных пытанняў, як вы пабудаваць ўнутраную базу дадзеных. Пры разборы, C код аналізатар будуе сваю ўнутраную базу дадзеных у той жа час. Калі роднай код Perl выкарыстоўваецца, ён можа выкарыстоўваць шмат месца для захоўвання усяго, што база дадзеных, якая ў сваю чаргу, спажывае шмат часу выканання.
int directory_list(char *url, char dirs[512][255]);правільна? Гэта не дае мне "папак" спіс!
[Адказ] Калі ласка, праверце наступныя "працоўны" прыклад. Вам неабходна высветліць, калі вашыя C руціннай вылучае сімвал буфера або няма, як пэўны апошнюю радок, і калі вам трэба скапіяваць 255 знакаў на Python або няма.
%include typemaps.i
%typemap(python,ignore) char *dir[512]{
static int initialized=0;
static char *tmp[512];
if(!initialized){
int i;
for(i=0;i<512;i++)
tmp[i]=(char*)malloc(255);
initialized=1;
}
$target=tmp;
}
%typemap(python,argout) char *dir[512] {
int len,i;
PyObject *o;
len = 0;
while(len<512 && *($source[len])!='\0')len++;
o = PyList_New(len);
for (i = 0; i < len; i++) {
// Uncomment the following line if
// output a fixed length (255 chars) string
// PyList_SetItem(o,i,Py_BuildValue("s#",$source[i],255));
PyList_SetItem(o,i,Py_BuildValue("s",$source[i]));
}
$target = l_output_helper($target,o);
}
%}
[Адказ] Паспрабуйце папярэднічаць # з%:
void SomeClassF() {
%#if SOME_FLAG
// some code
%#else
///
%#endif
}
[Адказ] Вось прыклад, які выкарыстоўвае ў Makefile.PL Perl для стварэння Perl, Python або Tcl модулі дадзенай імя модуля.
[Адказ] Адказ тут.