2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-27 07:02:15 +00:00

Added a FAQ

[SVN r17010]
This commit is contained in:
Dave Abrahams
2003-01-23 17:38:57 +00:00
parent 9dfe98abb0
commit 6f687ee402

View File

@@ -29,10 +29,10 @@
<hr>
<dl class="page-index">
<dt><a href="#question1">Is return_internal reference
<dt><a href="#question1">Is return_internal_reference
efficient?</a></dt>
<dt><a href="#question2">How can I wrap containers which take C++
<dt><a href="#question2">How can I wrap functions which take C++
containers as arguments?</a></dt>
<dt><a href="#c1204">fatal error C1204:Compiler limit:internal
@@ -40,13 +40,18 @@
<dt><a href="#debugging">How do I debug my Python extensions?</a></dt>
<dt><a href="#imul">Why doesn't my <code>*=</code> operator work?</a></dt>
<dt><a href="#imul">Why doesn't my <code>*=</code> operator
work?</a></dt>
<dt><a href="#macosx">Does Boost.Python work with Mac OS X?</a></dt>
<dt><a href="#xref">How can I find the existing PyObject that holds a
C++ object?</a></dt>
</dl>
<hr>
<h2><a name="question1"></a>Is return_internal reference efficient?</h2>
<h2><a name="question1"></a>Is return_internal_reference efficient?</h2>
<blockquote>
<b>Q:</b> <i>I have an object composed of 12 doubles. A const&amp; to
@@ -70,6 +75,7 @@
cycles.</p>
</blockquote>
<hr>
<h2><a name="question2"></a>How can I wrap functions which take C++
containers as arguments?</h2>
@@ -161,7 +167,7 @@ cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx login
cvs -d:pserver:anonymous@cvs.cctbx.sourceforge.net:/cvsroot/cctbx co scitbx
</pre>
<hr>
<h2><a name="c1204"></a>fatal error C1204:Compiler limit:internal
structure overflow</h2>
@@ -203,9 +209,9 @@ void more_of_my_module()
can always pass a reference to the <code>class_</code> object to a
function in another source file, and call some of its member
functions (e.g. <code>.def(...)</code>) in the auxilliary source
file: <code>
file:
<p><b>more_of_my_class.cpp</b></code>:
<p><code><b>more_of_my_class.cpp</b></code>:</p>
<pre>
void more_of_my_class(class&lt;my_class&gt;&amp; x)
{
@@ -221,28 +227,25 @@ void more_of_my_class(class&lt;my_class&gt;&amp; x)
</ol>
</blockquote>
<hr>
<h2><a name="debugging"></a>How do I debug my Python extensions?</h2>
<p>Greg Burley gives the following answer for Unix GCC users:
<p>Greg Burley gives the following answer for Unix GCC users:</p>
<blockquote>
Once you have created a boost python extension for your c++ library or
class, you may need to debug the code. Afterall this is one of the
reasons for wrapping the library in python. An expected side-effect or
benefit of using BPL is that debugging should be isolated to the c++
library that is under test, given that python code is minimal and
boost::python either works or it doesn't. (ie. While errors can occur
when the wrapping method is invalid, most errors are caught by the
compiler ;-).
<p>
The basic steps required to initiate a gdb session to debug a c++
library via python are shown here. Note, however that you should start
the gdb session in the directory that contains your BPL my_ext.so
module.
Once you have created a boost python extension for your c++ library or
class, you may need to debug the code. Afterall this is one of the
reasons for wrapping the library in python. An expected side-effect or
benefit of using BPL is that debugging should be isolated to the c++
library that is under test, given that python code is minimal and
boost::python either works or it doesn't. (ie. While errors can occur
when the wrapping method is invalid, most errors are caught by the
compiler ;-).
<p>The basic steps required to initiate a gdb session to debug a c++
library via python are shown here. Note, however that you should start
the gdb session in the directory that contains your BPL my_ext.so
module.</p>
<pre>
(gdb) target exec python
(gdb) run
@@ -258,63 +261,54 @@ Current language: auto; currently c++
</pre>
</blockquote>
<p>
<p>Greg's approach works even better using Emacs' "<code>gdb</code>"
command, since it will show you each line of source as you step through
it.</p>
Greg's approach works even better using Emacs'
&quot;<code>gdb</code>&quot; command, since it will show you each line
of source as you step through it.
<p>On <b>Windows</b>, my favorite debugging solution is the debugger that
comes with Microsoft Visual C++ 7. This debugger seems to work with code
generated by all versions of Microsoft and Metrowerks toolsets; it's rock
solid and "just works" without requiring any special tricks from the
user.</p>
<p>
On Windows, my favorite debugging solution is the debugger that comes
with Microsoft Visual C++ 7. This debugger seems to work with code
generated by all versions of Microsoft and Metrowerks toolsets; it's
rock solid and &quot;just works&quot; without requiring any special
tricks from the user.
<p>
Unfortunately for Cygwin and MinGW users, as of this writing gdb on
Windows has a very hard time dealing with shared libraries, which
could make Greg's approach next to useless for you. My best advice for
you is to use Metrowerks C++ for compiler conformance and Microsoft
Visual Studio as a debugger when you need one.
<h3>Debugging extensions through Boost.Build</h3>
If you are launching your extension module tests with <a
href="../../../tools/build">Boost.Build</a> using the
<code>boost-python-runtest</code> rule, you can ask it to launch your
debugger for you by adding &quot;-sPYTHON_LAUNCH=<i>debugger</i>&quot;
to your bjam command-line:
<p>Unfortunately for Cygwin and MinGW users, as of this writing gdb on
Windows has a very hard time dealing with shared libraries, which could
make Greg's approach next to useless for you. My best advice for you is
to use Metrowerks C++ for compiler conformance and Microsoft Visual
Studio as a debugger when you need one.</p>
<h3>Debugging extensions through Boost.Build</h3>
If you are launching your extension module tests with <a href=
"../../../tools/build">Boost.Build</a> using the
<code>boost-python-runtest</code> rule, you can ask it to launch your
debugger for you by adding "-sPYTHON_LAUNCH=<i>debugger</i>" to your bjam
command-line:
<pre>
bjam -sTOOLS=metrowerks &quot;-sPYTHON_LAUNCH=devenv /debugexe&quot; test
bjam -sTOOLS=metrowerks "-sPYTHON_LAUNCH=devenv /debugexe" test
bjam -sTOOLS=gcc -sPYTHON_LAUNCH=gdb test
</pre>
It can also be extremely useful to add the <code>-d+2</code> option when
you run your test, because Boost.Build will then show you the exact
commands it uses to invoke it. This will invariably involve setting up
PYTHONPATH and other important environment variables such as
LD_LIBRARY_PATH which may be needed by your debugger in order to get
things to work right.
It can also be extremely useful to add the <code>-d+2</code> option
when you run your test, because Boost.Build will then show you the
exact commands it uses to invoke it. This will invariably involve
setting up PYTHONPATH and other important environment variables such
as LD_LIBRARY_PATH which may be needed by your debugger in order to
get things to work right.
<hr>
<h2><a name="imul"></a>Why doesn't my <code>*=</code> operator work?</h2>
<blockquote>
<b>Q:</b> <i>I have exported my class to python, with many overloaded operators. it
works fine for me except the </i><code>*=</code><i> operator. It always tells
me "can't multiply sequence with non int type". If I use
</i><code>p1.__imul__(p2)</code><i> instead of </i><code>p1 *=
p2</code><i>, it successfully executes my code. What's wrong with
me?</i>
<p><b>A:</b> There's nothing wrong with you. This is a bug in Python
2.2. You can see the same effect in Pure Python (you can learn a lot
about what's happening in Boost.Python by playing with new-style
classes in Pure Python).
<blockquote>
<b>Q:</b> <i>I have exported my class to python, with many overloaded
operators. it works fine for me except the</i> <code>*=</code>
<i>operator. It always tells me "can't multiply sequence with non int
type". If I use</i> <code>p1.__imul__(p2)</code> <i>instead of</i>
<code>p1 *= p2</code><i>, it successfully executes my code. What's
wrong with me?</i>
<p><b>A:</b> There's nothing wrong with you. This is a bug in Python
2.2. You can see the same effect in Pure Python (you can learn a lot
about what's happening in Boost.Python by playing with new-style
classes in Pure Python).</p>
<pre>
&gt;&gt;&gt; class X(object):
... def __imul__(self, x):
@@ -323,44 +317,103 @@ classes in Pure Python).
&gt;&gt;&gt; x = X()
&gt;&gt;&gt; x *= 1
</pre>
To cure this problem, all you need to do is upgrade your Python to
version 2.2.1 or later.
</blockquote>
To cure this problem, all you need to do is upgrade your Python to
version 2.2.1 or later.
</blockquote>
<hr>
<h2><a name="macosx"></a>Does Boost.Python work with Mac OS X?</h2>
<blockquote>
<p>The short answer: as of January 2003, unfortunately not.
<p>
The longer answer: using Mac OS 10.2.3 with the December Developer's Kit,
Python 2.3a1, and bjam's darwin-tools.jam, Boost.Python compiles fine,
including the examples. However, there are problems at runtime
(see <a
href="http://mail.python.org/pipermail/c++-sig/2003-January/003267.html"
>http://mail.python.org/pipermail/c++-sig/2003-January/003267.html</a>).
Solutions are currently unknown.
<p>
It is known that under certain circumstances objects are double-destructed.
See <a
href="http://mail.python.org/pipermail/c++-sig/2003-January/003278.html"
>http://mail.python.org/pipermail/c++-sig/2003-January/003278.html"</a>
for details. It is not clear however if this problem is related to
the Boost.Python runtime issues.
</blockquote>
<blockquote>
<p>The short answer: as of January 2003, unfortunately not.</p>
<p>The longer answer: using Mac OS 10.2.3 with the December Developer's
Kit, Python 2.3a1, and bjam's darwin-tools.jam, Boost.Python compiles
fine, including the examples. However, there are problems at runtime
(see <a href=
"http://mail.python.org/pipermail/c++-sig/2003-January/003267.html">http://mail.python.org/pipermail/c++-sig/2003-January/003267.html</a>).
Solutions are currently unknown.</p>
<p>It is known that under certain circumstances objects are
double-destructed. See <a href=
"http://mail.python.org/pipermail/c++-sig/2003-January/003278.html">http://mail.python.org/pipermail/c++-sig/2003-January/003278.html"</a>
for details. It is not clear however if this problem is related to the
Boost.Python runtime issues.</p>
</blockquote>
<hr>
<h2><a name="xref">How can I find the existing PyObject that holds a C++
object?</a></h2>
<blockquote>
"I am wrapping a function that always returns a pointer to an
already-held C++ object."
</blockquote>
One way to do that is to hijack the mechanisms used for wrapping a class
with virtual functions. If you make a wrapper class with an initial
PyObject* constructor argument and store that PyObject* as "self", you
can get back to it by casting down to that wrapper type in a thin wrapper
function. For example:
<pre>
class X { X(int); virtual ~X(); ... };
X* f(); // known to return Xs that are managed by Python objects
// wrapping code
struct X_wrap : X
{
X_wrap(PyObject* self, int v) : self(self), X(v) {}
PyObject* self;
};
handle&lt;&gt; f_wrap()
{
X_wrap* xw = dynamic_cast&lt;X_wrap*&gt;(f());
assert(xw != 0);
return handle&lt;&gt;(borrowed(xw-&gt;self));
}
...
def("f", f_wrap());
class_&lt;X,X_wrap&gt;("X", init&lt;int&gt;())
...
;
</pre>
Of course, if X has no virtual functions you'll have to use
<code>static_cast</code> instead of <code>dynamic_cast</code> with no
runtime check that it's valid. This approach also only works if the
<code>X</code> object was constructed from Python, because
<code>X</code>s constructed from C++ are of course never
<code>X_wrap</code> objects.
<p>Another approach to this requires some work on Boost.Python, but it's
work we've been meaning to get to anyway. Currently, when a
<code>shared_ptr&lt;X&gt;</code> is converted from Python, the shared_ptr
actually manages a reference to the containing Python object. I plan to
make it so that when a shared_ptr&lt;X&gt; is converted back to Python,
the library checks to see if it's one of those "Python object managers"
and if so just returns the original Python object. To exploit this you'd
have to be able to change the C++ code you're wrapping so that it deals
with shared_ptr instead of raw pointers.</p>
<p>There are other approaches too. The functions that receive the Python
object that you eventually want to return could be wrapped with a thin
wrapper that records the correspondence between the object address and
its containing Python object, and you could have your f_wrap function
look in that mapping to get the Python object out.</p>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
14 January, 2003
23 January, 2003
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href=
"../../../../people/dave_abrahams.htm">Dave Abrahams</a> 2002-2003. All Rights
Reserved.</i></p>
"../../../../people/dave_abrahams.htm">Dave Abrahams</a> 2002-2003. All
Rights Reserved.</i></p>
</body>
</html>