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:
Mark Gossage 2006-02-13 02:36:05 +00:00
commit aabec2c542
2 changed files with 368 additions and 77 deletions

View file

@ -1,4 +1,7 @@
Version 1.3.29 (In progress) 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.

View file

@ -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> <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> <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> <H3><a name="Extending_nn39"></a>32.10.8 Configuration files</H3>