update to extending document
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@8809 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
4752a48da3
commit
aabec2c542
2 changed files with 368 additions and 77 deletions
|
|
@ -1,4 +1,7 @@
|
|||
Version 1.3.29 (In progress)
|
||||
============================
|
||||
|
||||
02/13/2006: mgossage
|
||||
[Documents] updated the extending documents to give a skeleton swigging code
|
||||
with a few typemaps.
|
||||
|
||||
|
|
|
|||
|
|
@ -2742,9 +2742,297 @@ int Python::top(Node *n) {
|
|||
|
||||
<H3><a name="Extending_nn37"></a>32.10.6 Module I/O and wrapper skeleton</H3>
|
||||
|
||||
<!-- please report bugs in this section to mgossage -->
|
||||
|
||||
|
||||
<p>
|
||||
Within SWIG wrappers, there are four main sections. These are (in order)
|
||||
|
||||
<ul>
|
||||
<li>runtime: This section has most of the common SWIG runtime code
|
||||
<li>header: This section holds declarations and inclusions from the .i file
|
||||
<li>wrapper: This section holds all the wrappering code
|
||||
<li>init: This section holds the module initalisation function
|
||||
(the entry point for the interpreter)
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
Different parts of the SWIG code will fill different sections,
|
||||
then upon completion of the wrappering all the sections will be saved
|
||||
to the wrapper file.
|
||||
</p>
|
||||
<p>
|
||||
To perform this will require several additions to the code in various places,
|
||||
such as:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
class PYTHON : public Language {
|
||||
protected:
|
||||
/* General DOH objects used for holding the strings */
|
||||
File *f_runtime;
|
||||
File *f_header;
|
||||
File *f_wrappers;
|
||||
File *f_init;
|
||||
|
||||
public:
|
||||
...
|
||||
|
||||
};
|
||||
|
||||
int Python::top(Node *n) {
|
||||
|
||||
...
|
||||
|
||||
/* Initialize I/O */
|
||||
f_runtime = NewFile(outfile, "w");
|
||||
if (!f_runtime) {
|
||||
FileErrorDisplay(outfile);
|
||||
SWIG_exit(EXIT_FAILURE);
|
||||
}
|
||||
f_init = NewString("");
|
||||
f_header = NewString("");
|
||||
f_wrappers = NewString("");
|
||||
|
||||
/* Register file targets with the SWIG file handler */
|
||||
Swig_register_filebyname("header", f_header);
|
||||
Swig_register_filebyname("wrapper", f_wrappers);
|
||||
Swig_register_filebyname("runtime", f_runtime);
|
||||
Swig_register_filebyname("init", f_init);
|
||||
|
||||
/* Output module initialization code */
|
||||
...
|
||||
|
||||
/* Emit code for children */
|
||||
Language::top(n);
|
||||
|
||||
...
|
||||
/* Write all to the file */
|
||||
Dump(f_header, f_runtime);
|
||||
Dump(f_wrappers, f_runtime);
|
||||
Wrapper_pretty_print(f_init, f_runtime);
|
||||
|
||||
/* Cleanup files */
|
||||
Delete(f_header);
|
||||
Delete(f_wrappers);
|
||||
Delete(f_init);
|
||||
Close(f_runtime);
|
||||
Delete(f_runtime);
|
||||
|
||||
return SWIG_OK;
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Using this to process a file will generate a wrapper file, however the
|
||||
wrapper will only consist of the common SWIG code as well as any inline
|
||||
code which was written in the .i file. It does not contain any wrappers for
|
||||
any of the functions of classes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The code to generate the wrappers are the various member functions, which
|
||||
currently have not been touched. We will look at functionWrapper() as this
|
||||
is the most commonly used function. In fact many of the other wrapper routines
|
||||
will call this to do their work.
|
||||
</p>
|
||||
<p>
|
||||
A simple modification to write some basic details to the wrapper looks like this:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
int Python::functionWrapper(Node *n) {
|
||||
/* Get some useful attributes of this function */
|
||||
String *name = Getattr(n,"sym:name");
|
||||
SwigType *type = Getattr(n,"type");
|
||||
ParmList *parms = Getattr(n,"parms");
|
||||
String *parmstr= ParmList_str_defaultargs(parms); // to string
|
||||
String *func = SwigType_str(type, NewStringf("%s(%s)", name, parmstr));
|
||||
String *action = Getattr(n,"wrap:action");
|
||||
|
||||
Printf(f_wrappers,"functionWrapper : %s\n", func);
|
||||
Printf(f_wrappers," action : %s\n", action);
|
||||
return SWIG_OK;
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This will now produce some useful information within your wrapper file.
|
||||
</p>
|
||||
|
||||
<div class="shell">
|
||||
<pre>
|
||||
functionWrapper : void delete_Shape(Shape *self)
|
||||
action : delete arg1;
|
||||
|
||||
functionWrapper : void Shape_x_set(Shape *self,double x)
|
||||
action : if (arg1) (arg1)->x = arg2;
|
||||
|
||||
functionWrapper : double Shape_x_get(Shape *self)
|
||||
action : result = (double) ((arg1)->x);
|
||||
|
||||
functionWrapper : void Shape_y_set(Shape *self,double y)
|
||||
action : if (arg1) (arg1)->y = arg2;
|
||||
...
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<H3><a name="Extending_nn38"></a>32.10.7 Low-level code generators</H3>
|
||||
|
||||
<!-- please report bugs in this section to mgossage -->
|
||||
|
||||
<p>
|
||||
As ingenious as SWIG is, and despite all its capabilities and the power of
|
||||
its parser, the Low-level code generation takes a lot of work to write
|
||||
properly. Mainly because every language insists on its own manner of
|
||||
interfacing to C/C++. To write the code generators you will need a good
|
||||
understanding of how to manually write an interface to your chosen
|
||||
language, so make sure you have your documentation handy.
|
||||
</p>
|
||||
<p>
|
||||
At this point is also probably a good idea to take a very simple file
|
||||
(just one function), and try letting SWIG generate up wrappers for many
|
||||
different languages. Take a look at all of the wrappers generated, and decide
|
||||
which one looks closest to the language you are trying to wrapper.
|
||||
This may help you to decide which code to look at.
|
||||
</p>
|
||||
<p>
|
||||
In general most language wrappers look a little like this:
|
||||
</p>
|
||||
<div class="code">
|
||||
<pre>
|
||||
/* wrapper for TYPE3 some_function(TYPE1,TYPE2); */
|
||||
RETURN_TYPE _wrap_some_function(ARGS){
|
||||
TYPE1 arg1;
|
||||
TYPE2 arg2;
|
||||
TYPE3 result;
|
||||
|
||||
if(ARG1 is not of TYPE1) goto fail;
|
||||
arg1=(convert ARG1);
|
||||
if(ARG2 is not of TYPE2) goto fail;
|
||||
arg2=(convert ARG2);
|
||||
|
||||
result=some_function(arg1,arg2);
|
||||
|
||||
convert 'result' to whatever the language wants;
|
||||
|
||||
do any tidy up;
|
||||
|
||||
return ALL_OK;
|
||||
|
||||
fail:
|
||||
do any tidy up;
|
||||
return ERROR;
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Yes, it is rather vague and not very clear. But each language works differently
|
||||
so this will have to do for now.
|
||||
</p>
|
||||
<p>
|
||||
To tackle this problem will be done in two stages:
|
||||
<ul>
|
||||
<li>The skeleton: the function wrapper, and call, but without the conversion
|
||||
<li>The conversion: converting the arguments to-from what the language wants
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
The first step will be done in the code, the second will be done in typemaps.
|
||||
</p>
|
||||
<p>
|
||||
Our first step will be to write the code for functionWrapper(). What is
|
||||
shown below is _NOT_ the solution, merely a step in the right direction.
|
||||
There are a lot of issues to address.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Variable length and default parameters
|
||||
<li>Typechecking and number of argument checks
|
||||
<li>Overloaded functions
|
||||
<li>Inout and Output only arguments
|
||||
</ul>
|
||||
<div class="code">
|
||||
<pre>
|
||||
virtual int functionWrapper(Node *n) {
|
||||
/* get useful atributes */
|
||||
String *name = Getattr(n,"sym:name");
|
||||
SwigType *type = Getattr(n,"type");
|
||||
ParmList *parms = Getattr(n,"parms");
|
||||
...
|
||||
|
||||
/* create the wrapper object */
|
||||
Wrapper *wrapper = NewWrapper();
|
||||
|
||||
/* create the functions wrappered name */
|
||||
String *wname = Swig_name_wrapper(iname);
|
||||
|
||||
/* deal with overloading */
|
||||
....
|
||||
|
||||
/* write the wrapper function definition */
|
||||
Printv(wrapper->def,"RETURN_TYPE ", wname, "(ARGS) {",NIL);
|
||||
|
||||
/* if any additional local variable needed, add them now */
|
||||
...
|
||||
|
||||
/* write the list of locals/arguments required */
|
||||
emit_args(type, parms, wrapper);
|
||||
|
||||
/* check arguments */
|
||||
...
|
||||
|
||||
/* write typemaps(in) */
|
||||
....
|
||||
|
||||
/* write constriants */
|
||||
....
|
||||
|
||||
/* Emit the function call */
|
||||
emit_action(n,wrapper);
|
||||
|
||||
/* return value if necessary */
|
||||
....
|
||||
|
||||
/* write typemaps(out) */
|
||||
....
|
||||
|
||||
/* add cleanup code */
|
||||
....
|
||||
|
||||
/* Close the function(ok) */
|
||||
Printv(wrapper->code, "return ALL_OK;\n", NIL);
|
||||
|
||||
/* add the failure cleanup code */
|
||||
...
|
||||
|
||||
/* Close the function(error) */
|
||||
Printv(wrapper->code, "return ERROR;\n", "}\n", NIL);
|
||||
|
||||
/* final substititions if applicable */
|
||||
...
|
||||
|
||||
/* Dump the function out */
|
||||
Wrapper_print(wrapper,f_wrappers);
|
||||
|
||||
/* tidy up */
|
||||
Delete(wname);
|
||||
DelWrapper(wrapper);
|
||||
|
||||
return SWIG_OK;
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Executing this code will produce wrappers which have our basic skeleton
|
||||
but without the typemaps, there are still work to do.
|
||||
</p>
|
||||
|
||||
|
||||
<H3><a name="Extending_nn39"></a>32.10.8 Configuration files</H3>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue