Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web development, networking and server security. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

SWIG1.3a5 Typemap FAQ для Python, Perl5 (, Tcl)

Гэта мая калекцыя SWIG typemap FAQ для Python і Perl5. Tcl частка будзе прадастаўлена пазней. Версія SWIG заснаваны на 1.3a5. Усе крэдыты павінны пайсці на аўтараў у SWIG спіс рассылкі. Прамая любыя вашы пытанні аб гэтым часта задаюць пытанні pinhong@eecs.berkeley.edu. [Апошняе абнаўленне 06/06, 2001]

  1. Стандартны typemaps для Int, кароткія, доўгія, сімвал * і файл *.
  2. Упакоўка-аб'ект C код, не ў аб'екце класа ў глыток.
  3. Перадача NULL з Perl / Tcl / Python на C / C + + функцыі.
  4. сЬаг ** ў / з typemaps.
  5. Int масіў у структуры поля
  6. C + + радок у / з typemap.
  7. Вярнуцца радок памылка ў інтэрфейсе Python.
  8. У C + + патокі.
  9. Стварэнне несапраўднымі * сумяшчальнасць з іншымі тыпамі дадзеных.
  10. несапраўдным * у / з typemaps.
  11. Паказальнік overcasting.
  12. Ўпакоўка C + + паслядоўнасць клас для Python.
  13. У тым ліку код у Python / Perl класа цені.
  14. Змена Python / Perl па змаўчанні метад класа (спароджаных SWIG-цень).
  15. Ўпакоўка C + + клас з перагружаным метадамі.
  16. Ўпакоўка C + + класа перагружаны канструктар.
  17. Забеспячэнне парадку, у якім зменныя пераўтворацца са сцэнараў тыпаў C тыпаў.
  18. Typemaps для фіксаванай даўжыні буфера.
  19. Няяўныя памер typemap з уваходнага масіва.
  20. Уваходны typemap для масіва (або STL вектара) паказальнікаў.
  21. Паказальнік тыпажоў ў спіс прадукцыі або STL вектара.
  22. Агульны паказальнік typemap argout.
  23. Аргумент з typemaps папярэдне вылучаны буфер.
  24. Аргумент з typemaps для C + + спасылкі на паказальнік.
  25. Аргумент з typemaps для C + + спасылкі.
  26. Агульныя argout typemaps для аб'ектаў / Розніца ў argout typemaps.
  27. Паказальнік на аб'ект не атрымлівае цені.
  28. Аб'ект тыпажоў ў спіс прадукцыі або STL вектара.
  29. Агульныя цень аб'екта тыпажоў ў C / C + +.
  30. Упакоўка прататып функцыі, як Foo (INT агдс, сЬаг агду **).
  31. Перагрузка аператараў падтрымкі.
  32. Ўпакоўка "озЬгеат аднаго і аператар <<" у Python
  33. Скарачэнне Perl схему сачэння над галавой.
  34. Выяўленне залежнасці паміж файлы загалоўкаў
  35. C + + скардзіцца несумяшчальныя тыпы ў прызначэнні сімвал] [па структуры функцыі мноства поля.
  36. Структура кода маршалинга / typemap.
  37. Аўтаматычны зваротны выклік пакалення.
  38. Прыклад для Perl5, Tcl8 і Python параўнання.
  39. 2-D typemaps argout.
  40. З дырэктывы препроцессора праход.
  41. Makefile пакалення для кампіляцыі глыток.

1. Стандартны typemaps для Int, кароткія, доўгія, сімвал * і файл *.
[Больш] Мне трэба скапіяваць і ўставіць некаторыя стандартныя typemaps. Дзе я магу іх знайсці?

[Адказ] У прынцыпе, вы можаце праверыць яго з 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);
}


[Perl5]

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);
}
FILE *
%typemap(perl5,in) FILE * {
  $target = IoIFP(sv_2io($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++;
}


2. Упакоўка-аб'ект C код, не ў аб'екце класа ў глыток.
[Больш] У мяне ёсць бібліятэка С, якая мае непразрысты тыпу, і некалькі "метадаў". Напрыклад:
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);
}


3. Перадача NULL з Perl / Tcl / Python на C / C + + функцыі.
[Больш] Як я магу перадаць нулявы значэнне майго C / C + + функцыі? Нешта накшталт гэтага:
tw_createDialogue(20,20, 2,2, 0, "NULL", "NULL");

[Адказ] Выкарыстоўвайце наступны элемент мовы для прадстаўлення NULL:

  • Perl : undef
  • Tcl : "NULL"
  • Python : None


4. char ** in/out typemaps.
[Больш] Як я магу атрымаць спіс радкоў, а не "_p_p_char ў SWIG?

[Адказ] наступны код з 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;
}


5. Int масіў у структуры поля
[Больш] Праблема ў мяне ёсць нешта накшталт гэтага:
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.

6. C + + радок у / з typemap.
[Больш] Выкарыстаньне радкі класа ў маёй ўваходны параметр функцыі.
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;
}


7. Вярнуцца радок памылка ў інтэрфейсе Python.
[Больш] Паспрабуйце наступны код глыток-Python
 
 %module example
 %inline %{
 char *ret_null(){
   return (char*)NULL;
 }
 %}
Я атрымаў дамп.

[Адказ] З дапамогай гэтай typemap, яно павінна быць у парадку

 
 %typemap(python,out) char *{
   $target=Py_BuildValue("s",$source);
 }


8. У C + + патокі.
[Больш] Многія з C + + метады прымаць патокі ў якасці параметраў. Напрыклад:
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)


9. Стварэнне несапраўднымі * сумяшчальнасць з іншымі тыпамі дадзеных.
[Больш] У мяне ёсць некалькі складаных структур у мае заявы, а ў шэрагу выпадкаў мы прайсці "несапраўдным * 'замест фактычнага тыпу паказальнік (або віцэ-назад). так як глыток патрабуе строгага паказальнік тыпу адпаведнасці, я шукаў спосаб ліцця паказальнік з глыток. Я ведаю, што можа стварыць кучу дапаможныя функцыі, каб зрабіць гэта, але гэта даволі брудны.

[Адказ] Калі вы дазволіце, каб змяніць 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 тыпу праверкі сістэмы, каб пазбегнуць праблемы вы атрымалі.


10. void* in/out typemaps.
[Больш] Пры выкарыстанні несапраўднымі * у якасці ўваходных выходных дадзеных тыпу /, любы typemaps неабходныя?

[Адказ] На самай справе, вам не патрэбныя ніякія typemap для несапраўдным * у typemap. SWIG не выконвае праверку тыпаў у дадзеным выпадку.

Пры выкарыстанні '* несапраўднымі ", як выхад, вы павінны воблачнасць яго тып дадзеных вам трэба. Праверыць гэта FAQ.


11. Паказальнік overcasting.
[Больш] Як я магу воблачнасць паказальнік у іншую?

[Адказ] Выкарыстоўвайце наступны код:
[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";


12. Ўпакоўка C + + паслядоўнасць клас для Python.
[Больш] Я выкарыстоўваю% addmethods на карце C + + інтэрфейс для паслядоўнасці інтэрфейс Python, т. е. to give it __len__, __getitem__, and __setitem__ methods. Усе яны працуюць як чакаецца, на сваёй уласнай. Аднак, калі я пішу
 >>> 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. Больш шырокае прыклад можна знайсці тут


13. У тым ліку код у Python / Perl класа цені.
[Больш] Ёсць зручны спосаб уключыць блок кода Python ў цень класаў падобна таму, як блокі кода C могуць быць дададзены ў абалонку файлы C?

[Адказ]

%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...


14. Змена Python / Perl па змаўчанні метад класа (спароджаных SWIG-цень).
[Больш] Я хацеў бы мець розныя C + + деструктор ў __del__ метад.

[Адказ] Вы можаце напісаць свой ??уласны деструктор ў 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)


15. Ўпакоўка C + + клас з перагружаным метадамі.
[Больш] Напрыклад,
//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);


16. Ўпакоўка C + + класа перагружаны канструктар.
[Больш] Я атрымаў класа з канструктарам / метад прымае розныя налады аргументаў.
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


17. Забеспячэнне парадку, у якім зменныя пераўтворацца са сцэнараў тыпаў C тыпаў.
[Больш] Выкажам здагадку, у вас ёсць наступныя функцыі:
  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().


18. Typemaps для фіксаванай даўжыні буфера.
[Больш] Я спрабаваў абгарнуць З "функцыя" для Python. У мяне ёсць наступныя радкі ў свой файл 'я.':
   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{
}


19. Няяўныя памер typemap з уваходнага масіва.
[Больш] Я спрабую зрабіць абгортку з лічбавай пакет у Python. Скажам, я хачу, каб абгарнуць функцыя, вызначаная
 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;
}
%}


20. Уваходны typemap для масіва (або STL вектара) паказальнікаў.
[Больш] Існуе функцыя ў SDK -
extern int SmDefineVocab(char *,short,*SM_VOCWORD[],SM_MSG *);
SM_VOCWORD чакае масіў паказальнікаў. Што такое typemap для SM_VOCWORD **?
[Адказ] Ключавым момантам з'яўляецца тое, каб абгарнуць аб'ект здабываецца з спісу Python па SWIG_ConvertPtr. Акрамя таго, памятайце, каб вызваліць дадатковую памяць з дапамогай freearg typemap.
%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);


21. Паказальнік тыпажоў ў спіс прадукцыі або STL вектара.
[Больш] Мне трэба кінуць C / C + + паказальнік на SWIGified паказальнік у STL вектара.

[Адказ] Выкарыстаньне наступныя радкі макраса некалькіх вызначэнне ў 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


22. Агульны паказальнік typemap argout.
[Больш] Як я магу звяртацца argout за структуры? Напрыклад,
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


23. Аргумент з typemaps папярэдне вылучаны буфер.
[Больш] У мяне ёсць функцыя:
   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 струны з вядомай даўжыні (гэта значыць вынік).


24. Аргумент з typemaps для C + + спасылкі на паказальнік.
[Больш] У нас ёсць некалькі аб'ектаў з метадамі наступны выгляд:
 Status GetItemAtIndex(int theIndex, Object* &item);
якія вяртаюць прыватнасці пункт з спісу. Swig выкідвае паведамленне пра памылку на гэтай канструкцыі ў інтэрфейс файла. Пры выдаленні і дазваляе складанне інтэрфейс, калі я спрабую "пункт" доступ такім чынам, значэнне 'імя' не тое, што з ў спісе.

[Адказ] Вам трэба

  1. Стварыць typemap для апрацоўкі аргумент OUT.
  2. Абгарніце выхад з паказальнікам класа Python. Гэта можа быць зроблена або ў C + + або Python.
Калі ласка, праверце "Generic argout typemaps для аб'ектаў" для падрабязнасьцяў. Наступны код з'яўляецца прыкладам:
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);


25. Аргумент з typemaps для C + + спасылкі.
[Больш] У маім C + + клас, у мяне ёсць наступны метад:
  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);


26. Агульныя argout typemaps для аб'ектаў / Розніца ў argout typemaps.
[Больш] У чым розніца ў argout typemap для C + + спасылка, аднаго паказальніка і двайны паказальнік на "argout" аб'ект?

[Адказ] Глядзіце наступны код:

%{
#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


27. Паказальнік на аб'ект не атрымлівае цені.
[Больш] Некаторыя з C + + аб'екты, створаныя Python не могуць быць выдаленыя. Глядзіце:
 >>> 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


28. Аб'ект тыпажоў ў спіс прадукцыі або STL вектара.
[Больш] Я выкарыстоўваю SWIG абгарнуць некаторыя з C + + класаў, якія выкарыстоўваюцца ў маёй MUD (Multi-карыстальнік Dungeon), і я затым запусціць модуль ўнутры інтэрпрэтатара Python які ўбудаваны ў маёй MUD. Я выкарыстоўваю-цень варыянт для стварэння класаў Python цені для кожнага з класаў З + +. Усё гэта працуе проста выдатна. Аднак у мяне ёсць сітуацыі, калі я адлюстраванне C + +, STL спісаў у спісы Python. Я выкарыстаў% typemap Напісаў Скот Снайдер ў парным разрадзе, і змяніла яго. Аб'екты, якія захоўваюцца ў спісе Python з'яўляюцца SWIGified C + + прыстасаваныя класы. Калі я атрымаю элементаў з спісу ў Python ён думае, што яны толькі радкі, і таму ў мяне да Python "прывядзенне" іх з char_classPtr (), якая генеруецца аўтаматычна па глыток.

[Адказ] Праверыць гэтую Пытанні і адказы аб тым, як цень паказальнік на аб'ект. Вось мой прыклад кода:

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.

29. Агульныя цень аб'екта тыпажоў ў C / C + +.
[Больш] Я атрымаў паказальнік
'_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;
}

[Perl] Увогуле, вам не трэба гэта ў Perl. Зацяненне механізму ў SWIG робіць спасылку на цень аб'екта аўтаматычна. Аднак, калі вам трэба атрымаць доступ член поля, наступны код карысна:
// 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);


30. Упакоўка прататып функцыі, як Foo (INT агдс, сЬаг агду **).
[Больш] У мяне ёсць прататып функцыі выгляду:
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")

[Perl5] Выкарыстоўвайце наступны код для Perl:
%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);
}


31. Перагрузка аператараў падтрымкі.
[Больш] SWIG не можа справіцца з C + + перагрузкі аператараў. Ці магу я працаваць-то вакол гэтага?

[Адказ] Выкарыстаньне наступны сцэнар 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;
  }
};


32. Ўпакоўка "озЬгеат аднаго і аператар <<" у Python
[Больш] Як я магу абгарнуць
озЬгеат аднаго і аператара <<(озЬгеат & 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.

33. Скарачэнне Perl схему сачэння над галавой.
[Больш] Perl зацянення аб'екта здаецца выкарыстаннем велізарнае збудаванне, каб абгарнуць яго так, як звязаны спасылкі. Калі я не выкарыстоўваю якіх члена дадзеных, я магу паменшыць яе?

[Адказ] Калі ў Вас не ўзнікае ніякіх дадзеных поля ў грамадскасці, вы можаце выкарыстоўваць наступны сцэнар 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. Ён не можа прымяняцца да ўсіх выпадках. Выкарыстоўвайце з асцярогай!

34. Выяўленне залежнасці паміж файлы загалоўкаў
[Больш] Я атрымаў некалькі загалоўкаў, але паняцці не маю, які з іх павінен быць уключаны першым у маёй інтэрфейс файла.

[Адказ] Паспрабуйце наступны сцэнар 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 


35. C + + скардзіцца несумяшчальныя тыпы ў прызначэнні сімвал] [па структуры функцыі мноства поля.
[Больш] G + + скардзіцца, што "_wrap.c" ёсць праблемы:
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));
}


36. Структура кода маршалинга / typemap.
[Больш] Цяпер я спрабую зрабіць нешта больш складанае: стварэння структуры маршалинга кода. Існуе невялікі прыклад, які сведчыць аб робіць гэта, выкарыстоўваючы typemap. Гэта вельмі адрозніваецца ад таго SWIG выкарыстоўваецца сёння, але падыходзіць агульныя напрамкі апісаны ў тэхнічным дакуменце.

[Адказ] Я атрымаў інструмент, які генерыраваць код маршалинга аўтаматычна. Скажам, да прыкладу, вы атрымалі вектар структуры для абкручванні:

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


37. Аўтаматычны зваротны выклік пакалення.
[Больш] Я атрымаў паказальнік зменнай функцыі. Як я магу зрабіць функцыю зваротнага выкліку Python?

[Адказ] Я проста рэалізуецца 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


38. Прыклад для Perl5, Tcl8 і Python параўнання.
[Больш] Я зрабіў некалькі эксперыментаў на не трывіяльны выпадак выкарыстання SWIG абгарнуць бібліятэкі З + + (які выкарыстоўвае аб'ект і STL шырока), і ёсць некаторыя паказчыкі прыбытковасці.

[Адказ] Я выкарыстоўваю: 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 выкарыстоўваецца, ён можа выкарыстоўваць шмат месца для захоўвання усяго, што база дадзеных, якая ў сваю чаргу, спажывае шмат часу выканання.


39. 2-D typemaps argout.
[Больш] SWIG не пераносіцца
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); 
} 
%} 


40. З дырэктывы препроцессора праход.
[Больш] я павінен выкарыстаць іншы клас функцыі, каб абгарнуць класа функцый ўмоўна. Ці магчыма гэта, што SWIG аб'язных дырэктывы препроцессора?

[Адказ] Паспрабуйце папярэднічаць # з%:

void SomeClassF() {
    %#if SOME_FLAG
    // some code
    %#else
    ///
    %#endif
  }


41. Makefile пакалення для кампіляцыі глыток.
[Больш] Ці ёсць Makefile сцэнар пакалення я магу выкарыстоўваць, каб паскорыць пакласці Makefile разам?

[Адказ] Вось прыклад, які выкарыстоўвае ў Makefile.PL Perl для стварэння Perl, Python або Tcl модулі дадзенай імя модуля.


999. Пытанні і адказы шаблону.
[Больш] Тут ідзе дэталёвае апісанне пытанне.

[Адказ] Адказ тут.


Published (Last edited): 04-06-2011 , source: http://embedded.eecs.berkeley.edu/Alumni/pinhong/scriptEDA/pyTypemapFAQ.html