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)
|
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>
|
<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>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue