mirror of
https://github.com/boostorg/python.git
synced 2026-02-22 15:42:16 +00:00
This commit was manufactured by cvs2svn to create tag
'merged_to_RC_1_30_0'. [SVN r19627]
This commit is contained in:
35
pyste/NEWS
35
pyste/NEWS
@@ -1,35 +0,0 @@
|
||||
07 Apr 2003
|
||||
- Removed the warnings about forward declarations: it was not accurate enough.
|
||||
Another strategy must be thought of.
|
||||
- Fixed bug in the --multiple mode, where the order of the class instantiations
|
||||
could end up wrong.
|
||||
- Lots of fixes in the documentation, pointed out by Dirk Gerrits. Thanks Dirk!
|
||||
- Fixed support for the return_opaque_pointer policy (the support macro was not
|
||||
being declared).
|
||||
|
||||
|
||||
06 Apr 2003
|
||||
Support for the improved static data members support of Boost.Python.
|
||||
|
||||
05 Apr 2003
|
||||
New option for generating the bindings: --multiple.
|
||||
|
||||
02 Apr 2003
|
||||
Forward declarations are now detected and a warning is generated.
|
||||
|
||||
24 Mar 2003
|
||||
Default policy for functions/methods that return const T& is now
|
||||
return_value_policy<copy_const_reference>().
|
||||
|
||||
22 Mar 2003
|
||||
Exporting virtual methods of the base classes in the derived classes too.
|
||||
|
||||
21 Mar 2003
|
||||
Added manual support for boost::shared_ptr and std::auto_ptr (see doc).
|
||||
|
||||
19 Mar 2003
|
||||
Added support for int, double, float and long operators acting as expected in
|
||||
python.
|
||||
|
||||
14 Mar 2003
|
||||
Fixed bug: Wrappers for protected and virtual methods were not being generated.
|
||||
2
pyste/dist/.cvsignore
vendored
2
pyste/dist/.cvsignore
vendored
@@ -1,2 +0,0 @@
|
||||
*.zip
|
||||
*.pyc
|
||||
51
pyste/dist/create_build.py
vendored
51
pyste/dist/create_build.py
vendored
@@ -1,51 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import fnmatch
|
||||
from zipfile import ZipFile, ZIP_DEFLATED
|
||||
|
||||
def findfiles(directory, mask):
|
||||
def visit(files, dir, names):
|
||||
for name in names:
|
||||
if fnmatch.fnmatch(name, mask):
|
||||
files.append(os.path.join(dir, name))
|
||||
files = []
|
||||
os.path.walk(directory, visit, files)
|
||||
return files
|
||||
|
||||
|
||||
def main():
|
||||
# test if PyXML is installed
|
||||
try:
|
||||
import _xmlplus.parsers.expat
|
||||
pyxml = '--includes _xmlplus.parsers.expat'
|
||||
except ImportError:
|
||||
pyxml = ''
|
||||
# create exe
|
||||
status = os.system('python setup.py py2exe %s >& build.log' % pyxml)
|
||||
if status != 0:
|
||||
raise RuntimeError, 'Error creating EXE'
|
||||
|
||||
# create distribution
|
||||
import pyste
|
||||
version = pyste.__VERSION__
|
||||
zip = ZipFile('pyste-%s.zip' % version, 'w', ZIP_DEFLATED)
|
||||
# include the base files
|
||||
dist_dir = 'dist/pyste'
|
||||
for basefile in os.listdir(dist_dir):
|
||||
zip.write(os.path.join(dist_dir, basefile), os.path.join('pyste', basefile))
|
||||
# include documentation
|
||||
for doc_file in findfiles('../doc', '*.*'):
|
||||
dest_name = os.path.join('pyste/doc', doc_file[3:])
|
||||
zip.write(doc_file, dest_name)
|
||||
zip.write('../index.html', 'pyste/doc/index.html')
|
||||
zip.close()
|
||||
# cleanup
|
||||
os.remove('build.log')
|
||||
shutil.rmtree('build')
|
||||
shutil.rmtree('dist')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.path.append('../src')
|
||||
main()
|
||||
6
pyste/dist/setup.py
vendored
6
pyste/dist/setup.py
vendored
@@ -1,6 +0,0 @@
|
||||
from distutils.core import setup
|
||||
import py2exe
|
||||
import sys
|
||||
|
||||
sys.path.append('../src')
|
||||
setup(name='pyste', scripts=['../src/pyste.py'])
|
||||
@@ -4,7 +4,6 @@
|
||||
<title>Exporting All Declarations from a Header</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="wrappers.html">
|
||||
<link rel="next" href="smart_pointers.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
@@ -21,7 +20,7 @@
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="smart_pointers.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
@@ -64,7 +63,7 @@ the members of the header object like this:</p>
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="smart_pointers.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
|
||||
@@ -51,13 +51,13 @@ Here's the interface file for it, named <tt>world.pyste</tt>:</p>
|
||||
<p>
|
||||
and that's it!</p>
|
||||
<p>
|
||||
The next step is invoke Pyste in the command-line:</p>
|
||||
The next step is invoke pyste in the command-line:</p>
|
||||
<code><pre>python pyste.py --module=hello world.pyste</pre></code><p>
|
||||
this will create a file "<tt>hello.cpp</tt>" in the directory where the command was
|
||||
run. </p>
|
||||
<p>
|
||||
Pyste supports the following features:</p>
|
||||
<ul><li>Functions</li><li>Classes</li><li>Class Templates</li><li>Virtual Methods</li><li>Overloading</li><li>Attributes </li><li>Enums (both "free" enums and class enums)</li><li>Nested Classes</li><li>Support for <tt>boost::shared_ptr</tt> and <tt>std::auto_ptr</tt></li></ul><table border="0">
|
||||
<ul><li>Functions</li><li>Classes</li><li>Class Templates</li><li>Virtual Methods</li><li>Overloading</li><li>Attributes </li><li>Enums (both "free" enums and class enums)</li><li>Nested Classes</li></ul><table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td>
|
||||
|
||||
@@ -55,21 +55,10 @@ function:</p>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img> <b>What if a function or method needs a policy and the user
|
||||
doesn't set one?</b><br><br> If a function/method needs a policy and one was not
|
||||
set, Pyste will issue a error. The user should then go in the interface file
|
||||
and set the policy for it, otherwise the generated cpp won't compile.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img>
|
||||
Note that, for functions/methods that return <tt>const T&</tt>, the policy
|
||||
<tt>return_value_policy<copy_const_reference>()</tt> wil be used by default, because
|
||||
that's normally what you want. You can change it to something else if you need
|
||||
to, though.
|
||||
doesn't set one?</b><br><br>
|
||||
If a function/method needs a policy and one was not set, Pyste will issue a error.
|
||||
The user should then go in the interface file and set the policy for it,
|
||||
otherwise the generated cpp won't compile.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -30,7 +30,7 @@ Here's the interface file for it, named [^world.pyste]:
|
||||
|
||||
and that's it!
|
||||
|
||||
The next step is invoke Pyste in the command-line:
|
||||
The next step is invoke pyste in the command-line:
|
||||
|
||||
[pre python pyste.py --module=hello world.pyste]
|
||||
|
||||
@@ -47,21 +47,20 @@ Pyste supports the following features:
|
||||
* Attributes
|
||||
* Enums (both "free" enums and class enums)
|
||||
* Nested Classes
|
||||
* Support for [^boost::shared_ptr] and [^std::auto_ptr]
|
||||
|
||||
[page Running Pyste]
|
||||
|
||||
To run Pyste, you will need:
|
||||
To run pyste, you will need:
|
||||
|
||||
* Python 2.2, available at [@http://www.python.org python's website].
|
||||
* Python 2.2, avaiable at [@http://www.python.org python's website].
|
||||
* The great [@http://effbot.org elementtree] library, from Fredrik Lundh.
|
||||
* The excellent GCCXML, from Brad King.
|
||||
|
||||
Installation for the tools is available in their respective webpages.
|
||||
Installation for the tools is avaiable in their respective webpages.
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif] GCCXML must be accessible in the PATH environment variable, so
|
||||
that Pyste can call it. How to do this varies from platform to platform.
|
||||
that pyste can call it. How to do this varies from platform to platform.
|
||||
]
|
||||
|
||||
[h2 Ok, now what?]
|
||||
@@ -72,56 +71,31 @@ Well, now let's fire it up:
|
||||
'''
|
||||
>python pyste.py
|
||||
|
||||
Pyste version 0.6.5
|
||||
|
||||
Usage:
|
||||
pyste [options] --module=<name> interface-files
|
||||
|
||||
where options are:
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--multiple create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--no-using do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug writes the xml for each file parsed in the current
|
||||
directory
|
||||
-h, --help print this help and exit
|
||||
-v, --version print version information
|
||||
default is "pyste"
|
||||
'''
|
||||
]
|
||||
|
||||
Options explained:
|
||||
|
||||
The [^-I] and [^-D] are preprocessor flags, which are needed by GCCXML to parse
|
||||
the header files correctly and by Pyste to find the header files declared in the
|
||||
The [^-I] and [^-D] are preprocessor flags, which are needed by gccxml to parse the header files correctly and by pyste to find the header files declared in the
|
||||
interface files.
|
||||
|
||||
[^--multiple] tells Pyste to generate multiple cpps for this module (one for
|
||||
each header parsed) in the directory named by [^--out], instead of the usual
|
||||
single cpp file. This mode is useful during development of a binding, because
|
||||
you are constantly changing source files, re-generating the bindings and
|
||||
recompiling. This saves a lot of time in compiling.
|
||||
|
||||
[^--out] names the output file (default: [^<module>.cpp]), or in multiple mode,
|
||||
names a output directory for the files (default: [^<module>]).
|
||||
|
||||
[^--no-using] tells Pyste to don't declare "[^using namespace boost;]" in the
|
||||
[^--no-using] tells pyste to don't declare "[^using namespace boost;]" in the
|
||||
generated cpp, using the namespace boost::python explicitly in all declarations.
|
||||
Use only if you're having a name conflict in one of the files.
|
||||
|
||||
Use [^--pyste-ns] to change the namespace where new types are declared (for
|
||||
instance, the virtual wrappers). Use only if you are having any problems. By
|
||||
default, Pyste uses the empty namespace.
|
||||
|
||||
[^--debug] will write in the current directory a xml file as outputted by GCCXML
|
||||
for each header parsed. Useful for bug reports.
|
||||
|
||||
[^-h, --help, -v, --version] are self-explaining, I believe. ;)
|
||||
instance, the virtual wrappers). Use only if one of your header files declare a
|
||||
namespace named "pyste" and this is causing conflicts.
|
||||
|
||||
So, the usage is simple enough:
|
||||
|
||||
@@ -129,13 +103,7 @@ So, the usage is simple enough:
|
||||
|
||||
will generate a file [^mymodule.cpp] in the same dir where the command was
|
||||
executed. Now you can compile the file using the same instructions of the
|
||||
[@../../doc/tutorial/doc/building_hello_world.html tutorial]. Or, if you prefer:
|
||||
|
||||
[pre >python pyste.py --module=mymodule --multiple file.pyste file2.pyste ...]
|
||||
|
||||
will create a directory named "mymodule" in the current directory, and will
|
||||
generate a bunch of cpp files, one for each header exported. You can then
|
||||
compile them all into a single shared library (or dll).
|
||||
[@../../doc/tutorial/doc/building_hello_world.html tutorial].
|
||||
|
||||
[h2 Wait... how do I set those I and D flags?]
|
||||
|
||||
@@ -152,15 +120,11 @@ which for Visual C++ 6 is normally located at:
|
||||
|
||||
with that, you should have little trouble setting up the flags.
|
||||
|
||||
[blurb [$theme/note.gif][*A note about Psyco][br][br]
|
||||
Although you don't have to install [@http://psyco.sourceforge.net/ Psyco] to use Pyste, if you do, Pyste will make use of it to speed up the wrapper generation. Speed ups of 30% can be achieved, so it's highly recommended.
|
||||
]
|
||||
|
||||
[page The Interface Files]
|
||||
|
||||
The interface files are the heart of Pyste. The user creates one or more
|
||||
interface files declaring the classes and functions he wants to export, and then
|
||||
invokes Pyste passing the interface files to it. Pyste then generates a single
|
||||
invokes pyste passing the interface files to it. Pyste then generates a single
|
||||
cpp file with Boost.Python code, with all the classes and functions exported.
|
||||
|
||||
Besides declaring the classes and functions, the user has a number of other
|
||||
@@ -221,14 +185,7 @@ with the function [^exclude]:
|
||||
exclude(World.greet)
|
||||
exclude(World.msg)
|
||||
|
||||
To access the operators of a class, access the member [^operator] like this
|
||||
(supposing that [^C] is a class being exported):
|
||||
|
||||
exclude(C.operator['+'])
|
||||
exclude(C.operator['*'])
|
||||
exclude(C.operator['<<'])
|
||||
|
||||
The string inside the brackets is the same as the name of the operator in C++.[br]
|
||||
Easy, huh? [$theme/smiley.gif]
|
||||
|
||||
[page:1 Policies]
|
||||
|
||||
@@ -255,22 +212,15 @@ function:
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif] [*What if a function or method needs a policy and the user
|
||||
doesn't set one?][br][br] If a function/method needs a policy and one was not
|
||||
set, Pyste will issue a error. The user should then go in the interface file
|
||||
and set the policy for it, otherwise the generated cpp won't compile.
|
||||
]
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif]
|
||||
Note that, for functions/methods that return [^const T&], the policy
|
||||
[^return_value_policy<copy_const_reference>()] wil be used by default, because
|
||||
that's normally what you want. You can change it to something else if you need
|
||||
to, though.
|
||||
doesn't set one?][br][br]
|
||||
If a function/method needs a policy and one was not set, Pyste will issue a error.
|
||||
The user should then go in the interface file and set the policy for it,
|
||||
otherwise the generated cpp won't compile.
|
||||
]
|
||||
|
||||
[page:1 Templates]
|
||||
|
||||
Template classes can easily be exported too, but you can't export the template
|
||||
Template Classes can easily exported too, but you can't export the "Template"
|
||||
itself... you have to export instantiations of it! So, if you want to export a
|
||||
[^std::vector], you will have to export vectors of int, doubles, etc.
|
||||
|
||||
@@ -297,7 +247,7 @@ rename the instantiations:
|
||||
double_inst = Point("double") // another way to do the same
|
||||
rename(double_inst, "DPoint")
|
||||
|
||||
Note that you can rename, exclude, set policies, etc, in the [^Template] object
|
||||
Note that you can rename, exclude, set policies, etc, in the [^Template] class
|
||||
like you would do with a [^Function] or a [^Class]. This changes affect all
|
||||
[*future] instantiations:
|
||||
|
||||
@@ -318,7 +268,7 @@ If you want to change a option of a particular instantiation, you can do so:
|
||||
|
||||
[blurb [$theme/note.gif] [*What if my template accepts more than one type?]
|
||||
[br][br]
|
||||
When you want to instantiate a template with more than one type, you can pass
|
||||
When you want to instantiate a Template with more than one type, you can pass
|
||||
either a string with the types separated by whitespace, or a list of strings
|
||||
'''("int double" or ["int", "double"]''' would both work).
|
||||
]
|
||||
@@ -329,20 +279,14 @@ Suppose you have this function:
|
||||
|
||||
std::vector<std::string> names();
|
||||
|
||||
But you don't want to export [^std::vector<std::string>], you want this function
|
||||
to return a python list of strings. Boost.Python has excellent support for
|
||||
that:
|
||||
But you don't want to export a vector<string>, you want this function to return
|
||||
a python list of strings. Boost.Python has an excellent support for that:
|
||||
|
||||
list names_wrapper()
|
||||
{
|
||||
list result;
|
||||
// call original function
|
||||
vector<string> v = names();
|
||||
// put all the strings inside the python list
|
||||
vector<string>::iterator it;
|
||||
for (it = v.begin(); it != v.end(); ++it){
|
||||
result.append(*it);
|
||||
}
|
||||
// put each string in the vector in the list
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -351,8 +295,9 @@ that:
|
||||
def("names", &names_wrapper);
|
||||
}
|
||||
|
||||
Nice heh? Pyste supports this mechanism too. You declare the [^names_wrapper]
|
||||
function in a header named "[^test_wrappers.h]" and in the interface file:
|
||||
Nice heh?
|
||||
Pyste supports this mechanism too. You declare the [^names_wrapper] function in a
|
||||
header, like "[^test_wrappers.h]", and in the interface file:
|
||||
|
||||
Include("test_wrappers.h")
|
||||
names = Function("names", "test.h")
|
||||
@@ -364,13 +309,13 @@ You can optionally declare the function in the interface file itself:
|
||||
"""
|
||||
list names_wrapper()
|
||||
{
|
||||
// code to call name() and convert the vector to a list...
|
||||
// call name() and convert the vector to a list...
|
||||
}
|
||||
""")
|
||||
names = Function("names", "test.h")
|
||||
set_wrapper(names, names_wrapper)
|
||||
|
||||
The same mechanism can be used with methods too. Just remember that the first
|
||||
The same mechanism can be done with methods too. Just remember that the first
|
||||
parameter of wrappers for methods is a pointer to the class, like in
|
||||
Boost.Python:
|
||||
|
||||
@@ -381,7 +326,7 @@ Boost.Python:
|
||||
|
||||
list names_wrapper(C* c)
|
||||
{
|
||||
// same as before, calling c->names() and converting result to a list
|
||||
// same as before, calling c->names() and converting result to a list
|
||||
}
|
||||
|
||||
And then in the interface file:
|
||||
@@ -389,13 +334,6 @@ And then in the interface file:
|
||||
C = Class("C", "test.h")
|
||||
set_wrapper(C.names, "names_wrapper")
|
||||
|
||||
[blurb
|
||||
[$theme/note.gif]Even though Boost.Python accepts either a pointer or a
|
||||
reference to the class in wrappers for member functions as the first parameter,
|
||||
Pyste expects them to be a [*pointer]. Doing otherwise will prevent your
|
||||
code to compile when you set a wrapper for a virtual method.
|
||||
]
|
||||
|
||||
[page:1 Exporting All Declarations from a Header]
|
||||
|
||||
Pyste also supports a mechanism to export all declarations found in a header
|
||||
@@ -430,38 +368,3 @@ the members of the header object like this:
|
||||
rename(hello.World.greet, "Greet")
|
||||
exclude(hello.World.set, "Set")
|
||||
|
||||
|
||||
[page:1 Smart Pointers]
|
||||
|
||||
Pyste for now has manual support for smart pointers. Suppose:
|
||||
|
||||
struct C
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
boost::shared_ptr<C> newC(int value)
|
||||
{
|
||||
boost::shared_ptr<C> c( new C() );
|
||||
c->value = value;
|
||||
return c;
|
||||
}
|
||||
|
||||
void printC(boost::shared_ptr<C> c)
|
||||
{
|
||||
std::cout << c->value << std::endl;
|
||||
}
|
||||
|
||||
To make [^newC] and [^printC] work correctly, you have to tell Pyste that a
|
||||
convertor for [^boost::shared_ptr<C>] is needed.
|
||||
|
||||
C = Class('C', 'C.h')
|
||||
use_shared_ptr(C)
|
||||
Function('newC', 'C.h')
|
||||
Function('printC', 'C.h')
|
||||
|
||||
For [^std::auto_ptr]'s, use the function [^use_auto_ptr].
|
||||
|
||||
This system is temporary, and in the future the converters will automatically be
|
||||
exported if needed, without the need to tell Pyste about them explicitly.
|
||||
|
||||
|
||||
@@ -50,15 +50,7 @@ with the function <tt>exclude</tt>:</p>
|
||||
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>msg</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
To access the operators of a class, access the member <tt>operator</tt> like this
|
||||
(supposing that <tt>C</tt> is a class being exported):</p>
|
||||
<code><pre>
|
||||
<span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'+'</span><span class=special>])
|
||||
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'*'</span><span class=special>])
|
||||
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'<<'</span><span class=special>])
|
||||
</span></pre></code>
|
||||
<p>
|
||||
The string inside the brackets is the same as the name of the operator in C++.<br></p>
|
||||
Easy, huh? <img src="theme/smiley.gif"></img></p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
|
||||
@@ -25,19 +25,19 @@
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
To run Pyste, you will need:</p>
|
||||
<ul><li>Python 2.2, available at <a href="http://www.python.org">
|
||||
To run pyste, you will need:</p>
|
||||
<ul><li>Python 2.2, avaiable at <a href="http://www.python.org">
|
||||
python's website</a>.</li><li>The great <a href="http://effbot.org">
|
||||
elementtree</a> library, from Fredrik Lundh.</li><li>The excellent <a href="http://www.gccxml.org">
|
||||
GCCXML</a>, from Brad King.</li></ul><p>
|
||||
Installation for the tools is available in their respective webpages.</p>
|
||||
Installation for the tools is avaiable in their respective webpages.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img> <a href="http://www.gccxml.org">
|
||||
GCCXML</a> must be accessible in the PATH environment variable, so
|
||||
that Pyste can call it. How to do this varies from platform to platform.
|
||||
that pyste can call it. How to do this varies from platform to platform.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -47,68 +47,37 @@ Well, now let's fire it up:</p>
|
||||
|
||||
>python pyste.py
|
||||
|
||||
Pyste version 0.6.5
|
||||
|
||||
Usage:
|
||||
pyste [options] --module=<name> interface-files
|
||||
|
||||
where options are:
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--multiple create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--no-using do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug writes the xml for each file parsed in the current
|
||||
directory
|
||||
-h, --help print this help and exit
|
||||
-v, --version print version information
|
||||
default is "pyste"
|
||||
|
||||
</pre></code><p>
|
||||
Options explained:</p>
|
||||
<p>
|
||||
The <tt>-I</tt> and <tt>-D</tt> are preprocessor flags, which are needed by <a href="http://www.gccxml.org">
|
||||
GCCXML</a> to parse
|
||||
the header files correctly and by Pyste to find the header files declared in the
|
||||
The <tt>-I</tt> and <tt>-D</tt> are preprocessor flags, which are needed by gccxml to parse the header files correctly and by pyste to find the header files declared in the
|
||||
interface files.</p>
|
||||
<p>
|
||||
<tt>--multiple</tt> tells Pyste to generate multiple cpps for this module (one for
|
||||
each header parsed) in the directory named by <tt>--out</tt>, instead of the usual
|
||||
single cpp file. This mode is useful during development of a binding, because
|
||||
you are constantly changing source files, re-generating the bindings and
|
||||
recompiling. This saves a lot of time in compiling.</p>
|
||||
<p>
|
||||
<tt>--out</tt> names the output file (default: <tt><module>.cpp</tt>), or in multiple mode,
|
||||
names a output directory for the files (default: <tt><module></tt>).</p>
|
||||
<p>
|
||||
<tt>--no-using</tt> tells Pyste to don't declare "<tt>using namespace boost;</tt>" in the
|
||||
<tt>--no-using</tt> tells pyste to don't declare "<tt>using namespace boost;</tt>" in the
|
||||
generated cpp, using the namespace boost::python explicitly in all declarations.
|
||||
Use only if you're having a name conflict in one of the files.</p>
|
||||
<p>
|
||||
Use <tt>--pyste-ns</tt> to change the namespace where new types are declared (for
|
||||
instance, the virtual wrappers). Use only if you are having any problems. By
|
||||
default, Pyste uses the empty namespace.</p>
|
||||
<p>
|
||||
<tt>--debug</tt> will write in the current directory a xml file as outputted by <a href="http://www.gccxml.org">
|
||||
GCCXML</a>
|
||||
for each header parsed. Useful for bug reports.</p>
|
||||
<p>
|
||||
<tt>-h, --help, -v, --version</tt> are self-explaining, I believe. ;)</p>
|
||||
instance, the virtual wrappers). Use only if one of your header files declare a
|
||||
namespace named "pyste" and this is causing conflicts.</p>
|
||||
<p>
|
||||
So, the usage is simple enough:</p>
|
||||
<code><pre>>python pyste.py --module=mymodule file.pyste file2.pyste ...</pre></code><p>
|
||||
will generate a file <tt>mymodule.cpp</tt> in the same dir where the command was
|
||||
executed. Now you can compile the file using the same instructions of the
|
||||
<a href="../../doc/tutorial/doc/building_hello_world.html">
|
||||
tutorial</a>. Or, if you prefer:</p>
|
||||
<code><pre>>python pyste.py --module=mymodule --multiple file.pyste file2.pyste ...</pre></code><p>
|
||||
will create a directory named "mymodule" in the current directory, and will
|
||||
generate a bunch of cpp files, one for each header exported. You can then
|
||||
compile them all into a single shared library (or dll).</p>
|
||||
tutorial</a>. </p>
|
||||
<a name="wait____how_do_i_set_those_i_and_d_flags_"></a><h2>Wait... how do I set those I and D flags?</h2><p>
|
||||
Don't worry: normally <a href="http://www.gccxml.org">
|
||||
GCCXML</a> is already configured correctly for your plataform,
|
||||
@@ -124,15 +93,6 @@ which for Visual C++ 6 is normally located at:</p>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
with that, you should have little trouble setting up the flags.</p>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif"></img><b>A note about Psyco</b><br><br>
|
||||
Although you don't have to install <a href="http://psyco.sourceforge.net/">
|
||||
Psyco</a> to use Pyste, if you do, Pyste will make use of it to speed up the wrapper generation. Speed ups of 30% can be achieved, so it's highly recommended.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Smart Pointers</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="prev" href="exporting_all_declarations_from_a_header.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" cellspacing="2">
|
||||
<tr>
|
||||
<td><img src="theme/c%2B%2Bboost.gif">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Smart Pointers</b></font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="exporting_all_declarations_from_a_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Pyste for now has manual support for smart pointers. Suppose:</p>
|
||||
<code><pre>
|
||||
<span class=keyword>struct </span><span class=identifier>C
|
||||
</span><span class=special>{
|
||||
</span><span class=keyword>int </span><span class=identifier>value</span><span class=special>;
|
||||
};
|
||||
|
||||
</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>newC</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>value</span><span class=special>)
|
||||
{
|
||||
</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>c</span><span class=special>( </span><span class=keyword>new </span><span class=identifier>C</span><span class=special>() );
|
||||
</span><span class=identifier>c</span><span class=special>-></span><span class=identifier>value </span><span class=special>= </span><span class=identifier>value</span><span class=special>;
|
||||
</span><span class=keyword>return </span><span class=identifier>c</span><span class=special>;
|
||||
}
|
||||
|
||||
</span><span class=keyword>void </span><span class=identifier>printC</span><span class=special>(</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special><</span><span class=identifier>C</span><span class=special>> </span><span class=identifier>c</span><span class=special>)
|
||||
{
|
||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special><< </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>value </span><span class=special><< </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>;
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
To make <tt>newC</tt> and <tt>printC</tt> work correctly, you have to tell Pyste that a
|
||||
convertor for <tt>boost::shared_ptr<C></tt> is needed.</p>
|
||||
<code><pre>
|
||||
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span><span class=identifier>use_shared_ptr</span><span class=special>(</span><span class=identifier>C</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'newC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'printC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
For <tt>std::auto_ptr</tt>'s, use the function <tt>use_auto_ptr</tt>.</p>
|
||||
<p>
|
||||
This system is temporary, and in the future the converters will automatically be
|
||||
exported if needed, without the need to tell Pyste about them explicitly.</p>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="exporting_all_declarations_from_a_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,7 +25,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Template classes can easily be exported too, but you can't export the template
|
||||
Template Classes can easily exported too, but you can't export the "Template"
|
||||
itself... you have to export instantiations of it! So, if you want to export a
|
||||
<tt>std::vector</tt>, you will have to export vectors of int, doubles, etc.</p>
|
||||
<p>
|
||||
@@ -55,7 +55,7 @@ rename the instantiations:</p>
|
||||
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>double_inst</span><span class=special>, </span><span class=string>"DPoint"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Note that you can rename, exclude, set policies, etc, in the <tt>Template</tt> object
|
||||
Note that you can rename, exclude, set policies, etc, in the <tt>Template</tt> class
|
||||
like you would do with a <tt>Function</tt> or a <tt>Class</tt>. This changes affect all
|
||||
<b>future</b> instantiations:</p>
|
||||
<code><pre>
|
||||
@@ -80,7 +80,7 @@ If you want to change a option of a particular instantiation, you can do so:</p>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif"></img> <b>What if my template accepts more than one type?</b>
|
||||
<br><br>
|
||||
When you want to instantiate a template with more than one type, you can pass
|
||||
When you want to instantiate a Template with more than one type, you can pass
|
||||
either a string with the types separated by whitespace, or a list of strings
|
||||
("int double" or ["int", "double"] would both work).
|
||||
</td>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<p>
|
||||
The interface files are the heart of Pyste. The user creates one or more
|
||||
interface files declaring the classes and functions he wants to export, and then
|
||||
invokes Pyste passing the interface files to it. Pyste then generates a single
|
||||
invokes pyste passing the interface files to it. Pyste then generates a single
|
||||
cpp file with <a href="../../index.html">
|
||||
Boost.Python</a> code, with all the classes and functions exported.</p>
|
||||
<p>
|
||||
|
||||
@@ -30,21 +30,15 @@ Suppose you have this function:</p>
|
||||
<span class=identifier>std</span><span class=special>::</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>names</span><span class=special>();
|
||||
</span></pre></code>
|
||||
<p>
|
||||
But you don't want to export <tt>std::vector<std::string></tt>, you want this function
|
||||
to return a python list of strings. <a href="../../index.html">
|
||||
Boost.Python</a> has excellent support for
|
||||
that:</p>
|
||||
But you don't want to export a vector<string>, you want this function to return
|
||||
a python list of strings. <a href="../../index.html">
|
||||
Boost.Python</a> has an excellent support for that:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>list </span><span class=identifier>names_wrapper</span><span class=special>()
|
||||
{
|
||||
</span><span class=identifier>list </span><span class=identifier>result</span><span class=special>;
|
||||
// </span><span class=identifier>call </span><span class=identifier>original </span><span class=identifier>function
|
||||
</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>v </span><span class=special>= </span><span class=identifier>names</span><span class=special>();
|
||||
// </span><span class=identifier>put </span><span class=identifier>all </span><span class=identifier>the </span><span class=identifier>strings </span><span class=identifier>inside </span><span class=identifier>the </span><span class=identifier>python </span><span class=identifier>list
|
||||
</span><span class=identifier>vector</span><span class=special><</span><span class=identifier>string</span><span class=special>>::</span><span class=identifier>iterator </span><span class=identifier>it</span><span class=special>;
|
||||
</span><span class=keyword>for </span><span class=special>(</span><span class=identifier>it </span><span class=special>= </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(); </span><span class=identifier>it </span><span class=special>!= </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>end</span><span class=special>(); ++</span><span class=identifier>it</span><span class=special>){
|
||||
</span><span class=identifier>result</span><span class=special>.</span><span class=identifier>append</span><span class=special>(*</span><span class=identifier>it</span><span class=special>);
|
||||
}
|
||||
// </span><span class=identifier>put </span><span class=identifier>each </span><span class=identifier>string </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>vector </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>list
|
||||
</span><span class=keyword>return </span><span class=identifier>result</span><span class=special>;
|
||||
}
|
||||
|
||||
@@ -54,8 +48,9 @@ that:</p>
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Nice heh? Pyste supports this mechanism too. You declare the <tt>names_wrapper</tt>
|
||||
function in a header named "<tt>test_wrappers.h</tt>" and in the interface file:</p>
|
||||
Nice heh?
|
||||
Pyste supports this mechanism too. You declare the <tt>names_wrapper</tt> function in a
|
||||
header, like "<tt>test_wrappers.h</tt>", and in the interface file:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Include</span><span class=special>(</span><span class=string>"test_wrappers.h"</span><span class=special>)
|
||||
</span><span class=identifier>names </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"names"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>)
|
||||
@@ -68,14 +63,14 @@ You can optionally declare the function in the interface file itself:</p>
|
||||
</span><span class=string>""</span><span class=string>"
|
||||
list names_wrapper()
|
||||
{
|
||||
// code to call name() and convert the vector to a list...
|
||||
// call name() and convert the vector to a list...
|
||||
}
|
||||
"</span><span class=string>""</span><span class=special>)
|
||||
</span><span class=identifier>names </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>"names"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>)
|
||||
</span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>names</span><span class=special>, </span><span class=identifier>names_wrapper</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<p>
|
||||
The same mechanism can be used with methods too. Just remember that the first
|
||||
The same mechanism can be done with methods too. Just remember that the first
|
||||
parameter of wrappers for methods is a pointer to the class, like in
|
||||
<a href="../../index.html">
|
||||
Boost.Python</a>:</p>
|
||||
@@ -87,7 +82,7 @@ Boost.Python</a>:</p>
|
||||
|
||||
</span><span class=identifier>list </span><span class=identifier>names_wrapper</span><span class=special>(</span><span class=identifier>C</span><span class=special>* </span><span class=identifier>c</span><span class=special>)
|
||||
{
|
||||
// </span><span class=identifier>same </span><span class=identifier>as </span><span class=identifier>before</span><span class=special>, </span><span class=identifier>calling </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>names</span><span class=special>() </span><span class=keyword>and </span><span class=identifier>converting </span><span class=identifier>result </span><span class=identifier>to </span><span class=identifier>a </span><span class=identifier>list
|
||||
// </span><span class=identifier>same </span><span class=identifier>as </span><span class=identifier>before</span><span class=special>, </span><span class=identifier>calling </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>names</span><span class=special>() </span><span class=keyword>and </span><span class=identifier>converting </span><span class=identifier>result </span><span class=identifier>to </span><span class=identifier>a </span><span class=identifier>list
|
||||
</span><span class=special>}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
@@ -96,18 +91,6 @@ And then in the interface file:</p>
|
||||
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>"C"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>)
|
||||
</span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>names</span><span class=special>, </span><span class=string>"names_wrapper"</span><span class=special>)
|
||||
</span></pre></code>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
|
||||
<img src="theme/note.gif"></img>Even though <a href="../../index.html">
|
||||
Boost.Python</a> accepts either a pointer or a
|
||||
reference to the class in wrappers for member functions as the first parameter,
|
||||
Pyste expects them to be a <b>pointer</b>. Doing otherwise will prevent your
|
||||
code to compile when you set a wrapper for a virtual method.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
.sconsign
|
||||
*.obj
|
||||
*.cpp
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#include "basic.h"
|
||||
|
||||
namespace basic {
|
||||
|
||||
int C::static_value = 3;
|
||||
const int C::const_static_value = 100;
|
||||
|
||||
}
|
||||
@@ -1,15 +1,7 @@
|
||||
#ifndef BASIC_H
|
||||
#define BASIC_H
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace basic {
|
||||
|
||||
struct C
|
||||
{
|
||||
// test virtuallity
|
||||
C(): value(1), const_value(0) {}
|
||||
virtual int f(int x = 10)
|
||||
{
|
||||
return x*2;
|
||||
@@ -18,42 +10,16 @@ struct C
|
||||
int foo(int x=1){
|
||||
return x+1;
|
||||
}
|
||||
|
||||
const std::string& name() { return _name; }
|
||||
void set_name(const std::string& name) { _name = name; }
|
||||
std::string _name;
|
||||
|
||||
// test data members
|
||||
static int static_value;
|
||||
static const int const_static_value;
|
||||
|
||||
int value;
|
||||
const int const_value;
|
||||
|
||||
// test static functions
|
||||
static int mul(int x=2, int y=3) { return x*y; }
|
||||
};
|
||||
|
||||
inline int call_f(C& c)
|
||||
int call_f(C& c)
|
||||
{
|
||||
return c.f();
|
||||
}
|
||||
|
||||
inline int call_f(C& c, int x)
|
||||
int call_f(C& c, int x)
|
||||
{
|
||||
return c.f(x);
|
||||
}
|
||||
|
||||
inline int get_static()
|
||||
{
|
||||
return C::static_value;
|
||||
}
|
||||
|
||||
inline int get_value(C& c)
|
||||
{
|
||||
return c.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
Class('basic::C', 'basic.h')
|
||||
Function('basic::call_f', 'basic.h')
|
||||
Function('basic::get_static', 'basic.h')
|
||||
Function('basic::get_value', 'basic.h')
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#ifndef ENUMS_H
|
||||
#define ENUMS_H
|
||||
|
||||
namespace enums {
|
||||
|
||||
enum color { red, blue };
|
||||
@@ -20,5 +17,3 @@ struct X
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#ifndef HEADER_TEST_H
|
||||
#define HEADER_TEST_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
@@ -8,7 +5,7 @@ namespace header_test {
|
||||
|
||||
enum choice { red, blue };
|
||||
|
||||
inline std::string choice_str(choice c)
|
||||
std::string choice_str(choice c)
|
||||
{
|
||||
std::map<choice, std::string> choice_map;
|
||||
choice_map[red] = "red";
|
||||
@@ -27,5 +24,3 @@ struct C
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
template<typename T>
|
||||
class A
|
||||
{
|
||||
public:
|
||||
void set(T v) { mData = v; }
|
||||
|
||||
T get() const { return mData; }
|
||||
|
||||
private:
|
||||
T mData;
|
||||
};
|
||||
|
||||
|
||||
class B : public A<int>
|
||||
{
|
||||
public:
|
||||
int go() { return get(); }
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
# Doesn't work:
|
||||
A = Template('A', 'inherit.h')
|
||||
A_int = A('int')
|
||||
|
||||
Class('B', 'inherit.h')
|
||||
|
||||
# Does work:
|
||||
#AllFromHeader('inherit.h')
|
||||
@@ -1,4 +0,0 @@
|
||||
#include "nested.h"
|
||||
|
||||
int nested::X::staticXValue = 10;
|
||||
int nested::X::Y::staticYValue = 20;
|
||||
@@ -1,6 +1,3 @@
|
||||
#ifndef NESTED_H
|
||||
#define NESTED_H
|
||||
|
||||
namespace nested {
|
||||
|
||||
struct X
|
||||
@@ -19,8 +16,9 @@ struct X
|
||||
int valueX;
|
||||
};
|
||||
|
||||
int X::staticXValue = 10;
|
||||
int X::Y::staticYValue = 20;
|
||||
|
||||
typedef X Root;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#ifndef OPAQUE_H
|
||||
#define OPAQUE_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace opaque {
|
||||
|
||||
|
||||
struct C {
|
||||
C(int v): value(v) {}
|
||||
int value;
|
||||
};
|
||||
|
||||
|
||||
inline C* new_C()
|
||||
{
|
||||
return new C(10);
|
||||
}
|
||||
|
||||
inline int get(C* c)
|
||||
{
|
||||
return c->value;
|
||||
}
|
||||
|
||||
struct D {
|
||||
D(double v): value(v) {}
|
||||
double value;
|
||||
};
|
||||
|
||||
struct A
|
||||
{
|
||||
D* new_handle()
|
||||
{
|
||||
return new D(3.0);
|
||||
}
|
||||
|
||||
double get(D* d)
|
||||
{
|
||||
return d->value;
|
||||
}
|
||||
|
||||
int f(int x=0) { return x; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +0,0 @@
|
||||
foo = Function('opaque::new_C', 'opaque.h')
|
||||
set_policy(foo, return_value_policy(return_opaque_pointer))
|
||||
Function('opaque::get', 'opaque.h' )
|
||||
A = Class('opaque::A', 'opaque.h')
|
||||
set_policy(A.new_handle, return_value_policy(return_opaque_pointer))
|
||||
47
pyste/example/operator.h
Normal file
47
pyste/example/operator.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#include <iostream>
|
||||
|
||||
|
||||
struct C
|
||||
{
|
||||
static double x;
|
||||
double value;
|
||||
|
||||
const C operator+(const C other) const
|
||||
{
|
||||
C c;
|
||||
c.value = value + other.value;
|
||||
return c;
|
||||
}
|
||||
operator int() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
double operator()()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
double operator()(double other)
|
||||
{
|
||||
return x + other;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
double C::x = 10;
|
||||
|
||||
const C operator*(const C& lhs, const C& rhs)
|
||||
{
|
||||
C c;
|
||||
c.value = lhs.value * rhs.value;
|
||||
return c;
|
||||
}
|
||||
|
||||
std::ostream& operator <<( std::ostream& s, const C& c)
|
||||
{
|
||||
std::cout << "here";
|
||||
s << "C instance: ";
|
||||
return s;
|
||||
}
|
||||
|
||||
12
pyste/example/operator.pyste
Normal file
12
pyste/example/operator.pyste
Normal file
@@ -0,0 +1,12 @@
|
||||
Include('iostream')
|
||||
test = Wrapper('sum',
|
||||
'''
|
||||
const C sum(const C&, const C&)
|
||||
{
|
||||
std::cout << "sum!" << std::endl;
|
||||
return C();
|
||||
}
|
||||
'''
|
||||
)
|
||||
C = Class('C', 'operator.h')
|
||||
set_wrapper(C.operator['+'], test)
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "operators.h"
|
||||
|
||||
double operators::C::x = 10;
|
||||
@@ -1,7 +1,3 @@
|
||||
#ifndef OPERATORS_H
|
||||
#define OPERATORS_H
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace operators {
|
||||
@@ -19,7 +15,7 @@ struct C
|
||||
}
|
||||
operator int() const
|
||||
{
|
||||
return (int)value;
|
||||
return value;
|
||||
}
|
||||
|
||||
double operator()()
|
||||
@@ -32,18 +28,16 @@ struct C
|
||||
return C::x + other;
|
||||
}
|
||||
|
||||
operator const char*() { return "C"; }
|
||||
|
||||
};
|
||||
|
||||
inline const C operator*(const C& lhs, const C& rhs)
|
||||
double C::x = 10;
|
||||
|
||||
const C operator*(const C& lhs, const C& rhs)
|
||||
{
|
||||
C c;
|
||||
c.value = lhs.value * rhs.value;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
C = Class('operators::C', 'operators.h')
|
||||
#exclude(C.operator['+'])
|
||||
Class('operators::C', 'operators.h')
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef SMART_PTR_H
|
||||
#define SMART_PTR_H
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace smart_ptr {
|
||||
|
||||
struct C
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
inline boost::shared_ptr<C> NewC() { return boost::shared_ptr<C>( new C() ); }
|
||||
|
||||
struct D
|
||||
{
|
||||
boost::shared_ptr<C> Get() { return ptr; }
|
||||
void Set( boost::shared_ptr<C> c ) { ptr = c; }
|
||||
private:
|
||||
boost::shared_ptr<C> ptr;
|
||||
};
|
||||
|
||||
inline std::auto_ptr<D> NewD() { return std::auto_ptr<D>( new D() ); }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +0,0 @@
|
||||
C = Class('smart_ptr::C', 'smart_ptr.h')
|
||||
use_shared_ptr(C)
|
||||
D = Class('smart_ptr::D', 'smart_ptr.h')
|
||||
use_auto_ptr(D)
|
||||
Function('smart_ptr::NewC', 'smart_ptr.h')
|
||||
Function('smart_ptr::NewD', 'smart_ptr.h')
|
||||
@@ -1,10 +1,10 @@
|
||||
namespace templates {
|
||||
|
||||
template <class T>
|
||||
template <class X, class Y>
|
||||
struct Point
|
||||
{
|
||||
T x;
|
||||
T y;
|
||||
X x;
|
||||
Y y;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
Point = Template('templates::Point', 'templates.h')
|
||||
rename(Point.x, 'i')
|
||||
rename(Point.y, 'j')
|
||||
IPoint = Point('int')
|
||||
FPoint = Point('double', 'FPoint')
|
||||
IPoint = Point('int double')
|
||||
FPoint = Point('double int', 'FPoint')
|
||||
rename(IPoint, 'IPoint')
|
||||
rename(IPoint.x, 'x')
|
||||
rename(IPoint.y, 'y')
|
||||
|
||||
|
||||
@@ -20,6 +20,6 @@ private:
|
||||
virtual const char* name() { return "C"; }
|
||||
};
|
||||
|
||||
inline int call_f(C& c) { return c.f(); }
|
||||
int call_f(C& c) { return c.f(); }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
namespace virtual2 {
|
||||
|
||||
struct A
|
||||
{
|
||||
virtual int f() { return 0; }
|
||||
virtual int f1() { return 10; }
|
||||
};
|
||||
|
||||
struct B: A
|
||||
{
|
||||
virtual int f() { return 1; }
|
||||
virtual int f2() { return 20; }
|
||||
};
|
||||
|
||||
inline int call_fs(A*a)
|
||||
{
|
||||
int r = a->f1();
|
||||
B* b = dynamic_cast<B*>(a);
|
||||
return r + b->f2();
|
||||
}
|
||||
|
||||
inline int call_f(A* a)
|
||||
{
|
||||
return a->f();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
Class('virtual2::A', 'virtual2.h')
|
||||
Class('virtual2::B', 'virtual2.h')
|
||||
Function('virtual2::call_fs', 'virtual2.h')
|
||||
Function('virtual2::call_f', 'virtual2.h')
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace wrappertest {
|
||||
|
||||
inline std::vector<int> Range(int count)
|
||||
std::vector<int> Range(int count)
|
||||
{
|
||||
std::vector<int> v;
|
||||
v.reserve(count);
|
||||
@@ -34,13 +34,6 @@ struct C
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct A
|
||||
{
|
||||
virtual int f() { return 1; };
|
||||
};
|
||||
|
||||
inline int call_foo(A* a){ return a->f(); }
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -13,9 +13,3 @@ list MulWrapper(wrappertest::C& c, int value){
|
||||
|
||||
C = Class('wrappertest::C', 'wrappertest.h')
|
||||
set_wrapper(C.Mul, mul)
|
||||
|
||||
|
||||
A = Class('wrappertest::A', 'wrappertest.h')
|
||||
set_wrapper(A.f, 'f_wrapper')
|
||||
|
||||
Function('wrappertest::call_foo', 'wrappertest.h')
|
||||
|
||||
@@ -11,7 +11,7 @@ template <class T>
|
||||
list VectorToList(const std::vector<T> & v)
|
||||
{
|
||||
list res;
|
||||
typename std::vector<T>::const_iterator it;
|
||||
std::vector<T>::const_iterator it;
|
||||
for(it = v.begin(); it != v.end(); ++it){
|
||||
res.append(*it);
|
||||
}
|
||||
@@ -19,10 +19,8 @@ list VectorToList(const std::vector<T> & v)
|
||||
return res;
|
||||
}
|
||||
|
||||
inline list RangeWrapper(int count){
|
||||
list RangeWrapper(int count){
|
||||
return VectorToList(wrappertest::Range(count));
|
||||
}
|
||||
|
||||
inline int f_wrapper(wrappertest::A*) { return 10; }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -60,11 +60,6 @@
|
||||
<a href="doc/exporting_all_declarations_from_a_header.html">Exporting All Declarations from a Header</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="toc_cells_L1">
|
||||
<a href="doc/smart_pointers.html">Smart Pointers</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import exporters
|
||||
from Exporter import Exporter
|
||||
from declarations import *
|
||||
from enumerate import enumerate
|
||||
from settings import *
|
||||
from policies import *
|
||||
from SingleCodeUnit import SingleCodeUnit
|
||||
from CodeUnit import CodeUnit
|
||||
from EnumExporter import EnumExporter
|
||||
from utils import makeid, enumerate
|
||||
from copy import deepcopy
|
||||
import exporterutils
|
||||
import re
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# ClassExporter
|
||||
@@ -36,22 +33,16 @@ class ClassExporter(Exporter):
|
||||
self.sections['scope'] = []
|
||||
# declarations: outside the BOOST_PYTHON_MODULE macro
|
||||
self.sections['declaration'] = []
|
||||
self.sections['declaration-outside'] = []
|
||||
self.sections['include'] = []
|
||||
# a list of Constructor instances
|
||||
self.constructors = []
|
||||
self.wrapper_generator = None
|
||||
# a list of code units, generated by nested declarations
|
||||
self.nested_codeunits = []
|
||||
self._exported_opaque_pointers = {}
|
||||
|
||||
|
||||
def ScopeName(self):
|
||||
return makeid(self.class_.FullName()) + '_scope'
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return makeid(self.class_.name)
|
||||
return _ID(self.class_.FullName()) + '_scope'
|
||||
|
||||
|
||||
def Name(self):
|
||||
@@ -71,28 +62,24 @@ class ClassExporter(Exporter):
|
||||
[x for x in self.class_.members if x.visibility == Scope.public]
|
||||
|
||||
|
||||
def ClassBases(self):
|
||||
bases = []
|
||||
def GetBases(class_):
|
||||
this_bases = [self.GetDeclaration(x.name) for x in class_.bases]
|
||||
bases.extend(this_bases)
|
||||
for base in this_bases:
|
||||
GetBases(base)
|
||||
|
||||
GetBases(self.class_)
|
||||
return bases
|
||||
|
||||
|
||||
def Order(self):
|
||||
'''Return the TOTAL number of bases that this class has, including the
|
||||
bases' bases. Do this because base classes must be instantialized
|
||||
before the derived classes in the module definition.
|
||||
'''
|
||||
return '%s_%s' % (len(self.ClassBases()), self.class_.FullName())
|
||||
|
||||
def BasesCount(classname):
|
||||
decl = self.GetDeclaration(classname)
|
||||
bases = [x.name for x in decl.bases]
|
||||
total = 0
|
||||
for base in bases:
|
||||
total += BasesCount(base)
|
||||
return len(bases) + total
|
||||
|
||||
return BasesCount(self.class_.FullName())
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
self.CheckForwardDeclarations()
|
||||
self.ExportBasics()
|
||||
self.ExportBases(exported_names)
|
||||
self.ExportConstructors()
|
||||
@@ -102,17 +89,9 @@ class ClassExporter(Exporter):
|
||||
self.ExportOperators()
|
||||
self.ExportNestedClasses(exported_names)
|
||||
self.ExportNestedEnums()
|
||||
self.ExportSmartPointer()
|
||||
self.ExportOpaquePointerPolicies()
|
||||
self.Write(codeunit)
|
||||
|
||||
|
||||
def CheckForwardDeclarations(self):
|
||||
for m in self.public_members:
|
||||
if isinstance(m, Function):
|
||||
exporterutils.WarnForwardDeclarations(m)
|
||||
|
||||
|
||||
def Write(self, codeunit):
|
||||
indent = self.INDENT
|
||||
boost_ns = namespaces.python
|
||||
@@ -157,9 +136,6 @@ class ClassExporter(Exporter):
|
||||
declarations += nested_unit.Section('declaration')
|
||||
if declarations:
|
||||
codeunit.Write('declaration', declarations + '\n')
|
||||
declarations_outside = '\n'.join(self.sections['declaration-outside'])
|
||||
if declarations_outside:
|
||||
codeunit.Write('declaration-outside', declarations_outside + '\n')
|
||||
|
||||
# write the includes to the codeunit
|
||||
includes = '\n'.join(self.sections['include'])
|
||||
@@ -254,32 +230,50 @@ class ClassExporter(Exporter):
|
||||
continue
|
||||
name = self.info[var.name].rename or var.name
|
||||
fullname = var.FullName()
|
||||
if var.type.const:
|
||||
def_ = '.def_readonly'
|
||||
if var.static:
|
||||
code = '%s->attr("%s") = %s;' % (self.ScopeName(), name, fullname)
|
||||
self.Add('scope', code)
|
||||
else:
|
||||
def_ = '.def_readwrite'
|
||||
code = '%s("%s", &%s)' % (def_, name, fullname)
|
||||
self.Add('inside', code)
|
||||
if var.type.const:
|
||||
def_ = '.def_readonly'
|
||||
else:
|
||||
def_ = '.def_readwrite'
|
||||
code = '%s("%s", &%s)' % (def_, name, fullname)
|
||||
self.Add('inside', code)
|
||||
|
||||
|
||||
printed_policy_warnings = {}
|
||||
|
||||
def CheckPolicy(self, m):
|
||||
'Warns the user if this method needs a policy'
|
||||
def IsString(type):
|
||||
return type.const and type.name == 'char' and isinstance(type, PointerType)
|
||||
needs_policy = isinstance(m.result, (ReferenceType, PointerType))
|
||||
if IsString(m.result):
|
||||
needs_policy = False
|
||||
has_policy = self.info[m.name].policy is not None
|
||||
if needs_policy and not has_policy:
|
||||
warning = '---> Error: Method "%s" needs a policy.' % m.FullName()
|
||||
if warning not in self.printed_policy_warnings:
|
||||
print warning
|
||||
print
|
||||
self.printed_policy_warnings[warning] = 1
|
||||
|
||||
|
||||
def ExportMethods(self):
|
||||
'Export all the non-virtual methods of this class'
|
||||
|
||||
def OverloadName(m):
|
||||
'Returns the name of the overloads struct for the given method'
|
||||
return makeid(m.FullName()) + ('_overloads_%i_%i' % (m.minArgs, m.maxArgs))
|
||||
return _ID(m.FullName()) + ('_overloads_%i_%i' % (m.minArgs, m.maxArgs))
|
||||
|
||||
declared = {}
|
||||
def DeclareOverloads(m):
|
||||
'Declares the macro for the generation of the overloads'
|
||||
if not m.virtual:
|
||||
if m.static:
|
||||
func = m.FullName()
|
||||
macro = 'BOOST_PYTHON_FUNCTION_OVERLOADS'
|
||||
else:
|
||||
func = m.name
|
||||
macro = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS'
|
||||
code = '%s(%s, %s, %i, %i)\n' % (macro, OverloadName(m), func, m.minArgs, m.maxArgs)
|
||||
func = m.name
|
||||
code = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(%s, %s, %i, %i)\n'
|
||||
code = code % (OverloadName(m), func, m.minArgs, m.maxArgs)
|
||||
if code not in declared:
|
||||
declared[code] = True
|
||||
self.Add('declaration', code)
|
||||
@@ -306,28 +300,24 @@ class ClassExporter(Exporter):
|
||||
methods = [x for x in self.public_members if IsExportable(x)]
|
||||
|
||||
for method in methods:
|
||||
method_info = self.info[method.name]
|
||||
|
||||
# skip this method if it was excluded by the user
|
||||
if method_info.exclude:
|
||||
continue
|
||||
if self.info[method.name].exclude:
|
||||
continue # skip this method
|
||||
|
||||
# rename the method if the user requested
|
||||
name = method_info.rename or method.name
|
||||
name = self.info[method.name].rename or method.name
|
||||
|
||||
# warn the user if this method needs a policy and doesn't have one
|
||||
method_info.policy = exporterutils.HandlePolicy(method, method_info.policy)
|
||||
self.CheckPolicy(method)
|
||||
|
||||
# check for policies
|
||||
policy = method_info.policy or ''
|
||||
policy = self.info[method.name].policy or ''
|
||||
if policy:
|
||||
policy = ', %s%s()' % (namespaces.python, policy.Code())
|
||||
# check for overloads
|
||||
overload = ''
|
||||
if method.minArgs != method.maxArgs:
|
||||
# add the overloads for this method
|
||||
DeclareOverloads(method)
|
||||
overload_name = OverloadName(method)
|
||||
DeclareOverloads(method)
|
||||
overload = ', %s%s()' % (namespaces.pyste, overload_name)
|
||||
|
||||
# build the .def string to export the method
|
||||
@@ -342,7 +332,7 @@ class ClassExporter(Exporter):
|
||||
code = '.staticmethod("%s")' % name
|
||||
self.Add('inside', code)
|
||||
# add wrapper code if this method has one
|
||||
wrapper = method_info.wrapper
|
||||
wrapper = self.info[method.name].wrapper
|
||||
if wrapper and wrapper.code:
|
||||
self.Add('declaration', wrapper.code)
|
||||
|
||||
@@ -356,7 +346,7 @@ class ClassExporter(Exporter):
|
||||
break
|
||||
|
||||
if has_virtual_methods:
|
||||
generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info)
|
||||
generator = _VirtualWrapperGenerator(self.class_, self.info)
|
||||
self.Add('template', generator.FullName())
|
||||
for definition in generator.GenerateDefinitions():
|
||||
self.Add('inside', definition)
|
||||
@@ -375,16 +365,12 @@ class ClassExporter(Exporter):
|
||||
'()' : '__call__',
|
||||
}
|
||||
|
||||
# converters which have a special name in python
|
||||
# it's a map of a regular expression of the converter's result to the
|
||||
# appropriate python name
|
||||
# converters which has a special name in python
|
||||
SPECIAL_CONVERTERS = {
|
||||
re.compile(r'(const)?\s*double$') : '__float__',
|
||||
re.compile(r'(const)?\s*float$') : '__float__',
|
||||
re.compile(r'(const)?\s*int$') : '__int__',
|
||||
re.compile(r'(const)?\s*long$') : '__long__',
|
||||
re.compile(r'(const)?\s*char\s*\*?$') : '__str__',
|
||||
re.compile(r'(const)?.*::basic_string<.*>\s*(\*|\&)?$') : '__str__',
|
||||
'double' : '__float__',
|
||||
'float' : '__float__',
|
||||
'int' : '__int__',
|
||||
'long' : '__long__',
|
||||
}
|
||||
|
||||
|
||||
@@ -497,18 +483,16 @@ class ClassExporter(Exporter):
|
||||
converters = [x for x in self.public_members if type(x) == ConverterOperator]
|
||||
|
||||
def ConverterMethodName(converter):
|
||||
result_fullname = converter.result.FullName()
|
||||
result_name = converter.result.name
|
||||
for regex, method_name in self.SPECIAL_CONVERTERS.items():
|
||||
if regex.match(result_fullname):
|
||||
return method_name
|
||||
result_fullname = converter.result.name
|
||||
if result_fullname in self.SPECIAL_CONVERTERS:
|
||||
return self.SPECIAL_CONVERTERS[result_fullname]
|
||||
else:
|
||||
# extract the last name from the full name
|
||||
result_name = makeid(result_name)
|
||||
result_name = _ID(result_fullname.split('::')[-1])
|
||||
return 'to_' + result_name
|
||||
|
||||
for converter in converters:
|
||||
info = self.info['operator'][converter.result.FullName()]
|
||||
info = self.info['operator'][converter.result.name]
|
||||
# check if this operator should be excluded
|
||||
if info.exclude:
|
||||
continue
|
||||
@@ -539,7 +523,7 @@ class ClassExporter(Exporter):
|
||||
nested_info.name = nested_class.FullName()
|
||||
exporter = ClassExporter(nested_info)
|
||||
exporter.SetDeclarations(self.declarations + [nested_class])
|
||||
codeunit = SingleCodeUnit(None, None)
|
||||
codeunit = CodeUnit(None)
|
||||
exporter.Export(codeunit, exported_names)
|
||||
self.nested_codeunits.append(codeunit)
|
||||
|
||||
@@ -552,30 +536,22 @@ class ClassExporter(Exporter):
|
||||
enum_info.name = enum.FullName()
|
||||
exporter = EnumExporter(enum_info)
|
||||
exporter.SetDeclarations(self.declarations + [enum])
|
||||
codeunit = SingleCodeUnit(None, None)
|
||||
codeunit = CodeUnit(None)
|
||||
exporter.Export(codeunit, None)
|
||||
self.nested_codeunits.append(codeunit)
|
||||
|
||||
|
||||
def ExportSmartPointer(self):
|
||||
smart_ptr = self.info.smart_ptr
|
||||
if smart_ptr:
|
||||
self.Add('template', smart_ptr % self.class_.FullName())
|
||||
|
||||
|
||||
def ExportOpaquePointerPolicies(self):
|
||||
# check all methods for 'return_opaque_pointer' policies
|
||||
methods = [x for x in self.public_members if isinstance(x, Method)]
|
||||
for method in methods:
|
||||
return_opaque_policy = return_value_policy(return_opaque_pointer)
|
||||
if self.info[method.name].policy == return_opaque_policy:
|
||||
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % method.result.name
|
||||
if macro not in self._exported_opaque_pointers:
|
||||
self.Add('declaration-outside', macro)
|
||||
self._exported_opaque_pointers[macro] = 1
|
||||
|
||||
|
||||
|
||||
|
||||
def _ID(name):
|
||||
'Returns the name as a valid identifier'
|
||||
for invalidchar in ('::', '<', '>', ' ', ','):
|
||||
name = name.replace(invalidchar, '_')
|
||||
# avoid duplications of '_' chars
|
||||
names = [x for x in name.split('_') if x]
|
||||
return '_'.join(names)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Virtual Wrapper utils
|
||||
#==============================================================================
|
||||
@@ -597,13 +573,10 @@ def _ParamsInfo(m, count=None):
|
||||
class _VirtualWrapperGenerator(object):
|
||||
'Generates code to export the virtual methods of the given class'
|
||||
|
||||
def __init__(self, class_, bases, info):
|
||||
def __init__(self, class_, info):
|
||||
self.class_ = class_
|
||||
self.bases = deepcopy(bases)
|
||||
self.info = info
|
||||
self.wrapper_name = makeid(class_.FullName()) + '_Wrapper'
|
||||
self.virtual_methods = None
|
||||
self.GenerateVirtualMethods()
|
||||
self.wrapper_name = _ID(class_.FullName()) + '_Wrapper'
|
||||
|
||||
|
||||
def DefaultImplementationNames(self, method):
|
||||
@@ -648,18 +621,6 @@ class _VirtualWrapperGenerator(object):
|
||||
|
||||
# default implementations (with overloading)
|
||||
# only for classes that are not abstract, and public methods
|
||||
def DefaultImpl(method, param_names):
|
||||
'Return the body of a default implementation wrapper'
|
||||
wrapper = self.info[method.name].wrapper
|
||||
if not wrapper:
|
||||
# return the default implementation of the class
|
||||
return '%s%s::%s(%s);\n' % \
|
||||
(return_str, self.class_.FullName(), method.name, ', '.join(param_names))
|
||||
else:
|
||||
# return a call for the wrapper
|
||||
params = ', '.join(['this'] + param_names)
|
||||
return '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
|
||||
|
||||
if not method.abstract and method.visibility == Scope.public:
|
||||
minArgs = method.minArgs
|
||||
maxArgs = method.maxArgs
|
||||
@@ -668,7 +629,8 @@ class _VirtualWrapperGenerator(object):
|
||||
params, param_names, param_types = _ParamsInfo(method, argNum)
|
||||
decl += '\n'
|
||||
decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness)
|
||||
decl += indent*2 + DefaultImpl(method, param_names)
|
||||
decl += indent*2 + '%s%s::%s(%s);\n' % \
|
||||
(return_str, self.class_.FullName(), method.name, ', '.join(param_names))
|
||||
decl += indent + '}\n'
|
||||
return decl
|
||||
|
||||
@@ -683,7 +645,7 @@ class _VirtualWrapperGenerator(object):
|
||||
class_name = self.class_.FullName()
|
||||
wrapper_name = pyste + self.wrapper_name
|
||||
result = method.result.FullName()
|
||||
is_method_unique = self.IsMethodUnique(method.name)
|
||||
is_method_unique = self.class_.IsUnique(method.name)
|
||||
constantness = ''
|
||||
if method.const:
|
||||
constantness = ' const'
|
||||
@@ -699,7 +661,7 @@ class _VirtualWrapperGenerator(object):
|
||||
param_list = [x.FullName() for x in method.parameters[:argNum]]
|
||||
params = ', '.join(param_list)
|
||||
signature = '%s (%s::*)(%s)%s' % (result, wrapper_name, params, constantness)
|
||||
default_pointer = '(%s)&%s::%s' % (signature, wrapper_name, impl_name)
|
||||
default_pointer = '(%s)%s::%s' % (signature, wrapper_name, impl_name)
|
||||
default_pointers.append(default_pointer)
|
||||
|
||||
# get the pointer of the method
|
||||
@@ -721,36 +683,13 @@ class _VirtualWrapperGenerator(object):
|
||||
return namespaces.pyste + self.wrapper_name
|
||||
|
||||
|
||||
def GenerateVirtualMethods(self):
|
||||
'''To correctly export all virtual methods, we must also make wrappers
|
||||
for the virtual methods of the bases of this class, as if the methods
|
||||
were from this class itself.
|
||||
This method creates the instance variable self.virtual_methods.
|
||||
'''
|
||||
def VirtualMethods(self):
|
||||
def IsVirtual(m):
|
||||
return type(m) == Method and m.virtual
|
||||
|
||||
all_members = self.class_.members[:]
|
||||
for base in self.bases:
|
||||
for base_member in base.members:
|
||||
base_member.class_ = self.class_.FullName()
|
||||
all_members.append(base_member)
|
||||
# extract the virtual methods, avoiding duplications
|
||||
self.virtual_methods = []
|
||||
already_added = {}
|
||||
for member in all_members:
|
||||
if IsVirtual(member) and not member.FullName() in already_added:
|
||||
self.virtual_methods.append(member)
|
||||
already_added[member.FullName()] = 0
|
||||
return [m for m in self.class_.members if IsVirtual(m)]
|
||||
|
||||
|
||||
|
||||
def IsMethodUnique(self, method):
|
||||
count = {}
|
||||
for m in self.virtual_methods:
|
||||
count[m.name] = count.get(m.name, 0) + 1
|
||||
return count[m.name] == 1
|
||||
|
||||
|
||||
def Constructors(self):
|
||||
def IsValid(m):
|
||||
return isinstance(m, Constructor) and m.visibility == Scope.public
|
||||
@@ -759,7 +698,7 @@ class _VirtualWrapperGenerator(object):
|
||||
|
||||
def GenerateDefinitions(self):
|
||||
defs = []
|
||||
for method in self.virtual_methods:
|
||||
for method in self.VirtualMethods():
|
||||
exclude = self.info[method.name].exclude
|
||||
# generate definitions only for public methods and non-abstract methods
|
||||
if method.visibility == Scope.public and not method.abstract and not exclude:
|
||||
@@ -792,7 +731,7 @@ class _VirtualWrapperGenerator(object):
|
||||
code += cons_code
|
||||
# generate the body
|
||||
body = []
|
||||
for method in self.virtual_methods:
|
||||
for method in self.VirtualMethods():
|
||||
if not self.info[method.name].exclude:
|
||||
body.append(self.Declaration(method, indent))
|
||||
body = '\n'.join(body)
|
||||
|
||||
78
pyste/src/CodeUnit.py
Normal file
78
pyste/src/CodeUnit.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from settings import *
|
||||
|
||||
#==============================================================================
|
||||
# RemoveDuplicatedLines
|
||||
#==============================================================================
|
||||
def RemoveDuplicatedLines(text):
|
||||
includes = text.splitlines()
|
||||
d = dict([(include, 0) for include in includes])
|
||||
return '\n'.join(d.keys())
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# CodeUnit
|
||||
#==============================================================================
|
||||
class CodeUnit:
|
||||
'''
|
||||
Represents a cpp file, where other objects can write in one of the
|
||||
predefined sections.
|
||||
The avaiable sections are:
|
||||
include - The include area of the cpp file
|
||||
declaration - The part before the module definition
|
||||
module - Inside the BOOST_PYTHON_MODULE macro
|
||||
'''
|
||||
|
||||
USING_BOOST_NS = True
|
||||
|
||||
def __init__(self, modulename):
|
||||
self.modulename = modulename
|
||||
# define the avaiable sections
|
||||
self.code = {}
|
||||
self.code['include'] = ''
|
||||
self.code['declaration'] = ''
|
||||
self.code['module'] = ''
|
||||
|
||||
|
||||
def Write(self, section, code):
|
||||
'write the given code in the section of the code unit'
|
||||
if section not in self.code:
|
||||
raise RuntimeError, 'Invalid CodeUnit section: %s' % section
|
||||
self.code[section] += code
|
||||
|
||||
|
||||
def Section(self, section):
|
||||
return self.code[section]
|
||||
|
||||
|
||||
def Save(self, filename):
|
||||
'Writes this code unit to the filename'
|
||||
space = '\n\n'
|
||||
fout = file(filename, 'w')
|
||||
# includes
|
||||
includes = RemoveDuplicatedLines(self.code['include'])
|
||||
fout.write('\n' + self._leftEquals('Includes'))
|
||||
fout.write('#include <boost/python.hpp>\n')
|
||||
fout.write(includes)
|
||||
fout.write(space)
|
||||
# using
|
||||
if self.USING_BOOST_NS:
|
||||
fout.write(self._leftEquals('Using'))
|
||||
fout.write('using namespace boost::python;\n\n')
|
||||
# declarations
|
||||
if self.code['declaration']:
|
||||
pyste_namespace = namespaces.pyste[:-2]
|
||||
fout.write(self._leftEquals('Declarations'))
|
||||
fout.write('namespace %s {\n\n\n' % pyste_namespace)
|
||||
fout.write(self.code['declaration'])
|
||||
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
|
||||
fout.write(space)
|
||||
# module
|
||||
fout.write(self._leftEquals('Module'))
|
||||
fout.write('BOOST_PYTHON_MODULE(%s)\n{\n' % self.modulename)
|
||||
fout.write(self.code['module'])
|
||||
fout.write('}\n')
|
||||
|
||||
|
||||
def _leftEquals(self, s):
|
||||
s = '// %s ' % s
|
||||
return s + ('='*(80-len(s))) + '\n'
|
||||
@@ -19,8 +19,6 @@ class CppParser:
|
||||
defines = []
|
||||
self.includes = includes
|
||||
self.defines = defines
|
||||
self._cache = []
|
||||
self._CACHE_SIZE = 5
|
||||
|
||||
|
||||
def _includeparams(self, filename):
|
||||
@@ -38,19 +36,6 @@ class CppParser:
|
||||
return ' '.join(defines)
|
||||
|
||||
|
||||
def UpdateCache(self, include, tail, declarations, header):
|
||||
self._cache.append((include, tail, declarations, header))
|
||||
if len(self._cache) > self._CACHE_SIZE:
|
||||
self._cache.pop(0)
|
||||
|
||||
|
||||
def Cache(self, include, tail):
|
||||
for cache_include, cache_tail, declarations, header in self._cache:
|
||||
if cache_include == include and cache_tail == tail:
|
||||
return declarations, header
|
||||
return None
|
||||
|
||||
|
||||
def FindFileName(self, include):
|
||||
if os.path.isfile(include):
|
||||
return include
|
||||
@@ -62,17 +47,13 @@ class CppParser:
|
||||
raise RuntimeError, 'Header file "%s" not found!' % name
|
||||
|
||||
|
||||
def parse(self, include, tail=None):
|
||||
def parse(self, include, symbols=None, tail=None):
|
||||
'''Parses the given filename, and returns (declaration, header). The
|
||||
header returned is normally the same as the given to this method,
|
||||
except if tail is not None: in this case, the header is copied to a temp
|
||||
filename and the tail code is appended to it before being passed on to gcc.
|
||||
This temp filename is then returned.
|
||||
'''
|
||||
# check if this header was already parsed
|
||||
cached = self.Cache(include, tail)
|
||||
if cached:
|
||||
return cached
|
||||
filename = self.FindFileName(include)
|
||||
# copy file to temp folder, if needed
|
||||
if tail:
|
||||
@@ -92,14 +73,14 @@ class CppParser:
|
||||
# call gccxml
|
||||
cmd = 'gccxml %s %s %s -fxml=%s' \
|
||||
% (includes, defines, infilename, xmlfile)
|
||||
if symbols:
|
||||
cmd += ' -fxml-start=' + ','.join(symbols)
|
||||
status = os.system(cmd)
|
||||
if status != 0 or not os.path.isfile(xmlfile):
|
||||
raise CppParserError, 'Error executing gccxml'
|
||||
# parse the resulting xml
|
||||
declarations = ParseDeclarations(xmlfile)
|
||||
# cache the results
|
||||
self.UpdateCache(include, tail, declarations, infilename)
|
||||
# return the declarations
|
||||
# return the declarations
|
||||
return declarations, infilename
|
||||
finally:
|
||||
if settings.DEBUG and os.path.isfile(xmlfile):
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from Exporter import Exporter
|
||||
from settings import *
|
||||
import utils
|
||||
|
||||
#==============================================================================
|
||||
# EnumExporter
|
||||
@@ -29,11 +28,3 @@ class EnumExporter(Exporter):
|
||||
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
|
||||
code += indent + ';\n\n'
|
||||
codeunit.Write('module', code)
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return utils.makeid(self.info.include)
|
||||
|
||||
|
||||
def Order(self):
|
||||
return self.info.name
|
||||
|
||||
@@ -12,10 +12,6 @@ class Exporter:
|
||||
self.info = info
|
||||
self.parser_tail = parser_tail
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def Parse(self, parser):
|
||||
self.parser = parser
|
||||
@@ -44,8 +40,11 @@ class Exporter:
|
||||
pass
|
||||
|
||||
|
||||
def Unit(self):
|
||||
raise NotImplementedError
|
||||
def Name(self):
|
||||
'''Returns the name of this Exporter. The name will be added to the
|
||||
list of names exported, which may have a use for other exporters.
|
||||
'''
|
||||
return None
|
||||
|
||||
|
||||
def GetDeclarations(self, fullname):
|
||||
@@ -62,11 +61,9 @@ class Exporter:
|
||||
|
||||
|
||||
def Order(self):
|
||||
'''Returns a string that uniquely identifies this instance. All
|
||||
exporters will be sorted by Order before being exported.
|
||||
'''Returns a number that indicates to which order this exporter
|
||||
belongs. The exporters will be called from the lowest order to the
|
||||
highest order.
|
||||
This function will only be called after Parse has been called.
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return self.info.include
|
||||
return None # don't care
|
||||
|
||||
@@ -2,31 +2,38 @@ from Exporter import Exporter
|
||||
from policies import *
|
||||
from declarations import *
|
||||
from settings import *
|
||||
import utils
|
||||
import exporterutils
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# FunctionExporter
|
||||
#==============================================================================
|
||||
class FunctionExporter(Exporter):
|
||||
'Generates boost.python code to export the given function.'
|
||||
|
||||
def __init__(self, info, tail=None):
|
||||
Exporter.__init__(self, info, tail)
|
||||
self._exported_opaque_pointers = {}
|
||||
|
||||
|
||||
def Export(self, codeunit, exported_names):
|
||||
decls = self.GetDeclarations(self.info.name)
|
||||
for decl in decls:
|
||||
self.info.policy = exporterutils.HandlePolicy(decl, self.info.policy)
|
||||
exporterutils.WarnForwardDeclarations(decl)
|
||||
self.CheckPolicy(decl)
|
||||
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
|
||||
self.ExportOpaquePointer(decl, codeunit)
|
||||
self.GenerateOverloads(decls, codeunit)
|
||||
self.GenerateOverloads(decls, codeunit)
|
||||
|
||||
|
||||
def Name(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def CheckPolicy(self, func):
|
||||
'Warns the user if this function needs a policy'
|
||||
def IsString(type):
|
||||
return type.const and type.name == 'char' and isinstance(type, PointerType)
|
||||
needs_policy = isinstance(func.result, (ReferenceType, PointerType))
|
||||
if IsString(func.result):
|
||||
needs_policy = False
|
||||
if needs_policy and self.info.policy is None:
|
||||
print '---> Error: Function "%s" needs a policy.' % func.FullName()
|
||||
print
|
||||
|
||||
def ExportDeclaration(self, decl, unique, codeunit):
|
||||
name = self.info.rename or decl.name
|
||||
defs = namespaces.python + 'def("%s", ' % name
|
||||
@@ -76,19 +83,3 @@ class FunctionExporter(Exporter):
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def ExportOpaquePointer(self, function, codeunit):
|
||||
if self.info.policy == return_value_policy(return_opaque_pointer):
|
||||
type = function.result.name
|
||||
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % type
|
||||
if macro not in self._exported_opaque_pointers:
|
||||
codeunit.Write('declaration-outside', macro)
|
||||
self._exported_opaque_pointers[macro] = 1
|
||||
|
||||
|
||||
def Order(self):
|
||||
return self.info.name
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return utils.makeid(self.info.include)
|
||||
|
||||
@@ -105,7 +105,6 @@ class GCCXMLParser(object):
|
||||
else:
|
||||
res = Type(decl.FullName(), const)
|
||||
res.volatile = volatile
|
||||
res.incomplete = decl.incomplete
|
||||
return res
|
||||
|
||||
|
||||
@@ -222,7 +221,6 @@ class GCCXMLParser(object):
|
||||
bases = self.GetBases(element.get('bases'))
|
||||
location = self.GetLocation(element.get('location'))
|
||||
context = self.GetDecl(element.get('context'))
|
||||
incomplete = bool(element.get('incomplete', False))
|
||||
if isinstance(context, str):
|
||||
class_ = Class(name, context, [], abstract, bases)
|
||||
self.AddDecl(class_)
|
||||
@@ -234,7 +232,6 @@ class GCCXMLParser(object):
|
||||
# we have to add the declaration of the class before trying
|
||||
# to parse its members, to avoid recursion.
|
||||
class_.location = location
|
||||
class_.incomplete = incomplete
|
||||
self.Update(id, class_)
|
||||
# now we can get the members
|
||||
class_.members = self.GetMembers(element.get('members'))
|
||||
@@ -261,14 +258,14 @@ class GCCXMLParser(object):
|
||||
def ParseReferenceType(self, id, element):
|
||||
type_ = self.GetType(element.get('type'))
|
||||
expand = not isinstance(type_, FunctionType)
|
||||
ref = ReferenceType(type_.name, type_.const, None, type_.incomplete, expand)
|
||||
ref = ReferenceType(type_.name, type_.const, None, expand)
|
||||
self.Update(id, ref)
|
||||
|
||||
|
||||
def ParsePointerType(self, id, element):
|
||||
type_ = self.GetType(element.get('type'))
|
||||
expand = not isinstance(type_, FunctionType)
|
||||
ref = PointerType(type_.name, type_.const, None, type_.incomplete, expand)
|
||||
ref = PointerType(type_.name, type_.const, None, expand)
|
||||
self.Update(id, ref)
|
||||
|
||||
|
||||
|
||||
@@ -63,12 +63,5 @@ class HeaderExporter(Exporter):
|
||||
exporter.SetDeclarations(self.declarations)
|
||||
exporters.exporters.append(exporter)
|
||||
|
||||
|
||||
def Unit(self):
|
||||
return None # doesn't write anything by himself
|
||||
|
||||
|
||||
def Order(self):
|
||||
return self.info.include
|
||||
|
||||
|
||||
|
||||
@@ -17,8 +17,3 @@ class IncludeExporter(Exporter):
|
||||
def Parse(self, parser):
|
||||
pass
|
||||
|
||||
def Order(self):
|
||||
return self.info.include
|
||||
|
||||
def Unit(self):
|
||||
return '__all__' # include it in all generated cpps (multiple mode)
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
from SingleCodeUnit import SingleCodeUnit
|
||||
import os
|
||||
import utils
|
||||
from SmartFile import SmartFile
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# MultipleCodeUnit
|
||||
#==============================================================================
|
||||
class MultipleCodeUnit(object):
|
||||
'''
|
||||
Represents a bunch of cpp files, where each cpp file represents a header
|
||||
to be exported by pyste. Another cpp, named <module>.cpp is created too.
|
||||
'''
|
||||
|
||||
def __init__(self, modulename, outdir):
|
||||
self.modulename = modulename
|
||||
self.outdir = outdir
|
||||
self.codeunits = {} # maps from a header to a SingleCodeUnit
|
||||
self.functions = []
|
||||
self._current = None
|
||||
|
||||
|
||||
def _FunctionName(self, code_unit_name):
|
||||
return '_Export_%s' % utils.makeid(code_unit_name)
|
||||
|
||||
|
||||
def _FileName(self, code_unit_name):
|
||||
filename = os.path.basename(code_unit_name)
|
||||
filename = '_%s.cpp' % os.path.splitext(filename)[0]
|
||||
return os.path.join(self.outdir, filename)
|
||||
|
||||
|
||||
def SetCurrent(self, code_unit_name):
|
||||
'Changes the current code unit'
|
||||
try:
|
||||
if code_unit_name is not None:
|
||||
codeunit = self.codeunits[code_unit_name]
|
||||
else:
|
||||
codeunit = None
|
||||
except KeyError:
|
||||
filename = self._FileName(code_unit_name)
|
||||
function_name = self._FunctionName(code_unit_name)
|
||||
codeunit = SingleCodeUnit(None, filename)
|
||||
codeunit.module_definition = 'void %s()' % function_name
|
||||
self.codeunits[code_unit_name] = codeunit
|
||||
if code_unit_name != '__all__':
|
||||
self.functions.append(function_name)
|
||||
self._current = codeunit
|
||||
|
||||
|
||||
def Current(self):
|
||||
return self._current
|
||||
|
||||
current = property(Current, SetCurrent)
|
||||
|
||||
|
||||
def Write(self, section, code):
|
||||
if self._current is not None:
|
||||
self.current.Write(section, code)
|
||||
|
||||
|
||||
def Section(self, section):
|
||||
if self._current is not None:
|
||||
return self.current.Section(section)
|
||||
|
||||
|
||||
def _CreateOutputDir(self):
|
||||
try:
|
||||
os.mkdir(self.outdir)
|
||||
except OSError: pass # already created
|
||||
|
||||
|
||||
def Save(self):
|
||||
# create the directory where all the files will go
|
||||
self._CreateOutputDir();
|
||||
# write all the codeunits, merging first the contents of
|
||||
# the special code unit named __all__
|
||||
__all__ = self.codeunits.get('__all__')
|
||||
for name, codeunit in self.codeunits.items():
|
||||
if name != '__all__':
|
||||
if __all__:
|
||||
codeunit.Merge(__all__)
|
||||
codeunit.Save()
|
||||
# generate the main cpp
|
||||
filename = os.path.join(self.outdir, self.modulename + '.cpp')
|
||||
fout = SmartFile(filename, 'w')
|
||||
fout.write(utils.left_equals('Include'))
|
||||
fout.write('#include <boost/python.hpp>\n\n')
|
||||
fout.write(utils.left_equals('Exports'))
|
||||
for function in self.functions:
|
||||
fout.write('void %s();\n' % function)
|
||||
fout.write('\n')
|
||||
fout.write(utils.left_equals('Module'))
|
||||
fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename)
|
||||
fout.write('{\n')
|
||||
indent = ' ' * 4
|
||||
for function in self.functions:
|
||||
fout.write(indent)
|
||||
fout.write('%s();\n' % function)
|
||||
fout.write('}\n')
|
||||
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
from settings import namespaces
|
||||
import settings
|
||||
from utils import remove_duplicated_lines, left_equals
|
||||
from SmartFile import SmartFile
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# SingleCodeUnit
|
||||
#==============================================================================
|
||||
class SingleCodeUnit:
|
||||
'''
|
||||
Represents a cpp file, where other objects can write in one of the
|
||||
predefined sections.
|
||||
The avaiable sections are:
|
||||
include - The include area of the cpp file
|
||||
declaration - The part before the module definition
|
||||
module - Inside the BOOST_PYTHON_MODULE macro
|
||||
'''
|
||||
|
||||
def __init__(self, modulename, filename):
|
||||
self.modulename = modulename
|
||||
self.filename = filename
|
||||
# define the avaiable sections
|
||||
self.code = {}
|
||||
# include section
|
||||
self.code['include'] = ''
|
||||
# declaration section (inside namespace)
|
||||
self.code['declaration'] = ''
|
||||
# declaration (outside namespace)
|
||||
self.code['declaration-outside'] = ''
|
||||
# inside BOOST_PYTHON_MACRO
|
||||
self.code['module'] = ''
|
||||
# create the default module definition
|
||||
self.module_definition = 'BOOST_PYTHON_MODULE(%s)' % modulename
|
||||
|
||||
|
||||
def Write(self, section, code):
|
||||
'write the given code in the section of the code unit'
|
||||
if section not in self.code:
|
||||
raise RuntimeError, 'Invalid CodeUnit section: %s' % section
|
||||
self.code[section] += code
|
||||
|
||||
|
||||
def Merge(self, other):
|
||||
for section in ('include', 'declaration', 'declaration-outside', 'module'):
|
||||
self.code[section] = self.code[section] + other.code[section]
|
||||
|
||||
|
||||
def Section(self, section):
|
||||
return self.code[section]
|
||||
|
||||
|
||||
def Save(self):
|
||||
'Writes this code unit to the filename'
|
||||
space = '\n\n'
|
||||
fout = SmartFile(self.filename, 'w')
|
||||
# includes
|
||||
includes = remove_duplicated_lines(self.code['include'])
|
||||
fout.write('\n' + left_equals('Includes'))
|
||||
fout.write('#include <boost/python.hpp>\n')
|
||||
fout.write(includes)
|
||||
fout.write(space)
|
||||
# using
|
||||
if settings.USING_BOOST_NS:
|
||||
fout.write(left_equals('Using'))
|
||||
fout.write('using namespace boost::python;\n\n')
|
||||
# declarations
|
||||
declaration = self.code['declaration']
|
||||
declaration_outside = self.code['declaration-outside']
|
||||
if declaration_outside or declaration:
|
||||
fout.write(left_equals('Declarations'))
|
||||
fout.write(declaration_outside + '\n\n')
|
||||
if declaration:
|
||||
pyste_namespace = namespaces.pyste[:-2]
|
||||
fout.write('namespace %s {\n\n\n' % pyste_namespace)
|
||||
fout.write(declaration)
|
||||
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
|
||||
fout.write(space)
|
||||
# module
|
||||
fout.write(left_equals('Module'))
|
||||
fout.write(self.module_definition + '\n')
|
||||
fout.write('{\n')
|
||||
fout.write(self.code['module'])
|
||||
fout.write('}\n')
|
||||
@@ -1,55 +0,0 @@
|
||||
import os
|
||||
import md5
|
||||
|
||||
#==============================================================================
|
||||
# SmartFile
|
||||
#==============================================================================
|
||||
class SmartFile(object):
|
||||
'''
|
||||
A file-like object used for writing files. The given file will only be
|
||||
actually written to disk if there's not a file with the same name, or if
|
||||
the existing file is *different* from the file to be written.
|
||||
'''
|
||||
|
||||
def __init__(self, filename, mode='w'):
|
||||
self.filename = filename
|
||||
self.mode = mode
|
||||
self._contents = []
|
||||
self._closed = False
|
||||
|
||||
|
||||
def __del__(self):
|
||||
if not self._closed:
|
||||
self.close()
|
||||
|
||||
|
||||
def write(self, string):
|
||||
self._contents.append(string)
|
||||
|
||||
|
||||
def _dowrite(self, contents):
|
||||
f = file(self.filename, self.mode)
|
||||
f.write(contents)
|
||||
f.close()
|
||||
|
||||
|
||||
def _GetMD5(self, string):
|
||||
return md5.new(string).digest()
|
||||
|
||||
|
||||
def close(self):
|
||||
# if the filename doesn't exist, write the file right away
|
||||
this_contents = ''.join(self._contents)
|
||||
if not os.path.isfile(self.filename):
|
||||
self._dowrite(this_contents)
|
||||
else:
|
||||
# read the contents of the file already in disk
|
||||
f = file(self.filename)
|
||||
other_contents = f.read()
|
||||
f.close()
|
||||
# test the md5 for both files
|
||||
this_md5 = self._GetMD5(this_contents)
|
||||
other_md5 = self._GetMD5(other_contents)
|
||||
if this_md5 != other_md5:
|
||||
self._dowrite(this_contents)
|
||||
self._closed = True
|
||||
@@ -15,9 +15,6 @@ class Declaration(object):
|
||||
self.namespace = namespace
|
||||
# tuple (filename, line)
|
||||
self.location = '', -1
|
||||
# if a declaration is incomplete it means that it was
|
||||
# forward declared
|
||||
self.incomplete = False
|
||||
|
||||
|
||||
def FullName(self):
|
||||
@@ -209,18 +206,13 @@ class Method(Function):
|
||||
|
||||
def PointerDeclaration(self):
|
||||
'returns a declaration of a pointer to this function'
|
||||
if self.static:
|
||||
# static methods are like normal functions
|
||||
return Function.PointerDeclaration(self)
|
||||
else:
|
||||
# using syntax of methods
|
||||
result = self.result.FullName()
|
||||
params = ', '.join([x.FullName() for x in self.parameters])
|
||||
const = ''
|
||||
if self.const:
|
||||
const = 'const'
|
||||
return '(%s (%s::*)(%s) %s)&%s' %\
|
||||
(result, self.class_, params, const, self.FullName())
|
||||
result = self.result.FullName()
|
||||
params = ', '.join([x.FullName() for x in self.parameters])
|
||||
const = ''
|
||||
if self.const:
|
||||
const = 'const'
|
||||
return '(%s (%s::*)(%s) %s)&%s' %\
|
||||
(result, self.class_, params, const, self.FullName())
|
||||
|
||||
|
||||
class Constructor(Method):
|
||||
@@ -266,21 +258,20 @@ class ConverterOperator(ClassOperator):
|
||||
'An operator in the form "operator OtherClass()".'
|
||||
|
||||
def FullName(self):
|
||||
return self.class_ + '::operator ' + self.result.FullName()
|
||||
return self.class_ + '::operator ' + self.result.name
|
||||
|
||||
|
||||
|
||||
class Type(Declaration):
|
||||
'Represents a type.'
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False):
|
||||
def __init__(self, name, const=False, default=None):
|
||||
Declaration.__init__(self, name, None)
|
||||
# whatever the type is constant or not
|
||||
self.const = const
|
||||
# used when the Type is a function argument
|
||||
self.default = default
|
||||
self.volatile = False
|
||||
self.incomplete = incomplete
|
||||
|
||||
def __repr__(self):
|
||||
if self.const:
|
||||
@@ -313,8 +304,8 @@ class ArrayType(Type):
|
||||
class ReferenceType(Type):
|
||||
'A reference type.'
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False, expandRef=True):
|
||||
Type.__init__(self, name, const, default, incomplete)
|
||||
def __init__(self, name, const=False, default=None, expandRef=True):
|
||||
Type.__init__(self, name, const, default)
|
||||
self.expand = expandRef
|
||||
|
||||
|
||||
@@ -330,8 +321,8 @@ class ReferenceType(Type):
|
||||
class PointerType(Type):
|
||||
'A pointer type.'
|
||||
|
||||
def __init__(self, name, const=False, default=None, incomplete=False, expandPointer=False):
|
||||
Type.__init__(self, name, const, default, incomplete)
|
||||
def __init__(self, name, const=False, default=None, expandPointer=False):
|
||||
Type.__init__(self, name, const, default)
|
||||
self.expand = expandPointer
|
||||
|
||||
|
||||
|
||||
7
pyste/src/enumerate.py
Normal file
7
pyste/src/enumerate.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from __future__ import generators
|
||||
|
||||
def enumerate(seq):
|
||||
i = 0
|
||||
for x in seq:
|
||||
yield i, x
|
||||
i += 1
|
||||
@@ -3,8 +3,6 @@ Various helpers for interface files.
|
||||
'''
|
||||
|
||||
from settings import *
|
||||
from policies import *
|
||||
from declarations import *
|
||||
|
||||
#==============================================================================
|
||||
# FunctionWrapper
|
||||
@@ -26,66 +24,3 @@ class FunctionWrapper(object):
|
||||
return namespaces.pyste + self.name
|
||||
else:
|
||||
return self.name
|
||||
|
||||
|
||||
_printed_warnings = {} # used to avoid double-prints of warnings
|
||||
|
||||
#==============================================================================
|
||||
# HandlePolicy
|
||||
#==============================================================================
|
||||
def HandlePolicy(function, policy):
|
||||
'''Show a warning to the user if the function needs a policy and doesn't
|
||||
have one. Return a policy to the function, which is the given policy itself
|
||||
if it is not None, or a default policy for this method.
|
||||
'''
|
||||
|
||||
def IsString(type):
|
||||
'Return True if the Type instance can be considered a string'
|
||||
return type.const and type.name == 'char' and isinstance(type, PointerType)
|
||||
|
||||
def IsPyObject(type):
|
||||
return type.FullName() == '_object *' # internal name of PyObject
|
||||
|
||||
result = function.result
|
||||
# basic test if the result type demands a policy
|
||||
needs_policy = isinstance(result, (ReferenceType, PointerType))
|
||||
# if the function returns const char*, a policy is not needed
|
||||
if IsString(result) or IsPyObject(result):
|
||||
needs_policy = False
|
||||
# if returns a const T&, set the default policy
|
||||
if policy is None and result.const and isinstance(result, ReferenceType):
|
||||
policy = return_value_policy(copy_const_reference)
|
||||
# show a warning to the user, if needed
|
||||
if needs_policy and policy is None:
|
||||
global _printed_warnings
|
||||
warning = '---> Error: %s returns a pointer or a reference, ' \
|
||||
'but no policy was specified.' % function.FullName()
|
||||
if warning not in _printed_warnings:
|
||||
print warning
|
||||
print
|
||||
# avoid double prints of the same warning
|
||||
_printed_warnings[warning] = 1
|
||||
return policy
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# WarnForwardDeclarations
|
||||
#==============================================================================
|
||||
def WarnForwardDeclarations(function):
|
||||
'''Checks if any of the parameters or the result of the function are
|
||||
incomplete types.'''
|
||||
|
||||
types = [function.result] + function.parameters
|
||||
types = [x for x in types if x]
|
||||
for type in types:
|
||||
if type.incomplete:
|
||||
msg = '---> Error: %s is forward declared. Please include the ' \
|
||||
'appropriate header with its definition' % type.name
|
||||
# disable this for now... it was reporting too many false
|
||||
# forward declarations to be useful
|
||||
if 0 and msg not in _printed_warnings:
|
||||
print msg
|
||||
print
|
||||
_printed_warnings[msg] = 1
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ from IncludeExporter import IncludeExporter
|
||||
from EnumExporter import EnumExporter
|
||||
from HeaderExporter import HeaderExporter
|
||||
from exporterutils import FunctionWrapper
|
||||
from utils import makeid
|
||||
|
||||
|
||||
#==============================================================================
|
||||
@@ -91,7 +90,7 @@ class IncludeInfo(DeclarationInfo):
|
||||
def GenerateName(name, type_list):
|
||||
name = name.replace('::', '_')
|
||||
names = [name] + type_list
|
||||
return makeid('_'.join(names))
|
||||
return '_'.join(names)
|
||||
|
||||
|
||||
class ClassTemplateInfo(DeclarationInfo):
|
||||
@@ -185,11 +184,4 @@ def instantiate(template, types, rename=None):
|
||||
if isinstance(types, str):
|
||||
types = types.split()
|
||||
return template.Instantiate(types, rename)
|
||||
|
||||
def use_shared_ptr(option):
|
||||
option._Attribute('smart_ptr', 'boost::shared_ptr< %s >')
|
||||
|
||||
def use_auto_ptr(option):
|
||||
option._Attribute('smart_ptr', 'std::auto_ptr< %s >')
|
||||
|
||||
|
||||
|
||||
@@ -19,13 +19,6 @@ class Policy:
|
||||
return ' >'
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.Code() == other.Code()
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
class return_internal_reference(Policy):
|
||||
'Ties the return value to one of the parameters.'
|
||||
@@ -80,4 +73,3 @@ reference_existing_object = 'reference_existing_object'
|
||||
copy_const_reference = 'copy_const_reference'
|
||||
copy_non_const_reference = 'copy_non_const_reference'
|
||||
manage_new_object = 'manage_new_object'
|
||||
return_opaque_pointer = 'return_opaque_pointer'
|
||||
|
||||
@@ -1,52 +1,33 @@
|
||||
'''
|
||||
Pyste version %s
|
||||
|
||||
Usage:
|
||||
pyste [options] --module=<name> interface-files
|
||||
|
||||
where options are:
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--multiple create various cpps, instead of only one
|
||||
(useful during development)
|
||||
--out specify output filename (default: <module>.cpp)
|
||||
in --multiple mode, this will be a directory
|
||||
-I <path> add an include path
|
||||
-D <symbol> define symbol
|
||||
--no-using do not declare "using namespace boost";
|
||||
use explicit declarations instead
|
||||
--pyste-ns=<name> set the namespace where new types will be declared;
|
||||
default is the empty namespace
|
||||
--debug writes the xml for each file parsed in the current
|
||||
directory
|
||||
-h, --help print this help and exit
|
||||
-v, --version print version information
|
||||
default is "pyste"
|
||||
'''
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import exporters
|
||||
import SingleCodeUnit
|
||||
import MultipleCodeUnit
|
||||
import CodeUnit
|
||||
import infos
|
||||
import exporterutils
|
||||
import settings
|
||||
from policies import *
|
||||
from CppParser import CppParser, CppParserError
|
||||
import time
|
||||
from Exporter import Exporter
|
||||
from FunctionExporter import FunctionExporter
|
||||
from ClassExporter import ClassExporter
|
||||
from IncludeExporter import IncludeExporter
|
||||
from HeaderExporter import HeaderExporter
|
||||
|
||||
__VERSION__ = '0.7.3'
|
||||
|
||||
def RecursiveIncludes(include):
|
||||
'Return a list containg the include dir and all its subdirectories'
|
||||
dirs = [include]
|
||||
def visit(arg, dir, names):
|
||||
# ignore CVS dirs
|
||||
if os.path.split(dir)[1] != 'CVS':
|
||||
dirs.append(dir)
|
||||
os.path.walk(include, visit, None)
|
||||
return dirs
|
||||
|
||||
|
||||
def GetDefaultIncludes():
|
||||
if 'INCLUDE' in os.environ:
|
||||
include = os.environ['INCLUDE']
|
||||
@@ -58,59 +39,39 @@ def GetDefaultIncludes():
|
||||
def ParseArguments():
|
||||
|
||||
def Usage():
|
||||
print __doc__ % __VERSION__
|
||||
print __doc__
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
options, files = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
'R:I:D:vh',
|
||||
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'version', 'help'])
|
||||
except getopt.GetoptError, e:
|
||||
print
|
||||
print 'ERROR:', e
|
||||
Usage()
|
||||
options, files = getopt.getopt(sys.argv[1:], 'I:D:', ['module=', 'out=', 'no-using', 'pyste-ns=', 'debug'])
|
||||
includes = GetDefaultIncludes()
|
||||
defines = []
|
||||
module = None
|
||||
out = None
|
||||
multiple = False
|
||||
for opt, value in options:
|
||||
if opt == '-I':
|
||||
includes.append(value)
|
||||
elif opt == '-D':
|
||||
defines.append(value)
|
||||
elif opt == '-R':
|
||||
includes.extend(RecursiveIncludes(value))
|
||||
elif opt == '--module':
|
||||
module = value
|
||||
elif opt == '--out':
|
||||
out = value
|
||||
elif opt == '--no-using':
|
||||
settings.namespaces.python = 'boost::python::'
|
||||
settings.USING_BOOST_NS = False
|
||||
CodeUnit.CodeUnit.USING_BOOST_NS = False
|
||||
elif opt == '--pyste-ns':
|
||||
settings.namespaces.pyste = value + '::'
|
||||
elif opt == '--debug':
|
||||
settings.DEBUG = True
|
||||
elif opt == '--multiple':
|
||||
multiple = True
|
||||
elif opt in ['-h', '--help']:
|
||||
Usage()
|
||||
elif opt in ['-v', '--version']:
|
||||
print 'Pyste version %s' % __VERSION__
|
||||
sys.exit(2)
|
||||
else:
|
||||
print 'Unknown option:', opt
|
||||
Usage()
|
||||
|
||||
if not files or not module:
|
||||
Usage()
|
||||
Usage()
|
||||
if not out:
|
||||
out = module
|
||||
if not multiple:
|
||||
out += '.cpp'
|
||||
return includes, defines, module, out, files, multiple
|
||||
out = module + '.cpp'
|
||||
return includes, defines, module, out, files
|
||||
|
||||
|
||||
def CreateContext():
|
||||
@@ -128,8 +89,6 @@ def CreateContext():
|
||||
context['set_policy'] = infos.set_policy
|
||||
context['exclude'] = infos.exclude
|
||||
context['set_wrapper'] = infos.set_wrapper
|
||||
context['use_shared_ptr'] = infos.use_shared_ptr
|
||||
context['use_auto_ptr'] = infos.use_auto_ptr
|
||||
# policies
|
||||
context['return_internal_reference'] = return_internal_reference
|
||||
context['with_custodian_and_ward'] = with_custodian_and_ward
|
||||
@@ -137,7 +96,6 @@ def CreateContext():
|
||||
context['reference_existing_object'] = reference_existing_object
|
||||
context['copy_const_reference'] = copy_const_reference
|
||||
context['copy_non_const_reference'] = copy_non_const_reference
|
||||
context['return_opaque_pointer'] = return_opaque_pointer
|
||||
context['manage_new_object'] = manage_new_object
|
||||
# utils
|
||||
context['Wrapper'] = exporterutils.FunctionWrapper
|
||||
@@ -145,7 +103,7 @@ def CreateContext():
|
||||
|
||||
|
||||
def Main():
|
||||
includes, defines, module, out, interfaces, multiple = ParseArguments()
|
||||
includes, defines, module, out, interfaces = ParseArguments()
|
||||
# execute the interface files
|
||||
for interface in interfaces:
|
||||
context = CreateContext()
|
||||
@@ -166,32 +124,31 @@ def Main():
|
||||
exports.sort()
|
||||
exports = [x for _, x in exports]
|
||||
# now generate the wrapper code
|
||||
if multiple:
|
||||
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
|
||||
else:
|
||||
codeunit = SingleCodeUnit.SingleCodeUnit(module, out)
|
||||
codeunit = CodeUnit.CodeUnit(module)
|
||||
exported_names = []
|
||||
for export in exports:
|
||||
if multiple:
|
||||
codeunit.SetCurrent(export.Unit())
|
||||
export.GenerateCode(codeunit, exported_names)
|
||||
exported_names.append(export.Name())
|
||||
codeunit.Save()
|
||||
codeunit.Save(out)
|
||||
print 'Module %s generated' % module
|
||||
return 0
|
||||
|
||||
|
||||
def UsePsyco():
|
||||
'Tries to use psyco if possible'
|
||||
'Tries to use psyco if it is installed'
|
||||
try:
|
||||
import psyco
|
||||
psyco.profile()
|
||||
except: pass
|
||||
import elementtree.XMLTreeBuilder as XMLTreeBuilder
|
||||
import GCCXMLParser
|
||||
|
||||
psyco.bind(XMLTreeBuilder.fixtext)
|
||||
psyco.bind(XMLTreeBuilder.fixname)
|
||||
psyco.bind(XMLTreeBuilder.TreeBuilder)
|
||||
psyco.bind(GCCXMLParser.GCCXMLParser)
|
||||
except ImportError: pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
start = time.clock()
|
||||
UsePsyco()
|
||||
status = Main()
|
||||
print '%0.2f seconds' % (time.clock()-start)
|
||||
sys.exit(status)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#==============================================================================
|
||||
|
||||
DEBUG = False
|
||||
USING_BOOST_NS = True
|
||||
|
||||
class namespaces:
|
||||
boost = 'boost::'
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
from __future__ import generators
|
||||
import string
|
||||
|
||||
#==============================================================================
|
||||
# enumerate
|
||||
#==============================================================================
|
||||
def enumerate(seq):
|
||||
i = 0
|
||||
for x in seq:
|
||||
yield i, x
|
||||
i += 1
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# makeid
|
||||
#==============================================================================
|
||||
_valid_chars = string.ascii_letters + string.digits + '_'
|
||||
_valid_chars = dict(zip(_valid_chars, _valid_chars))
|
||||
|
||||
def makeid(name):
|
||||
'Returns the name as a valid identifier'
|
||||
newname = []
|
||||
for char in name:
|
||||
if char not in _valid_chars:
|
||||
char = '_'
|
||||
newname.append(char)
|
||||
newname = ''.join(newname)
|
||||
# avoid duplications of '_' chars
|
||||
names = [x for x in newname.split('_') if x]
|
||||
return '_'.join(names)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# remove_duplicated_lines
|
||||
#==============================================================================
|
||||
def remove_duplicated_lines(text):
|
||||
includes = text.splitlines()
|
||||
d = dict([(include, 0) for include in includes])
|
||||
return '\n'.join(d.keys())
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# left_equals
|
||||
#==============================================================================
|
||||
def left_equals(s):
|
||||
s = '// %s ' % s
|
||||
return s + ('='*(80-len(s))) + '\n'
|
||||
@@ -1,8 +1,3 @@
|
||||
*.pyc
|
||||
*.exp
|
||||
*.lib
|
||||
*.obj
|
||||
*.arg
|
||||
*.dll
|
||||
*.cpp
|
||||
.sconsign
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
import glob
|
||||
import sys
|
||||
import os
|
||||
|
||||
# constants
|
||||
if sys.platform == 'win32':
|
||||
BOOST_ROOT = 'D:/Programming/Libraries/boost-cvs'
|
||||
STLPORT_ROOT = 'D:/Programming/Libraries/stlport-4.5.3'
|
||||
PYTHON_ROOT = 'C:/Python'
|
||||
|
||||
if BOOST_ROOT:
|
||||
BOOST_INCLUDE = BOOST_ROOT + '/boost'
|
||||
BOOST_LIB = BOOST_ROOT + '/lib'
|
||||
|
||||
if STLPORT_ROOT:
|
||||
STLPORT_INCLUDE = STLPORT_ROOT + '/stlport'
|
||||
STLPORT_LIB = STLPORT_ROOT + '/lib'
|
||||
|
||||
if PYTHON_ROOT:
|
||||
PYTHON_INCLUDE = PYTHON_ROOT + '/include'
|
||||
PYTHON_LIB = PYTHON_ROOT + '/libs'
|
||||
|
||||
LIBS = ['boost_python', 'python22']
|
||||
|
||||
INCLUDES = ['../example']
|
||||
if sys.platform == 'win32':
|
||||
CXX = 'icl'
|
||||
CXXFLAGS='/GR /GX /MD /nologo'
|
||||
INCLUDES += [BOOST_INCLUDE, STLPORT_INCLUDE, PYTHON_INCLUDE]
|
||||
LIBPATH = [STLPORT_LIB, PYTHON_LIB, BOOST_LIB]
|
||||
else:
|
||||
CXX = 'g++'
|
||||
CXXFLAGS = ''
|
||||
LIBPATH = []
|
||||
#INCLUDES = ['..']
|
||||
|
||||
# Create the environment
|
||||
env = Environment(
|
||||
CXX=CXX,
|
||||
CXXFLAGS=CXXFLAGS,
|
||||
CPPPATH=INCLUDES,
|
||||
LIBS=LIBS,
|
||||
LIBPATH=LIBPATH)
|
||||
|
||||
|
||||
# Build all the cpp files
|
||||
modules = [os.path.splitext(os.path.basename(x))[0] for x in glob.glob('../example/*.pyste')]
|
||||
for module in modules:
|
||||
multiple = ARGUMENTS.get('multiple', '')
|
||||
example_cpp = '../example/%s.cpp' % module
|
||||
if os.path.isfile(example_cpp):
|
||||
sources = [example_cpp]
|
||||
else:
|
||||
sources = []
|
||||
if multiple:
|
||||
env.SharedLibrary(target=module, source=sources + glob.glob('_%s/*.cpp'%module))
|
||||
else:
|
||||
env.SharedLibrary(target=module, source=sources + ['_%s.cpp' % module])
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
from SmartFile import *
|
||||
import unittest
|
||||
import tempfile
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
class SmartFileTest(unittest.TestCase):
|
||||
|
||||
FILENAME = tempfile.mktemp()
|
||||
|
||||
def setUp(self):
|
||||
self._Clean()
|
||||
|
||||
def tearDown(self):
|
||||
self._Clean()
|
||||
|
||||
def _Clean(self):
|
||||
try:
|
||||
os.remove(self.FILENAME)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def testNonExistant(self):
|
||||
"Must override the file, as there's no file in the disk yet"
|
||||
self.assert_(not os.path.isfile(self.FILENAME))
|
||||
f = SmartFile(self.FILENAME, 'w')
|
||||
f.write('Testing 123\nTesting again.')
|
||||
f.close()
|
||||
self.assert_(os.path.isfile(self.FILENAME))
|
||||
|
||||
|
||||
def testOverride(self):
|
||||
"Must override the file, because the contents are different"
|
||||
contents = 'Contents!\nContents!'
|
||||
# create the file normally first
|
||||
f = file(self.FILENAME, 'w')
|
||||
f.write(contents)
|
||||
f.close()
|
||||
file_time = os.path.getmtime(self.FILENAME)
|
||||
self.assert_(os.path.isfile(self.FILENAME))
|
||||
time.sleep(2)
|
||||
f = SmartFile(self.FILENAME, 'w')
|
||||
f.write(contents + '_')
|
||||
f.close()
|
||||
new_file_time = os.path.getmtime(self.FILENAME)
|
||||
self.assert_(new_file_time != file_time)
|
||||
|
||||
|
||||
def testNoOverride(self):
|
||||
"Must not override the file, because the contents are the same"
|
||||
contents = 'Contents!\nContents!'
|
||||
# create the file normally first
|
||||
f = file(self.FILENAME, 'w')
|
||||
f.write(contents)
|
||||
f.close()
|
||||
file_time = os.path.getmtime(self.FILENAME)
|
||||
self.assert_(os.path.isfile(self.FILENAME))
|
||||
time.sleep(2)
|
||||
f = SmartFile(self.FILENAME, 'w')
|
||||
f.write(contents)
|
||||
f.close()
|
||||
new_file_time = os.path.getmtime(self.FILENAME)
|
||||
self.assert_(new_file_time == file_time)
|
||||
|
||||
|
||||
def testAutoClose(self):
|
||||
"Must be closed when garbage-collected"
|
||||
def foo():
|
||||
f = SmartFile(self.FILENAME)
|
||||
f.write('testing')
|
||||
self.assert_(not os.path.isfile(self.FILENAME))
|
||||
foo()
|
||||
self.assert_(os.path.isfile(self.FILENAME))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
19
pyste/tests/build_pyste_nt.bat
Normal file
19
pyste/tests/build_pyste_nt.bat
Normal file
@@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set MODULE_NAME=%1
|
||||
set PYSTE_FILE=%2
|
||||
set BOOST_ROOT=d:/programming/libraries/boost-cvs
|
||||
set PYTHON_ROOT=c:/python
|
||||
set STLPORT_ROOT=d:/programming/libraries/stlport-4.5.3
|
||||
set PYSTE_FILE_DIR=%@PATH[%PYSTE_FILE]
|
||||
|
||||
python ../src/pyste.py -I%PYSTE_FILE_DIR --out=%MODULE_NAME.cpp --module=%MODULE_NAME %PYSTE_FILE
|
||||
|
||||
icl /nologo /LD /GR /GX -I%PYSTE_FILE_DIR -I%STLPORT_ROOT/stlport -I%BOOST_ROOT/boost -I%PYTHON_ROOT/include %MODULE_NAME.cpp /link /libpath:%PYTHON_ROOT/libs /libpath:%BOOST_ROOT/lib /libpath:%STLPORT_ROOT/lib boost_python.lib
|
||||
|
||||
rm %MODULE_NAME.cpp
|
||||
rm %MODULE_NAME.exp
|
||||
rm %MODULE_NAME.lib
|
||||
rm %MODULE_NAME.obj
|
||||
|
||||
endlocal
|
||||
@@ -1,11 +1,11 @@
|
||||
import unittest
|
||||
from basic import *
|
||||
import os
|
||||
|
||||
class BasicExampleTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
from basic import C, call_f
|
||||
|
||||
# test virtual functions
|
||||
class D(C):
|
||||
def f(self, x=10):
|
||||
return x+1
|
||||
@@ -21,45 +21,6 @@ class BasicExampleTest(unittest.TestCase):
|
||||
self.assertEqual(call_f(c, 4), 8)
|
||||
self.assertEqual(call_f(d), 11)
|
||||
self.assertEqual(call_f(d, 3), 4)
|
||||
|
||||
# test data members
|
||||
def testValue(value):
|
||||
self.assertEqual(c.value, value)
|
||||
self.assertEqual(d.value, value)
|
||||
self.assertEqual(get_value(c), value)
|
||||
self.assertEqual(get_value(d), value)
|
||||
testValue(1)
|
||||
c.value = 30
|
||||
d.value = 30
|
||||
testValue(30)
|
||||
self.assertEqual(c.const_value, 0)
|
||||
self.assertEqual(d.const_value, 0)
|
||||
def set_const_value():
|
||||
c.const_value = 12
|
||||
self.assertRaises(AttributeError, set_const_value)
|
||||
|
||||
# test static data-members
|
||||
def testStatic(value):
|
||||
self.assertEqual(C.static_value, value)
|
||||
self.assertEqual(c.static_value, value)
|
||||
self.assertEqual(D.static_value, value)
|
||||
self.assertEqual(d.static_value, value)
|
||||
self.assertEqual(get_static(), value)
|
||||
testStatic(3)
|
||||
C.static_value = 10
|
||||
testStatic(10)
|
||||
self.assertEqual(C.const_static_value, 100)
|
||||
def set_const_static():
|
||||
C.const_static_value = 1
|
||||
self.assertRaises(AttributeError, set_const_static)
|
||||
|
||||
# test static function
|
||||
def test_mul(result, *args):
|
||||
self.assertEqual(C.mul(*args), result)
|
||||
self.assertEqual(c.mul(*args), result)
|
||||
test_mul(6)
|
||||
test_mul(3, 1)
|
||||
test_mul(16, 8, 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import unittest
|
||||
from inherit import *
|
||||
|
||||
class InheritExampleTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
a = A_int()
|
||||
b = B()
|
||||
self.assert_(isinstance(b, A_int))
|
||||
self.assert_(issubclass(B, A_int))
|
||||
a.set(10)
|
||||
self.assertEqual(a.get(), 10)
|
||||
b.set(1)
|
||||
self.assertEqual(b.go(), 1)
|
||||
self.assertEqual(b.get(), 1)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,18 +0,0 @@
|
||||
import unittest
|
||||
from opaque import *
|
||||
|
||||
class OpaqueTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
|
||||
c = new_C()
|
||||
self.assertEqual(get(c), 10)
|
||||
a = A()
|
||||
d = a.new_handle()
|
||||
self.assertEqual(a.get(d), 3.0)
|
||||
self.assertEqual(a.f(), 0)
|
||||
self.assertEqual(a.f(3), 3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -19,7 +19,6 @@ class OperatorTest(unittest.TestCase):
|
||||
self.assertEqual(d(), 10)
|
||||
self.assertEqual(c(3.0), 13.0)
|
||||
self.assertEqual(d(6.0), 16.0)
|
||||
self.assertEqual(str(c), "C")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import unittest
|
||||
from smart_ptr import *
|
||||
|
||||
class BasicExampleTest(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
c = NewC()
|
||||
d = NewD()
|
||||
c.value = 3
|
||||
d.Set(c)
|
||||
c1 = d.Get()
|
||||
c1.value = 6
|
||||
self.assertEqual(c.value, 6)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -6,19 +6,19 @@ class TemplatesTest(unittest.TestCase):
|
||||
def testIt(self):
|
||||
fp = FPoint()
|
||||
fp.i = 3.0
|
||||
fp.j = 4.0
|
||||
fp.j = 4
|
||||
ip = IPoint()
|
||||
ip.x = 10
|
||||
ip.y = 3
|
||||
ip.y = 3.0
|
||||
|
||||
self.assertEqual(fp.i, 3.0)
|
||||
self.assertEqual(fp.j, 4.0)
|
||||
self.assertEqual(fp.j, 4)
|
||||
self.assertEqual(ip.x, 10)
|
||||
self.assertEqual(ip.y, 3)
|
||||
self.assertEqual(ip.y, 3.0)
|
||||
self.assertEqual(type(fp.i), float)
|
||||
self.assertEqual(type(fp.j), float)
|
||||
self.assertEqual(type(fp.j), int)
|
||||
self.assertEqual(type(ip.x), int)
|
||||
self.assertEqual(type(ip.y), int)
|
||||
self.assertEqual(type(ip.y), float)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import unittest
|
||||
from virtual2 import *
|
||||
|
||||
class Virtual2Test(unittest.TestCase):
|
||||
|
||||
def testIt(self):
|
||||
a = A()
|
||||
self.assertEqual(a.f1(), 10)
|
||||
b = B()
|
||||
self.assertEqual(b.f1(), 10)
|
||||
self.assertEqual(b.f2(), 20)
|
||||
self.assertEqual(call_fs(b), 30)
|
||||
self.assertEqual(call_f(a), 0)
|
||||
self.assertEqual(call_f(b), 1)
|
||||
|
||||
class C(B):
|
||||
def f1(self): return 1
|
||||
def f2(self): return 2
|
||||
def f(self): return 100
|
||||
|
||||
c = C()
|
||||
self.assertEqual(call_fs(c), 3)
|
||||
self.assertEqual(call_fs(c), 3)
|
||||
self.assertEqual(call_f(c), 100)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -7,14 +7,5 @@ class WrapperTest(unittest.TestCase):
|
||||
self.assertEqual(Range(10), range(10))
|
||||
self.assertEqual(C().Mul(10), [x*10 for x in range(10)])
|
||||
|
||||
a = A()
|
||||
self.assertEqual(a.f(), 10)
|
||||
self.assertEqual(call_foo(a), 10)
|
||||
class D(A):
|
||||
def f(self): return 2
|
||||
d = D()
|
||||
self.assertEqual(d.f(), 2)
|
||||
self.assertEqual(call_foo(d), 2)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
@echo off
|
||||
call nt_build_all.bat
|
||||
runtests.py
|
||||
call nt_clean.bat
|
||||
call nt_build_all.bat --multiple
|
||||
runtests.py
|
||||
call nt_clean.bat
|
||||
@@ -1,15 +0,0 @@
|
||||
@echo off
|
||||
|
||||
call nt_build_pyste.bat basic %1
|
||||
call nt_build_pyste.bat enums %1
|
||||
call nt_build_pyste.bat header_test %1
|
||||
call nt_build_pyste.bat nested %1
|
||||
call nt_build_pyste.bat operators %1
|
||||
call nt_build_pyste.bat smart_ptr %1
|
||||
call nt_build_pyste.bat templates %1
|
||||
call nt_build_pyste.bat unions %1
|
||||
call nt_build_pyste.bat virtual %1
|
||||
call nt_build_pyste.bat virtual2 %1
|
||||
call nt_build_pyste.bat wrappertest %1
|
||||
call nt_build_pyste.bat opaque %1
|
||||
call nt_build_pyste.bat inherit %1
|
||||
@@ -1,8 +0,0 @@
|
||||
@echo off
|
||||
set BOOST_INCLUDE=D:\Programming\Libraries\boost-cvs\boost
|
||||
set out=_%1.cpp
|
||||
if "%2" == "--multiple" set out=_%1
|
||||
rem python ../src/pyste.py %2 -I%BOOST_INCLUDE -I../example --module=%1 --out=%out ../example/%1.pyste
|
||||
pyste %2 -I%BOOST_INCLUDE -I../example --module=%1 --out=%out ../example/%1.pyste
|
||||
|
||||
scons --quiet multiple=%2 %1.dll
|
||||
@@ -1,24 +0,0 @@
|
||||
@echo off
|
||||
|
||||
rm -Rf _basic
|
||||
rm -Rf _enums
|
||||
rm -Rf _header_test
|
||||
rm -Rf _nested
|
||||
rm -Rf _operators
|
||||
rm -Rf _smart_ptr
|
||||
rm -Rf _templates
|
||||
rm -Rf _unions
|
||||
rm -Rf _virtual
|
||||
rm -Rf _virtual2
|
||||
rm -Rf _wrappertest
|
||||
rm -Rf _opaque
|
||||
rm -Rf _inherit
|
||||
|
||||
rm -f *.cpp
|
||||
rm -f *.obj
|
||||
rm -f *.exp
|
||||
rm -f *.arg
|
||||
rm -f *.dll
|
||||
rm -f *.pyc
|
||||
rm -f *.lib
|
||||
rm -f ../example/*.obj
|
||||
@@ -1,5 +1,5 @@
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
sys.path.append('..')
|
||||
import unittest
|
||||
from policies import *
|
||||
|
||||
@@ -35,8 +35,7 @@ class PoliciesTest(unittest.TestCase):
|
||||
self.assertEqual(x.Code(), ret % 'copy_non_const_reference')
|
||||
x = return_value_policy(manage_new_object)
|
||||
self.assertEqual(x.Code(), ret % 'manage_new_object')
|
||||
x = return_value_policy(return_opaque_pointer)
|
||||
self.assertEqual(x.Code(), ret % 'return_opaque_pointer')
|
||||
|
||||
|
||||
def testReturnWithCustodiam(self):
|
||||
'test the mix of return_internal with custodian'
|
||||
|
||||
20
pyste/tests/test_all.bat
Normal file
20
pyste/tests/test_all.bat
Normal file
@@ -0,0 +1,20 @@
|
||||
@echo off
|
||||
call build_pyste_nt basic ../example/basic.pyste
|
||||
call build_pyste_nt enums ../example/enums.pyste
|
||||
call build_pyste_nt header_test ../example/header_test.pyste
|
||||
call build_pyste_nt nested ../example/nested.pyste
|
||||
call build_pyste_nt operators ../example/operators.pyste
|
||||
call build_pyste_nt templates ../example/templates.pyste
|
||||
call build_pyste_nt virtual ../example/virtual.pyste
|
||||
call build_pyste_nt wrappertest ../example/wrappertest.pyste
|
||||
call build_pyste_nt unions ../example/unions.pyste
|
||||
|
||||
|
||||
runtests.py
|
||||
|
||||
if errorlevel != 0 goto end
|
||||
|
||||
rm *.dll
|
||||
rm *.pyc
|
||||
|
||||
:end
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import os
|
||||
import glob
|
||||
import shutil
|
||||
|
||||
def build_pyste_files(multiple):
|
||||
# list all pyste files in the example directory
|
||||
examples = glob.glob('../example/*.pyste')
|
||||
# generate the cpp file for each example
|
||||
for example in examples:
|
||||
path, filename = os.path.split(example)
|
||||
module = os.path.splitext(filename)[0]
|
||||
os.system('python ../src/pyste.py %s -I%s --module=%s %s' % \
|
||||
(multiple, path, module, example))
|
||||
|
||||
|
||||
def compile_pyste_files(multiple):
|
||||
if not multiple:
|
||||
# compile each cpp into a shared library
|
||||
for cpp in glob.glob('*.cpp'):
|
||||
print
|
||||
print 'compiling', cpp
|
||||
out = os.path.splitext(cpp)[0] + '.so'
|
||||
cmdline = 'g++ -shared -o %s -I../example ' \
|
||||
'-I/usr/include/python2.2 -lboost_python %s' % (out, cpp)
|
||||
os.system(cmdline)
|
||||
else:
|
||||
modules = get_modules()
|
||||
# list cpp files in each module directory
|
||||
print
|
||||
for module in modules:
|
||||
# compile each
|
||||
for file in glob.glob(module+'/*.cpp'):
|
||||
print 'compiling', file
|
||||
out = os.path.splitext(file)[0] + '.obj'
|
||||
cmdline = 'g++ -shared -c -o %s -I../example ' \
|
||||
'-I/usr/include/python2.2 %s' % (out, file)
|
||||
os.system(cmdline)
|
||||
# generate a dynamic library
|
||||
print 'linking'
|
||||
objs = ' '.join([x for x in glob.glob(module+'/*.obj')])
|
||||
out = module + '.so'
|
||||
cmdline = 'g++ -shared -o %s -lboost_python %s' % (out, objs)
|
||||
os.system(cmdline)
|
||||
|
||||
|
||||
|
||||
|
||||
def run_tests():
|
||||
if os.system('python runtests.py') != 0:
|
||||
raise RuntimeError, 'tests failed'
|
||||
|
||||
|
||||
def cleanup():
|
||||
extensions = '*.cpp *.so *.pyc'
|
||||
files = []
|
||||
for ext in extensions.split():
|
||||
files += glob.glob(ext)
|
||||
for file in files:
|
||||
try:
|
||||
os.remove(file)
|
||||
except OSError: pass
|
||||
|
||||
modules = get_modules()
|
||||
for module in modules:
|
||||
try:
|
||||
shutil.rmtree(module)
|
||||
except OSError: pass
|
||||
|
||||
|
||||
def main(multiple):
|
||||
build_pyste_files(multiple)
|
||||
compile_pyste_files(multiple)
|
||||
run_tests()
|
||||
cleanup()
|
||||
|
||||
def get_modules():
|
||||
def getname(file):
|
||||
return os.path.splitext(os.path.basename(file))[0]
|
||||
return [getname(x) for x in glob.glob('../example/*.pyste')]
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main('--multiple')
|
||||
main('')
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
Reference in New Issue
Block a user