Compare commits
14 Commits
boost-1.30
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d6b042c4c | ||
|
|
55a7884912 | ||
|
|
2566e1dd3a | ||
|
|
9bca6982a4 | ||
|
|
c7e12ecf3d | ||
|
|
5031479fa2 | ||
|
|
fc9a6ac369 | ||
|
|
905074542e | ||
|
|
b7957da50a | ||
|
|
1b1620b62a | ||
|
|
0ed5af25a7 | ||
|
|
1dbcf12502 | ||
|
|
10c2fbd63a | ||
|
|
9b602d16b4 |
@@ -1,84 +0,0 @@
|
|||||||
# (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
|
|
||||||
# distribute this software is granted provided this copyright notice appears
|
|
||||||
# in all copies. This software is provided "as is" without express or implied
|
|
||||||
# warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
#
|
|
||||||
# Boost.Python library Jamfile
|
|
||||||
|
|
||||||
|
|
||||||
# declare the location of this subproject relative to the root
|
|
||||||
subproject libs/python/build ;
|
|
||||||
|
|
||||||
# bring in the rules for python
|
|
||||||
SEARCH on <module@>python.jam = $(BOOST_BUILD_PATH) ;
|
|
||||||
include <module@>python.jam ;
|
|
||||||
|
|
||||||
if [ check-python-config ]
|
|
||||||
{
|
|
||||||
|
|
||||||
local bpl-linkflags ;
|
|
||||||
|
|
||||||
if $(UNIX) && ( $(OS) = AIX )
|
|
||||||
{
|
|
||||||
bpl-linkflags = <linkflags>"-e initlibboost_python" ;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Enabling intrinsics (/0i) or maximize speed (/02) seem to cause
|
|
||||||
# internal compiler errors with this toolset.
|
|
||||||
local msvc-stlport-workarounds
|
|
||||||
= <optimization>off "<cxxflags>-Ogty -O1 -Gs" ;
|
|
||||||
|
|
||||||
local sources =
|
|
||||||
numeric.cpp
|
|
||||||
list.cpp
|
|
||||||
long.cpp
|
|
||||||
dict.cpp
|
|
||||||
tuple.cpp
|
|
||||||
str.cpp
|
|
||||||
|
|
||||||
aix_init_module.cpp
|
|
||||||
converter/from_python.cpp
|
|
||||||
converter/registry.cpp
|
|
||||||
converter/type_id.cpp
|
|
||||||
object/enum.cpp
|
|
||||||
object/class.cpp
|
|
||||||
object/function.cpp
|
|
||||||
object/inheritance.cpp
|
|
||||||
object/life_support.cpp
|
|
||||||
object/pickle_support.cpp
|
|
||||||
errors.cpp
|
|
||||||
module.cpp
|
|
||||||
converter/builtin_converters.cpp
|
|
||||||
converter/arg_to_python_base.cpp
|
|
||||||
object/iterator.cpp
|
|
||||||
object_protocol.cpp
|
|
||||||
object_operators.cpp
|
|
||||||
;
|
|
||||||
|
|
||||||
dll boost_python
|
|
||||||
: ../src/$(sources)
|
|
||||||
: $(BOOST_PYTHON_V2_PROPERTIES)
|
|
||||||
<define>BOOST_PYTHON_SOURCE
|
|
||||||
$(bpl-linkflags)
|
|
||||||
<msvc-stlport><release>$(msvc-stlport-workarounds)
|
|
||||||
;
|
|
||||||
|
|
||||||
lib boost_python
|
|
||||||
: # sources
|
|
||||||
../src/$(sources)
|
|
||||||
|
|
||||||
: # requirements
|
|
||||||
$(BOOST_PYTHON_V2_PROPERTIES)
|
|
||||||
<define>BOOST_PYTHON_SOURCE
|
|
||||||
<define>BOOST_STATIC_LIB
|
|
||||||
$(bpl-linkflags)
|
|
||||||
<msvc-stlport><release>$(msvc-stlport-workarounds)
|
|
||||||
;
|
|
||||||
|
|
||||||
stage bin-stage : <dll>boost_python <lib>boost_python
|
|
||||||
: <tag><debug>"_debug"
|
|
||||||
<tag><debug-python>"_pydebug"
|
|
||||||
:
|
|
||||||
debug release
|
|
||||||
;
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
import os ;
|
|
||||||
|
|
||||||
# Use a very crude way to sense there python is locatted
|
|
||||||
|
|
||||||
local PYTHON_PATH ;
|
|
||||||
|
|
||||||
if [ GLOB /usr/local/include/python2.2 : * ]
|
|
||||||
{
|
|
||||||
PYTHON_PATH = /usr/local ;
|
|
||||||
}
|
|
||||||
else if [ GLOB /usr/include/python2.2 : * ]
|
|
||||||
{
|
|
||||||
PYTHON_PATH = /usr ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ os.name ] in CYGWIN NT
|
|
||||||
{
|
|
||||||
lib_condition = <link>shared: ;
|
|
||||||
defines = USE_DL_IMPORT ;
|
|
||||||
|
|
||||||
# Declare a target for the python interpreter library
|
|
||||||
lib python : : <name>python2.2.dll ;
|
|
||||||
PYTHON_LIB = python ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lib python : : <name>python2.2 ;
|
|
||||||
PYTHON_LIB = python ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if $(PYTHON_PATH) {
|
|
||||||
|
|
||||||
|
|
||||||
project boost/python
|
|
||||||
: source-location ../src
|
|
||||||
: requirements <include>$(PYTHON_PATH)/include/python2.2
|
|
||||||
$(lib_condition)<library-path>$(PYTHON_PATH)/lib/python2.2/config
|
|
||||||
<link>shared:<library>$(PYTHON_LIB)
|
|
||||||
<define>$(defines)
|
|
||||||
: usage-requirements # requirement that will be propageted to *users* of this library
|
|
||||||
<include>$(PYTHON_PATH)/include/python2.2
|
|
||||||
|
|
||||||
# We have a bug which causes us to conclude that conditionalized
|
|
||||||
# properties in this section are not free.
|
|
||||||
# $(lib_condition)<library-path>$(PYTHON_PATH)/lib/python2.2/config
|
|
||||||
# <shared>true:<find-library>$(PYTHON_LIB)
|
|
||||||
|
|
||||||
<library-path>$(PYTHON_PATH)/lib/python2.2/config
|
|
||||||
<library>$(PYTHON_LIB)
|
|
||||||
;
|
|
||||||
|
|
||||||
lib boost_python
|
|
||||||
:
|
|
||||||
numeric.cpp
|
|
||||||
|
|
||||||
list.cpp
|
|
||||||
long.cpp
|
|
||||||
dict.cpp
|
|
||||||
tuple.cpp
|
|
||||||
str.cpp
|
|
||||||
|
|
||||||
aix_init_module.cpp
|
|
||||||
converter/from_python.cpp
|
|
||||||
converter/registry.cpp
|
|
||||||
converter/type_id.cpp
|
|
||||||
object/enum.cpp
|
|
||||||
object/class.cpp
|
|
||||||
object/function.cpp
|
|
||||||
object/inheritance.cpp
|
|
||||||
object/life_support.cpp
|
|
||||||
object/pickle_support.cpp
|
|
||||||
errors.cpp
|
|
||||||
module.cpp
|
|
||||||
converter/builtin_converters.cpp
|
|
||||||
converter/arg_to_python_base.cpp
|
|
||||||
object/iterator.cpp
|
|
||||||
object_protocol.cpp
|
|
||||||
object_operators.cpp
|
|
||||||
: <link>static:<define>BOOST_PYTHON_STATIC_LIB
|
|
||||||
<define>BOOST_PYTHON_SOURCE
|
|
||||||
: <link>shared
|
|
||||||
;
|
|
||||||
}
|
|
||||||
@@ -1,882 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="boost_python" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
|
||||||
|
|
||||||
CFG=BOOST_PYTHON - WIN32 RELEASE
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "boost_python.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "boost_python.mak" CFG="BOOST_PYTHON - WIN32 RELEASE"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "boost_python - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE "boost_python - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
MTL=midl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "boost_python - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "../bin-stage"
|
|
||||||
# PROP Intermediate_Dir "release-obj"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
F90=df.exe
|
|
||||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BPL_EXPORTS" /YX /FD /Zm800 /Zm800 /Zm800 /c
|
|
||||||
# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "../../../../" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BOOST_PYTHON_DYNAMIC_LIB" /D "BOOST_PYTHON_SOURCE" /FD /Zm800 /Zm800 /Zm800 /Zm800 /c
|
|
||||||
# SUBTRACT CPP /YX
|
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x1409 /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x1409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib /nologo /dll /machine:I386
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "boost_python - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "../bin-stage"
|
|
||||||
# PROP Intermediate_Dir "debug-obj"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
F90=df.exe
|
|
||||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BPL_EXPORTS" /YX /FD /Zm800 /Zm800 /Zm800 /GZ /c
|
|
||||||
# ADD CPP /nologo /MDd /W3 /GR /GX /Zi /Od /I "../../../../" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "BOOST_PYTHON_DYNAMIC_LIB" /D "BOOST_PYTHON_SOURCE" /FD /Zm800 /Zm800 /Zm800 /Zm800 /Zm800 /GZ /c
|
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x1409 /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x1409 /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"../bin-stage/boost_python_debug.dll" /pdbtype:sept
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "boost_python - Win32 Release"
|
|
||||||
# Name "boost_python - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\aix_init_module.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\converter\arg_to_python_base.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\converter\builtin_converters.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object\class.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\dict.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object\enum.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\errors.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\converter\from_python.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object\function.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object\inheritance.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object\iterator.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object\life_support.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\list.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\long.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\module.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\numeric.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object_operators.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object_protocol.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\object\pickle_support.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\converter\registry.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\str.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\tuple.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\src\converter\type_id.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Group "detail"
|
|
||||||
|
|
||||||
# PROP Default_Filter ""
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\aix_init_module.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\api_placeholder.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\arg_tuple_size.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\borrowed_ptr.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\call_object.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\caller.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\char_array.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\config.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\construct.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\convertible.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\cv_category.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\decorated_type_id.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\def_helper.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\defaults_def.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\defaults_gen.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\dependent.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\destroy.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\exception_handler.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\force_instantiate.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\if_else.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\indirect_traits.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\make_keyword_range_fn.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\make_tuple.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\map_entry.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\member_function_cast.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\module_base.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\module_init.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\msvc_typeinfo.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\none.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\not_specified.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\operator_id.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\overloads_fwd.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\pointee.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\preprocessor.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\python22_fixed.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\raw_pyobject.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\referent_storage.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\result.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\returning.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\scope.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\string_literal.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\target.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\translate_exception.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\type_list.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\type_list_impl.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\type_list_impl_no_pts.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\type_list_utils.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\unwind_type.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\void_ptr.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\void_return.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\detail\wrap_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "converter"
|
|
||||||
|
|
||||||
# PROP Default_Filter ""
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\arg_from_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\arg_to_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\arg_to_python_base.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\builtin_converters.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\constructor_function.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\convertible_function.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\from_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\implicit.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\obj_mgr_arg_from_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\object_manager.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\pointer_type_id.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\pyobject_traits.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\pyobject_type.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\pytype_arg_from_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\pytype_object_mgr_traits.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\registered.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\registered_pointee.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\registrations.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\registry.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\return_from_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\rvalue_from_python_data.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\converter\to_python_function_type.hpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "object"
|
|
||||||
|
|
||||||
# PROP Default_Filter ""
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\add_to_namespace.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\class.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\class_converters.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\class_detail.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\class_wrapper.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\construct.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\enum_base.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\find_instance.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\forward.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\function.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\function_handle.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\function_object.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\inheritance.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\instance.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\iterator.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\iterator_core.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\life_support.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\make_holder.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\make_instance.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\pickle_support.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\pointer_holder.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\py_function.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\select_holder.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\value_holder.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object\value_holder_fwd.hpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\arg_from_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\args.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\args_fwd.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\back_reference.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\base_type_traits.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\bases.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\borrowed.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\call.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\call_method.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\cast.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\class.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\class_fwd.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\copy_const_reference.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\copy_non_const_reference.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\data_members.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\def.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\default_call_policies.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\dict.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\enum.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\errors.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\exception_translator.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\extract.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\handle.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\handle_fwd.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\has_back_reference.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\implicit.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\init.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\instance_holder.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\iterator.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\list.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\long.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\lvalue_from_pytype.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\make_function.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\manage_new_object.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\module.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\module_init.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\numeric.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_attributes.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_call.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_core.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_fwd.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_items.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_operators.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_protocol.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_protocol_core.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\object_slices.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\operators.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\operators2.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\other.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\overloads.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\pointee.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\proxy.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\ptr.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\refcount.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\reference_existing_object.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\return_internal_reference.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\return_value_policy.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\scope.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\self.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\signature.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\slice_nil.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\str.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\tag.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\to_python_converter.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\to_python_indirect.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\to_python_value.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\tuple.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\type_id.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\..\boost\python\with_custodian_and_ward.hpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Resource Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
|
||||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "boost_python"=".\boost_python.dsp" - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Global:
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<3>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
241
build/bpl_static.dsp
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
# Microsoft Developer Studio Project File - Name="bpl_static" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||||
|
|
||||||
|
CFG=bpl_static - Win32 DebugPython
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "bpl_static.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "bpl_static.mak" CFG="bpl_static - Win32 DebugPython"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "bpl_static - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||||
|
!MESSAGE "bpl_static - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||||
|
!MESSAGE "bpl_static - Win32 DebugPython" (based on "Win32 (x86) Static Library")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=cl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "bpl_static - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /MD /W4 /WX /GR /GX /O2 /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LIB32=link.exe -lib
|
||||||
|
# ADD BASE LIB32 /nologo
|
||||||
|
# ADD LIB32 /nologo
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "bpl_static - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W4 /WX /Gm- /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LIB32=link.exe -lib
|
||||||
|
# ADD BASE LIB32 /nologo
|
||||||
|
# ADD LIB32 /nologo
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "bpl_static - Win32 DebugPython"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "bpl_static___Win32_DebugPython"
|
||||||
|
# PROP BASE Intermediate_Dir "bpl_static___Win32_DebugPython"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "DebugPython"
|
||||||
|
# PROP Intermediate_Dir "DebugPython"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MDd /W4 /WX /Gm /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W4 /WX /Gm- /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "BOOST_DEBUG_PYTHON" /FR /YX /FD /GZ /EHs /c
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LIB32=link.exe -lib
|
||||||
|
# ADD BASE LIB32 /nologo
|
||||||
|
# ADD LIB32 /nologo
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "bpl_static - Win32 Release"
|
||||||
|
# Name "bpl_static - Win32 Debug"
|
||||||
|
# Name "bpl_static - Win32 DebugPython"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\src\classes.cpp
|
||||||
|
# ADD CPP /W3
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\src\conversions.cpp
|
||||||
|
# ADD CPP /W3
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\src\extension_class.cpp
|
||||||
|
# ADD CPP /W3
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\src\functions.cpp
|
||||||
|
# ADD CPP /W3
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\src\init_function.cpp
|
||||||
|
# ADD CPP /W3
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\src\module_builder.cpp
|
||||||
|
# ADD CPP /W3
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\src\objects.cpp
|
||||||
|
# ADD CPP /W3
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\src\types.cpp
|
||||||
|
# ADD CPP /W3
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\base_object.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\callback.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\caller.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\cast.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\class_builder.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\classes.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\config.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\conversions.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\errors.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\extension_class.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\functions.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\init_function.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\module_builder.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\none.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\objects.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\operators.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\reference.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\signatures.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\singleton.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\types.hpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\..\boost\python\detail\wrap_python.hpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
||||||
108
build/build.dsw
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||||
|
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "bpl_static"=.\bpl_static.dsp - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "example1"=.\example1\example1.dsp - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
Begin Project Dependency
|
||||||
|
Project_Dep_Name bpl_static
|
||||||
|
End Project Dependency
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "getting_started1"=.\getting_started1\getting_started1.dsp - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
Begin Project Dependency
|
||||||
|
Project_Dep_Name bpl_static
|
||||||
|
End Project Dependency
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "getting_started2"=.\getting_started2\getting_started2.dsp - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
begin source code control
|
||||||
|
getting_started2
|
||||||
|
.\getting_started2
|
||||||
|
end source code control
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
Begin Project Dependency
|
||||||
|
Project_Dep_Name bpl_static
|
||||||
|
End Project Dependency
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "rwgk1"=.\rwgk1\rwgk1.dsp - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
Begin Project Dependency
|
||||||
|
Project_Dep_Name bpl_static
|
||||||
|
End Project Dependency
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Project: "test"=.\test\test.dsp - Package Owner=<4>
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<4>
|
||||||
|
{{{
|
||||||
|
Begin Project Dependency
|
||||||
|
Project_Dep_Name bpl_static
|
||||||
|
End Project Dependency
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Global:
|
||||||
|
|
||||||
|
Package=<5>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
Package=<3>
|
||||||
|
{{{
|
||||||
|
}}}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
BIN
build/build.opt
Normal file
58
build/como.mak
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Revision History:
|
||||||
|
# 17 Apr 01 include cross-module support, compile getting_started1 (R.W. Grosse-Kunstleve) UNTESTED!
|
||||||
|
# 06 Mar 01 Fixed typo in use of "PYTHON_LIB" (Dave Abrahams)
|
||||||
|
# 04 Mar 01 Changed library name to libboost_python.a (David Abrahams)
|
||||||
|
|
||||||
|
LIBSRC = \
|
||||||
|
classes.cpp \
|
||||||
|
conversions.cpp \
|
||||||
|
cross_module.cpp \
|
||||||
|
extension_class.cpp \
|
||||||
|
functions.cpp \
|
||||||
|
init_function.cpp \
|
||||||
|
module_builder.cpp \
|
||||||
|
objects.cpp \
|
||||||
|
types.cpp
|
||||||
|
|
||||||
|
LIBOBJ = $(LIBSRC:.cpp=.o)
|
||||||
|
OBJ = $(LIBOBJ)
|
||||||
|
|
||||||
|
|
||||||
|
ifeq "$(OS)" "Windows_NT"
|
||||||
|
PYTHON_LIB=c:/tools/python/libs/python15.lib
|
||||||
|
INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include
|
||||||
|
MODULE_EXTENSION=dll
|
||||||
|
else
|
||||||
|
INC = -I/usr/local/include/python1.5
|
||||||
|
MODULE_EXTENSION=so
|
||||||
|
endif
|
||||||
|
|
||||||
|
%.o: ../src/%.cpp
|
||||||
|
como --pic $(INC) -o $*.o -c $<
|
||||||
|
|
||||||
|
%.d: ../src/%.cpp
|
||||||
|
@echo creating $@
|
||||||
|
@set -e; como -M $(INC) -c $< \
|
||||||
|
| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
|
||||||
|
[ -s $@ ] || rm -f $@
|
||||||
|
|
||||||
|
getting_started1: getting_started1.o libboost_python.a
|
||||||
|
como-dyn-link -o ../example/getting_started1.$(MODULE_EXTENSION) $(PYTHON_LIB) getting_started1.o -L. -lboost_python
|
||||||
|
ln -s ../test/doctest.py ../example
|
||||||
|
python ../example/test_getting_started1.py
|
||||||
|
|
||||||
|
getting_started1.o: ../example/getting_started1.cpp
|
||||||
|
como --pic $(INC) -o $*.o -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out
|
||||||
|
|
||||||
|
libboost_python.a: $(LIBOBJ)
|
||||||
|
rm -f libboost_python.a
|
||||||
|
ar cq libboost_python.a $(LIBOBJ)
|
||||||
|
|
||||||
|
DEP = $(OBJ:.o=.d)
|
||||||
|
|
||||||
|
ifneq "$(MAKECMDGOALS)" "clean"
|
||||||
|
include $(DEP)
|
||||||
|
endif
|
||||||
136
build/example1/example1.dsp
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
# Microsoft Developer Studio Project File - Name="example1" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||||
|
|
||||||
|
CFG=example1 - Win32 DebugPython
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "example1.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "example1.mak" CFG="example1 - Win32 DebugPython"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "example1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "example1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "example1 - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=cl.exe
|
||||||
|
MTL=midl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "example1 - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /c
|
||||||
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/hello.dll" /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "example1 - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"Debug/hello.dll" /pdbtype:sept /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "example1 - Win32 DebugPython"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "example1___Win32_DebugPython"
|
||||||
|
# PROP BASE Intermediate_Dir "example1___Win32_DebugPython"
|
||||||
|
# PROP BASE Ignore_Export_Lib 0
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "DebugPython"
|
||||||
|
# PROP Intermediate_Dir "DebugPython"
|
||||||
|
# PROP Ignore_Export_Lib 1
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /EHs /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"Debug/hello.dll" /pdbtype:sept /libpath:"c:\tools\python\libs"
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"DebugPython/hello_d.dll" /pdbtype:sept /libpath:"c:\tools\python\src\PCbuild"
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "example1 - Win32 Release"
|
||||||
|
# Name "example1 - Win32 Debug"
|
||||||
|
# Name "example1 - Win32 DebugPython"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\example\example1.cpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Resource Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
||||||
142
build/filemgr.py
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
# Revision history:
|
||||||
|
# 12 Apr 01 use os.path, shutil
|
||||||
|
# Initial version: R.W. Grosse-Kunstleve
|
||||||
|
|
||||||
|
bpl_src = "/libs/python/src"
|
||||||
|
bpl_tst = "/libs/python/test"
|
||||||
|
bpl_exa = "/libs/python/example"
|
||||||
|
files = (
|
||||||
|
bpl_src + "/classes.cpp",
|
||||||
|
bpl_src + "/conversions.cpp",
|
||||||
|
bpl_src + "/extension_class.cpp",
|
||||||
|
bpl_src + "/functions.cpp",
|
||||||
|
bpl_src + "/init_function.cpp",
|
||||||
|
bpl_src + "/module_builder.cpp",
|
||||||
|
bpl_src + "/objects.cpp",
|
||||||
|
bpl_src + "/types.cpp",
|
||||||
|
bpl_src + "/cross_module.cpp",
|
||||||
|
bpl_tst + "/comprehensive.cpp",
|
||||||
|
bpl_tst + "/comprehensive.hpp",
|
||||||
|
bpl_tst + "/comprehensive.py",
|
||||||
|
bpl_tst + "/doctest.py",
|
||||||
|
bpl_exa + "/abstract.cpp",
|
||||||
|
bpl_exa + "/getting_started1.cpp",
|
||||||
|
bpl_exa + "/getting_started2.cpp",
|
||||||
|
bpl_exa + "/simple_vector.cpp",
|
||||||
|
bpl_exa + "/do_it_yourself_converters.cpp",
|
||||||
|
bpl_exa + "/pickle1.cpp",
|
||||||
|
bpl_exa + "/pickle2.cpp",
|
||||||
|
bpl_exa + "/pickle3.cpp",
|
||||||
|
bpl_exa + "/test_abstract.py",
|
||||||
|
bpl_exa + "/test_getting_started1.py",
|
||||||
|
bpl_exa + "/test_getting_started2.py",
|
||||||
|
bpl_exa + "/test_simple_vector.py",
|
||||||
|
bpl_exa + "/test_do_it_yourself_converters.py",
|
||||||
|
bpl_exa + "/test_pickle1.py",
|
||||||
|
bpl_exa + "/test_pickle2.py",
|
||||||
|
bpl_exa + "/test_pickle3.py",
|
||||||
|
bpl_exa + "/noncopyable.h",
|
||||||
|
bpl_exa + "/noncopyable_export.cpp",
|
||||||
|
bpl_exa + "/noncopyable_import.cpp",
|
||||||
|
bpl_exa + "/dvect.h",
|
||||||
|
bpl_exa + "/dvect.cpp",
|
||||||
|
bpl_exa + "/dvect_conversions.cpp",
|
||||||
|
bpl_exa + "/dvect_defs.cpp",
|
||||||
|
bpl_exa + "/ivect.h",
|
||||||
|
bpl_exa + "/ivect.cpp",
|
||||||
|
bpl_exa + "/ivect_conversions.cpp",
|
||||||
|
bpl_exa + "/ivect_defs.cpp",
|
||||||
|
bpl_exa + "/tst_noncopyable.py",
|
||||||
|
bpl_exa + "/tst_dvect1.py",
|
||||||
|
bpl_exa + "/tst_dvect2.py",
|
||||||
|
bpl_exa + "/tst_ivect1.py",
|
||||||
|
bpl_exa + "/tst_ivect2.py",
|
||||||
|
bpl_exa + "/test_cross_module.py",
|
||||||
|
bpl_exa + "/vector_wrapper.h",
|
||||||
|
bpl_exa + "/richcmp1.cpp",
|
||||||
|
bpl_exa + "/richcmp2.cpp",
|
||||||
|
bpl_exa + "/richcmp3.cpp",
|
||||||
|
bpl_exa + "/test_richcmp1.py",
|
||||||
|
bpl_exa + "/test_richcmp2.py",
|
||||||
|
bpl_exa + "/test_richcmp3.py",
|
||||||
|
)
|
||||||
|
|
||||||
|
defs = (
|
||||||
|
"boost_python_test",
|
||||||
|
"abstract",
|
||||||
|
"getting_started1",
|
||||||
|
"getting_started2",
|
||||||
|
"simple_vector",
|
||||||
|
"do_it_yourself_converters",
|
||||||
|
"pickle1",
|
||||||
|
"pickle2",
|
||||||
|
"pickle3",
|
||||||
|
"noncopyable_export",
|
||||||
|
"noncopyable_import",
|
||||||
|
"ivect",
|
||||||
|
"dvect",
|
||||||
|
"richcmp1",
|
||||||
|
"richcmp2",
|
||||||
|
"richcmp3",
|
||||||
|
)
|
||||||
|
|
||||||
|
if (__name__ == "__main__"):
|
||||||
|
|
||||||
|
import sys, os, shutil
|
||||||
|
|
||||||
|
path = sys.argv[1]
|
||||||
|
mode = sys.argv[2]
|
||||||
|
if (not mode in ("softlinks", "unlink", "cp", "rm", "copy", "del")):
|
||||||
|
raise RuntimeError, \
|
||||||
|
"usage: python filemgr.py path <softlinks|unlink|cp|rm|copy|del>"
|
||||||
|
|
||||||
|
if (mode in ("cp", "copy")):
|
||||||
|
for fn in files:
|
||||||
|
f = os.path.basename(fn)
|
||||||
|
print "Copying: " + f
|
||||||
|
shutil.copy(path + fn, ".")
|
||||||
|
|
||||||
|
elif (mode == "softlinks"):
|
||||||
|
for fn in files:
|
||||||
|
f = os.path.basename(fn)
|
||||||
|
if (os.path.exists(f)):
|
||||||
|
print "File exists: " + f
|
||||||
|
else:
|
||||||
|
print "Linking: " + f
|
||||||
|
os.symlink(path + fn, f)
|
||||||
|
|
||||||
|
elif (mode in ("rm", "del")):
|
||||||
|
for fn in files:
|
||||||
|
f = os.path.basename(fn)
|
||||||
|
if (os.path.exists(f)):
|
||||||
|
print "Removing: " + f
|
||||||
|
try: os.unlink(f)
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
elif (mode == "unlink"):
|
||||||
|
for fn in files:
|
||||||
|
f = os.path.basename(fn)
|
||||||
|
if (os.path.exists(f)):
|
||||||
|
if (os.path.islink(f)):
|
||||||
|
print "Unlinking: " + f
|
||||||
|
try: os.unlink(f)
|
||||||
|
except: pass
|
||||||
|
else:
|
||||||
|
print "Not a softlink: " + f
|
||||||
|
|
||||||
|
if (mode in ("softlinks", "cp", "copy")):
|
||||||
|
for d in defs:
|
||||||
|
fn = d + ".def"
|
||||||
|
print "Creating: " + fn
|
||||||
|
f = open(fn, "w")
|
||||||
|
f.write("EXPORTS\n")
|
||||||
|
f.write("\tinit" + d + "\n")
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
if (mode in ("unlink", "rm", "del")):
|
||||||
|
for d in defs:
|
||||||
|
fn = d + ".def"
|
||||||
|
if (os.path.exists(fn)):
|
||||||
|
print "Removing: " + fn
|
||||||
|
try: os.unlink(fn)
|
||||||
|
except: pass
|
||||||
87
build/gcc.mak
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Revision History
|
||||||
|
|
||||||
|
# 17 Apr 01 include cross-module support, compile getting_started1 (R.W. Grosse-Kunstleve)
|
||||||
|
# 17 Apr 01 build shared library (patch provided by Dan Nuffer)
|
||||||
|
# 04 Mar 01 Changed library name to libboost_python.a, various cleanups,
|
||||||
|
# attempted Cygwin compatibility. Still needs testing on Linux
|
||||||
|
# (David Abrahams)
|
||||||
|
|
||||||
|
|
||||||
|
LIBSRC = \
|
||||||
|
classes.cpp \
|
||||||
|
conversions.cpp \
|
||||||
|
cross_module.cpp \
|
||||||
|
extension_class.cpp \
|
||||||
|
functions.cpp \
|
||||||
|
init_function.cpp \
|
||||||
|
module_builder.cpp \
|
||||||
|
objects.cpp \
|
||||||
|
types.cpp
|
||||||
|
|
||||||
|
LIBOBJ = $(LIBSRC:.cpp=.o)
|
||||||
|
OBJ = $(LIBOBJ)
|
||||||
|
|
||||||
|
LIBNAME = libboost_python
|
||||||
|
# libpython2.0.dll
|
||||||
|
|
||||||
|
ifeq "$(OS)" "Windows_NT"
|
||||||
|
ROOT=c:/cygnus
|
||||||
|
INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -I$(PYTHON_INC)
|
||||||
|
MODULE_EXTENSION=dll
|
||||||
|
PYTHON_LIB=c:/cygnus/usr/local/lib/python2.0/config/libpython2.0.dll.a
|
||||||
|
SHARED_LIB = $(LIBNAME).dll
|
||||||
|
else
|
||||||
|
PYTHON_INC=$(ROOT)/usr/local/Python-2.0/include/python2.0
|
||||||
|
BOOST_INC=../../..
|
||||||
|
INC = -I$(BOOST_INC) -I$(PYTHON_INC)
|
||||||
|
MODULE_EXTENSION=so
|
||||||
|
VERSION=1
|
||||||
|
SHARED_LIB = $(LIBNAME).so.$(VERSION)
|
||||||
|
endif
|
||||||
|
|
||||||
|
%.o: ../src/%.cpp
|
||||||
|
g++ -fPIC -Wall -W $(INC) $(CXXFLAGS) -o $*.o -c $<
|
||||||
|
|
||||||
|
%.d: ../src/%.cpp
|
||||||
|
@echo creating $@
|
||||||
|
@set -e; g++ -M $(INC) -c $< \
|
||||||
|
| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
|
||||||
|
[ -s $@ ] || rm -f $@
|
||||||
|
|
||||||
|
|
||||||
|
PYTHON = python
|
||||||
|
|
||||||
|
all: test $(SHARED_LIB) getting_started1
|
||||||
|
|
||||||
|
test: comprehensive.o $(LIBNAME).a $(SHARED_LIB)
|
||||||
|
g++ $(CXXFLAGS) -shared -o ../test/boost_python_test.$(MODULE_EXTENSION) comprehensive.o -L. -lboost_python $(PYTHON_LIB)
|
||||||
|
$(PYTHON) ../test/comprehensive.py
|
||||||
|
|
||||||
|
comprehensive.o: ../test/comprehensive.cpp
|
||||||
|
g++ $(CXXFLAGS) --template-depth-32 -fPIC -Wall -W $(INC) -o $*.o -c $<
|
||||||
|
|
||||||
|
|
||||||
|
getting_started1: getting_started1.o $(LIBNAME).a
|
||||||
|
g++ $(CXXFLAGS) -shared -o ../example/getting_started1.$(MODULE_EXTENSION) getting_started1.o -L. -lboost_python $(PYTHON_LIB)
|
||||||
|
ln -s ../test/doctest.py ../example
|
||||||
|
$(PYTHON) ../example/test_getting_started1.py
|
||||||
|
|
||||||
|
getting_started1.o: ../example/getting_started1.cpp
|
||||||
|
g++ $(CXXFLAGS) --template-depth-32 -fPIC -Wall -W $(INC) -o $*.o -c $<
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out
|
||||||
|
|
||||||
|
$(LIBNAME).a: $(LIBOBJ)
|
||||||
|
rm -f $@
|
||||||
|
ar cqs $@ $(LIBOBJ)
|
||||||
|
|
||||||
|
$(SHARED_LIB): $(LIBOBJ)
|
||||||
|
g++ $(CXXFLAGS) -shared -o $@ -Wl,--soname=$(LIBNAME).$(MODULE_EXTENSION)
|
||||||
|
|
||||||
|
DEP = $(OBJ:.o=.d)
|
||||||
|
|
||||||
|
ifneq "$(MAKECMDGOALS)" "clean"
|
||||||
|
include $(DEP)
|
||||||
|
endif
|
||||||
136
build/getting_started1/getting_started1.dsp
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
# Microsoft Developer Studio Project File - Name="getting_started1" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||||
|
|
||||||
|
CFG=getting_started1 - Win32 DebugPython
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "getting_started1.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "getting_started1.mak" CFG="getting_started1 - Win32 DebugPython"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "getting_started1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "getting_started1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "getting_started1 - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=xicl6.exe
|
||||||
|
MTL=midl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "getting_started1 - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||||
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=xilink6.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "getting_started1 - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /GR /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=xilink6.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "getting_started1 - Win32 DebugPython"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "DebugPython"
|
||||||
|
# PROP BASE Intermediate_Dir "DebugPython"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "DebugPython"
|
||||||
|
# PROP Intermediate_Dir "DebugPython"
|
||||||
|
# PROP Ignore_Export_Lib 1
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=xilink6.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /pdb:"DebugPython/boost_python_test_d.pdb" /debug /machine:I386 /out:"DebugPython/getting_started1_d.dll" /pdbtype:sept /libpath:"c:\tools\python\src\PCbuild"
|
||||||
|
# SUBTRACT LINK32 /pdb:none
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "getting_started1 - Win32 Release"
|
||||||
|
# Name "getting_started1 - Win32 Debug"
|
||||||
|
# Name "getting_started1 - Win32 DebugPython"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\example\getting_started1.cpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Resource Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
||||||
135
build/getting_started2/getting_started2.dsp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# Microsoft Developer Studio Project File - Name="getting_started2" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||||
|
|
||||||
|
CFG=getting_started2 - Win32 DebugPython
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "getting_started2.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "getting_started2.mak" CFG="getting_started2 - Win32 DebugPython"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "getting_started2 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "getting_started2 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "getting_started2 - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName "getting_started2"
|
||||||
|
# PROP Scc_LocalPath "."
|
||||||
|
CPP=xicl6.exe
|
||||||
|
MTL=midl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "getting_started2 - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||||
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=xilink6.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "getting_started2 - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=xilink6.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "getting_started2 - Win32 DebugPython"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "getting_started2___Win32_DebugPython"
|
||||||
|
# PROP BASE Intermediate_Dir "getting_started2___Win32_DebugPython"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "getting_started2___Win32_DebugPython"
|
||||||
|
# PROP Intermediate_Dir "getting_started2___Win32_DebugPython"
|
||||||
|
# PROP Ignore_Export_Lib 1
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /D "BOOST_DEBUG_PYTHON" /FR /YX /FD /GZ /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=xilink6.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"DebugPython/getting_started2_d.dll" /pdbtype:sept /libpath:"c:\tools\python\src\pcbuild"
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "getting_started2 - Win32 Release"
|
||||||
|
# Name "getting_started2 - Win32 Debug"
|
||||||
|
# Name "getting_started2 - Win32 DebugPython"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\example\getting_started2.cpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Resource Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
||||||
177
build/irix_CC.mak
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# Create a new empty directory anywhere (preferably not in the boost tree).
|
||||||
|
# Copy this Makefile to that new directory and rename it to "Makefile"
|
||||||
|
# Adjust the pathnames below.
|
||||||
|
#
|
||||||
|
# make softlinks Create softlinks to source code and tests
|
||||||
|
# make Compile all sources
|
||||||
|
# make test Run doctest tests
|
||||||
|
# make clean Remove all object files
|
||||||
|
# make unlink Remove softlinks
|
||||||
|
#
|
||||||
|
# Revision history:
|
||||||
|
# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve)
|
||||||
|
# Initial version: R.W. Grosse-Kunstleve
|
||||||
|
|
||||||
|
ROOT=$(HOME)
|
||||||
|
BOOST=$(ROOT)/boost
|
||||||
|
|
||||||
|
PYEXE=/usr/local/Python-1.5.2/bin/python
|
||||||
|
PYINC=-I/usr/local/Python-1.5.2/include/python1.5
|
||||||
|
#PYEXE=/usr/local/Python-2.1/bin/python
|
||||||
|
#PYINC=-I/usr/local/Python-2.1/include/python2.1
|
||||||
|
STLPORTINC=-I$(BOOST)/boost/compatibility/cpp_c_headers
|
||||||
|
|
||||||
|
STDOPTS=
|
||||||
|
WARNOPTS=-woff 1001,1234,1682
|
||||||
|
OPTOPTS=-g
|
||||||
|
|
||||||
|
CPP=CC -LANG:std -n32 -mips4
|
||||||
|
CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \
|
||||||
|
$(STDOPTS) $(WARNOPTS) $(OPTOPTS)
|
||||||
|
MAKEDEP=-M
|
||||||
|
|
||||||
|
LD=CC -LANG:std -n32 -mips4
|
||||||
|
LDOPTS=-shared
|
||||||
|
|
||||||
|
OBJ=classes.o conversions.o extension_class.o functions.o \
|
||||||
|
init_function.o module_builder.o \
|
||||||
|
objects.o types.o cross_module.o
|
||||||
|
DEPOBJ=$(OBJ) \
|
||||||
|
comprehensive.o \
|
||||||
|
abstract.o \
|
||||||
|
getting_started1.o getting_started2.o \
|
||||||
|
simple_vector.o \
|
||||||
|
do_it_yourself_converters.o \
|
||||||
|
pickle1.o pickle2.o pickle3.o \
|
||||||
|
noncopyable_export.o noncopyable_import.o \
|
||||||
|
ivect.o dvect.o \
|
||||||
|
richcmp1.o richcmp2.o richcmp3.o
|
||||||
|
|
||||||
|
.SUFFIXES: .o .cpp
|
||||||
|
|
||||||
|
all: libboost_python.a \
|
||||||
|
boost_python_test.so \
|
||||||
|
abstract.so \
|
||||||
|
getting_started1.so getting_started2.so \
|
||||||
|
simple_vector.so \
|
||||||
|
do_it_yourself_converters.so \
|
||||||
|
pickle1.so pickle2.so pickle3.so \
|
||||||
|
noncopyable_export.so noncopyable_import.so \
|
||||||
|
ivect.so dvect.so \
|
||||||
|
richcmp1.so richcmp2.so richcmp3.so
|
||||||
|
|
||||||
|
libboost_python.a: $(OBJ)
|
||||||
|
rm -f libboost_python.a
|
||||||
|
$(CPP) -ar -o libboost_python.a $(OBJ)
|
||||||
|
|
||||||
|
boost_python_test.so: $(OBJ) comprehensive.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm
|
||||||
|
|
||||||
|
abstract.so: $(OBJ) abstract.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so
|
||||||
|
|
||||||
|
getting_started1.so: $(OBJ) getting_started1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) getting_started1.o -o getting_started1.so
|
||||||
|
|
||||||
|
getting_started2.so: $(OBJ) getting_started2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so
|
||||||
|
|
||||||
|
simple_vector.so: $(OBJ) simple_vector.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so
|
||||||
|
|
||||||
|
do_it_yourself_converters.so: $(OBJ) do_it_yourself_converters.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.o -o do_it_yourself_converters.so
|
||||||
|
|
||||||
|
pickle1.so: $(OBJ) pickle1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle1.o -o pickle1.so
|
||||||
|
|
||||||
|
pickle2.so: $(OBJ) pickle2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle2.o -o pickle2.so
|
||||||
|
|
||||||
|
pickle3.so: $(OBJ) pickle3.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle3.o -o pickle3.so
|
||||||
|
|
||||||
|
noncopyable_export.so: $(OBJ) noncopyable_export.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \
|
||||||
|
noncopyable_export.o -o noncopyable_export.so
|
||||||
|
|
||||||
|
noncopyable_import.so: $(OBJ) noncopyable_import.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \
|
||||||
|
noncopyable_import.o -o noncopyable_import.so
|
||||||
|
|
||||||
|
ivect.so: $(OBJ) ivect.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) ivect.o -o ivect.so
|
||||||
|
|
||||||
|
dvect.so: $(OBJ) dvect.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so
|
||||||
|
|
||||||
|
richcmp1.so: $(OBJ) richcmp1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp1.o -o richcmp1.so
|
||||||
|
|
||||||
|
richcmp2.so: $(OBJ) richcmp2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp2.o -o richcmp2.so
|
||||||
|
|
||||||
|
richcmp3.so: $(OBJ) richcmp3.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp3.o -o richcmp3.so
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CPP) $(CPPOPTS) -c $*.cpp
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(PYEXE) comprehensive.py
|
||||||
|
$(PYEXE) test_abstract.py
|
||||||
|
$(PYEXE) test_getting_started1.py
|
||||||
|
$(PYEXE) test_getting_started2.py
|
||||||
|
$(PYEXE) test_simple_vector.py
|
||||||
|
$(PYEXE) test_do_it_yourself_converters.py
|
||||||
|
$(PYEXE) test_pickle1.py
|
||||||
|
$(PYEXE) test_pickle2.py
|
||||||
|
$(PYEXE) test_pickle3.py
|
||||||
|
$(PYEXE) test_cross_module.py
|
||||||
|
$(PYEXE) test_richcmp1.py
|
||||||
|
$(PYEXE) test_richcmp2.py
|
||||||
|
$(PYEXE) test_richcmp3.py
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ) libboost_python.a libboost_python.a.input
|
||||||
|
rm -f comprehensive.o boost_python_test.so
|
||||||
|
rm -f abstract.o abstract.so
|
||||||
|
rm -f getting_started1.o getting_started1.so
|
||||||
|
rm -f getting_started2.o getting_started2.so
|
||||||
|
rm -f simple_vector.o simple_vector.so
|
||||||
|
rm -f do_it_yourself_converters.o do_it_yourself_converters.so
|
||||||
|
rm -f pickle1.o pickle1.so
|
||||||
|
rm -f pickle2.o pickle2.so
|
||||||
|
rm -f pickle3.o pickle3.so
|
||||||
|
rm -f noncopyable_export.o noncopyable_export.so
|
||||||
|
rm -f noncopyable_import.o noncopyable_import.so
|
||||||
|
rm -f ivect.o ivect.so
|
||||||
|
rm -f dvect.o dvect.so
|
||||||
|
rm -f richcmp1.o richcmp1.so
|
||||||
|
rm -f richcmp2.o richcmp2.so
|
||||||
|
rm -f richcmp3.o richcmp3.so
|
||||||
|
rm -f so_locations *.pyc
|
||||||
|
rm -rf ii_files
|
||||||
|
|
||||||
|
softlinks:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) softlinks
|
||||||
|
|
||||||
|
unlink:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) unlink
|
||||||
|
|
||||||
|
cp:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) cp
|
||||||
|
|
||||||
|
rm:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) rm
|
||||||
|
|
||||||
|
depend:
|
||||||
|
@ cat Makefile.nodepend; \
|
||||||
|
for obj in $(DEPOBJ); \
|
||||||
|
do \
|
||||||
|
bn=`echo "$$obj" | cut -d. -f1`; \
|
||||||
|
$(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \
|
||||||
|
done
|
||||||
|
|
||||||
177
build/linux_gcc.mak
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# Create a new empty directory anywhere (preferably not in the boost tree).
|
||||||
|
# Copy this Makefile to that new directory and rename it to "Makefile"
|
||||||
|
# Adjust the pathnames below.
|
||||||
|
#
|
||||||
|
# make softlinks Create softlinks to source code and tests
|
||||||
|
# make Compile all sources
|
||||||
|
# make test Run doctest tests
|
||||||
|
# make clean Remove all object files
|
||||||
|
# make unlink Remove softlinks
|
||||||
|
#
|
||||||
|
# Revision history:
|
||||||
|
# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve)
|
||||||
|
# Initial version: R.W. Grosse-Kunstleve
|
||||||
|
|
||||||
|
ROOT=$(HOME)
|
||||||
|
BOOST=$(ROOT)/boost
|
||||||
|
|
||||||
|
PYEXE=PYTHONPATH=. /usr/bin/python
|
||||||
|
PYINC=-I/usr/include/python1.5
|
||||||
|
#PYEXE=/usr/local/Python-1.5.2/bin/python
|
||||||
|
#PYINC=-I/usr/local/Python-1.5.2/include/python1.5
|
||||||
|
#PYEXE=/usr/local/Python-2.1/bin/python
|
||||||
|
#PYINC=-I/usr/local/Python-2.1/include/python2.1
|
||||||
|
|
||||||
|
STDOPTS=-fPIC -ftemplate-depth-21
|
||||||
|
WARNOPTS=
|
||||||
|
OPTOPTS=-g
|
||||||
|
|
||||||
|
CPP=g++
|
||||||
|
CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \
|
||||||
|
$(STDOPTS) $(WARNOPTS) $(OPTOPTS)
|
||||||
|
MAKEDEP=-M
|
||||||
|
|
||||||
|
LD=$(CPP)
|
||||||
|
LDOPTS=-shared
|
||||||
|
|
||||||
|
OBJ=classes.o conversions.o extension_class.o functions.o \
|
||||||
|
init_function.o module_builder.o \
|
||||||
|
objects.o types.o cross_module.o
|
||||||
|
DEPOBJ=$(OBJ) \
|
||||||
|
comprehensive.o \
|
||||||
|
abstract.o \
|
||||||
|
getting_started1.o getting_started2.o \
|
||||||
|
simple_vector.o \
|
||||||
|
do_it_yourself_converters.o \
|
||||||
|
pickle1.o pickle2.o pickle3.o \
|
||||||
|
noncopyable_export.o noncopyable_import.o \
|
||||||
|
ivect.o dvect.o \
|
||||||
|
richcmp1.o richcmp2.o richcmp3.o
|
||||||
|
|
||||||
|
.SUFFIXES: .o .cpp
|
||||||
|
|
||||||
|
all: libboost_python.a \
|
||||||
|
boost_python_test.so \
|
||||||
|
abstract.so \
|
||||||
|
getting_started1.so getting_started2.so \
|
||||||
|
simple_vector.so \
|
||||||
|
do_it_yourself_converters.so \
|
||||||
|
pickle1.so pickle2.so pickle3.so \
|
||||||
|
noncopyable_export.so noncopyable_import.so \
|
||||||
|
ivect.so dvect.so \
|
||||||
|
richcmp1.so richcmp2.so richcmp3.so
|
||||||
|
|
||||||
|
libboost_python.a: $(OBJ)
|
||||||
|
rm -f libboost_python.a
|
||||||
|
ar r libboost_python.a $(OBJ)
|
||||||
|
|
||||||
|
boost_python_test.so: $(OBJ) comprehensive.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm
|
||||||
|
|
||||||
|
abstract.so: $(OBJ) abstract.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so
|
||||||
|
|
||||||
|
getting_started1.so: $(OBJ) getting_started1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) getting_started1.o -o getting_started1.so
|
||||||
|
|
||||||
|
getting_started2.so: $(OBJ) getting_started2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so
|
||||||
|
|
||||||
|
simple_vector.so: $(OBJ) simple_vector.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so
|
||||||
|
|
||||||
|
do_it_yourself_converters.so: $(OBJ) do_it_yourself_converters.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.o -o do_it_yourself_converters.so
|
||||||
|
|
||||||
|
pickle1.so: $(OBJ) pickle1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle1.o -o pickle1.so
|
||||||
|
|
||||||
|
pickle2.so: $(OBJ) pickle2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle2.o -o pickle2.so
|
||||||
|
|
||||||
|
pickle3.so: $(OBJ) pickle3.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle3.o -o pickle3.so
|
||||||
|
|
||||||
|
noncopyable_export.so: $(OBJ) noncopyable_export.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \
|
||||||
|
noncopyable_export.o -o noncopyable_export.so
|
||||||
|
|
||||||
|
noncopyable_import.so: $(OBJ) noncopyable_import.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \
|
||||||
|
noncopyable_import.o -o noncopyable_import.so
|
||||||
|
|
||||||
|
ivect.so: $(OBJ) ivect.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) ivect.o -o ivect.so
|
||||||
|
|
||||||
|
dvect.so: $(OBJ) dvect.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so
|
||||||
|
|
||||||
|
richcmp1.so: $(OBJ) richcmp1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp1.o -o richcmp1.so
|
||||||
|
|
||||||
|
richcmp2.so: $(OBJ) richcmp2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp2.o -o richcmp2.so
|
||||||
|
|
||||||
|
richcmp3.so: $(OBJ) richcmp3.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp3.o -o richcmp3.so
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CPP) $(CPPOPTS) -c $*.cpp
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(PYEXE) comprehensive.py
|
||||||
|
$(PYEXE) test_abstract.py
|
||||||
|
$(PYEXE) test_getting_started1.py
|
||||||
|
$(PYEXE) test_getting_started2.py
|
||||||
|
$(PYEXE) test_simple_vector.py
|
||||||
|
$(PYEXE) test_do_it_yourself_converters.py
|
||||||
|
$(PYEXE) test_pickle1.py
|
||||||
|
$(PYEXE) test_pickle2.py
|
||||||
|
$(PYEXE) test_pickle3.py
|
||||||
|
$(PYEXE) test_cross_module.py
|
||||||
|
$(PYEXE) test_richcmp1.py
|
||||||
|
$(PYEXE) test_richcmp2.py
|
||||||
|
$(PYEXE) test_richcmp3.py
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ) libboost_python.a libboost_python.a.input
|
||||||
|
rm -f comprehensive.o boost_python_test.so
|
||||||
|
rm -f abstract.o abstract.so
|
||||||
|
rm -f getting_started1.o getting_started1.so
|
||||||
|
rm -f getting_started2.o getting_started2.so
|
||||||
|
rm -f simple_vector.o simple_vector.so
|
||||||
|
rm -f do_it_yourself_converters.o do_it_yourself_converters.so
|
||||||
|
rm -f pickle1.o pickle1.so
|
||||||
|
rm -f pickle2.o pickle2.so
|
||||||
|
rm -f pickle3.o pickle3.so
|
||||||
|
rm -f noncopyable_export.o noncopyable_export.so
|
||||||
|
rm -f noncopyable_import.o noncopyable_import.so
|
||||||
|
rm -f ivect.o ivect.so
|
||||||
|
rm -f dvect.o dvect.so
|
||||||
|
rm -f richcmp1.o richcmp1.so
|
||||||
|
rm -f richcmp2.o richcmp2.so
|
||||||
|
rm -f richcmp3.o richcmp3.so
|
||||||
|
rm -f so_locations *.pyc
|
||||||
|
|
||||||
|
softlinks:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) softlinks
|
||||||
|
|
||||||
|
unlink:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) unlink
|
||||||
|
|
||||||
|
cp:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) cp
|
||||||
|
|
||||||
|
rm:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) rm
|
||||||
|
|
||||||
|
depend:
|
||||||
|
@ cat Makefile.nodepend; \
|
||||||
|
for obj in $(DEPOBJ); \
|
||||||
|
do \
|
||||||
|
bn=`echo "$$obj" | cut -d. -f1`; \
|
||||||
|
$(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \
|
||||||
|
done
|
||||||
|
|
||||||
211
build/mingw32.mak
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# make copy Copy the sources and tests
|
||||||
|
# make Compile all sources
|
||||||
|
# make test Run doctest tests
|
||||||
|
# make clean Remove all object files
|
||||||
|
# make del Remove the sources and tests
|
||||||
|
#
|
||||||
|
# Revision history:
|
||||||
|
# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve)
|
||||||
|
# Initial version: R.W. Grosse-Kunstleve
|
||||||
|
|
||||||
|
# To install mingw32, follow instructions at:
|
||||||
|
# http://starship.python.net/crew/kernr/mingw32/Notes.html
|
||||||
|
# In particular, install:
|
||||||
|
# ftp://ftp.xraylith.wisc.edu/pub/khan/gnu-win32/mingw32/gcc-2.95.2/gcc-2.95.2-msvcrt.exe
|
||||||
|
# ftp://ftp.xraylith.wisc.edu/pub/khan/gnu-win32/mingw32/gcc-2.95.2/fixes/quote-fix-msvcrt.exe
|
||||||
|
# http://starship.python.net/crew/kernr/mingw32/Python-1.5.2-mingw32.zip
|
||||||
|
# Unpack the first two archives in the default locations and update your PATH.
|
||||||
|
# Unpack the third archive in \usr.
|
||||||
|
|
||||||
|
# Note: comprehensive.cpp generates compiler errors and later crashes.
|
||||||
|
# L:\boost\boost\python\detail\extension_class.hpp:643: warning:
|
||||||
|
# alignment of `vtable for class
|
||||||
|
# boost::python::detail::held_instance<bpl_test::Derived1>'
|
||||||
|
# is greater than maximum object file alignment. Using 16.
|
||||||
|
# Could this be fixed with compiler options?
|
||||||
|
# -fhuge-objects looks interesting, but requires recompiling the C++ library.
|
||||||
|
# (what exactly does that mean?)
|
||||||
|
# -fvtable-thunks eliminates the compiler warning, but
|
||||||
|
# "import boost_python_test" still causes a crash.
|
||||||
|
|
||||||
|
ROOT=L:
|
||||||
|
BOOST_WIN="$(ROOT)\boost"
|
||||||
|
BOOST_UNIX=$(HOME)/boost
|
||||||
|
|
||||||
|
PYEXE="C:\Program files\Python\python.exe"
|
||||||
|
PYINC=-I"C:\usr\include\python1.5"
|
||||||
|
PYLIB="C:\usr\lib\libpython15.a"
|
||||||
|
|
||||||
|
STDOPTS=-ftemplate-depth-21
|
||||||
|
WARNOPTS=
|
||||||
|
OPTOPTS=-g
|
||||||
|
|
||||||
|
CPP=g++
|
||||||
|
CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST_WIN) $(PYINC) \
|
||||||
|
$(STDOPTS) $(WARNOPTS) $(OPTOPTS)
|
||||||
|
|
||||||
|
LD=g++
|
||||||
|
LDOPTS=-shared
|
||||||
|
|
||||||
|
OBJ=classes.o conversions.o extension_class.o functions.o \
|
||||||
|
init_function.o module_builder.o \
|
||||||
|
objects.o types.o cross_module.o
|
||||||
|
|
||||||
|
.SUFFIXES: .o .cpp
|
||||||
|
|
||||||
|
all: libboost_python.a \
|
||||||
|
abstract.pyd \
|
||||||
|
getting_started1.pyd getting_started2.pyd \
|
||||||
|
simple_vector.pyd \
|
||||||
|
do_it_yourself_converters.pyd \
|
||||||
|
pickle1.pyd pickle2.pyd pickle3.pyd \
|
||||||
|
noncopyable_export.pyd noncopyable_import.pyd \
|
||||||
|
ivect.pyd dvect.pyd \
|
||||||
|
richcmp1.pyd richcmp2.pyd richcmp3.pyd
|
||||||
|
|
||||||
|
libboost_python.a: $(OBJ)
|
||||||
|
-del libboost_python.a
|
||||||
|
ar r libboost_python.a $(OBJ)
|
||||||
|
|
||||||
|
DLLWRAPOPTS=-s --driver-name g++ -s \
|
||||||
|
--entry _DllMainCRTStartup@12 --target=i386-mingw32
|
||||||
|
|
||||||
|
boost_python_test.pyd: $(OBJ) comprehensive.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname boost_python_test.pyd \
|
||||||
|
--def boost_python_test.def \
|
||||||
|
$(OBJ) comprehensive.o $(PYLIB)
|
||||||
|
|
||||||
|
abstract.pyd: $(OBJ) abstract.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname abstract.pyd \
|
||||||
|
--def abstract.def \
|
||||||
|
$(OBJ) abstract.o $(PYLIB)
|
||||||
|
|
||||||
|
getting_started1.pyd: $(OBJ) getting_started1.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname getting_started1.pyd \
|
||||||
|
--def getting_started1.def \
|
||||||
|
$(OBJ) getting_started1.o $(PYLIB)
|
||||||
|
|
||||||
|
getting_started2.pyd: $(OBJ) getting_started2.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname getting_started2.pyd \
|
||||||
|
--def getting_started2.def \
|
||||||
|
$(OBJ) getting_started2.o $(PYLIB)
|
||||||
|
|
||||||
|
simple_vector.pyd: $(OBJ) simple_vector.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname simple_vector.pyd \
|
||||||
|
--def simple_vector.def \
|
||||||
|
$(OBJ) simple_vector.o $(PYLIB)
|
||||||
|
|
||||||
|
do_it_yourself_converters.pyd: $(OBJ) do_it_yourself_converters.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname do_it_yourself_converters.pyd \
|
||||||
|
--def do_it_yourself_converters.def \
|
||||||
|
$(OBJ) do_it_yourself_converters.o $(PYLIB)
|
||||||
|
|
||||||
|
pickle1.pyd: $(OBJ) pickle1.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname pickle1.pyd \
|
||||||
|
--def pickle1.def \
|
||||||
|
$(OBJ) pickle1.o $(PYLIB)
|
||||||
|
|
||||||
|
pickle2.pyd: $(OBJ) pickle2.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname pickle2.pyd \
|
||||||
|
--def pickle2.def \
|
||||||
|
$(OBJ) pickle2.o $(PYLIB)
|
||||||
|
|
||||||
|
pickle3.pyd: $(OBJ) pickle3.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname pickle3.pyd \
|
||||||
|
--def pickle3.def \
|
||||||
|
$(OBJ) pickle3.o $(PYLIB)
|
||||||
|
|
||||||
|
noncopyable_export.pyd: $(OBJ) noncopyable_export.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname noncopyable_export.pyd \
|
||||||
|
--def noncopyable_export.def \
|
||||||
|
$(OBJ) noncopyable_export.o $(PYLIB)
|
||||||
|
|
||||||
|
noncopyable_import.pyd: $(OBJ) noncopyable_import.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname noncopyable_import.pyd \
|
||||||
|
--def noncopyable_import.def \
|
||||||
|
$(OBJ) noncopyable_import.o $(PYLIB)
|
||||||
|
|
||||||
|
ivect.pyd: $(OBJ) ivect.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname ivect.pyd \
|
||||||
|
--def ivect.def \
|
||||||
|
$(OBJ) ivect.o $(PYLIB)
|
||||||
|
|
||||||
|
dvect.pyd: $(OBJ) dvect.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname dvect.pyd \
|
||||||
|
--def dvect.def \
|
||||||
|
$(OBJ) dvect.o $(PYLIB)
|
||||||
|
|
||||||
|
richcmp1.pyd: $(OBJ) richcmp1.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname richcmp1.pyd \
|
||||||
|
--def richcmp1.def \
|
||||||
|
$(OBJ) richcmp1.o $(PYLIB)
|
||||||
|
|
||||||
|
richcmp2.pyd: $(OBJ) richcmp2.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname richcmp2.pyd \
|
||||||
|
--def richcmp2.def \
|
||||||
|
$(OBJ) richcmp2.o $(PYLIB)
|
||||||
|
|
||||||
|
richcmp3.pyd: $(OBJ) richcmp3.o
|
||||||
|
dllwrap $(DLLWRAPOPTS) \
|
||||||
|
--dllname richcmp3.pyd \
|
||||||
|
--def richcmp3.def \
|
||||||
|
$(OBJ) richcmp3.o $(PYLIB)
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CPP) $(CPPOPTS) -c $*.cpp
|
||||||
|
|
||||||
|
test:
|
||||||
|
# $(PYEXE) comprehensive.py
|
||||||
|
$(PYEXE) test_abstract.py
|
||||||
|
$(PYEXE) test_getting_started1.py
|
||||||
|
$(PYEXE) test_getting_started2.py
|
||||||
|
$(PYEXE) test_simple_vector.py
|
||||||
|
$(PYEXE) test_do_it_yourself_converters.py
|
||||||
|
$(PYEXE) test_pickle1.py
|
||||||
|
$(PYEXE) test_pickle2.py
|
||||||
|
$(PYEXE) test_pickle3.py
|
||||||
|
$(PYEXE) test_cross_module.py
|
||||||
|
$(PYEXE) test_richcmp1.py
|
||||||
|
$(PYEXE) test_richcmp2.py
|
||||||
|
$(PYEXE) test_richcmp3.py
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-del *.o
|
||||||
|
-del *.a
|
||||||
|
-del *.pyd
|
||||||
|
-del *.pyc
|
||||||
|
|
||||||
|
softlinks:
|
||||||
|
python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) softlinks
|
||||||
|
|
||||||
|
unlink:
|
||||||
|
python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) unlink
|
||||||
|
|
||||||
|
cp:
|
||||||
|
python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) cp
|
||||||
|
|
||||||
|
rm:
|
||||||
|
python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) rm
|
||||||
|
|
||||||
|
copy:
|
||||||
|
$(PYEXE) $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) copy
|
||||||
|
|
||||||
|
del:
|
||||||
|
$(PYEXE) $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) del
|
||||||
135
build/rwgk1/rwgk1.dsp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# Microsoft Developer Studio Project File - Name="rwgk1" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||||
|
|
||||||
|
CFG=rwgk1 - Win32 DebugPython
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "rwgk1.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "rwgk1.mak" CFG="rwgk1 - Win32 DebugPython"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "rwgk1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "rwgk1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "rwgk1 - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=cl.exe
|
||||||
|
MTL=midl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "rwgk1 - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /c
|
||||||
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "rwgk1 - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /Gm- /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "rwgk1 - Win32 DebugPython"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "rwgk1___Win32_DebugPython"
|
||||||
|
# PROP BASE Intermediate_Dir "rwgk1___Win32_DebugPython"
|
||||||
|
# PROP BASE Ignore_Export_Lib 0
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "DebugPython"
|
||||||
|
# PROP Intermediate_Dir "DebugPython"
|
||||||
|
# PROP Ignore_Export_Lib 1
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /Gm- /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs"
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"DebugPython/rwgk1_d.dll" /pdbtype:sept /libpath:"C:\tools\python\src\PCbuild"
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "rwgk1 - Win32 Release"
|
||||||
|
# Name "rwgk1 - Win32 Debug"
|
||||||
|
# Name "rwgk1 - Win32 DebugPython"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\example\rwgk1.cpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Resource Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
||||||
145
build/test/test.dsp
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# Microsoft Developer Studio Project File - Name="test" - Package Owner=<4>
|
||||||
|
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||||
|
# ** DO NOT EDIT **
|
||||||
|
|
||||||
|
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||||
|
|
||||||
|
CFG=test - Win32 DebugPython
|
||||||
|
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||||
|
!MESSAGE use the Export Makefile command and run
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "test.mak".
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE You can specify a configuration when running NMAKE
|
||||||
|
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 DebugPython"
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE Possible choices for configuration are:
|
||||||
|
!MESSAGE
|
||||||
|
!MESSAGE "test - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "test - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE "test - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library")
|
||||||
|
!MESSAGE
|
||||||
|
|
||||||
|
# Begin Project
|
||||||
|
# PROP AllowPerConfigDependencies 0
|
||||||
|
# PROP Scc_ProjName ""
|
||||||
|
# PROP Scc_LocalPath ""
|
||||||
|
CPP=cl.exe
|
||||||
|
MTL=midl.exe
|
||||||
|
RSC=rc.exe
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "test - Win32 Release"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 0
|
||||||
|
# PROP BASE Output_Dir "Release"
|
||||||
|
# PROP BASE Intermediate_Dir "Release"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 0
|
||||||
|
# PROP Output_Dir "Release"
|
||||||
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /c
|
||||||
|
# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /Zm200 /c
|
||||||
|
# SUBTRACT CPP /Fr
|
||||||
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/boost_python_test.dll" /libpath:"c:\tools\python\libs"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "test - Win32 Debug"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "Debug"
|
||||||
|
# PROP BASE Intermediate_Dir "Debug"
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "Debug"
|
||||||
|
# PROP Intermediate_Dir "Debug"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c
|
||||||
|
# SUBTRACT CPP /Fr
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"Debug/boost_python_test.dll" /pdbtype:sept /libpath:"c:\tools\python\libs"
|
||||||
|
# SUBTRACT LINK32 /pdb:none
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "test - Win32 DebugPython"
|
||||||
|
|
||||||
|
# PROP BASE Use_MFC 0
|
||||||
|
# PROP BASE Use_Debug_Libraries 1
|
||||||
|
# PROP BASE Output_Dir "test___Win32_DebugPython"
|
||||||
|
# PROP BASE Intermediate_Dir "test___Win32_DebugPython"
|
||||||
|
# PROP BASE Ignore_Export_Lib 0
|
||||||
|
# PROP BASE Target_Dir ""
|
||||||
|
# PROP Use_MFC 0
|
||||||
|
# PROP Use_Debug_Libraries 1
|
||||||
|
# PROP Output_Dir "DebugPython"
|
||||||
|
# PROP Intermediate_Dir "DebugPython"
|
||||||
|
# PROP Ignore_Export_Lib 1
|
||||||
|
# PROP Target_Dir ""
|
||||||
|
# ADD BASE CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c
|
||||||
|
# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /Zm200 /EHs /c
|
||||||
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
BSC32=bscmake.exe
|
||||||
|
# ADD BASE BSC32 /nologo
|
||||||
|
# ADD BSC32 /nologo
|
||||||
|
LINK32=link.exe
|
||||||
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs"
|
||||||
|
# SUBTRACT BASE LINK32 /pdb:none
|
||||||
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"DebugPython/boost_python_test_d.dll" /pdbtype:sept /libpath:"c:\tools\python\src\PCbuild"
|
||||||
|
# SUBTRACT LINK32 /pdb:none
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# Begin Target
|
||||||
|
|
||||||
|
# Name "test - Win32 Release"
|
||||||
|
# Name "test - Win32 Debug"
|
||||||
|
# Name "test - Win32 DebugPython"
|
||||||
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\test\comprehensive.cpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=..\..\test\comprehensive.hpp
|
||||||
|
# End Source File
|
||||||
|
# End Group
|
||||||
|
# Begin Group "Resource Files"
|
||||||
|
|
||||||
|
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||||
|
# End Group
|
||||||
|
# End Target
|
||||||
|
# End Project
|
||||||
192
build/tru64_cxx.mak
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# Create a new empty directory anywhere (preferably not in the boost tree).
|
||||||
|
# Copy this Makefile to that new directory and rename it to "Makefile"
|
||||||
|
# Adjust the pathnames below.
|
||||||
|
#
|
||||||
|
# make softlinks Create softlinks to source code and tests
|
||||||
|
# make Compile all sources
|
||||||
|
# make test Run doctest tests
|
||||||
|
# make clean Remove all object files
|
||||||
|
# make unlink Remove softlinks
|
||||||
|
#
|
||||||
|
# Revision history:
|
||||||
|
# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve)
|
||||||
|
# Initial version: R.W. Grosse-Kunstleve
|
||||||
|
|
||||||
|
ROOT=$(HOME)
|
||||||
|
BOOST=$(ROOT)/boost
|
||||||
|
|
||||||
|
PYEXE=/usr/local/Python-1.5.2/bin/python
|
||||||
|
PYINC=-I/usr/local/Python-1.5.2/include/python1.5
|
||||||
|
#PYEXE=/usr/local/Python-2.1/bin/python
|
||||||
|
#PYINC=-I/usr/local/Python-2.1/include/python2.1
|
||||||
|
#STLPORTINC=-I/usr/local/STLport-4.1b3/stlport
|
||||||
|
#STLPORTINC=-I/usr/local/STLport-4.1b4/stlport
|
||||||
|
#STLPORTOPTS= \
|
||||||
|
# -D__USE_STD_IOSTREAM \
|
||||||
|
# -D__STL_NO_SGI_IOSTREAMS \
|
||||||
|
# -D__STL_USE_NATIVE_STRING \
|
||||||
|
# -D__STL_NO_NEW_C_HEADERS \
|
||||||
|
# -D_RWSTD_COMPILE_INSTANTIATE=1
|
||||||
|
STLPORTINC=-I$(BOOST)/boost/compatibility/cpp_c_headers
|
||||||
|
|
||||||
|
STDOPTS=-std strict_ansi
|
||||||
|
# use -msg_display_number to obtain integer tags for -msg_disable
|
||||||
|
WARNOPTS=-msg_disable 186,450,1115
|
||||||
|
OPTOPTS=-g
|
||||||
|
|
||||||
|
CPP=cxx
|
||||||
|
CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \
|
||||||
|
$(STDOPTS) $(WARNOPTS) $(OPTOPTS)
|
||||||
|
MAKEDEP=-Em
|
||||||
|
|
||||||
|
LD=cxx
|
||||||
|
LDOPTS=-shared -expect_unresolved 'Py*' -expect_unresolved '_Py*'
|
||||||
|
|
||||||
|
#HIDDEN=-hidden
|
||||||
|
|
||||||
|
OBJ=classes.o conversions.o extension_class.o functions.o \
|
||||||
|
init_function.o module_builder.o \
|
||||||
|
objects.o types.o cross_module.o
|
||||||
|
DEPOBJ=$(OBJ) \
|
||||||
|
comprehensive.o \
|
||||||
|
abstract.o \
|
||||||
|
getting_started1.o getting_started2.o \
|
||||||
|
simple_vector.o \
|
||||||
|
do_it_yourself_converters.o \
|
||||||
|
pickle1.o pickle2.o pickle3.o \
|
||||||
|
noncopyable_export.o noncopyable_import.o \
|
||||||
|
ivect.o dvect.o \
|
||||||
|
richcmp1.o richcmp2.o richcmp3.o
|
||||||
|
|
||||||
|
.SUFFIXES: .o .cpp
|
||||||
|
|
||||||
|
all: libboost_python.a \
|
||||||
|
boost_python_test.so \
|
||||||
|
abstract.so \
|
||||||
|
getting_started1.so getting_started2.so \
|
||||||
|
simple_vector.so \
|
||||||
|
do_it_yourself_converters.so \
|
||||||
|
pickle1.so pickle2.so pickle3.so \
|
||||||
|
noncopyable_export.so noncopyable_import.so \
|
||||||
|
ivect.so dvect.so \
|
||||||
|
richcmp1.so richcmp2.so richcmp3.so
|
||||||
|
|
||||||
|
libboost_python.a: $(OBJ)
|
||||||
|
rm -f libboost_python.a
|
||||||
|
cd cxx_repository; \
|
||||||
|
ls -1 > ../libboost_python.a.input; \
|
||||||
|
ar r ../libboost_python.a -input ../libboost_python.a.input
|
||||||
|
rm -f libboost_python.a.input
|
||||||
|
ar r libboost_python.a $(OBJ)
|
||||||
|
|
||||||
|
boost_python_test.so: $(OBJ) comprehensive.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm
|
||||||
|
|
||||||
|
abstract.so: $(OBJ) abstract.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so
|
||||||
|
|
||||||
|
getting_started1.so: $(OBJ) getting_started1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) getting_started1.o -o getting_started1.so
|
||||||
|
|
||||||
|
getting_started2.so: $(OBJ) getting_started2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so
|
||||||
|
|
||||||
|
simple_vector.so: $(OBJ) simple_vector.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so
|
||||||
|
|
||||||
|
do_it_yourself_converters.so: $(OBJ) do_it_yourself_converters.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.o -o do_it_yourself_converters.so
|
||||||
|
|
||||||
|
pickle1.so: $(OBJ) pickle1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle1.o -o pickle1.so
|
||||||
|
|
||||||
|
pickle2.so: $(OBJ) pickle2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle2.o -o pickle2.so
|
||||||
|
|
||||||
|
pickle3.so: $(OBJ) pickle3.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle3.o -o pickle3.so
|
||||||
|
|
||||||
|
noncopyable_export.so: $(OBJ) noncopyable_export.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \
|
||||||
|
noncopyable_export.o -o noncopyable_export.so
|
||||||
|
|
||||||
|
noncopyable_import.so: $(OBJ) noncopyable_import.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \
|
||||||
|
noncopyable_import.o -o noncopyable_import.so
|
||||||
|
|
||||||
|
ivect.so: $(OBJ) ivect.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) ivect.o -o ivect.so
|
||||||
|
|
||||||
|
dvect.so: $(OBJ) dvect.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so
|
||||||
|
|
||||||
|
richcmp1.so: $(OBJ) richcmp1.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp1.o -o richcmp1.so
|
||||||
|
|
||||||
|
richcmp2.so: $(OBJ) richcmp2.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp2.o -o richcmp2.so
|
||||||
|
|
||||||
|
richcmp3.so: $(OBJ) richcmp3.o
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp3.o -o richcmp3.so
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CPP) $(CPPOPTS) -c $*.cpp
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(PYEXE) comprehensive.py
|
||||||
|
$(PYEXE) test_abstract.py
|
||||||
|
$(PYEXE) test_getting_started1.py
|
||||||
|
$(PYEXE) test_getting_started2.py
|
||||||
|
$(PYEXE) test_simple_vector.py
|
||||||
|
$(PYEXE) test_do_it_yourself_converters.py
|
||||||
|
$(PYEXE) test_pickle1.py
|
||||||
|
$(PYEXE) test_pickle2.py
|
||||||
|
$(PYEXE) test_pickle3.py
|
||||||
|
$(PYEXE) test_cross_module.py
|
||||||
|
$(PYEXE) test_richcmp1.py
|
||||||
|
$(PYEXE) test_richcmp2.py
|
||||||
|
$(PYEXE) test_richcmp3.py
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ) libboost_python.a libboost_python.a.input
|
||||||
|
rm -f comprehensive.o boost_python_test.so
|
||||||
|
rm -f abstract.o abstract.so
|
||||||
|
rm -f getting_started1.o getting_started1.so
|
||||||
|
rm -f getting_started2.o getting_started2.so
|
||||||
|
rm -f simple_vector.o simple_vector.so
|
||||||
|
rm -f do_it_yourself_converters.o do_it_yourself_converters.so
|
||||||
|
rm -f pickle1.o pickle1.so
|
||||||
|
rm -f pickle2.o pickle2.so
|
||||||
|
rm -f pickle3.o pickle3.so
|
||||||
|
rm -f noncopyable_export.o noncopyable_export.so
|
||||||
|
rm -f noncopyable_import.o noncopyable_import.so
|
||||||
|
rm -f ivect.o ivect.so
|
||||||
|
rm -f dvect.o dvect.so
|
||||||
|
rm -f richcmp1.o richcmp1.so
|
||||||
|
rm -f richcmp2.o richcmp2.so
|
||||||
|
rm -f richcmp3.o richcmp3.so
|
||||||
|
rm -f so_locations *.pyc
|
||||||
|
rm -rf cxx_repository
|
||||||
|
|
||||||
|
softlinks:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) softlinks
|
||||||
|
|
||||||
|
unlink:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) unlink
|
||||||
|
|
||||||
|
cp:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) cp
|
||||||
|
|
||||||
|
rm:
|
||||||
|
$(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) rm
|
||||||
|
|
||||||
|
depend:
|
||||||
|
@ cat Makefile.nodepend; \
|
||||||
|
for obj in $(DEPOBJ); \
|
||||||
|
do \
|
||||||
|
bn=`echo "$$obj" | cut -d. -f1`; \
|
||||||
|
$(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \
|
||||||
|
done
|
||||||
|
|
||||||
145
build/vc60.mak
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# make copy Copy the sources and tests
|
||||||
|
# make Compile all sources
|
||||||
|
# make test Run doctest tests
|
||||||
|
# make clean Remove all object files
|
||||||
|
# make del Remove the sources and tests
|
||||||
|
#
|
||||||
|
# Revision history:
|
||||||
|
# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve)
|
||||||
|
# Initial version: R.W. Grosse-Kunstleve
|
||||||
|
|
||||||
|
ROOT=L:
|
||||||
|
BOOST_WIN="$(ROOT)\boost"
|
||||||
|
BOOST_UNIX=$(HOME)/boost
|
||||||
|
|
||||||
|
PYEXE="C:\Program files\Python\python.exe"
|
||||||
|
PYINC=/I"C:\Program files\Python\include"
|
||||||
|
PYLIB="C:\Program files\Python\libs\python15.lib"
|
||||||
|
#PYEXE="C:\Python21\python.exe"
|
||||||
|
#PYINC=/I"C:\Python21\include"
|
||||||
|
#PYLIB="C:\Python21\libs\python21.lib"
|
||||||
|
|
||||||
|
STDOPTS=/nologo /MD /GR /GX /Zm200
|
||||||
|
WARNOPTS=
|
||||||
|
OPTOPTS=
|
||||||
|
|
||||||
|
CPP=cl.exe
|
||||||
|
CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) /I$(BOOST_WIN) $(PYINC) \
|
||||||
|
$(STDOPTS) $(WARNOPTS) $(OPTOPTS)
|
||||||
|
|
||||||
|
LD=link.exe
|
||||||
|
LDOPTS=/nologo /dll /incremental:no
|
||||||
|
|
||||||
|
OBJ=classes.obj conversions.obj extension_class.obj functions.obj \
|
||||||
|
init_function.obj module_builder.obj \
|
||||||
|
objects.obj types.obj cross_module.obj
|
||||||
|
|
||||||
|
.SUFFIXES: .obj .cpp
|
||||||
|
|
||||||
|
all: boost_python.lib \
|
||||||
|
boost_python_test.pyd \
|
||||||
|
abstract.pyd \
|
||||||
|
getting_started1.pyd getting_started2.pyd \
|
||||||
|
simple_vector.pyd \
|
||||||
|
do_it_yourself_converters.pyd \
|
||||||
|
pickle1.pyd pickle2.pyd pickle3.pyd \
|
||||||
|
noncopyable_export.pyd noncopyable_import.pyd \
|
||||||
|
ivect.pyd dvect.pyd \
|
||||||
|
richcmp1.pyd richcmp2.pyd richcmp3.pyd
|
||||||
|
|
||||||
|
boost_python.lib: $(OBJ)
|
||||||
|
$(LD) -lib /nologo /out:boost_python.lib $(OBJ)
|
||||||
|
|
||||||
|
boost_python_test.pyd: $(OBJ) comprehensive.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) comprehensive.obj $(PYLIB) /export:initboost_python_test /out:"boost_python_test.pyd"
|
||||||
|
|
||||||
|
abstract.pyd: $(OBJ) abstract.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) abstract.obj $(PYLIB) /export:initabstract /out:"abstract.pyd"
|
||||||
|
|
||||||
|
getting_started1.pyd: $(OBJ) getting_started1.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) getting_started1.obj $(PYLIB) /export:initgetting_started1 /out:"getting_started1.pyd"
|
||||||
|
|
||||||
|
getting_started2.pyd: $(OBJ) getting_started2.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) getting_started2.obj $(PYLIB) /export:initgetting_started2 /out:"getting_started2.pyd"
|
||||||
|
|
||||||
|
simple_vector.pyd: $(OBJ) simple_vector.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) simple_vector.obj $(PYLIB) /export:initsimple_vector /out:"simple_vector.pyd"
|
||||||
|
|
||||||
|
do_it_yourself_converters.pyd: $(OBJ) do_it_yourself_converters.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.obj $(PYLIB) /export:initdo_it_yourself_converters /out:"do_it_yourself_converters.pyd"
|
||||||
|
|
||||||
|
pickle1.pyd: $(OBJ) pickle1.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle1.obj $(PYLIB) /export:initpickle1 /out:"pickle1.pyd"
|
||||||
|
|
||||||
|
pickle2.pyd: $(OBJ) pickle2.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle2.obj $(PYLIB) /export:initpickle2 /out:"pickle2.pyd"
|
||||||
|
|
||||||
|
pickle3.pyd: $(OBJ) pickle3.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) pickle3.obj $(PYLIB) /export:initpickle3 /out:"pickle3.pyd"
|
||||||
|
|
||||||
|
noncopyable_export.pyd: $(OBJ) noncopyable_export.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) noncopyable_export.obj $(PYLIB) /export:initnoncopyable_export /out:"noncopyable_export.pyd"
|
||||||
|
|
||||||
|
noncopyable_import.pyd: $(OBJ) noncopyable_import.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) noncopyable_import.obj $(PYLIB) /export:initnoncopyable_import /out:"noncopyable_import.pyd"
|
||||||
|
|
||||||
|
ivect.pyd: $(OBJ) ivect.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) ivect.obj $(PYLIB) /export:initivect /out:"ivect.pyd"
|
||||||
|
|
||||||
|
dvect.pyd: $(OBJ) dvect.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) dvect.obj $(PYLIB) /export:initdvect /out:"dvect.pyd"
|
||||||
|
|
||||||
|
richcmp1.pyd: $(OBJ) richcmp1.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp1.obj $(PYLIB) /export:initrichcmp1 /out:"richcmp1.pyd"
|
||||||
|
|
||||||
|
richcmp2.pyd: $(OBJ) richcmp2.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp2.obj $(PYLIB) /export:initrichcmp2 /out:"richcmp2.pyd"
|
||||||
|
|
||||||
|
richcmp3.pyd: $(OBJ) richcmp3.obj
|
||||||
|
$(LD) $(LDOPTS) $(OBJ) richcmp3.obj $(PYLIB) /export:initrichcmp3 /out:"richcmp3.pyd"
|
||||||
|
|
||||||
|
.cpp.obj:
|
||||||
|
$(CPP) $(CPPOPTS) /c $*.cpp
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(PYEXE) comprehensive.py --broken-auto-ptr
|
||||||
|
$(PYEXE) test_abstract.py
|
||||||
|
$(PYEXE) test_getting_started1.py
|
||||||
|
$(PYEXE) test_getting_started2.py
|
||||||
|
$(PYEXE) test_simple_vector.py
|
||||||
|
$(PYEXE) test_do_it_yourself_converters.py
|
||||||
|
$(PYEXE) test_pickle1.py
|
||||||
|
$(PYEXE) test_pickle2.py
|
||||||
|
$(PYEXE) test_pickle3.py
|
||||||
|
$(PYEXE) test_cross_module.py --broken-auto-ptr
|
||||||
|
$(PYEXE) test_richcmp1.py
|
||||||
|
$(PYEXE) test_richcmp2.py
|
||||||
|
$(PYEXE) test_richcmp3.py
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-del *.obj
|
||||||
|
-del *.lib
|
||||||
|
-del *.exp
|
||||||
|
-del *.idb
|
||||||
|
-del *.pyd
|
||||||
|
-del *.pyc
|
||||||
|
|
||||||
|
softlinks:
|
||||||
|
python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) softlinks
|
||||||
|
|
||||||
|
unlink:
|
||||||
|
python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) unlink
|
||||||
|
|
||||||
|
cp:
|
||||||
|
python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) cp
|
||||||
|
|
||||||
|
rm:
|
||||||
|
python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) rm
|
||||||
|
|
||||||
|
copy:
|
||||||
|
$(PYEXE) $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) copy
|
||||||
|
|
||||||
|
del:
|
||||||
|
$(PYEXE) $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) del
|
||||||
@@ -1,947 +0,0 @@
|
|||||||
+++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
Building Hybrid Systems with Boost.Python
|
|
||||||
+++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
|
|
||||||
:Author: David Abrahams
|
|
||||||
:Contact: dave@boost-consulting.com
|
|
||||||
:organization: `Boost Consulting`_
|
|
||||||
:date: $Date$
|
|
||||||
|
|
||||||
:Author: Ralf W. Grosse-Kunstleve
|
|
||||||
|
|
||||||
:copyright: Copyright David Abrahams and Ralf W. Grosse-Kunstleve 2003. All rights reserved
|
|
||||||
|
|
||||||
.. contents:: Table of Contents
|
|
||||||
|
|
||||||
.. _`Boost Consulting`: http://www.boost-consulting.com
|
|
||||||
|
|
||||||
==========
|
|
||||||
Abstract
|
|
||||||
==========
|
|
||||||
|
|
||||||
Boost.Python is an open source C++ library which provides a concise
|
|
||||||
IDL-like interface for binding C++ classes and functions to
|
|
||||||
Python. Leveraging the full power of C++ compile-time introspection
|
|
||||||
and of recently developed metaprogramming techniques, this is achieved
|
|
||||||
entirely in pure C++, without introducing a new syntax.
|
|
||||||
Boost.Python's rich set of features and high-level interface make it
|
|
||||||
possible to engineer packages from the ground up as hybrid systems,
|
|
||||||
giving programmers easy and coherent access to both the efficient
|
|
||||||
compile-time polymorphism of C++ and the extremely convenient run-time
|
|
||||||
polymorphism of Python.
|
|
||||||
|
|
||||||
==============
|
|
||||||
Introduction
|
|
||||||
==============
|
|
||||||
|
|
||||||
Python and C++ are in many ways as different as two languages could
|
|
||||||
be: while C++ is usually compiled to machine-code, Python is
|
|
||||||
interpreted. Python's dynamic type system is often cited as the
|
|
||||||
foundation of its flexibility, while in C++ static typing is the
|
|
||||||
cornerstone of its efficiency. C++ has an intricate and difficult
|
|
||||||
compile-time meta-language, while in Python, practically everything
|
|
||||||
happens at runtime.
|
|
||||||
|
|
||||||
Yet for many programmers, these very differences mean that Python and
|
|
||||||
C++ complement one another perfectly. Performance bottlenecks in
|
|
||||||
Python programs can be rewritten in C++ for maximal speed, and
|
|
||||||
authors of powerful C++ libraries choose Python as a middleware
|
|
||||||
language for its flexible system integration capabilities.
|
|
||||||
Furthermore, the surface differences mask some strong similarities:
|
|
||||||
|
|
||||||
* 'C'-family control structures (if, while, for...)
|
|
||||||
|
|
||||||
* Support for object-orientation, functional programming, and generic
|
|
||||||
programming (these are both *multi-paradigm* programming languages.)
|
|
||||||
|
|
||||||
* Comprehensive operator overloading facilities, recognizing the
|
|
||||||
importance of syntactic variability for readability and
|
|
||||||
expressivity.
|
|
||||||
|
|
||||||
* High-level concepts such as collections and iterators.
|
|
||||||
|
|
||||||
* High-level encapsulation facilities (C++: namespaces, Python: modules)
|
|
||||||
to support the design of re-usable libraries.
|
|
||||||
|
|
||||||
* Exception-handling for effective management of error conditions.
|
|
||||||
|
|
||||||
* C++ idioms in common use, such as handle/body classes and
|
|
||||||
reference-counted smart pointers mirror Python reference semantics.
|
|
||||||
|
|
||||||
Given Python's rich 'C' interoperability API, it should in principle
|
|
||||||
be possible to expose C++ type and function interfaces to Python with
|
|
||||||
an analogous interface to their C++ counterparts. However, the
|
|
||||||
facilities provided by Python alone for integration with C++ are
|
|
||||||
relatively meager. Compared to C++ and Python, 'C' has only very
|
|
||||||
rudimentary abstraction facilities, and support for exception-handling
|
|
||||||
is completely missing. 'C' extension module writers are required to
|
|
||||||
manually manage Python reference counts, which is both annoyingly
|
|
||||||
tedious and extremely error-prone. Traditional extension modules also
|
|
||||||
tend to contain a great deal of boilerplate code repetition which
|
|
||||||
makes them difficult to maintain, especially when wrapping an evolving
|
|
||||||
API.
|
|
||||||
|
|
||||||
These limitations have lead to the development of a variety of wrapping
|
|
||||||
systems. SWIG_ is probably the most popular package for the
|
|
||||||
integration of C/C++ and Python. A more recent development is SIP_,
|
|
||||||
which was specifically designed for interfacing Python with the Qt_
|
|
||||||
graphical user interface library. Both SWIG and SIP introduce their
|
|
||||||
own specialized languages for customizing inter-language bindings.
|
|
||||||
This has certain advantages, but having to deal with three different
|
|
||||||
languages (Python, C/C++ and the interface language) also introduces
|
|
||||||
practical and mental difficulties. The CXX_ package demonstrates an
|
|
||||||
interesting alternative. It shows that at least some parts of
|
|
||||||
Python's 'C' API can be wrapped and presented through a much more
|
|
||||||
user-friendly C++ interface. However, unlike SWIG and SIP, CXX does
|
|
||||||
not include support for wrapping C++ classes as new Python types.
|
|
||||||
|
|
||||||
The features and goals of Boost.Python_ overlap significantly with
|
|
||||||
many of these other systems. That said, Boost.Python attempts to
|
|
||||||
maximize convenience and flexibility without introducing a separate
|
|
||||||
wrapping language. Instead, it presents the user with a high-level
|
|
||||||
C++ interface for wrapping C++ classes and functions, managing much of
|
|
||||||
the complexity behind-the-scenes with static metaprogramming.
|
|
||||||
Boost.Python also goes beyond the scope of earlier systems by
|
|
||||||
providing:
|
|
||||||
|
|
||||||
* Support for C++ virtual functions that can be overridden in Python.
|
|
||||||
|
|
||||||
* Comprehensive lifetime management facilities for low-level C++
|
|
||||||
pointers and references.
|
|
||||||
|
|
||||||
* Support for organizing extensions as Python packages,
|
|
||||||
with a central registry for inter-language type conversions.
|
|
||||||
|
|
||||||
* A safe and convenient mechanism for tying into Python's powerful
|
|
||||||
serialization engine (pickle).
|
|
||||||
|
|
||||||
* Coherence with the rules for handling C++ lvalues and rvalues that
|
|
||||||
can only come from a deep understanding of both the Python and C++
|
|
||||||
type systems.
|
|
||||||
|
|
||||||
The key insight that sparked the development of Boost.Python is that
|
|
||||||
much of the boilerplate code in traditional extension modules could be
|
|
||||||
eliminated using C++ compile-time introspection. Each argument of a
|
|
||||||
wrapped C++ function must be extracted from a Python object using a
|
|
||||||
procedure that depends on the argument type. Similarly the function's
|
|
||||||
return type determines how the return value will be converted from C++
|
|
||||||
to Python. Of course argument and return types are part of each
|
|
||||||
function's type, and this is exactly the source from which
|
|
||||||
Boost.Python deduces most of the information required.
|
|
||||||
|
|
||||||
This approach leads to *user guided wrapping*: as much information is
|
|
||||||
extracted directly from the source code to be wrapped as is possible
|
|
||||||
within the framework of pure C++, and some additional information is
|
|
||||||
supplied explicitly by the user. Mostly the guidance is mechanical
|
|
||||||
and little real intervention is required. Because the interface
|
|
||||||
specification is written in the same full-featured language as the
|
|
||||||
code being exposed, the user has unprecedented power available when
|
|
||||||
she does need to take control.
|
|
||||||
|
|
||||||
.. _Python: http://www.python.org/
|
|
||||||
.. _SWIG: http://www.swig.org/
|
|
||||||
.. _SIP: http://www.riverbankcomputing.co.uk/sip/index.php
|
|
||||||
.. _Qt: http://www.trolltech.com/
|
|
||||||
.. _CXX: http://cxx.sourceforge.net/
|
|
||||||
.. _Boost.Python: http://www.boost.org/libs/python/doc
|
|
||||||
|
|
||||||
===========================
|
|
||||||
Boost.Python Design Goals
|
|
||||||
===========================
|
|
||||||
|
|
||||||
The primary goal of Boost.Python is to allow users to expose C++
|
|
||||||
classes and functions to Python using nothing more than a C++
|
|
||||||
compiler. In broad strokes, the user experience should be one of
|
|
||||||
directly manipulating C++ objects from Python.
|
|
||||||
|
|
||||||
However, it's also important not to translate all interfaces *too*
|
|
||||||
literally: the idioms of each language must be respected. For
|
|
||||||
example, though C++ and Python both have an iterator concept, they are
|
|
||||||
expressed very differently. Boost.Python has to be able to bridge the
|
|
||||||
interface gap.
|
|
||||||
|
|
||||||
It must be possible to insulate Python users from crashes resulting
|
|
||||||
from trivial misuses of C++ interfaces, such as accessing
|
|
||||||
already-deleted objects. By the same token the library should
|
|
||||||
insulate C++ users from low-level Python 'C' API, replacing
|
|
||||||
error-prone 'C' interfaces like manual reference-count management and
|
|
||||||
raw ``PyObject`` pointers with more-robust alternatives.
|
|
||||||
|
|
||||||
Support for component-based development is crucial, so that C++ types
|
|
||||||
exposed in one extension module can be passed to functions exposed in
|
|
||||||
another without loss of crucial information like C++ inheritance
|
|
||||||
relationships.
|
|
||||||
|
|
||||||
Finally, all wrapping must be *non-intrusive*, without modifying or
|
|
||||||
even seeing the original C++ source code. Existing C++ libraries have
|
|
||||||
to be wrappable by third parties who only have access to header files
|
|
||||||
and binaries.
|
|
||||||
|
|
||||||
==========================
|
|
||||||
Hello Boost.Python World
|
|
||||||
==========================
|
|
||||||
|
|
||||||
And now for a preview of Boost.Python, and how it improves on the raw
|
|
||||||
facilities offered by Python. Here's a function we might want to
|
|
||||||
expose::
|
|
||||||
|
|
||||||
char const* greet(unsigned x)
|
|
||||||
{
|
|
||||||
static char const* const msgs[] = { "hello", "Boost.Python", "world!" };
|
|
||||||
|
|
||||||
if (x > 2)
|
|
||||||
throw std::range_error("greet: index out of range");
|
|
||||||
|
|
||||||
return msgs[x];
|
|
||||||
}
|
|
||||||
|
|
||||||
To wrap this function in standard C++ using the Python 'C' API, we'd
|
|
||||||
need something like this::
|
|
||||||
|
|
||||||
extern "C" // all Python interactions use 'C' linkage and calling convention
|
|
||||||
{
|
|
||||||
// Wrapper to handle argument/result conversion and checking
|
|
||||||
PyObject* greet_wrap(PyObject* args, PyObject * keywords)
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
if (PyArg_ParseTuple(args, "i", &x)) // extract/check arguments
|
|
||||||
{
|
|
||||||
char const* result = greet(x); // invoke wrapped function
|
|
||||||
return PyString_FromString(result); // convert result to Python
|
|
||||||
}
|
|
||||||
return 0; // error occurred
|
|
||||||
}
|
|
||||||
|
|
||||||
// Table of wrapped functions to be exposed by the module
|
|
||||||
static PyMethodDef methods[] = {
|
|
||||||
{ "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" }
|
|
||||||
, { NULL, NULL, 0, NULL } // sentinel
|
|
||||||
};
|
|
||||||
|
|
||||||
// module initialization function
|
|
||||||
DL_EXPORT init_hello()
|
|
||||||
{
|
|
||||||
(void) Py_InitModule("hello", methods); // add the methods to the module
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Now here's the wrapping code we'd use to expose it with Boost.Python::
|
|
||||||
|
|
||||||
#include <boost/python.hpp>
|
|
||||||
using namespace boost::python;
|
|
||||||
BOOST_PYTHON_MODULE(hello)
|
|
||||||
{
|
|
||||||
def("greet", greet, "return one of 3 parts of a greeting");
|
|
||||||
}
|
|
||||||
|
|
||||||
and here it is in action::
|
|
||||||
|
|
||||||
>>> import hello
|
|
||||||
>>> for x in range(3):
|
|
||||||
... print hello.greet(x)
|
|
||||||
...
|
|
||||||
hello
|
|
||||||
Boost.Python
|
|
||||||
world!
|
|
||||||
|
|
||||||
Aside from the fact that the 'C' API version is much more verbose,
|
|
||||||
it's worth noting a few things that it doesn't handle correctly:
|
|
||||||
|
|
||||||
* The original function accepts an unsigned integer, and the Python
|
|
||||||
'C' API only gives us a way of extracting signed integers. The
|
|
||||||
Boost.Python version will raise a Python exception if we try to pass
|
|
||||||
a negative number to ``hello.greet``, but the other one will proceed
|
|
||||||
to do whatever the C++ implementation does when converting an
|
|
||||||
negative integer to unsigned (usually wrapping to some very large
|
|
||||||
number), and pass the incorrect translation on to the wrapped
|
|
||||||
function.
|
|
||||||
|
|
||||||
* That brings us to the second problem: if the C++ ``greet()``
|
|
||||||
function is called with a number greater than 2, it will throw an
|
|
||||||
exception. Typically, if a C++ exception propagates across the
|
|
||||||
boundary with code generated by a 'C' compiler, it will cause a
|
|
||||||
crash. As you can see in the first version, there's no C++
|
|
||||||
scaffolding there to prevent this from happening. Functions wrapped
|
|
||||||
by Boost.Python automatically include an exception-handling layer
|
|
||||||
which protects Python users by translating unhandled C++ exceptions
|
|
||||||
into a corresponding Python exception.
|
|
||||||
|
|
||||||
* A slightly more-subtle limitation is that the argument conversion
|
|
||||||
used in the Python 'C' API case can only get that integer ``x`` in
|
|
||||||
*one way*. PyArg_ParseTuple can't convert Python ``long`` objects
|
|
||||||
(arbitrary-precision integers) which happen to fit in an ``unsigned
|
|
||||||
int`` but not in a ``signed long``, nor will it ever handle a
|
|
||||||
wrapped C++ class with a user-defined implicit ``operator unsigned
|
|
||||||
int()`` conversion. Boost.Python's dynamic type conversion
|
|
||||||
registry allows users to add arbitrary conversion methods.
|
|
||||||
|
|
||||||
==================
|
|
||||||
Library Overview
|
|
||||||
==================
|
|
||||||
|
|
||||||
This section outlines some of the library's major features. Except as
|
|
||||||
neccessary to avoid confusion, details of library implementation are
|
|
||||||
omitted.
|
|
||||||
|
|
||||||
------------------
|
|
||||||
Exposing Classes
|
|
||||||
------------------
|
|
||||||
|
|
||||||
C++ classes and structs are exposed with a similarly-terse interface.
|
|
||||||
Given::
|
|
||||||
|
|
||||||
struct World
|
|
||||||
{
|
|
||||||
void set(std::string msg) { this->msg = msg; }
|
|
||||||
std::string greet() { return msg; }
|
|
||||||
std::string msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
The following code will expose it in our extension module::
|
|
||||||
|
|
||||||
#include <boost/python.hpp>
|
|
||||||
BOOST_PYTHON_MODULE(hello)
|
|
||||||
{
|
|
||||||
class_<World>("World")
|
|
||||||
.def("greet", &World::greet)
|
|
||||||
.def("set", &World::set)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
Although this code has a certain pythonic familiarity, people
|
|
||||||
sometimes find the syntax bit confusing because it doesn't look like
|
|
||||||
most of the C++ code they're used to. All the same, this is just
|
|
||||||
standard C++. Because of their flexible syntax and operator
|
|
||||||
overloading, C++ and Python are great for defining domain-specific
|
|
||||||
(sub)languages
|
|
||||||
(DSLs), and that's what we've done in Boost.Python. To break it down::
|
|
||||||
|
|
||||||
class_<World>("World")
|
|
||||||
|
|
||||||
constructs an unnamed object of type ``class_<World>`` and passes
|
|
||||||
``"World"`` to its constructor. This creates a new-style Python class
|
|
||||||
called ``World`` in the extension module, and associates it with the
|
|
||||||
C++ type ``World`` in the Boost.Python type conversion registry. We
|
|
||||||
might have also written::
|
|
||||||
|
|
||||||
class_<World> w("World");
|
|
||||||
|
|
||||||
but that would've been more verbose, since we'd have to name ``w``
|
|
||||||
again to invoke its ``def()`` member function::
|
|
||||||
|
|
||||||
w.def("greet", &World::greet)
|
|
||||||
|
|
||||||
There's nothing special about the location of the dot for member
|
|
||||||
access in the original example: C++ allows any amount of whitespace on
|
|
||||||
either side of a token, and placing the dot at the beginning of each
|
|
||||||
line allows us to chain as many successive calls to member functions
|
|
||||||
as we like with a uniform syntax. The other key fact that allows
|
|
||||||
chaining is that ``class_<>`` member functions all return a reference
|
|
||||||
to ``*this``.
|
|
||||||
|
|
||||||
So the example is equivalent to::
|
|
||||||
|
|
||||||
class_<World> w("World");
|
|
||||||
w.def("greet", &World::greet);
|
|
||||||
w.def("set", &World::set);
|
|
||||||
|
|
||||||
It's occasionally useful to be able to break down the components of a
|
|
||||||
Boost.Python class wrapper in this way, but the rest of this article
|
|
||||||
will stick to the terse syntax.
|
|
||||||
|
|
||||||
For completeness, here's the wrapped class in use: ::
|
|
||||||
|
|
||||||
>>> import hello
|
|
||||||
>>> planet = hello.World()
|
|
||||||
>>> planet.set('howdy')
|
|
||||||
>>> planet.greet()
|
|
||||||
'howdy'
|
|
||||||
|
|
||||||
Constructors
|
|
||||||
============
|
|
||||||
|
|
||||||
Since our ``World`` class is just a plain ``struct``, it has an
|
|
||||||
implicit no-argument (nullary) constructor. Boost.Python exposes the
|
|
||||||
nullary constructor by default, which is why we were able to write: ::
|
|
||||||
|
|
||||||
>>> planet = hello.World()
|
|
||||||
|
|
||||||
However, well-designed classes in any language may require constructor
|
|
||||||
arguments in order to establish their invariants. Unlike Python,
|
|
||||||
where ``__init__`` is just a specially-named method, In C++
|
|
||||||
constructors cannot be handled like ordinary member functions. In
|
|
||||||
particular, we can't take their address: ``&World::World`` is an
|
|
||||||
error. The library provides a different interface for specifying
|
|
||||||
constructors. Given::
|
|
||||||
|
|
||||||
struct World
|
|
||||||
{
|
|
||||||
World(std::string msg); // added constructor
|
|
||||||
...
|
|
||||||
|
|
||||||
we can modify our wrapping code as follows::
|
|
||||||
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
...
|
|
||||||
|
|
||||||
of course, a C++ class may have additional constructors, and we can
|
|
||||||
expose those as well by passing more instances of ``init<...>`` to
|
|
||||||
``def()``::
|
|
||||||
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
.def(init<double, double>())
|
|
||||||
...
|
|
||||||
|
|
||||||
Boost.Python allows wrapped functions, member functions, and
|
|
||||||
constructors to be overloaded to mirror C++ overloading.
|
|
||||||
|
|
||||||
Data Members and Properties
|
|
||||||
===========================
|
|
||||||
|
|
||||||
Any publicly-accessible data members in a C++ class can be easily
|
|
||||||
exposed as either ``readonly`` or ``readwrite`` attributes::
|
|
||||||
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
.def_readonly("msg", &World::msg)
|
|
||||||
...
|
|
||||||
|
|
||||||
and can be used directly in Python: ::
|
|
||||||
|
|
||||||
>>> planet = hello.World('howdy')
|
|
||||||
>>> planet.msg
|
|
||||||
'howdy'
|
|
||||||
|
|
||||||
This does *not* result in adding attributes to the ``World`` instance
|
|
||||||
``__dict__``, which can result in substantial memory savings when
|
|
||||||
wrapping large data structures. In fact, no instance ``__dict__``
|
|
||||||
will be created at all unless attributes are explicitly added from
|
|
||||||
Python. Boost.Python owes this capability to the new Python 2.2 type
|
|
||||||
system, in particular the descriptor interface and ``property`` type.
|
|
||||||
|
|
||||||
In C++, publicly-accessible data members are considered a sign of poor
|
|
||||||
design because they break encapsulation, and style guides usually
|
|
||||||
dictate the use of "getter" and "setter" functions instead. In
|
|
||||||
Python, however, ``__getattr__``, ``__setattr__``, and since 2.2,
|
|
||||||
``property`` mean that attribute access is just one more
|
|
||||||
well-encapsulated syntactic tool at the programmer's disposal.
|
|
||||||
Boost.Python bridges this idiomatic gap by making Python ``property``
|
|
||||||
creation directly available to users. If ``msg`` were private, we
|
|
||||||
could still expose it as attribute in Python as follows::
|
|
||||||
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
.add_property("msg", &World::greet, &World::set)
|
|
||||||
...
|
|
||||||
|
|
||||||
The example above mirrors the familiar usage of properties in Python
|
|
||||||
2.2+: ::
|
|
||||||
|
|
||||||
>>> class World(object):
|
|
||||||
... __init__(self, msg):
|
|
||||||
... self.__msg = msg
|
|
||||||
... def greet(self):
|
|
||||||
... return self.__msg
|
|
||||||
... def set(self, msg):
|
|
||||||
... self.__msg = msg
|
|
||||||
... msg = property(greet, set)
|
|
||||||
|
|
||||||
Operator Overloading
|
|
||||||
====================
|
|
||||||
|
|
||||||
The ability to write arithmetic operators for user-defined types has
|
|
||||||
been a major factor in the success of both languages for numerical
|
|
||||||
computation, and the success of packages like NumPy_ attests to the
|
|
||||||
power of exposing operators in extension modules. Boost.Python
|
|
||||||
provides a concise mechanism for wrapping operator overloads. The
|
|
||||||
example below shows a fragment from a wrapper for the Boost rational
|
|
||||||
number library::
|
|
||||||
|
|
||||||
class_<rational<int> >("rational_int")
|
|
||||||
.def(init<int, int>()) // constructor, e.g. rational_int(3,4)
|
|
||||||
.def("numerator", &rational<int>::numerator)
|
|
||||||
.def("denominator", &rational<int>::denominator)
|
|
||||||
.def(-self) // __neg__ (unary minus)
|
|
||||||
.def(self + self) // __add__ (homogeneous)
|
|
||||||
.def(self * self) // __mul__
|
|
||||||
.def(self + int()) // __add__ (heterogenous)
|
|
||||||
.def(int() + self) // __radd__
|
|
||||||
...
|
|
||||||
|
|
||||||
The magic is performed using a simplified application of "expression
|
|
||||||
templates" [VELD1995]_, a technique originally developed for
|
|
||||||
optimization of high-performance matrix algebra expressions. The
|
|
||||||
essence is that instead of performing the computation immediately,
|
|
||||||
operators are overloaded to construct a type *representing* the
|
|
||||||
computation. In matrix algebra, dramatic optimizations are often
|
|
||||||
available when the structure of an entire expression can be taken into
|
|
||||||
account, rather than evaluating each operation "greedily".
|
|
||||||
Boost.Python uses the same technique to build an appropriate Python
|
|
||||||
method object based on expressions involving ``self``.
|
|
||||||
|
|
||||||
.. _NumPy: http://www.pfdubois.com/numpy/
|
|
||||||
|
|
||||||
Inheritance
|
|
||||||
===========
|
|
||||||
|
|
||||||
C++ inheritance relationships can be represented to Boost.Python by adding
|
|
||||||
an optional ``bases<...>`` argument to the ``class_<...>`` template
|
|
||||||
parameter list as follows::
|
|
||||||
|
|
||||||
class_<Derived, bases<Base1,Base2> >("Derived")
|
|
||||||
...
|
|
||||||
|
|
||||||
This has two effects:
|
|
||||||
|
|
||||||
1. When the ``class_<...>`` is created, Python type objects
|
|
||||||
corresponding to ``Base1`` and ``Base2`` are looked up in
|
|
||||||
Boost.Python's registry, and are used as bases for the new Python
|
|
||||||
``Derived`` type object, so methods exposed for the Python ``Base1``
|
|
||||||
and ``Base2`` types are automatically members of the ``Derived``
|
|
||||||
type. Because the registry is global, this works correctly even if
|
|
||||||
``Derived`` is exposed in a different module from either of its
|
|
||||||
bases.
|
|
||||||
|
|
||||||
2. C++ conversions from ``Derived`` to its bases are added to the
|
|
||||||
Boost.Python registry. Thus wrapped C++ methods expecting (a
|
|
||||||
pointer or reference to) an object of either base type can be
|
|
||||||
called with an object wrapping a ``Derived`` instance. Wrapped
|
|
||||||
member functions of class ``T`` are treated as though they have an
|
|
||||||
implicit first argument of ``T&``, so these conversions are
|
|
||||||
neccessary to allow the base class methods to be called for derived
|
|
||||||
objects.
|
|
||||||
|
|
||||||
Of course it's possible to derive new Python classes from wrapped C++
|
|
||||||
class instances. Because Boost.Python uses the new-style class
|
|
||||||
system, that works very much as for the Python built-in types. There
|
|
||||||
is one significant detail in which it differs: the built-in types
|
|
||||||
generally establish their invariants in their ``__new__`` function, so
|
|
||||||
that derived classes do not need to call ``__init__`` on the base
|
|
||||||
class before invoking its methods : ::
|
|
||||||
|
|
||||||
>>> class L(list):
|
|
||||||
... def __init__(self):
|
|
||||||
... pass
|
|
||||||
...
|
|
||||||
>>> L().reverse()
|
|
||||||
>>>
|
|
||||||
|
|
||||||
Because C++ object construction is a one-step operation, C++ instance
|
|
||||||
data cannot be constructed until the arguments are available, in the
|
|
||||||
``__init__`` function: ::
|
|
||||||
|
|
||||||
>>> class D(SomeBoostPythonClass):
|
|
||||||
... def __init__(self):
|
|
||||||
... pass
|
|
||||||
...
|
|
||||||
>>> D().some_boost_python_method()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "<stdin>", line 1, in ?
|
|
||||||
TypeError: bad argument type for built-in operation
|
|
||||||
|
|
||||||
This happened because Boost.Python couldn't find instance data of type
|
|
||||||
``SomeBoostPythonClass`` within the ``D`` instance; ``D``'s ``__init__``
|
|
||||||
function masked construction of the base class. It could be corrected
|
|
||||||
by either removing ``D``'s ``__init__`` function or having it call
|
|
||||||
``SomeBoostPythonClass.__init__(...)`` explicitly.
|
|
||||||
|
|
||||||
Virtual Functions
|
|
||||||
=================
|
|
||||||
|
|
||||||
Deriving new types in Python from extension classes is not very
|
|
||||||
interesting unless they can be used polymorphically from C++. In
|
|
||||||
other words, Python method implementations should appear to override
|
|
||||||
the implementation of C++ virtual functions when called *through base
|
|
||||||
class pointers/references from C++*. Since the only way to alter the
|
|
||||||
behavior of a virtual function is to override it in a derived class,
|
|
||||||
the user must build a special derived class to dispatch a polymorphic
|
|
||||||
class' virtual functions::
|
|
||||||
|
|
||||||
//
|
|
||||||
// interface to wrap:
|
|
||||||
//
|
|
||||||
class Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual int f(std::string x) { return 42; }
|
|
||||||
virtual ~Base();
|
|
||||||
};
|
|
||||||
|
|
||||||
int calls_f(Base const& b, std::string x) { return b.f(x); }
|
|
||||||
|
|
||||||
//
|
|
||||||
// Wrapping Code
|
|
||||||
//
|
|
||||||
|
|
||||||
// Dispatcher class
|
|
||||||
struct BaseWrap : Base
|
|
||||||
{
|
|
||||||
// Store a pointer to the Python object
|
|
||||||
BaseWrap(PyObject* self_) : self(self_) {}
|
|
||||||
PyObject* self;
|
|
||||||
|
|
||||||
// Default implementation, for when f is not overridden
|
|
||||||
int f_default(std::string x) { return this->Base::f(x); }
|
|
||||||
// Dispatch implementation
|
|
||||||
int f(std::string x) { return call_method<int>(self, "f", x); }
|
|
||||||
};
|
|
||||||
|
|
||||||
...
|
|
||||||
def("calls_f", calls_f);
|
|
||||||
class_<Base, BaseWrap>("Base")
|
|
||||||
.def("f", &Base::f, &BaseWrap::f_default)
|
|
||||||
;
|
|
||||||
|
|
||||||
Now here's some Python code which demonstrates: ::
|
|
||||||
|
|
||||||
>>> class Derived(Base):
|
|
||||||
... def f(self, s):
|
|
||||||
... return len(s)
|
|
||||||
...
|
|
||||||
>>> calls_f(Base(), 'foo')
|
|
||||||
42
|
|
||||||
>>> calls_f(Derived(), 'forty-two')
|
|
||||||
9
|
|
||||||
|
|
||||||
Things to notice about the dispatcher class:
|
|
||||||
|
|
||||||
* The key element which allows overriding in Python is the
|
|
||||||
``call_method`` invocation, which uses the same global type
|
|
||||||
conversion registry as the C++ function wrapping does to convert its
|
|
||||||
arguments from C++ to Python and its return type from Python to C++.
|
|
||||||
|
|
||||||
* Any constructor signatures you wish to wrap must be replicated with
|
|
||||||
an initial ``PyObject*`` argument
|
|
||||||
|
|
||||||
* The dispatcher must store this argument so that it can be used to
|
|
||||||
invoke ``call_method``
|
|
||||||
|
|
||||||
* The ``f_default`` member function is needed when the function being
|
|
||||||
exposed is not pure virtual; there's no other way ``Base::f`` can be
|
|
||||||
called on an object of type ``BaseWrap``, since it overrides ``f``.
|
|
||||||
|
|
||||||
Deeper Reflection on the Horizon?
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Admittedly, this formula is tedious to repeat, especially on a project
|
|
||||||
with many polymorphic classes. That it is neccessary reflects some
|
|
||||||
limitations in C++'s compile-time introspection capabilities: there's
|
|
||||||
no way to enumerate the members of a class and find out which are
|
|
||||||
virtual functions. At least one very promising project has been
|
|
||||||
started to write a front-end which can generate these dispatchers (and
|
|
||||||
other wrapping code) automatically from C++ headers.
|
|
||||||
|
|
||||||
Pyste_ is being developed by Bruno da Silva de Oliveira. It builds on
|
|
||||||
GCC_XML_, which generates an XML version of GCC's internal program
|
|
||||||
representation. Since GCC is a highly-conformant C++ compiler, this
|
|
||||||
ensures correct handling of the most-sophisticated template code and
|
|
||||||
full access to the underlying type system. In keeping with the
|
|
||||||
Boost.Python philosophy, a Pyste interface description is neither
|
|
||||||
intrusive on the code being wrapped, nor expressed in some unfamiliar
|
|
||||||
language: instead it is a 100% pure Python script. If Pyste is
|
|
||||||
successful it will mark a move away from wrapping everything directly
|
|
||||||
in C++ for many of our users. It will also allow us the choice to
|
|
||||||
shift some of the metaprogram code from C++ to Python. We expect that
|
|
||||||
soon, not only our users but the Boost.Python developers themselves
|
|
||||||
will be "thinking hybrid" about their own code.
|
|
||||||
|
|
||||||
.. _`GCC_XML`: http://www.gccxml.org/HTML/Index.html
|
|
||||||
.. _`Pyste`: http://www.boost.org/libs/python/pyste
|
|
||||||
|
|
||||||
---------------
|
|
||||||
Serialization
|
|
||||||
---------------
|
|
||||||
|
|
||||||
*Serialization* is the process of converting objects in memory to a
|
|
||||||
form that can be stored on disk or sent over a network connection. The
|
|
||||||
serialized object (most often a plain string) can be retrieved and
|
|
||||||
converted back to the original object. A good serialization system will
|
|
||||||
automatically convert entire object hierarchies. Python's standard
|
|
||||||
``pickle`` module is just such a system. It leverages the language's strong
|
|
||||||
runtime introspection facilities for serializing practically arbitrary
|
|
||||||
user-defined objects. With a few simple and unintrusive provisions this
|
|
||||||
powerful machinery can be extended to also work for wrapped C++ objects.
|
|
||||||
Here is an example::
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
struct World
|
|
||||||
{
|
|
||||||
World(std::string a_msg) : msg(a_msg) {}
|
|
||||||
std::string greet() const { return msg; }
|
|
||||||
std::string msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include <boost/python.hpp>
|
|
||||||
using namespace boost::python;
|
|
||||||
|
|
||||||
struct World_picklers : pickle_suite
|
|
||||||
{
|
|
||||||
static tuple
|
|
||||||
getinitargs(World const& w) { return make_tuple(w.greet()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
BOOST_PYTHON_MODULE(hello)
|
|
||||||
{
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
.def("greet", &World::greet)
|
|
||||||
.def_pickle(World_picklers())
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
Now let's create a ``World`` object and put it to rest on disk::
|
|
||||||
|
|
||||||
>>> import hello
|
|
||||||
>>> import pickle
|
|
||||||
>>> a_world = hello.World("howdy")
|
|
||||||
>>> pickle.dump(a_world, open("my_world", "w"))
|
|
||||||
|
|
||||||
In a potentially *different script* on a potentially *different
|
|
||||||
computer* with a potentially *different operating system*::
|
|
||||||
|
|
||||||
>>> import pickle
|
|
||||||
>>> resurrected_world = pickle.load(open("my_world", "r"))
|
|
||||||
>>> resurrected_world.greet()
|
|
||||||
'howdy'
|
|
||||||
|
|
||||||
Of course the ``cPickle`` module can also be used for faster
|
|
||||||
processing.
|
|
||||||
|
|
||||||
Boost.Python's ``pickle_suite`` fully supports the ``pickle`` protocol
|
|
||||||
defined in the standard Python documentation. Like a __getinitargs__
|
|
||||||
function in Python, the pickle_suite's getinitargs() is responsible for
|
|
||||||
creating the argument tuple that will be use to reconstruct the pickled
|
|
||||||
object. The other elements of the Python pickling protocol,
|
|
||||||
__getstate__ and __setstate__ can be optionally provided via C++
|
|
||||||
getstate and setstate functions. C++'s static type system allows the
|
|
||||||
library to ensure at compile-time that nonsensical combinations of
|
|
||||||
functions (e.g. getstate without setstate) are not used.
|
|
||||||
|
|
||||||
Enabling serialization of more complex C++ objects requires a little
|
|
||||||
more work than is shown in the example above. Fortunately the
|
|
||||||
``object`` interface (see next section) greatly helps in keeping the
|
|
||||||
code manageable.
|
|
||||||
|
|
||||||
------------------
|
|
||||||
Object interface
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Experienced 'C' language extension module authors will be familiar
|
|
||||||
with the ubiquitous ``PyObject*``, manual reference-counting, and the
|
|
||||||
need to remember which API calls return "new" (owned) references or
|
|
||||||
"borrowed" (raw) references. These constraints are not just
|
|
||||||
cumbersome but also a major source of errors, especially in the
|
|
||||||
presence of exceptions.
|
|
||||||
|
|
||||||
Boost.Python provides a class ``object`` which automates reference
|
|
||||||
counting and provides conversion to Python from C++ objects of
|
|
||||||
arbitrary type. This significantly reduces the learning effort for
|
|
||||||
prospective extension module writers.
|
|
||||||
|
|
||||||
Creating an ``object`` from any other type is extremely simple::
|
|
||||||
|
|
||||||
object s("hello, world"); // s manages a Python string
|
|
||||||
|
|
||||||
``object`` has templated interactions with all other types, with
|
|
||||||
automatic to-python conversions. It happens so naturally that it's
|
|
||||||
easily overlooked::
|
|
||||||
|
|
||||||
object ten_Os = 10 * s[4]; // -> "oooooooooo"
|
|
||||||
|
|
||||||
In the example above, ``4`` and ``10`` are converted to Python objects
|
|
||||||
before the indexing and multiplication operations are invoked.
|
|
||||||
|
|
||||||
The ``extract<T>`` class template can be used to convert Python objects
|
|
||||||
to C++ types::
|
|
||||||
|
|
||||||
double x = extract<double>(o);
|
|
||||||
|
|
||||||
If a conversion in either direction cannot be performed, an
|
|
||||||
appropriate exception is thrown at runtime.
|
|
||||||
|
|
||||||
The ``object`` type is accompanied by a set of derived types
|
|
||||||
that mirror the Python built-in types such as ``list``, ``dict``,
|
|
||||||
``tuple``, etc. as much as possible. This enables convenient
|
|
||||||
manipulation of these high-level types from C++::
|
|
||||||
|
|
||||||
dict d;
|
|
||||||
d["some"] = "thing";
|
|
||||||
d["lucky_number"] = 13;
|
|
||||||
list l = d.keys();
|
|
||||||
|
|
||||||
This almost looks and works like regular Python code, but it is pure
|
|
||||||
C++. Of course we can wrap C++ functions which accept or return
|
|
||||||
``object`` instances.
|
|
||||||
|
|
||||||
=================
|
|
||||||
Thinking hybrid
|
|
||||||
=================
|
|
||||||
|
|
||||||
Because of the practical and mental difficulties of combining
|
|
||||||
programming languages, it is common to settle a single language at the
|
|
||||||
outset of any development effort. For many applications, performance
|
|
||||||
considerations dictate the use of a compiled language for the core
|
|
||||||
algorithms. Unfortunately, due to the complexity of the static type
|
|
||||||
system, the price we pay for runtime performance is often a
|
|
||||||
significant increase in development time. Experience shows that
|
|
||||||
writing maintainable C++ code usually takes longer and requires *far*
|
|
||||||
more hard-earned working experience than developing comparable Python
|
|
||||||
code. Even when developers are comfortable working exclusively in
|
|
||||||
compiled languages, they often augment their systems by some type of
|
|
||||||
ad hoc scripting layer for the benefit of their users without ever
|
|
||||||
availing themselves of the same advantages.
|
|
||||||
|
|
||||||
Boost.Python enables us to *think hybrid*. Python can be used for
|
|
||||||
rapidly prototyping a new application; its ease of use and the large
|
|
||||||
pool of standard libraries give us a head start on the way to a
|
|
||||||
working system. If necessary, the working code can be used to
|
|
||||||
discover rate-limiting hotspots. To maximize performance these can
|
|
||||||
be reimplemented in C++, together with the Boost.Python bindings
|
|
||||||
needed to tie them back into the existing higher-level procedure.
|
|
||||||
|
|
||||||
Of course, this *top-down* approach is less attractive if it is clear
|
|
||||||
from the start that many algorithms will eventually have to be
|
|
||||||
implemented in C++. Fortunately Boost.Python also enables us to
|
|
||||||
pursue a *bottom-up* approach. We have used this approach very
|
|
||||||
successfully in the development of a toolbox for scientific
|
|
||||||
applications. The toolbox started out mainly as a library of C++
|
|
||||||
classes with Boost.Python bindings, and for a while the growth was
|
|
||||||
mainly concentrated on the C++ parts. However, as the toolbox is
|
|
||||||
becoming more complete, more and more newly added functionality can be
|
|
||||||
implemented in Python.
|
|
||||||
|
|
||||||
.. image:: python_cpp_mix.jpg
|
|
||||||
|
|
||||||
This figure shows the estimated ratio of newly added C++ and Python
|
|
||||||
code over time as new algorithms are implemented. We expect this
|
|
||||||
ratio to level out near 70% Python. Being able to solve new problems
|
|
||||||
mostly in Python rather than a more difficult statically typed
|
|
||||||
language is the return on our investment in Boost.Python. The ability
|
|
||||||
to access all of our code from Python allows a broader group of
|
|
||||||
developers to use it in the rapid development of new applications.
|
|
||||||
|
|
||||||
=====================
|
|
||||||
Development history
|
|
||||||
=====================
|
|
||||||
|
|
||||||
The first version of Boost.Python was developed in 2000 by Dave
|
|
||||||
Abrahams at Dragon Systems, where he was privileged to have Tim Peters
|
|
||||||
as a guide to "The Zen of Python". One of Dave's jobs was to develop
|
|
||||||
a Python-based natural language processing system. Since it was
|
|
||||||
eventually going to be targeting embedded hardware, it was always
|
|
||||||
assumed that the compute-intensive core would be rewritten in C++ to
|
|
||||||
optimize speed and memory footprint [#proto]_. The project also wanted to
|
|
||||||
test all of its C++ code using Python test scripts [#test]_. The only
|
|
||||||
tool we knew of for binding C++ and Python was SWIG_, and at the time
|
|
||||||
its handling of C++ was weak. It would be false to claim any deep
|
|
||||||
insight into the possible advantages of Boost.Python's approach at
|
|
||||||
this point. Dave's interest and expertise in fancy C++ template
|
|
||||||
tricks had just reached the point where he could do some real damage,
|
|
||||||
and Boost.Python emerged as it did because it filled a need and
|
|
||||||
because it seemed like a cool thing to try.
|
|
||||||
|
|
||||||
This early version was aimed at many of the same basic goals we've
|
|
||||||
described in this paper, differing most-noticeably by having a
|
|
||||||
slightly more cumbersome syntax and by lack of special support for
|
|
||||||
operator overloading, pickling, and component-based development.
|
|
||||||
These last three features were quickly added by Ullrich Koethe and
|
|
||||||
Ralf Grosse-Kunstleve [#feature]_, and other enthusiastic contributors arrived
|
|
||||||
on the scene to contribute enhancements like support for nested
|
|
||||||
modules and static member functions.
|
|
||||||
|
|
||||||
By early 2001 development had stabilized and few new features were
|
|
||||||
being added, however a disturbing new fact came to light: Ralf had
|
|
||||||
begun testing Boost.Python on pre-release versions of a compiler using
|
|
||||||
the EDG_ front-end, and the mechanism at the core of Boost.Python
|
|
||||||
responsible for handling conversions between Python and C++ types was
|
|
||||||
failing to compile. As it turned out, we had been exploiting a very
|
|
||||||
common bug in the implementation of all the C++ compilers we had
|
|
||||||
tested. We knew that as C++ compilers rapidly became more
|
|
||||||
standards-compliant, the library would begin failing on more
|
|
||||||
platforms. Unfortunately, because the mechanism was so central to the
|
|
||||||
functioning of the library, fixing the problem looked very difficult.
|
|
||||||
|
|
||||||
Fortunately, later that year Lawrence Berkeley and later Lawrence
|
|
||||||
Livermore National labs contracted with `Boost Consulting`_ for support
|
|
||||||
and development of Boost.Python, and there was a new opportunity to
|
|
||||||
address fundamental issues and ensure a future for the library. A
|
|
||||||
redesign effort began with the low level type conversion architecture,
|
|
||||||
building in standards-compliance and support for component-based
|
|
||||||
development (in contrast to version 1 where conversions had to be
|
|
||||||
explicitly imported and exported across module boundaries). A new
|
|
||||||
analysis of the relationship between the Python and C++ objects was
|
|
||||||
done, resulting in more intuitive handling for C++ lvalues and
|
|
||||||
rvalues.
|
|
||||||
|
|
||||||
The emergence of a powerful new type system in Python 2.2 made the
|
|
||||||
choice of whether to maintain compatibility with Python 1.5.2 easy:
|
|
||||||
the opportunity to throw away a great deal of elaborate code for
|
|
||||||
emulating classic Python classes alone was too good to pass up. In
|
|
||||||
addition, Python iterators and descriptors provided crucial and
|
|
||||||
elegant tools for representing similar C++ constructs. The
|
|
||||||
development of the generalized ``object`` interface allowed us to
|
|
||||||
further shield C++ programmers from the dangers and syntactic burdens
|
|
||||||
of the Python 'C' API. A great number of other features including C++
|
|
||||||
exception translation, improved support for overloaded functions, and
|
|
||||||
most significantly, CallPolicies for handling pointers and
|
|
||||||
references, were added during this period.
|
|
||||||
|
|
||||||
In October 2002, version 2 of Boost.Python was released. Development
|
|
||||||
since then has concentrated on improved support for C++ runtime
|
|
||||||
polymorphism and smart pointers. Peter Dimov's ingenious
|
|
||||||
``boost::shared_ptr`` design in particular has allowed us to give the
|
|
||||||
hybrid developer a consistent interface for moving objects back and
|
|
||||||
forth across the language barrier without loss of information. At
|
|
||||||
first, we were concerned that the sophistication and complexity of the
|
|
||||||
Boost.Python v2 implementation might discourage contributors, but the
|
|
||||||
emergence of Pyste_ and several other significant feature
|
|
||||||
contributions have laid those fears to rest. Daily questions on the
|
|
||||||
Python C++-sig and a backlog of desired improvements show that the
|
|
||||||
library is getting used. To us, the future looks bright.
|
|
||||||
|
|
||||||
.. _`EDG`: http://www.edg.com
|
|
||||||
|
|
||||||
=============
|
|
||||||
Conclusions
|
|
||||||
=============
|
|
||||||
|
|
||||||
Boost.Python achieves seamless interoperability between two rich and
|
|
||||||
complimentary language environments. Because it leverages template
|
|
||||||
metaprogramming to introspect about types and functions, the user
|
|
||||||
never has to learn a third syntax: the interface definitions are
|
|
||||||
written in concise and maintainable C++. Also, the wrapping system
|
|
||||||
doesn't have to parse C++ headers or represent the type system: the
|
|
||||||
compiler does that work for us.
|
|
||||||
|
|
||||||
Computationally intensive tasks play to the strengths of C++ and are
|
|
||||||
often impossible to implement efficiently in pure Python, while jobs
|
|
||||||
like serialization that are trivial in Python can be very difficult in
|
|
||||||
pure C++. Given the luxury of building a hybrid software system from
|
|
||||||
the ground up, we can approach design with new confidence and power.
|
|
||||||
|
|
||||||
===========
|
|
||||||
Citations
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. [VELD1995] T. Veldhuizen, "Expression Templates," C++ Report,
|
|
||||||
Vol. 7 No. 5 June 1995, pp. 26-31.
|
|
||||||
http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html
|
|
||||||
|
|
||||||
===========
|
|
||||||
Footnotes
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. [#proto] In retrospect, it seems that "thinking hybrid" from the
|
|
||||||
ground up might have been better for the NLP system: the
|
|
||||||
natural component boundaries defined by the pure python
|
|
||||||
prototype turned out to be inappropriate for getting the
|
|
||||||
desired performance and memory footprint out of the C++ core,
|
|
||||||
which eventually caused some redesign overhead on the Python
|
|
||||||
side when the core was moved to C++.
|
|
||||||
|
|
||||||
.. [#test] We also have some reservations about driving all C++
|
|
||||||
testing through a Python interface, unless that's the only way
|
|
||||||
it will be ultimately used. Any transition across language
|
|
||||||
boundaries with such different object models can inevitably
|
|
||||||
mask bugs.
|
|
||||||
|
|
||||||
.. [#feature] These features were expressed very differently in v1 of
|
|
||||||
Boost.Python
|
|
||||||
@@ -1,908 +0,0 @@
|
|||||||
.. This is a comment. Note how any initial comments are moved by
|
|
||||||
transforms to after the document title, subtitle, and docinfo.
|
|
||||||
|
|
||||||
.. Need intro and conclusion
|
|
||||||
.. Exposing classes
|
|
||||||
.. Constructors
|
|
||||||
.. Overloading
|
|
||||||
.. Properties and data members
|
|
||||||
.. Inheritance
|
|
||||||
.. Operators and Special Functions
|
|
||||||
.. Virtual Functions
|
|
||||||
.. Call Policies
|
|
||||||
|
|
||||||
++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
Introducing Boost.Python (Extended Abstract)
|
|
||||||
++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
|
|
||||||
|
|
||||||
.. bibliographic fields (which also require a transform):
|
|
||||||
|
|
||||||
:Author: David Abrahams
|
|
||||||
:Address: 45 Walnut Street
|
|
||||||
Somerville, MA 02143
|
|
||||||
:Contact: dave@boost-consulting.com
|
|
||||||
:organization: `Boost Consulting`_
|
|
||||||
:date: $Date$
|
|
||||||
:status: This is a "work in progress"
|
|
||||||
:version: 1
|
|
||||||
:copyright: Copyright David Abrahams 2002. All rights reserved
|
|
||||||
|
|
||||||
:Dedication:
|
|
||||||
|
|
||||||
For my girlfriend, wife, and partner Luann
|
|
||||||
|
|
||||||
:abstract:
|
|
||||||
|
|
||||||
This paper describes the Boost.Python library, a system for
|
|
||||||
C++/Python interoperability.
|
|
||||||
|
|
||||||
.. meta::
|
|
||||||
:keywords: Boost,python,Boost.Python,C++
|
|
||||||
:description lang=en: C++/Python interoperability with Boost.Python
|
|
||||||
|
|
||||||
.. contents:: Table of Contents
|
|
||||||
.. section-numbering::
|
|
||||||
|
|
||||||
|
|
||||||
.. _`Boost Consulting`: http://www.boost-consulting.com
|
|
||||||
|
|
||||||
==============
|
|
||||||
Introduction
|
|
||||||
==============
|
|
||||||
|
|
||||||
Python and C++ are in many ways as different as two languages could
|
|
||||||
be: while C++ is usually compiled to machine-code, Python is
|
|
||||||
interpreted. Python's dynamic type system is often cited as the
|
|
||||||
foundation of its flexibility, while in C++ static typing is the
|
|
||||||
cornerstone of its efficiency. C++ has an intricate and difficult
|
|
||||||
meta-language to support compile-time polymorphism, while Python is
|
|
||||||
a uniform language with convenient runtime polymorphism.
|
|
||||||
|
|
||||||
Yet for many programmers, these very differences mean that Python and
|
|
||||||
C++ complement one another perfectly. Performance bottlenecks in
|
|
||||||
Python programs can be rewritten in C++ for maximal speed, and
|
|
||||||
authors of powerful C++ libraries choose Python as a middleware
|
|
||||||
language for its flexible system integration capabilities.
|
|
||||||
Furthermore, the surface differences mask some strong similarities:
|
|
||||||
|
|
||||||
* 'C'-family control structures (if, while, for...)
|
|
||||||
|
|
||||||
* Support for object-orientation, functional programming, and generic
|
|
||||||
programming (these are both *multi-paradigm* programming languages.)
|
|
||||||
|
|
||||||
* Comprehensive operator overloading facilities, recognizing the
|
|
||||||
importance of syntactic variability for readability and
|
|
||||||
expressivity.
|
|
||||||
|
|
||||||
* High-level concepts such as collections and iterators.
|
|
||||||
|
|
||||||
* High-level encapsulation facilities (C++: namespaces, Python: modules)
|
|
||||||
to support the design of re-usable libraries.
|
|
||||||
|
|
||||||
* Exception-handling for effective management of error conditions.
|
|
||||||
|
|
||||||
* C++ idioms in common use, such as handle/body classes and
|
|
||||||
reference-counted smart pointers mirror Python reference semantics.
|
|
||||||
|
|
||||||
Python provides a rich 'C' API for writers of 'C' extension modules.
|
|
||||||
Unfortunately, using this API directly for exposing C++ type and
|
|
||||||
function interfaces to Python is much more tedious than it should be.
|
|
||||||
This is mainly due to the limitations of the 'C' language. Compared to
|
|
||||||
C++ and Python, 'C' has only very rudimentary abstraction facilities.
|
|
||||||
Support for exception-handling is completely missing. One important
|
|
||||||
undesirable consequence is that 'C' extension module writers are
|
|
||||||
required to manually manage Python reference counts. Another unpleasant
|
|
||||||
consequence is a very high degree of repetition of similar code in 'C'
|
|
||||||
extension modules. Of course highly redundant code does not only cause
|
|
||||||
frustration for the module writer, but is also very difficult to
|
|
||||||
maintain.
|
|
||||||
|
|
||||||
The limitations of the 'C' API have lead to the development of a
|
|
||||||
variety of wrapping systems. SWIG_ is probably the most popular package
|
|
||||||
for the integration of C/C++ and Python. A more recent development is
|
|
||||||
the SIP_ package, which is specifically designed for interfacing Python
|
|
||||||
with the Qt_ graphical user interface library. Both SWIG and SIP
|
|
||||||
introduce a new specialized language for defining the inter-language
|
|
||||||
bindings. Of course being able to use a specialized language has
|
|
||||||
advantages, but having to deal with three different languages (Python,
|
|
||||||
C/C++ and the interface language) also introduces practical and mental
|
|
||||||
difficulties. The CXX_ package demonstrates an interesting alternative.
|
|
||||||
It shows that at least some parts of Python's 'C' API can be wrapped
|
|
||||||
and presented through a much more user-friendly C++ interface. However,
|
|
||||||
unlike SWIG and SIP, CXX does not include support for wrapping C++
|
|
||||||
classes as new Python types. CXX is also no longer actively developed.
|
|
||||||
|
|
||||||
In some respects Boost.Python combines ideas from SWIG and SIP with
|
|
||||||
ideas from CXX. Like SWIG and SIP, Boost.Python is a system for
|
|
||||||
wrapping C++ classes as new Python "built-in" types, and C/C++
|
|
||||||
functions as Python functions. Like CXX, Boost.Python presents Python's
|
|
||||||
'C' API through a C++ interface. Boost.Python goes beyond the scope of
|
|
||||||
other systems with the unique support for C++ virtual functions that
|
|
||||||
are overrideable in Python, support for organizing extensions as Python
|
|
||||||
packages with a central registry for inter-language type conversions,
|
|
||||||
and a convenient mechanism for tying into Python's serialization engine
|
|
||||||
(pickle). Importantly, all this is achieved without introducing a new
|
|
||||||
syntax. Boost.Python leverages the power of C++ meta-programming
|
|
||||||
techniques to introspect about the C++ type system, and presents a
|
|
||||||
simple, IDL-like C++ interface for exposing C/C++ code in extension
|
|
||||||
modules. Boost.Python is a pure C++ library, the inter-language
|
|
||||||
bindings are defined in pure C++, and other than a C++ compiler only
|
|
||||||
Python itself is required to get started with Boost.Python. Last but
|
|
||||||
not least, Boost.Python is an unrestricted open source library. There
|
|
||||||
are no strings attached even for commercial applications.
|
|
||||||
|
|
||||||
.. _SWIG: http://www.swig.org/
|
|
||||||
.. _SIP: http://www.riverbankcomputing.co.uk/sip/index.php
|
|
||||||
.. _Qt: http://www.trolltech.com/
|
|
||||||
.. _CXX: http://cxx.sourceforge.net/
|
|
||||||
|
|
||||||
===========================
|
|
||||||
Boost.Python Design Goals
|
|
||||||
===========================
|
|
||||||
|
|
||||||
The primary goal of Boost.Python is to allow users to expose C++
|
|
||||||
classes and functions to Python using nothing more than a C++
|
|
||||||
compiler. In broad strokes, the user experience should be one of
|
|
||||||
directly manipulating C++ objects from Python.
|
|
||||||
|
|
||||||
However, it's also important not to translate all interfaces *too*
|
|
||||||
literally: the idioms of each language must be respected. For
|
|
||||||
example, though C++ and Python both have an iterator concept, they are
|
|
||||||
expressed very differently. Boost.Python has to be able to bridge the
|
|
||||||
interface gap.
|
|
||||||
|
|
||||||
It must be possible to insulate Python users from crashes resulting
|
|
||||||
from trivial misuses of C++ interfaces, such as accessing
|
|
||||||
already-deleted objects. By the same token the library should
|
|
||||||
insulate C++ users from low-level Python 'C' API, replacing
|
|
||||||
error-prone 'C' interfaces like manual reference-count management and
|
|
||||||
raw ``PyObject`` pointers with more-robust alternatives.
|
|
||||||
|
|
||||||
Support for component-based development is crucial, so that C++ types
|
|
||||||
exposed in one extension module can be passed to functions exposed in
|
|
||||||
another without loss of crucial information like C++ inheritance
|
|
||||||
relationships.
|
|
||||||
|
|
||||||
Finally, all wrapping must be *non-intrusive*, without modifying or
|
|
||||||
even seeing the original C++ source code. Existing C++ libraries have
|
|
||||||
to be wrappable by third parties who only have access to header files
|
|
||||||
and binaries.
|
|
||||||
|
|
||||||
==========================
|
|
||||||
Hello Boost.Python World
|
|
||||||
==========================
|
|
||||||
|
|
||||||
And now for a preview of Boost.Python, and how it improves on the raw
|
|
||||||
facilities offered by Python. Here's a function we might want to
|
|
||||||
expose::
|
|
||||||
|
|
||||||
char const* greet(unsigned x)
|
|
||||||
{
|
|
||||||
static char const* const msgs[] = { "hello", "Boost.Python", "world!" };
|
|
||||||
|
|
||||||
if (x > 2)
|
|
||||||
throw std::range_error("greet: index out of range");
|
|
||||||
|
|
||||||
return msgs[x];
|
|
||||||
}
|
|
||||||
|
|
||||||
To wrap this function in standard C++ using the Python 'C' API, we'd
|
|
||||||
need something like this::
|
|
||||||
|
|
||||||
extern "C" // all Python interactions use 'C' linkage and calling convention
|
|
||||||
{
|
|
||||||
// Wrapper to handle argument/result conversion and checking
|
|
||||||
PyObject* greet_wrap(PyObject* args, PyObject * keywords)
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
if (PyArg_ParseTuple(args, "i", &x)) // extract/check arguments
|
|
||||||
{
|
|
||||||
char const* result = greet(x); // invoke wrapped function
|
|
||||||
return PyString_FromString(result); // convert result to Python
|
|
||||||
}
|
|
||||||
return 0; // error occurred
|
|
||||||
}
|
|
||||||
|
|
||||||
// Table of wrapped functions to be exposed by the module
|
|
||||||
static PyMethodDef methods[] = {
|
|
||||||
{ "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" }
|
|
||||||
, { NULL, NULL, 0, NULL } // sentinel
|
|
||||||
};
|
|
||||||
|
|
||||||
// module initialization function
|
|
||||||
DL_EXPORT init_hello()
|
|
||||||
{
|
|
||||||
(void) Py_InitModule("hello", methods); // add the methods to the module
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Now here's the wrapping code we'd use to expose it with Boost.Python::
|
|
||||||
|
|
||||||
#include <boost/python.hpp>
|
|
||||||
using namespace boost::python;
|
|
||||||
BOOST_PYTHON_MODULE(hello)
|
|
||||||
{
|
|
||||||
def("greet", greet, "return one of 3 parts of a greeting");
|
|
||||||
}
|
|
||||||
|
|
||||||
and here it is in action::
|
|
||||||
|
|
||||||
>>> import hello
|
|
||||||
>>> for x in range(3):
|
|
||||||
... print hello.greet(x)
|
|
||||||
...
|
|
||||||
hello
|
|
||||||
Boost.Python
|
|
||||||
world!
|
|
||||||
|
|
||||||
Aside from the fact that the 'C' API version is much more verbose than
|
|
||||||
the BPL one, it's worth noting that it doesn't handle a few things
|
|
||||||
correctly:
|
|
||||||
|
|
||||||
* The original function accepts an unsigned integer, and the Python
|
|
||||||
'C' API only gives us a way of extracting signed integers. The
|
|
||||||
Boost.Python version will raise a Python exception if we try to pass
|
|
||||||
a negative number to ``hello.greet``, but the other one will proceed
|
|
||||||
to do whatever the C++ implementation does when converting an
|
|
||||||
negative integer to unsigned (usually wrapping to some very large
|
|
||||||
number), and pass the incorrect translation on to the wrapped
|
|
||||||
function.
|
|
||||||
|
|
||||||
* That brings us to the second problem: if the C++ ``greet()``
|
|
||||||
function is called with a number greater than 2, it will throw an
|
|
||||||
exception. Typically, if a C++ exception propagates across the
|
|
||||||
boundary with code generated by a 'C' compiler, it will cause a
|
|
||||||
crash. As you can see in the first version, there's no C++
|
|
||||||
scaffolding there to prevent this from happening. Functions wrapped
|
|
||||||
by Boost.Python automatically include an exception-handling layer
|
|
||||||
which protects Python users by translating unhandled C++ exceptions
|
|
||||||
into a corresponding Python exception.
|
|
||||||
|
|
||||||
* A slightly more-subtle limitation is that the argument conversion
|
|
||||||
used in the Python 'C' API case can only get that integer ``x`` in
|
|
||||||
*one way*. PyArg_ParseTuple can't convert Python ``long`` objects
|
|
||||||
(arbitrary-precision integers) which happen to fit in an ``unsigned
|
|
||||||
int`` but not in a ``signed long``, nor will it ever handle a
|
|
||||||
wrapped C++ class with a user-defined implicit ``operator unsigned
|
|
||||||
int()`` conversion. The BPL's dynamic type conversion registry
|
|
||||||
allows users to add arbitrary conversion methods.
|
|
||||||
|
|
||||||
==================
|
|
||||||
Library Overview
|
|
||||||
==================
|
|
||||||
|
|
||||||
This section outlines some of the library's major features. Except as
|
|
||||||
neccessary to avoid confusion, details of library implementation are
|
|
||||||
omitted.
|
|
||||||
|
|
||||||
-------------------------------------------
|
|
||||||
The fundamental type-conversion mechanism
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
XXX This needs to be rewritten.
|
|
||||||
|
|
||||||
Every argument of every wrapped function requires some kind of
|
|
||||||
extraction code to convert it from Python to C++. Likewise, the
|
|
||||||
function return value has to be converted from C++ to Python.
|
|
||||||
Appropriate Python exceptions must be raised if the conversion fails.
|
|
||||||
Argument and return types are part of the function's type, and much of
|
|
||||||
this tedium can be relieved if the wrapping system can extract that
|
|
||||||
information through introspection.
|
|
||||||
|
|
||||||
Passing a wrapped C++ derived class instance to a C++ function
|
|
||||||
accepting a pointer or reference to a base class requires knowledge of
|
|
||||||
the inheritance relationship and how to translate the address of a base
|
|
||||||
class into that of a derived class.
|
|
||||||
|
|
||||||
------------------
|
|
||||||
Exposing Classes
|
|
||||||
------------------
|
|
||||||
|
|
||||||
C++ classes and structs are exposed with a similarly-terse interface.
|
|
||||||
Given::
|
|
||||||
|
|
||||||
struct World
|
|
||||||
{
|
|
||||||
void set(std::string msg) { this->msg = msg; }
|
|
||||||
std::string greet() { return msg; }
|
|
||||||
std::string msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
The following code will expose it in our extension module::
|
|
||||||
|
|
||||||
#include <boost/python.hpp>
|
|
||||||
BOOST_PYTHON_MODULE(hello)
|
|
||||||
{
|
|
||||||
class_<World>("World")
|
|
||||||
.def("greet", &World::greet)
|
|
||||||
.def("set", &World::set)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
Although this code has a certain pythonic familiarity, people
|
|
||||||
sometimes find the syntax bit confusing because it doesn't look like
|
|
||||||
most of the C++ code they're used to. All the same, this is just
|
|
||||||
standard C++. Because of their flexible syntax and operator
|
|
||||||
overloading, C++ and Python are great for defining domain-specific
|
|
||||||
(sub)languages
|
|
||||||
(DSLs), and that's what we've done in BPL. To break it down::
|
|
||||||
|
|
||||||
class_<World>("World")
|
|
||||||
|
|
||||||
constructs an unnamed object of type ``class_<World>`` and passes
|
|
||||||
``"World"`` to its constructor. This creates a new-style Python class
|
|
||||||
called ``World`` in the extension module, and associates it with the
|
|
||||||
C++ type ``World`` in the BPL type conversion registry. We might have
|
|
||||||
also written::
|
|
||||||
|
|
||||||
class_<World> w("World");
|
|
||||||
|
|
||||||
but that would've been more verbose, since we'd have to name ``w``
|
|
||||||
again to invoke its ``def()`` member function::
|
|
||||||
|
|
||||||
w.def("greet", &World::greet)
|
|
||||||
|
|
||||||
There's nothing special about the location of the dot for member
|
|
||||||
access in the original example: C++ allows any amount of whitespace on
|
|
||||||
either side of a token, and placing the dot at the beginning of each
|
|
||||||
line allows us to chain as many successive calls to member functions
|
|
||||||
as we like with a uniform syntax. The other key fact that allows
|
|
||||||
chaining is that ``class_<>`` member functions all return a reference
|
|
||||||
to ``*this``.
|
|
||||||
|
|
||||||
So the example is equivalent to::
|
|
||||||
|
|
||||||
class_<World> w("World");
|
|
||||||
w.def("greet", &World::greet);
|
|
||||||
w.def("set", &World::set);
|
|
||||||
|
|
||||||
It's occasionally useful to be able to break down the components of a
|
|
||||||
Boost.Python class wrapper in this way, but the rest of this paper
|
|
||||||
will tend to stick to the terse syntax.
|
|
||||||
|
|
||||||
For completeness, here's the wrapped class in use:
|
|
||||||
|
|
||||||
>>> import hello
|
|
||||||
>>> planet = hello.World()
|
|
||||||
>>> planet.set('howdy')
|
|
||||||
>>> planet.greet()
|
|
||||||
'howdy'
|
|
||||||
|
|
||||||
Constructors
|
|
||||||
============
|
|
||||||
|
|
||||||
Since our ``World`` class is just a plain ``struct``, it has an
|
|
||||||
implicit no-argument (nullary) constructor. Boost.Python exposes the
|
|
||||||
nullary constructor by default, which is why we were able to write:
|
|
||||||
|
|
||||||
>>> planet = hello.World()
|
|
||||||
|
|
||||||
However, well-designed classes in any language may require constructor
|
|
||||||
arguments in order to establish their invariants. Unlike Python,
|
|
||||||
where ``__init__`` is just a specially-named method, In C++
|
|
||||||
constructors cannot be handled like ordinary member functions. In
|
|
||||||
particular, we can't take their address: ``&World::World`` is an
|
|
||||||
error. The library provides a different interface for specifying
|
|
||||||
constructors. Given::
|
|
||||||
|
|
||||||
struct World
|
|
||||||
{
|
|
||||||
World(std::string msg); // added constructor
|
|
||||||
...
|
|
||||||
|
|
||||||
we can modify our wrapping code as follows::
|
|
||||||
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
...
|
|
||||||
|
|
||||||
of course, a C++ class may have additional constructors, and we can
|
|
||||||
expose those as well by passing more instances of ``init<...>`` to
|
|
||||||
``def()``::
|
|
||||||
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
.def(init<double, double>())
|
|
||||||
...
|
|
||||||
|
|
||||||
Boost.Python allows wrapped functions, member functions, and
|
|
||||||
constructors to be overloaded to mirror C++ overloading.
|
|
||||||
|
|
||||||
Data Members and Properties
|
|
||||||
===========================
|
|
||||||
|
|
||||||
Any publicly-accessible data members in a C++ class can be easily
|
|
||||||
exposed as either ``readonly`` or ``readwrite`` attributes::
|
|
||||||
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
.def_readonly("msg", &World::msg)
|
|
||||||
...
|
|
||||||
|
|
||||||
and can be used directly in Python:
|
|
||||||
|
|
||||||
>>> planet = hello.World('howdy')
|
|
||||||
>>> planet.msg
|
|
||||||
'howdy'
|
|
||||||
|
|
||||||
This does *not* result in adding attributes to the ``World`` instance
|
|
||||||
``__dict__``, which can result in substantial memory savings when
|
|
||||||
wrapping large data structures. In fact, no instance ``__dict__``
|
|
||||||
will be created at all unless attributes are explicitly added from
|
|
||||||
Python. BPL owes this capability to the new Python 2.2 type system,
|
|
||||||
in particular the descriptor interface and ``property`` type.
|
|
||||||
|
|
||||||
In C++, publicly-accessible data members are considered a sign of poor
|
|
||||||
design because they break encapsulation, and style guides usually
|
|
||||||
dictate the use of "getter" and "setter" functions instead. In
|
|
||||||
Python, however, ``__getattr__``, ``__setattr__``, and since 2.2,
|
|
||||||
``property`` mean that attribute access is just one more
|
|
||||||
well-encapsulated syntactic tool at the programmer's disposal. BPL
|
|
||||||
bridges this idiomatic gap by making Python ``property`` creation
|
|
||||||
directly available to users. So if ``msg`` were private, we could
|
|
||||||
still expose it as attribute in Python as follows::
|
|
||||||
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
.add_property("msg", &World::greet, &World::set)
|
|
||||||
...
|
|
||||||
|
|
||||||
The example above mirrors the familiar usage of properties in Python
|
|
||||||
2.2+:
|
|
||||||
|
|
||||||
>>> class World(object):
|
|
||||||
... __init__(self, msg):
|
|
||||||
... self.__msg = msg
|
|
||||||
... def greet(self):
|
|
||||||
... return self.__msg
|
|
||||||
... def set(self, msg):
|
|
||||||
... self.__msg = msg
|
|
||||||
... msg = property(greet, set)
|
|
||||||
|
|
||||||
Operators and Special Functions
|
|
||||||
===============================
|
|
||||||
|
|
||||||
The ability to write arithmetic operators for user-defined types that
|
|
||||||
C++ and Python both allow the definition of has been a major factor in
|
|
||||||
the popularity of both languages for scientific computing. The
|
|
||||||
success of packages like NumPy attests to the power of exposing
|
|
||||||
operators in extension modules. In this example we'll wrap a class
|
|
||||||
representing a position in a large file::
|
|
||||||
|
|
||||||
class FilePos { /*...*/ };
|
|
||||||
|
|
||||||
// Linear offset
|
|
||||||
FilePos operator+(FilePos, int);
|
|
||||||
FilePos operator+(int, FilePos);
|
|
||||||
FilePos operator-(FilePos, int);
|
|
||||||
|
|
||||||
// Distance between two FilePos objects
|
|
||||||
int operator-(FilePos, FilePos);
|
|
||||||
|
|
||||||
// Offset with assignment
|
|
||||||
FilePos& operator+=(FilePos&, int);
|
|
||||||
FilePos& operator-=(FilePos&, int);
|
|
||||||
|
|
||||||
// Comparison
|
|
||||||
bool operator<(FilePos, FilePos);
|
|
||||||
|
|
||||||
The wrapping code looks like this::
|
|
||||||
|
|
||||||
class_<FilePos>("FilePos")
|
|
||||||
.def(self + int()) // __add__
|
|
||||||
.def(int() + self) // __radd__
|
|
||||||
.def(self - int()) // __sub__
|
|
||||||
|
|
||||||
.def(self - self) // __sub__
|
|
||||||
|
|
||||||
.def(self += int()) // __iadd__
|
|
||||||
.def(self -= int()) // __isub__
|
|
||||||
|
|
||||||
.def(self < self); // __lt__
|
|
||||||
;
|
|
||||||
|
|
||||||
The magic is performed using a simplified application of "expression
|
|
||||||
templates" [VELD1995]_, a technique originally developed by for
|
|
||||||
optimization of high-performance matrix algebra expressions. The
|
|
||||||
essence is that instead of performing the computation immediately,
|
|
||||||
operators are overloaded to construct a type *representing* the
|
|
||||||
computation. In matrix algebra, dramatic optimizations are often
|
|
||||||
available when the structure of an entire expression can be taken into
|
|
||||||
account, rather than processing each operation "greedily".
|
|
||||||
Boost.Python uses the same technique to build an appropriate Python
|
|
||||||
callable object based on an expression involving ``self``, which is
|
|
||||||
then added to the class.
|
|
||||||
|
|
||||||
Inheritance
|
|
||||||
===========
|
|
||||||
|
|
||||||
C++ inheritance relationships can be represented to Boost.Python by adding
|
|
||||||
an optional ``bases<...>`` argument to the ``class_<...>`` template
|
|
||||||
parameter list as follows::
|
|
||||||
|
|
||||||
class_<Derived, bases<Base1,Base2> >("Derived")
|
|
||||||
...
|
|
||||||
|
|
||||||
This has two effects:
|
|
||||||
|
|
||||||
1. When the ``class_<...>`` is created, Python type objects
|
|
||||||
corresponding to ``Base1`` and ``Base2`` are looked up in the BPL
|
|
||||||
registry, and are used as bases for the new Python ``Derived`` type
|
|
||||||
object [#mi]_, so methods exposed for the Python ``Base1`` and
|
|
||||||
``Base2`` types are automatically members of the ``Derived`` type.
|
|
||||||
Because the registry is global, this works correctly even if
|
|
||||||
``Derived`` is exposed in a different module from either of its
|
|
||||||
bases.
|
|
||||||
|
|
||||||
2. C++ conversions from ``Derived`` to its bases are added to the
|
|
||||||
Boost.Python registry. Thus wrapped C++ methods expecting (a
|
|
||||||
pointer or reference to) an object of either base type can be
|
|
||||||
called with an object wrapping a ``Derived`` instance. Wrapped
|
|
||||||
member functions of class ``T`` are treated as though they have an
|
|
||||||
implicit first argument of ``T&``, so these conversions are
|
|
||||||
neccessary to allow the base class methods to be called for derived
|
|
||||||
objects.
|
|
||||||
|
|
||||||
Of course it's possible to derive new Python classes from wrapped C++
|
|
||||||
class instances. Because Boost.Python uses the new-style class
|
|
||||||
system, that works very much as for the Python built-in types. There
|
|
||||||
is one significant detail in which it differs: the built-in types
|
|
||||||
generally establish their invariants in their ``__new__`` function, so
|
|
||||||
that derived classes do not need to call ``__init__`` on the base
|
|
||||||
class before invoking its methods :
|
|
||||||
|
|
||||||
>>> class L(list):
|
|
||||||
... def __init__(self):
|
|
||||||
... pass
|
|
||||||
...
|
|
||||||
>>> L().reverse()
|
|
||||||
>>>
|
|
||||||
|
|
||||||
Because C++ object construction is a one-step operation, C++ instance
|
|
||||||
data cannot be constructed until the arguments are available, in the
|
|
||||||
``__init__`` function:
|
|
||||||
|
|
||||||
>>> class D(SomeBPLClass):
|
|
||||||
... def __init__(self):
|
|
||||||
... pass
|
|
||||||
...
|
|
||||||
>>> D().some_bpl_method()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "<stdin>", line 1, in ?
|
|
||||||
TypeError: bad argument type for built-in operation
|
|
||||||
|
|
||||||
This happened because Boost.Python couldn't find instance data of type
|
|
||||||
``SomeBPLClass`` within the ``D`` instance; ``D``'s ``__init__``
|
|
||||||
function masked construction of the base class. It could be corrected
|
|
||||||
by either removing ``D``'s ``__init__`` function or having it call
|
|
||||||
``SomeBPLClass.__init__(...)`` explicitly.
|
|
||||||
|
|
||||||
Virtual Functions
|
|
||||||
=================
|
|
||||||
|
|
||||||
Deriving new types in Python from extension classes is not very
|
|
||||||
interesting unless they can be used polymorphically from C++. In
|
|
||||||
other words, Python method implementations should appear to override
|
|
||||||
the implementation of C++ virtual functions when called *through base
|
|
||||||
class pointers/references from C++*. Since the only way to alter the
|
|
||||||
behavior of a virtual function is to override it in a derived class,
|
|
||||||
the user must build a special derived class to dispatch a polymorphic
|
|
||||||
class' virtual functions::
|
|
||||||
|
|
||||||
//
|
|
||||||
// interface to wrap:
|
|
||||||
//
|
|
||||||
class Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual int f(std::string x) { return 42; }
|
|
||||||
virtual ~Base();
|
|
||||||
};
|
|
||||||
|
|
||||||
int calls_f(Base const& b, std::string x) { return b.f(x); }
|
|
||||||
|
|
||||||
//
|
|
||||||
// Wrapping Code
|
|
||||||
//
|
|
||||||
|
|
||||||
// Dispatcher class
|
|
||||||
struct BaseWrap : Base
|
|
||||||
{
|
|
||||||
// Store a pointer to the Python object
|
|
||||||
BaseWrap(PyObject* self_) : self(self_) {}
|
|
||||||
PyObject* self;
|
|
||||||
|
|
||||||
// Default implementation, for when f is not overridden
|
|
||||||
int f_default(std::string x) { return this->Base::f(x); }
|
|
||||||
// Dispatch implementation
|
|
||||||
int f(std::string x) { return call_method<int>(self, "f", x); }
|
|
||||||
};
|
|
||||||
|
|
||||||
...
|
|
||||||
def("calls_f", calls_f);
|
|
||||||
class_<Base, BaseWrap>("Base")
|
|
||||||
.def("f", &Base::f, &BaseWrap::f_default)
|
|
||||||
;
|
|
||||||
|
|
||||||
Now here's some Python code which demonstrates:
|
|
||||||
|
|
||||||
>>> class Derived(Base):
|
|
||||||
... def f(self, s):
|
|
||||||
... return len(s)
|
|
||||||
...
|
|
||||||
>>> calls_f(Base(), 'foo')
|
|
||||||
42
|
|
||||||
>>> calls_f(Derived(), 'forty-two')
|
|
||||||
9
|
|
||||||
|
|
||||||
Things to notice about the dispatcher class:
|
|
||||||
|
|
||||||
* The key element which allows overriding in Python is the
|
|
||||||
``call_method`` invocation, which uses the same global type
|
|
||||||
conversion registry as the C++ function wrapping does to convert its
|
|
||||||
arguments from C++ to Python and its return type from Python to C++.
|
|
||||||
|
|
||||||
* Any constructor signatures you wish to wrap must be replicated with
|
|
||||||
an initial ``PyObject*`` argument
|
|
||||||
|
|
||||||
* The dispatcher must store this argument so that it can be used to
|
|
||||||
invoke ``call_method``
|
|
||||||
|
|
||||||
* The ``f_default`` member function is needed when the function being
|
|
||||||
exposed is not pure virtual; there's no other way ``Base::f`` can be
|
|
||||||
called on an object of type ``BaseWrap``, since it overrides ``f``.
|
|
||||||
|
|
||||||
Admittedly, this formula is tedious to repeat, especially on a project
|
|
||||||
with many polymorphic classes; that it is neccessary reflects
|
|
||||||
limitations in C++'s compile-time reflection capabilities. Several
|
|
||||||
efforts are underway to write front-ends for Boost.Python which can
|
|
||||||
generate these dispatchers (and other wrapping code) automatically.
|
|
||||||
If these are successful it will mark a move away from wrapping
|
|
||||||
everything directly in pure C++ for many of our users.
|
|
||||||
|
|
||||||
---------------
|
|
||||||
Serialization
|
|
||||||
---------------
|
|
||||||
|
|
||||||
*Serialization* is the process of converting objects in memory to a
|
|
||||||
form that can be stored on disk or sent over a network connection. The
|
|
||||||
serialized object (most often a plain string) can be retrieved and
|
|
||||||
converted back to the original object. A good serialization system will
|
|
||||||
automatically convert entire object hierarchies. Python's standard
|
|
||||||
``pickle`` module is such a system. It leverages the language's strong
|
|
||||||
runtime introspection facilities for serializing practically arbitrary
|
|
||||||
user-defined objects. With a few simple and unintrusive provisions this
|
|
||||||
powerful machinery can be extended to also work for wrapped C++ objects.
|
|
||||||
Here is an example::
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
struct World
|
|
||||||
{
|
|
||||||
World(std::string a_msg) : msg(a_msg) {}
|
|
||||||
std::string greet() const { return msg; }
|
|
||||||
std::string msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
#include <boost/python.hpp>
|
|
||||||
using namespace boost::python;
|
|
||||||
|
|
||||||
struct World_picklers : pickle_suite
|
|
||||||
{
|
|
||||||
static tuple
|
|
||||||
getinitargs(World const& w) { return make_tuple(w.greet()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
BOOST_PYTHON_MODULE(hello)
|
|
||||||
{
|
|
||||||
class_<World>("World", init<std::string>())
|
|
||||||
.def("greet", &World::greet)
|
|
||||||
.def_pickle(World_picklers())
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
Now let's create a ``World`` object and put it to rest on disk::
|
|
||||||
|
|
||||||
>>> import hello
|
|
||||||
>>> import pickle
|
|
||||||
>>> a_world = hello.World("howdy")
|
|
||||||
>>> pickle.dump(a_world, open("my_world", "w"))
|
|
||||||
|
|
||||||
In a potentially *different script* on a potentially *different
|
|
||||||
computer* with a potentially *different operating system*::
|
|
||||||
|
|
||||||
>>> import pickle
|
|
||||||
>>> resurrected_world = pickle.load(open("my_world", "r"))
|
|
||||||
>>> resurrected_world.greet()
|
|
||||||
'howdy'
|
|
||||||
|
|
||||||
Of course the ``cPickle`` module can also be used for faster
|
|
||||||
processing.
|
|
||||||
|
|
||||||
Boost.Python's ``pickle_suite`` fully supports the ``pickle`` protocol
|
|
||||||
defined in the standard Python documentation. There is a one-to-one
|
|
||||||
correspondence between the standard pickling methods (``__getinitargs__``,
|
|
||||||
``__getstate__``, ``__setstate__``) and the functions defined by the
|
|
||||||
user in the class derived from ``pickle_suite`` (``getinitargs``,
|
|
||||||
``getstate``, ``setstate``). The ``class_::def_pickle()`` member function
|
|
||||||
is used to establish the Python bindings for all user-defined functions
|
|
||||||
simultaneously. Correct signatures for these functions are enforced at
|
|
||||||
compile time. Non-sensical combinations of the three pickle functions
|
|
||||||
are also rejected at compile time. These measures are designed to
|
|
||||||
help the user in avoiding obvious errors.
|
|
||||||
|
|
||||||
Enabling serialization of more complex C++ objects requires a little
|
|
||||||
more work than is shown in the example above. Fortunately the
|
|
||||||
``object`` interface (see next section) greatly helps in keeping the
|
|
||||||
code manageable.
|
|
||||||
|
|
||||||
------------------
|
|
||||||
Object interface
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Experienced extension module authors will be familiar with the 'C' view
|
|
||||||
of Python objects, the ubiquitous ``PyObject*``. Most if not all Python
|
|
||||||
'C' API functions involve ``PyObject*`` as arguments or return type. A
|
|
||||||
major complication is the raw reference counting interface presented to
|
|
||||||
the 'C' programmer. E.g. some API functions return *new references* and
|
|
||||||
others return *borrowed references*. It is up to the extension module
|
|
||||||
writer to properly increment and decrement reference counts. This
|
|
||||||
quickly becomes cumbersome and error prone, especially if there are
|
|
||||||
multiple execution paths.
|
|
||||||
|
|
||||||
Boost.Python provides a type ``object`` which is essentially a high
|
|
||||||
level wrapper around ``PyObject*``. ``object`` automates reference
|
|
||||||
counting as much as possible. It also provides the facilities for
|
|
||||||
converting arbitrary C++ types to Python objects and vice versa.
|
|
||||||
This significantly reduces the learning effort for prospective
|
|
||||||
extension module writers.
|
|
||||||
|
|
||||||
Creating an ``object`` from any other type is extremely simple::
|
|
||||||
|
|
||||||
object o(3);
|
|
||||||
|
|
||||||
``object`` has templated interactions with all other types, with
|
|
||||||
automatic to-python conversions. It happens so naturally that it's
|
|
||||||
easily overlooked.
|
|
||||||
|
|
||||||
The ``extract<T>`` class template can be used to convert Python objects
|
|
||||||
to C++ types::
|
|
||||||
|
|
||||||
double x = extract<double>(o);
|
|
||||||
|
|
||||||
All registered user-defined conversions are automatically accessible
|
|
||||||
through the ``object`` interface. With reference to the ``World`` class
|
|
||||||
defined in previous examples::
|
|
||||||
|
|
||||||
object as_python_object(World("howdy"));
|
|
||||||
World back_as_c_plus_plus_object = extract<World>(as_python_object);
|
|
||||||
|
|
||||||
If a C++ type cannot be converted to a Python object an appropriate
|
|
||||||
exception is thrown at runtime. Similarly, an appropriate exception is
|
|
||||||
thrown if a C++ type cannot be extracted from a Python object.
|
|
||||||
``extract<T>`` provides facilities for avoiding exceptions if this is
|
|
||||||
desired.
|
|
||||||
|
|
||||||
The ``object::attr()`` member function is available for accessing
|
|
||||||
and manipulating attributes of Python objects. For example::
|
|
||||||
|
|
||||||
object planet(World());
|
|
||||||
planet.attr("set")("howdy");
|
|
||||||
|
|
||||||
``planet.attr("set")`` returns a callable ``object``. ``"howdy"`` is
|
|
||||||
converted to a Python string object which is then passed as an argument
|
|
||||||
to the ``set`` method.
|
|
||||||
|
|
||||||
The ``object`` type is accompanied by a set of derived types
|
|
||||||
that mirror the Python built-in types such as ``list``, ``dict``,
|
|
||||||
``tuple``, etc. as much as possible. This enables convenient
|
|
||||||
manipulation of these high-level types from C++::
|
|
||||||
|
|
||||||
dict d;
|
|
||||||
d["some"] = "thing";
|
|
||||||
d["lucky_number"] = 13;
|
|
||||||
list l = d.keys();
|
|
||||||
|
|
||||||
This almost looks and works like regular Python code, but it is pure C++.
|
|
||||||
|
|
||||||
=================
|
|
||||||
Thinking hybrid
|
|
||||||
=================
|
|
||||||
|
|
||||||
For many applications runtime performance considerations are very
|
|
||||||
important. This is particularly true for most scientific applications.
|
|
||||||
Often the performance considerations dictate the use of a compiled
|
|
||||||
language for the core algorithms. Traditionally the decision to use a
|
|
||||||
particular programming language is an exclusive one. Because of the
|
|
||||||
practical and mental difficulties of combining different languages many
|
|
||||||
systems are written in just one language. This is quite unfortunate
|
|
||||||
because the price payed for runtime performance is typically a
|
|
||||||
significant overhead due to static typing. For example, our experience
|
|
||||||
shows that developing maintainable C++ code is typically much more
|
|
||||||
time-consuming and requires much more hard-earned working experience
|
|
||||||
than developing useful Python code. A related observation is that many
|
|
||||||
compiled packages are augmented by some type of rudimentary scripting
|
|
||||||
layer. These ad hoc solutions clearly show that many times a compiled
|
|
||||||
language alone does not get the job done. On the other hand it is also
|
|
||||||
clear that a pure Python implementation is too slow for numerically
|
|
||||||
intensive production code.
|
|
||||||
|
|
||||||
Boost.Python enables us to *think hybrid* when developing new
|
|
||||||
applications. Python can be used for rapidly prototyping a
|
|
||||||
new application. Python's ease of use and the large pool of standard
|
|
||||||
libraries give us a head start on the way to a first working system. If
|
|
||||||
necessary, the working procedure can be used to discover the
|
|
||||||
rate-limiting algorithms. To maximize performance these can be
|
|
||||||
reimplemented in C++, together with the Boost.Python bindings needed to
|
|
||||||
tie them back into the existing higher-level procedure.
|
|
||||||
|
|
||||||
Of course, this *top-down* approach is less attractive if it is clear
|
|
||||||
from the start that many algorithms will eventually have to be
|
|
||||||
implemented in a compiled language. Fortunately Boost.Python also
|
|
||||||
enables us to pursue a *bottom-up* approach. We have used this approach
|
|
||||||
very successfully in the development of a toolbox for scientific
|
|
||||||
applications (scitbx) that we will describe elsewhere. The toolbox
|
|
||||||
started out mainly as a library of C++ classes with Boost.Python
|
|
||||||
bindings, and for a while the growth was mainly concentrated on the C++
|
|
||||||
parts. However, as the toolbox is becoming more complete, more and more
|
|
||||||
newly added functionality can be implemented in Python. We expect this
|
|
||||||
trend to continue, as illustrated qualitatively in this figure:
|
|
||||||
|
|
||||||
.. image:: python_cpp_mix.png
|
|
||||||
|
|
||||||
This figure shows the ratio of newly added C++ and Python code over
|
|
||||||
time as new algorithms are implemented. We expect this ratio to level
|
|
||||||
out near 70% Python. The increasing ability to solve new problems
|
|
||||||
mostly with the easy-to-use Python language rather than a necessarily
|
|
||||||
more arcane statically typed language is the return on the investment
|
|
||||||
of learning how to use Boost.Python. The ability to solve some problems
|
|
||||||
entirely using only Python will enable a larger group of people to
|
|
||||||
participate in the rapid development of new applications.
|
|
||||||
|
|
||||||
=============
|
|
||||||
Conclusions
|
|
||||||
=============
|
|
||||||
|
|
||||||
The examples in this paper illustrate that Boost.Python enables
|
|
||||||
seamless interoperability between C++ and Python. Importantly, this is
|
|
||||||
achieved without introducing a third syntax: the Python/C++ interface
|
|
||||||
definitions are written in pure C++. This avoids any problems with
|
|
||||||
parsing the C++ code to be interfaced to Python, yet the interface
|
|
||||||
definitions are concise and maintainable. Freed from most of the
|
|
||||||
development-time penalties of crossing a language boundary, software
|
|
||||||
designers can take full advantage of two rich and complimentary
|
|
||||||
language environments. In practice it turns out that some things are
|
|
||||||
very difficult to do with pure Python/C (e.g. an efficient array
|
|
||||||
library with an intuitive interface in the compiled language) and
|
|
||||||
others are very difficult to do with pure C++ (e.g. serialization).
|
|
||||||
If one has the luxury of being able to design a software system as a
|
|
||||||
hybrid system from the ground up there are many new ways of avoiding
|
|
||||||
road blocks in one language or the other.
|
|
||||||
|
|
||||||
.. I'm not ready to give up on all of this quite yet
|
|
||||||
|
|
||||||
.. Perhaps one day we'll have a language with the simplicity and
|
|
||||||
expressive power of Python and the compile-time muscle of C++. Being
|
|
||||||
able to take advantage of all of these facilities without paying the
|
|
||||||
mental and development-time penalties of crossing a language barrier
|
|
||||||
would bring enormous benefits. Until then, interoperability tools
|
|
||||||
like Boost.Python can help lower the barrier and make the benefits of
|
|
||||||
both languages more accessible to both communities.
|
|
||||||
|
|
||||||
===========
|
|
||||||
Footnotes
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. [#mi] For hard-core new-style class/extension module writers it is
|
|
||||||
worth noting that the normal requirement that all extension classes
|
|
||||||
with data form a layout-compatible single-inheritance chain is
|
|
||||||
lifted for Boost.Python extension classes. Clearly, either
|
|
||||||
``Base1`` or ``Base2`` has to occupy a different offset in the
|
|
||||||
``Derived`` class instance. This is possible because the wrapped
|
|
||||||
part of BPL extension class instances is never assumed to have a
|
|
||||||
fixed offset within the wrapper.
|
|
||||||
|
|
||||||
===========
|
|
||||||
Citations
|
|
||||||
===========
|
|
||||||
|
|
||||||
.. [VELD1995] T. Veldhuizen, "Expression Templates," C++ Report,
|
|
||||||
Vol. 7 No. 5 June 1995, pp. 26-31.
|
|
||||||
http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
/*
|
|
||||||
:Author: David Goodger
|
|
||||||
:Contact: goodger@users.sourceforge.net
|
|
||||||
:date: $Date$
|
|
||||||
:version: $Revision$
|
|
||||||
:copyright: This stylesheet has been placed in the public domain.
|
|
||||||
|
|
||||||
Default cascading style sheet for the HTML output of Docutils.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.first {
|
|
||||||
margin-top: 0 }
|
|
||||||
|
|
||||||
.last {
|
|
||||||
margin-bottom: 0 }
|
|
||||||
|
|
||||||
a.toc-backref {
|
|
||||||
text-decoration: none ;
|
|
||||||
color: black }
|
|
||||||
|
|
||||||
dd {
|
|
||||||
margin-bottom: 0.5em }
|
|
||||||
|
|
||||||
div.abstract {
|
|
||||||
margin: 2em 5em }
|
|
||||||
|
|
||||||
div.abstract p.topic-title {
|
|
||||||
font-weight: bold ;
|
|
||||||
text-align: center }
|
|
||||||
|
|
||||||
div.attention, div.caution, div.danger, div.error, div.hint,
|
|
||||||
div.important, div.note, div.tip, div.warning {
|
|
||||||
margin: 2em ;
|
|
||||||
border: medium outset ;
|
|
||||||
padding: 1em }
|
|
||||||
|
|
||||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
|
||||||
div.danger p.admonition-title, div.error p.admonition-title,
|
|
||||||
div.warning p.admonition-title {
|
|
||||||
color: red ;
|
|
||||||
font-weight: bold ;
|
|
||||||
font-family: sans-serif }
|
|
||||||
|
|
||||||
div.hint p.admonition-title, div.important p.admonition-title,
|
|
||||||
div.note p.admonition-title, div.tip p.admonition-title {
|
|
||||||
font-weight: bold ;
|
|
||||||
font-family: sans-serif }
|
|
||||||
|
|
||||||
div.dedication {
|
|
||||||
margin: 2em 5em ;
|
|
||||||
text-align: center ;
|
|
||||||
font-style: italic }
|
|
||||||
|
|
||||||
div.dedication p.topic-title {
|
|
||||||
font-weight: bold ;
|
|
||||||
font-style: normal }
|
|
||||||
|
|
||||||
div.figure {
|
|
||||||
margin-left: 2em }
|
|
||||||
|
|
||||||
div.footer, div.header {
|
|
||||||
font-size: smaller }
|
|
||||||
|
|
||||||
div.system-messages {
|
|
||||||
margin: 5em }
|
|
||||||
|
|
||||||
div.system-messages h1 {
|
|
||||||
color: red }
|
|
||||||
|
|
||||||
div.system-message {
|
|
||||||
border: medium outset ;
|
|
||||||
padding: 1em }
|
|
||||||
|
|
||||||
div.system-message p.system-message-title {
|
|
||||||
color: red ;
|
|
||||||
font-weight: bold }
|
|
||||||
|
|
||||||
div.topic {
|
|
||||||
margin: 2em }
|
|
||||||
|
|
||||||
h1.title {
|
|
||||||
text-align: center }
|
|
||||||
|
|
||||||
h2.subtitle {
|
|
||||||
text-align: center }
|
|
||||||
|
|
||||||
hr {
|
|
||||||
width: 75% }
|
|
||||||
|
|
||||||
ol.simple, ul.simple {
|
|
||||||
margin-bottom: 1em }
|
|
||||||
|
|
||||||
ol.arabic {
|
|
||||||
list-style: decimal }
|
|
||||||
|
|
||||||
ol.loweralpha {
|
|
||||||
list-style: lower-alpha }
|
|
||||||
|
|
||||||
ol.upperalpha {
|
|
||||||
list-style: upper-alpha }
|
|
||||||
|
|
||||||
ol.lowerroman {
|
|
||||||
list-style: lower-roman }
|
|
||||||
|
|
||||||
ol.upperroman {
|
|
||||||
list-style: upper-roman }
|
|
||||||
|
|
||||||
p.caption {
|
|
||||||
font-style: italic }
|
|
||||||
|
|
||||||
p.credits {
|
|
||||||
font-style: italic ;
|
|
||||||
font-size: smaller }
|
|
||||||
|
|
||||||
p.label {
|
|
||||||
white-space: nowrap }
|
|
||||||
|
|
||||||
p.topic-title {
|
|
||||||
font-weight: bold }
|
|
||||||
|
|
||||||
pre.address {
|
|
||||||
margin-bottom: 0 ;
|
|
||||||
margin-top: 0 ;
|
|
||||||
font-family: serif ;
|
|
||||||
font-size: 100% }
|
|
||||||
|
|
||||||
pre.line-block {
|
|
||||||
font-family: serif ;
|
|
||||||
font-size: 100% }
|
|
||||||
|
|
||||||
pre.literal-block, pre.doctest-block {
|
|
||||||
margin-left: 2em ;
|
|
||||||
margin-right: 2em ;
|
|
||||||
background-color: #eeeeee }
|
|
||||||
|
|
||||||
span.classifier {
|
|
||||||
font-family: sans-serif ;
|
|
||||||
font-style: oblique }
|
|
||||||
|
|
||||||
span.classifier-delimiter {
|
|
||||||
font-family: sans-serif ;
|
|
||||||
font-weight: bold }
|
|
||||||
|
|
||||||
span.interpreted {
|
|
||||||
font-family: sans-serif }
|
|
||||||
|
|
||||||
span.option-argument {
|
|
||||||
font-style: italic }
|
|
||||||
|
|
||||||
span.pre {
|
|
||||||
white-space: pre }
|
|
||||||
|
|
||||||
span.problematic {
|
|
||||||
color: red }
|
|
||||||
|
|
||||||
table {
|
|
||||||
margin-top: 0.5em ;
|
|
||||||
margin-bottom: 0.5em }
|
|
||||||
|
|
||||||
table.citation {
|
|
||||||
border-left: solid thin gray ;
|
|
||||||
padding-left: 0.5ex }
|
|
||||||
|
|
||||||
table.docinfo {
|
|
||||||
margin: 2em 4em }
|
|
||||||
|
|
||||||
table.footnote {
|
|
||||||
border-left: solid thin black ;
|
|
||||||
padding-left: 0.5ex }
|
|
||||||
|
|
||||||
td, th {
|
|
||||||
padding-left: 0.5em ;
|
|
||||||
padding-right: 0.5em ;
|
|
||||||
vertical-align: top }
|
|
||||||
|
|
||||||
th.docinfo-name, th.field-name {
|
|
||||||
font-weight: bold ;
|
|
||||||
text-align: left ;
|
|
||||||
white-space: nowrap }
|
|
||||||
|
|
||||||
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
|
||||||
font-size: 100% }
|
|
||||||
|
|
||||||
tt {
|
|
||||||
background-color: #eeeeee }
|
|
||||||
|
|
||||||
ul.auto-toc {
|
|
||||||
list-style-type: none }
|
|
||||||
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
@@ -1,59 +0,0 @@
|
|||||||
H1
|
|
||||||
{
|
|
||||||
FONT-SIZE: 200%
|
|
||||||
COLOR: #00007f
|
|
||||||
}
|
|
||||||
H2
|
|
||||||
{
|
|
||||||
FONT-SIZE: 150%;
|
|
||||||
}
|
|
||||||
H3
|
|
||||||
{
|
|
||||||
FONT-SIZE: 125%;
|
|
||||||
}
|
|
||||||
H4
|
|
||||||
{
|
|
||||||
FONT-SIZE: 108%;
|
|
||||||
}
|
|
||||||
BODY
|
|
||||||
{
|
|
||||||
FONT-SIZE: 100%;
|
|
||||||
BACKGROUND-COLOR: #ffffff
|
|
||||||
}
|
|
||||||
PRE
|
|
||||||
{
|
|
||||||
MARGIN-LEFT: 2pc;
|
|
||||||
FONT-SIZE: 80%;
|
|
||||||
BACKGROUND-COLOR: #dfffff
|
|
||||||
}
|
|
||||||
CODE
|
|
||||||
{
|
|
||||||
FONT-SIZE: 95%;
|
|
||||||
white-space: pre
|
|
||||||
}
|
|
||||||
.index
|
|
||||||
{
|
|
||||||
TEXT-ALIGN: left
|
|
||||||
}
|
|
||||||
.page-index
|
|
||||||
{
|
|
||||||
TEXT-ALIGN: left
|
|
||||||
}
|
|
||||||
.definition
|
|
||||||
{
|
|
||||||
TEXT-ALIGN: left
|
|
||||||
}
|
|
||||||
.footnote
|
|
||||||
{
|
|
||||||
FONT-SIZE: 66%;
|
|
||||||
VERTICAL-ALIGN: super;
|
|
||||||
TEXT-DECORATION: none
|
|
||||||
}
|
|
||||||
.function-semantics
|
|
||||||
{
|
|
||||||
CLEAR: left
|
|
||||||
}
|
|
||||||
.metafunction-semantics
|
|
||||||
{
|
|
||||||
CLEAR: left
|
|
||||||
}
|
|
||||||
@@ -1,402 +1,180 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
|
||||||
<html>
|
<meta name="generator" content="HTML Tidy, see www.w3.org">
|
||||||
<head>
|
|
||||||
<meta name="generator" content=
|
<title>Building an Extension Module</title>
|
||||||
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
<div>
|
||||||
<link rel="stylesheet" type="text/css" href="boost.css">
|
<h1><img width="277" height="86" align="center" src=
|
||||||
|
"../../../c++boost.gif" alt="c++boost.gif (8819 bytes)">Building an
|
||||||
<title>Boost.Python - Building and Testing</title>
|
Extension Module</h1>
|
||||||
</head>
|
|
||||||
|
<p>The build process for Boost is currently undergoing some evolution,
|
||||||
<body link="#0000ff" vlink="#800080">
|
and, it is to be hoped, improvement. The following facts may help:
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
|
||||||
"header">
|
<hr>
|
||||||
<tr>
|
Makefiles for various platforms and a Visual Studio project
|
||||||
<td valign="top" width="300">
|
reside in the Boost subdirectory <tt>libs/python/build</tt>.
|
||||||
<h3><a href="../../../index.htm"><img height="86" width="277" alt=
|
Build targets include:
|
||||||
"C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
<ul>
|
||||||
|
<li>The <tt>boost_python</tt> library for static linking with your
|
||||||
<td valign="top">
|
extension module. On the various Unices, this library will be
|
||||||
<h1 align="center"><a href="index.html">Boost.Python</a></h1>
|
called <tt>libboost_python.a</tt>. When using Visual C++, the
|
||||||
|
library will be called <tt>boost_python.lib</tt>.
|
||||||
<h2 align="center">Building and Testing</h2>
|
|
||||||
</td>
|
<p>
|
||||||
</tr>
|
<li>A comprehensive test of Boost.Python features. This test builds
|
||||||
</table>
|
a Boost.Python extension module, then runs Python to import the
|
||||||
<hr>
|
module, and runs a series of tests on it using <tt><a href=
|
||||||
|
"../test/doctest.py">doctest</a></tt>. Source code for the module
|
||||||
<h2>Contents</h2>
|
and tests is available in the Boost subdirectory
|
||||||
|
<tt>libs/python/test</tt>.
|
||||||
<dl class="Reference">
|
|
||||||
<dt><a href="#requirements">Requirements</a></dt>
|
<p>
|
||||||
|
<li>Various examples from the Boost subdirectory
|
||||||
<dt><a href="#building">Building Boost.Python</a></dt>
|
<tt>libs/python/example</tt>.
|
||||||
|
All these examples include a doctest modeled
|
||||||
<dd>
|
on the comprehensive test above.
|
||||||
<dl class="index">
|
|
||||||
<dt><a href="#configuration">Configuration</a></dt>
|
</ul>
|
||||||
|
|
||||||
<dt><a href="#results">Results</a></dt>
|
<hr>
|
||||||
|
There is a group of makefiles with support for simultaneous
|
||||||
<dt><a href="#cygwin">Notes for Cygwin GCC Users</a></dt>
|
compilation on multiple platforms and a consistent set of
|
||||||
|
features that build the <tt>boost_python</tt> library for static
|
||||||
<dt><a href="#testing">Testing</a></dt>
|
linking, the comprehensive test, and all examples in
|
||||||
</dl>
|
<tt>libs/python/example</tt>:
|
||||||
</dd>
|
|
||||||
|
<ul>
|
||||||
<dt><a href="#building_ext">Building your Extension Module</a></dt>
|
<li><a href="../build/vc60.mak">vc60.mak</a>:
|
||||||
|
Visual C++ 6.0 Service Pack 4
|
||||||
<dd>
|
|
||||||
<dl>
|
<li><a href="../build/mingw32.mak">mingw32.mak</a>:
|
||||||
<dt><a href="#easy">The Easy Way</a></dt>
|
mingw32 (Win32-targeted) gcc 2.95.2
|
||||||
|
|
||||||
<dt><a href="#outside">Building your module outside the Boost
|
<li><a href="../build/linux_gcc.mak">linux_gcc.mak</a>:
|
||||||
project tree</a></dt>
|
gcc 2.95.2 on Linux/Unix
|
||||||
</dl>
|
|
||||||
</dd>
|
<li><a href="../build/tru64_cxx.mak">tru64_cxx.mak</a>:
|
||||||
|
Compaq Alpha using the Compaq cxx compiler
|
||||||
<dt><a href="#variants">Build Variants</a></dt>
|
|
||||||
|
<li><a href="../build/irix_CC.mak">irix_CC.mak</a>:
|
||||||
<dt><a href="#VisualStudio">Building Using the Microsoft Visual Studio
|
Silicon Graphics IRIX 6.5 CC compiler
|
||||||
IDE</a></dt>
|
|
||||||
</dl>
|
</ul>
|
||||||
<hr>
|
<a href="http://cctbx.sourceforge.net/page_installation_adv.html#installation_boost_python"
|
||||||
|
>Usage of these makefiles is described here.</a>
|
||||||
<h2><a name="requirements">Requirements</a></h2>
|
|
||||||
<b>Boost.Python</b> version 2 requires <a href=
|
<hr>
|
||||||
"http://www.python.org/2.2">Python 2.2</a> <i>or <a href=
|
There is another group of makefiles for GNU make.
|
||||||
"http://www.python.org">newer</a></i>. An unsupported archive of
|
These makefiles are less redundant than the makefiles
|
||||||
Boost.Python version 1, which works with versions of Python since 1.5.2,
|
in the group above,
|
||||||
is available <a href="../build/python_v1.zip">here</a>.
|
but the list of compilation targets is not as complete
|
||||||
|
and there is no support for simultaneous compilation
|
||||||
<h2><a name="building">Building Boost.Python</a></h2>
|
on multiple platforms.
|
||||||
|
|
||||||
<p>Normally, Boost.Python extension modules must be linked with the
|
<ul>
|
||||||
<code>boost_python</code> shared library. In special circumstances you
|
<li><a href="../build/como.mak">como.mak</a>:
|
||||||
may want to link to a static version of the <code>boost_python</code>
|
Comeau C++ on Linux
|
||||||
library, but if multiple Boost.Pythone extension modules are used
|
|
||||||
together, it will prevent sharing of types across extension modules, and
|
<li><a href="../build/gcc.mak">gcc.mak</a>:
|
||||||
consume extra code space. To build <code>boost_python</code>, use <a
|
GCC on Linux/Unix.
|
||||||
href="../../../tools/build/index.html">Boost.Build</a> in the usual way
|
|
||||||
from the <code>libs/python/build</code> subdirectory of your boost
|
</ul>
|
||||||
installation (if you have already built boost from the top level this may
|
|
||||||
have no effect, since the work is already done).</p>
|
<hr>
|
||||||
|
A project workspace for Microsoft Visual Studio is provided at <tt><a
|
||||||
<h3><a name="configuration">Configuration</a></h3>
|
href="../build/build.dsw">libs/python/build/build.dsw</a></tt>. The
|
||||||
You may need to configure the following variables to point Boost.Build at
|
include paths for this project may need to be changed for your
|
||||||
your Python installation:
|
installation. They currently assume that python has been installed at
|
||||||
|
<tt>c:\tools\python</tt>. Three configurations of all targets are
|
||||||
<table border="1" summary="build configuration variables">
|
supported:
|
||||||
<tr>
|
|
||||||
<th>Variable Name</th>
|
<ul>
|
||||||
|
<li>Release (optimization, <tt>-DNDEBUG</tt>)
|
||||||
<th>Semantics</th>
|
|
||||||
|
<li>Debug (no optimization <tt>-D_DEBUG</tt>)
|
||||||
<th>Default</th>
|
|
||||||
|
<li>DebugPython (no optimization, <tt>-D_DEBUG
|
||||||
<th>Notes</th>
|
-DBOOST_DEBUG_PYTHON</tt>)
|
||||||
</tr>
|
</ul>
|
||||||
|
|
||||||
<tr>
|
<p>When extension modules are built with Visual C++ using
|
||||||
<td><code>PYTHON_ROOT</code></td>
|
<tt>-D_DEBUG</tt>, Python defaults to <i>force</i> linking with a
|
||||||
|
special debugging version of the Python DLL. Since this debug DLL
|
||||||
<td>The root directory of your Python installation</td>
|
isn't supplied with the default Python installation for Windows,
|
||||||
|
Boost.Python uses <tt><a href=
|
||||||
<td>Windows: <code>c:/tools/python</code>
|
"../../../boost/python/detail/wrap_python.hpp">boost/python/detail/wrap_python.hpp</a></tt>
|
||||||
Unix: <code>/usr/local</code></td>
|
to temporarily undefine <tt>_DEBUG</tt> when <tt>Python.h</tt> is
|
||||||
|
<tt>#include</tt>d.
|
||||||
<td>On Unix, this is the <code>--with-prefix=</code> directory used
|
|
||||||
to configure Python</td>
|
<p>If you want the extra runtime checks available with the debugging
|
||||||
</tr>
|
version of the library, <tt>#define BOOST_DEBUG_PYTHON</tt> to
|
||||||
|
re-enable library forcing, and link with the DebugPython version of
|
||||||
<tr>
|
<tt>boost_python.lib</tt>. You'll need to get the debugging version
|
||||||
<td><code>PYTHON_VERSION</code></td>
|
of the Python executable (<tt>python_d.exe</tt>) and DLL
|
||||||
|
(<tt>python20_d.dll</tt> or <tt>python15_d.dll</tt>). The Python
|
||||||
<td>The The 2-part python Major.Minor version number</td>
|
sources include project files for building these. If you <a href=
|
||||||
|
"http://www.python.org">download</a> them, change the name of the
|
||||||
<td><code>2.2</code></td>
|
top-level directory to <tt>src</tt>, and install it under
|
||||||
|
<tt>c:\tools\python</tt>, the workspace supplied by Boost.Python will
|
||||||
<td>Be sure not to include a third number, e.g. <b>not</b>
|
be able to use it without modification. Just open
|
||||||
"<code>2.2.1</code>", even if that's the version you have.</td>
|
<tt>c:\tools\python\src\pcbuild\pcbuild.dsw</tt> and invoke "build
|
||||||
</tr>
|
all" to generate all the debugging targets.
|
||||||
|
|
||||||
<tr>
|
<p>If you do not <tt>#define BOOST_DEBUG_PYTHON</tt>, be sure that
|
||||||
<td><code>PYTHON_INCLUDES</code></td>
|
any source files <tt>#include <<a href=
|
||||||
|
"../../../boost/python/detail/wrap_python.hpp">boost/python/detail/wrap_python.hpp</a>></tt>
|
||||||
<td>path to Python <code>#include</code> directories</td>
|
instead of the usual <tt>Python.h</tt>, or you will have link
|
||||||
|
incompatibilities.<br>
|
||||||
<td>Autoconfigured from <code>PYTHON_ROOT</code></td>
|
|
||||||
</tr>
|
<hr>
|
||||||
|
If your platform isn't directly supported, you can build a static
|
||||||
<tr>
|
library from the following source files (in the Boost subdirectory
|
||||||
<td><code>PYTHON_LIB_PATH</code></td>
|
<tt>libs/python/src</tt>), or compile them directly and link the
|
||||||
|
resulting objects into your extension module:
|
||||||
<td>path to Python library object.</td>
|
|
||||||
|
<ul>
|
||||||
<td>Autoconfigured from <code>PYTHON_ROOT</code></td>
|
<li><a href=
|
||||||
</tr>
|
"../../../libs/python/src/classes.cpp">classes.cpp</a>
|
||||||
|
|
||||||
<tr>
|
<li><a href=
|
||||||
<td><code>CYGWIN_PYTHON_[DEBUG_]VERSION</code></td>
|
"../../../libs/python/src/conversions.cpp">conversions.cpp</a>
|
||||||
|
|
||||||
<td>The version of python being used under Cygwin. </td>
|
<li><a href=
|
||||||
|
"../../../libs/python/src/cross_module.cpp">cross_module.cpp</a>
|
||||||
<td>$(PYTHON_VERSION)
|
|
||||||
|
<li><a href=
|
||||||
</td>
|
"../../../libs/python/src/extension_class.cpp">extension_class.cpp</a>
|
||||||
|
|
||||||
<td>Use only when building with <a href=
|
<li><a href=
|
||||||
"http://www.cygwin.com">Cygwin</a> GCC. This and the following
|
"../../../libs/python/src/functions.cpp">functions.cpp</a>
|
||||||
settings are useful when building with multiple toolsets on
|
|
||||||
Windows, since Cygwin GCC requires a different build of
|
<li><a href=
|
||||||
Python.</td> </tr>
|
"../../../libs/python/src/init_function.cpp">init_function.cpp</a>
|
||||||
|
|
||||||
<tr>
|
<li><a href=
|
||||||
<td><code>CYGWIN_PYTHON_[DEBUG_]ROOT</code></td>
|
"../../../libs/python/src/module_builder.cpp">module_builder.cpp</a>
|
||||||
|
|
||||||
<td>unix-style path containing the <code>include/</code>
|
<li><a href=
|
||||||
directory containing
|
"../../../libs/python/src/objects.cpp">objects.cpp</a>
|
||||||
<code>python$(CYGWIN_PYTHON_[DEBUG_]VERSION)/python.h</code>. </td>
|
|
||||||
|
<li><a href=
|
||||||
<td>$(PYTHON_ROOT)
|
"../../../libs/python/src/types.cpp">types.cpp</a>
|
||||||
|
</ul>
|
||||||
</td>
|
|
||||||
|
<hr>
|
||||||
<td>Use only when building with <a href=
|
Next: <a href="enums.html">Wrapping Enums</a> Previous: <a href=
|
||||||
"http://www.cygwin.com">Cygwin</a> GCC.</td> </tr>
|
"under-the-hood.html">A Peek Under the Hood</a> Up: <a href=
|
||||||
|
"index.html">Top</a>
|
||||||
<tr>
|
|
||||||
<td><code>CYGWIN_PYTHON_[DEBUG_]LIB_PATH</code></td>
|
<hr>
|
||||||
|
<p>© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||||
<td>path containing the user's Cygwin Python import lib
|
sell and distribute this document is granted provided this copyright
|
||||||
<code>libpython$(CYGWIN_PYTHON_[DEBUG_]VERSION).dll.a</code></td>
|
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
|
||||||
<td>Autoconfigured from <code>CYGWIN_PYTHON_ROOT</code></td>
|
any purpose.
|
||||||
|
|
||||||
<td>Use only when building with <a href=
|
<p>Updated: Apr 17, 2001 (R.W. Grosse-Kunstleve)
|
||||||
"http://www.cygwin.com">Cygwin</a> GCC.</td> </tr>
|
</div>
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><code>CYGWIN_PYTHON_[DEBUG_]DLL_PATH</code></td>
|
|
||||||
|
|
||||||
<td>path containing the user's Cygwin Python dll
|
|
||||||
(<code>libpython$(CYGWIN_PYTHON_[DEBUG_]VERSION).dll</code>)</td>
|
|
||||||
|
|
||||||
<td><code>/bin</code></td>
|
|
||||||
|
|
||||||
<td>Use only when building with <a href=
|
|
||||||
"http://www.cygwin.com">Cygwin</a> GCC.</td> </tr>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3><a name="cygwin">Notes for Cygwin GCC Users</a></h3>
|
|
||||||
|
|
||||||
<p>If you are using Cygwin GCC to build extension modules, you must use a
|
|
||||||
Cygwin build of Python. The regular Win32 Python installation that you
|
|
||||||
can download from <a href="http://www.python.org">python.org</a> will not
|
|
||||||
work with your compiler because the dynamic linking conventions are
|
|
||||||
different (you can use <a href="http://www.mingw.org/">MinGW</a> GCC if
|
|
||||||
you want to build extension modules which are compatible with a stock
|
|
||||||
Win32 Python). The Cygwin installer may be able to install an appropriate
|
|
||||||
version of Python, or you can follow the traditional <a href=
|
|
||||||
"http://www.python.org/download/download_source.html">Unix installation
|
|
||||||
process</a> to build Python from source.</p>
|
|
||||||
|
|
||||||
<p>The special build configuration variables listed above as "Cygwin
|
|
||||||
only" make it possible to use a regular Win32 build of bjam to build and
|
|
||||||
test Boost.Python and Boost.Python extensions using Cygwin GCC and
|
|
||||||
targeting a Cygwin build of Python.</p>
|
|
||||||
|
|
||||||
<h3><a name="results">Results</a></h3>
|
|
||||||
|
|
||||||
<p>The build process will create a
|
|
||||||
<code>libs/python/build/bin-stage</code> subdirectory of the boost root
|
|
||||||
(or of <code>$(ALL_LOCATE_TARGET)</code>, if you have set that variable),
|
|
||||||
containing the built libraries. The libraries are actually built to
|
|
||||||
unique directories for each toolset and variant elsewhere in the
|
|
||||||
filesystem, and copied to the <code>bin-stage</code> directory as a
|
|
||||||
convenience, so if you build with multiple toolsets at once, the product
|
|
||||||
of later toolsets will overwrite that of earlier toolsets in
|
|
||||||
<code>bin-stage</code>.</p>
|
|
||||||
|
|
||||||
<h3><a name="testing">Testing</a></h3>
|
|
||||||
|
|
||||||
<p>To build and test Boost.Python, start from the
|
|
||||||
<code>libs/python/test</code> directory and invoke</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
bjam -sTOOLS=<i><a href=
|
|
||||||
"../../../tools/build/index.html#Tools">toolset</a></i> test
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
This will update all of the Boost.Python v1 test and example targets. The
|
|
||||||
tests are relatively quiet by default. To get more-verbose output, you
|
|
||||||
might try
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
bjam -sTOOLS=<i><a href=
|
|
||||||
"../../../tools/build/index.html#Tools">toolset</a></i> -sPYTHON_TEST_ARGS=-v test
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
which will print each test's Python code with the expected output as it
|
|
||||||
passes.
|
|
||||||
|
|
||||||
<h2><a name="building_ext">Building your Extension Module</a></h2>
|
|
||||||
Though there are other approaches, the best way to build an extension
|
|
||||||
module using Boost.Python is with Boost.Build. If you have to use another
|
|
||||||
build system, you should use Boost.Build at least once with the
|
|
||||||
"<code><b>-n</b></code>" option so you can see the command-lines it uses,
|
|
||||||
and replicate them. You are likely to run into compilation or linking
|
|
||||||
problems otherwise.
|
|
||||||
|
|
||||||
<h3><a name="easy">The Easy Way</a></h3>
|
|
||||||
Until Boost.Build v2 is released, cross-project build dependencies are
|
|
||||||
not supported, so it works most smoothly if you add a new subproject to
|
|
||||||
your boost installation. The <code>libs/python/example</code>
|
|
||||||
subdirectory of your boost installation contains a minimal example (along
|
|
||||||
with many extra sources). To copy the example subproject:
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Create a new subdirectory in, <code>libs/python</code>, say
|
|
||||||
<code>libs/python/my_project</code>.</li>
|
|
||||||
|
|
||||||
<li>Copy <code><a href=
|
|
||||||
"../example/Jamfile">libs/python/example/Jamfile</a></code> to your new
|
|
||||||
directory.</li>
|
|
||||||
|
|
||||||
<li>Edit the Jamfile as appropriate for your project. You'll want to
|
|
||||||
change the "<code>subproject</code>" rule invocation at the top, and
|
|
||||||
the names of some of the source files and/or targets.</li>
|
|
||||||
</ol>
|
|
||||||
The instructions <a href="#testing">above</a> for testing Boost.Python
|
|
||||||
apply equally to your new extension modules in this subproject.
|
|
||||||
|
|
||||||
<h3><a name="outside">Building your module outside the Boost project
|
|
||||||
tree</a></h3>
|
|
||||||
If you can't (or don't wish to) modify your boost installation, the
|
|
||||||
alternative is to create your own Boost.Build project. A similar example
|
|
||||||
you can use as a starting point is available in <code><a href=
|
|
||||||
"../example/project.zip">this archive</a></code>. You'll need to edit the
|
|
||||||
Jamfile and Jamrules files, depending on the relative location of your
|
|
||||||
Boost installation and the new project. Note that automatic testing of
|
|
||||||
extension modules is not available in this configuration.
|
|
||||||
|
|
||||||
<h2><a name="variants">Build Variants</a></h2>
|
|
||||||
Three <a href=
|
|
||||||
"../../../tools/build/build_system.htm#variants">variant</a>
|
|
||||||
configurations of all python-related targets are supported, and can be
|
|
||||||
selected by setting the <code><a href=
|
|
||||||
"../../../tools/build/build_system.htm#user_globals">BUILD</a></code>
|
|
||||||
variable:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><code>release</code> (optimization, <tt>-DNDEBUG</tt>)</li>
|
|
||||||
|
|
||||||
<li><code>debug</code> (no optimization <tt>-D_DEBUG</tt>)</li>
|
|
||||||
|
|
||||||
<li><code>debug-python</code> (no optimization, <tt>-D_DEBUG
|
|
||||||
-DBOOST_DEBUG_PYTHON</tt>)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>The first two variants of the <code>boost_python</code> library are
|
|
||||||
built by default, and are compatible with the default Python
|
|
||||||
distribution. The <code>debug-python</code> variant corresponds to a
|
|
||||||
specially-built debugging version of Python. On Unix platforms, this
|
|
||||||
python is built by adding <code>--with-pydebug</code> when configuring
|
|
||||||
the Python build. On Windows, the debugging version of Python is
|
|
||||||
generated by the "Win32 Debug" target of the <code>PCBuild.dsw</code>
|
|
||||||
Visual C++ 6.0 project in the <code>PCBuild</code> subdirectory of your
|
|
||||||
Python distribution. Extension modules built with Python debugging
|
|
||||||
enabled are <b>not link-compatible</b> with a non-debug build of Python.
|
|
||||||
Since few people actually have a debug build of Python (it doesn't come
|
|
||||||
with the standard distribution), the normal <code>debug</code> variant
|
|
||||||
builds modules which are compatible with ordinary Python.</p>
|
|
||||||
|
|
||||||
<p>On many windows compilers, when extension modules are built with
|
|
||||||
<tt>-D_DEBUG</tt>, Python defaults to <i>force</i> linking with a special
|
|
||||||
debugging version of the Python DLL. Since this debug DLL isn't supplied
|
|
||||||
with the default Python installation for Windows, Boost.Python uses
|
|
||||||
<tt><a href=
|
|
||||||
"../../../boost/python/detail/wrap_python.hpp">boost/python/detail/wrap_python.hpp</a></tt>
|
|
||||||
to temporarily undefine <tt>_DEBUG</tt> when <tt>Python.h</tt> is
|
|
||||||
<tt>#include</tt>d - unless <code>BOOST_DEBUG_PYTHON</code> is
|
|
||||||
defined.</p>
|
|
||||||
|
|
||||||
<p>If you want the extra runtime checks available with the debugging
|
|
||||||
version of the library, <tt>#define BOOST_DEBUG_PYTHON</tt> to re-enable
|
|
||||||
python debuggin, and link with the <code>debug-python</code> variant of
|
|
||||||
<tt>boost_python</tt>.</p>
|
|
||||||
|
|
||||||
<p>If you do not <tt>#define BOOST_DEBUG_PYTHON</tt>, be sure that any
|
|
||||||
source files in your extension module <tt>#include <<a href=
|
|
||||||
"../../../boost/python/detail/wrap_python.hpp">boost/python/detail/wrap_python.hpp</a>></tt>
|
|
||||||
instead of the usual <tt>Python.h</tt>, or you will have link
|
|
||||||
incompatibilities.<br>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2><a name="VisualStudio">Building Using the Microsoft Visual Studio
|
|
||||||
IDE</a></h2>
|
|
||||||
|
|
||||||
<p>For the those of you who feel more comfortable in the IDE world, a
|
|
||||||
workspace and project file have been included in the <a href=
|
|
||||||
"../build/VisualStudio">libs/python/build/VisualStudio</a> subdirectory.
|
|
||||||
It builds release and debug versions of the Boost.Python libraries and
|
|
||||||
places them and the same directory as Jamfile build does, though the
|
|
||||||
intermediate object files are placed in a different directory. The files
|
|
||||||
have been created using Microsoft Visual C++ version 6, but they should
|
|
||||||
work for later versions as well. You will need to tell the IDE where to
|
|
||||||
find the Python <code>Include/</code> and <code>Libs/</code> directories.
|
|
||||||
Under <b>Tools>Options>Directories</b>, add an entry for the Python
|
|
||||||
include dir (i.e. <code>c:/Python22/Include</code>), and one for the Lib
|
|
||||||
(i.e. <code>c:/Python/Libs</code>. Make sure it is <code>Libs</code> with
|
|
||||||
an "<code>s</code>" and not just <code>Lib</code>).</p>
|
|
||||||
|
|
||||||
<h3>Using the IDE for your own projects</h3>
|
|
||||||
|
|
||||||
<p>Building your own projects using the IDE is slightly more complicated.
|
|
||||||
Firstly, you need to make sure that the project you create as the right
|
|
||||||
kind. It should be a "Win32 Dynamic-Link Library". The default one that
|
|
||||||
Visual Studio 6 creates needs some modifications: turn on RTTI, and
|
|
||||||
change the debug and release builds to use the respective debug and
|
|
||||||
release Multithreaded DLL versions. You should probably turn off
|
|
||||||
incremental linking too -- I believe it a bit flaky. If you do this, then
|
|
||||||
change the "Debug Info" to "Program Database" to get rid of the Edit and
|
|
||||||
Continue warning.</p>
|
|
||||||
|
|
||||||
<p>You'll need to add the Boost root directory under
|
|
||||||
<b>Tools>Options>Directories</b> to get your code compiling. To
|
|
||||||
make it link, add the above <code>boost_python.dsp</code> file to your
|
|
||||||
workspace, and make your project depend upon it (under
|
|
||||||
<b>Project>Dependencies</b>). You should be able to build now.</p>
|
|
||||||
|
|
||||||
<p>Lastly, go to the <b>Project Settings>Debug</b> Page and add the
|
|
||||||
<code>Python.exe</code> as the executable for the project. Set a startup
|
|
||||||
directory, and make sure that your current project's output dll, the
|
|
||||||
<code>boost_python.dll</code> and the <code>python22.dll</code> are on
|
|
||||||
the current <code>PATH</code>. If you have a python script that tests
|
|
||||||
your dll, then add it in the "Program Arguments". Now, if all went well,
|
|
||||||
you should be able to hit the Run (F5) button, and debug your code.</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
<em>The Visual Studio project files are graciously contributed and
|
|
||||||
maintained by <a href="mailto:brett.calcott@paradise.net.nz">Brett
|
|
||||||
Calcott</a></em>.
|
|
||||||
</blockquote>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>© Copyright David Abrahams 2002. 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.</p>
|
|
||||||
|
|
||||||
<p>Updated: 29 December, 2002 (David Abrahams)</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|||||||
231
doc/comparisons.html
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<title>
|
||||||
|
Comparisons with Other Systems
|
||||||
|
</title>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<img width="277" height="86" id="_x0000_i1025" align="center"
|
||||||
|
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)"><br>
|
||||||
|
Comparisons with
|
||||||
|
Other Systems
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<h2>CXX</h2>
|
||||||
|
<p>
|
||||||
|
Like Boost.Python, <a href="http://cxx.sourceforge.net/">CXX</a> attempts to
|
||||||
|
provide a C++-oriented interface to Python. In most cases, as with the
|
||||||
|
boost library, it relieves the user from worrying about
|
||||||
|
reference-counts. Both libraries automatically convert thrown C++
|
||||||
|
exceptions into Python exceptions. As far as I can tell, CXX has no
|
||||||
|
support for subclassing C++ extension types in Python. An even
|
||||||
|
more significant difference is that a user's C++ code is still basically
|
||||||
|
``dealing with Python objects'', though they are wrapped in
|
||||||
|
C++ classes. This means such jobs as argument parsing and conversion are
|
||||||
|
still left to be done explicitly by the user.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
CXX claims to interoperate well with the C++ Standard Library
|
||||||
|
(a.k.a. STL) by providing iterators into Python Lists and Dictionaries,
|
||||||
|
but the claim is unfortunately unsupportable. The problem is that in
|
||||||
|
general, access to Python sequence and mapping elements through
|
||||||
|
iterators requires the use of proxy objects as the return value of
|
||||||
|
iterator dereference operations. This usage conflicts with the basic
|
||||||
|
ForwardIterator requirements in <a
|
||||||
|
href="http://anubis.dkuug.dk/jtc1/sc22/open/n2356/lib-iterators.html#lib.forward.iterators">
|
||||||
|
section 24.1.3 of the standard</a> (dereferencing must produce a
|
||||||
|
reference). Although you may be able to use these iterators with some
|
||||||
|
operations in some standard library implementations, it is neither
|
||||||
|
guaranteed to work nor portable.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
As far as I can tell, CXX enables one to write what is essentially
|
||||||
|
idiomatic Python code in C++, manipulating Python objects through the
|
||||||
|
same fully-generic interfaces we use in Python. While you're hardly
|
||||||
|
programming directly to the ``bare metal'' with CXX, it basically
|
||||||
|
presents a ``C++-ized'' version of the Python 'C' API. Some fraction of
|
||||||
|
that capability is available in Boost.Python through <tt><a
|
||||||
|
href="../../../boost/python/objects.hpp">boost/python/objects.hpp</a></tt>,
|
||||||
|
which provides C++ objects corresponding to Python lists, tuples,
|
||||||
|
strings, and dictionaries, and through <tt><a
|
||||||
|
href="../../../boost/python/callback.hpp">boost/python/callback.hpp</a></tt>,
|
||||||
|
which allows you to call back into python with C++ arguments.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="mailto:dubois1@llnl.gov">Paul F. Dubois</a>, the original
|
||||||
|
author of CXX, has told me that what I've described is only half of the
|
||||||
|
picture with CXX, but I never understood his explanation well-enough to
|
||||||
|
fill in the other half. Here is his response to the commentary above:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
``My intention with CXX was not to do what you are doing. It was to enable a
|
||||||
|
person to write an extension directly in C++ rather than C. I figured others had
|
||||||
|
the wrapping business covered. I thought maybe CXX would provide an easier
|
||||||
|
target language for those making wrappers, but I never explored
|
||||||
|
that.''<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<h2>SWIG</h2>
|
||||||
|
<p>
|
||||||
|
<a href= "http://www.swig.org/">SWIG</a> is an impressively mature tool
|
||||||
|
for exporting an existing ANSI 'C' interface into various scripting
|
||||||
|
languages. Swig relies on a parser to read your source code and produce
|
||||||
|
additional source code files which can be compiled into a Python (or
|
||||||
|
Perl or Tcl) extension module. It has been successfully used to create
|
||||||
|
many Python extension modules. Like Boost.Python, SWIG is trying to allow an
|
||||||
|
existing interface to be wrapped with little or no change to the
|
||||||
|
existing code. The documentation says ``SWIG parses a form of ANSI C
|
||||||
|
syntax that has been extended with a number of special directives. As a
|
||||||
|
result, interfaces are usually built by grabbing a header file and
|
||||||
|
tweaking it a little bit.'' For C++ interfaces, the tweaking has often
|
||||||
|
proven to amount to more than just a little bit. One user
|
||||||
|
writes:
|
||||||
|
|
||||||
|
<blockquote> ``The problem with swig (when I used it) is that it
|
||||||
|
couldnt handle templates, didnt do func overloading properly etc. For
|
||||||
|
ANSI C libraries this was fine. But for usual C++ code this was a
|
||||||
|
problem. Simple things work. But for anything very complicated (or
|
||||||
|
realistic), one had to write code by hand. I believe Boost.Python doesn't have
|
||||||
|
this problem[<a href="#sic">sic</a>]... IMHO overloaded functions are very important to
|
||||||
|
wrap correctly.''<br><i>-Prabhu Ramachandran</i>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
By contrast, Boost.Python doesn't attempt to parse C++ - the problem is simply
|
||||||
|
too complex to do correctly. <a name="sic">Technically</a>, one does
|
||||||
|
write code by hand to use Boost.Python. The goal, however, has been to make
|
||||||
|
that code nearly as simple as listing the names of the classes and
|
||||||
|
member functions you want to expose in Python.
|
||||||
|
|
||||||
|
<h2>SIP</h2>
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href="http://www.thekompany.com/projects/pykde/background.php3?dhtml_ok=1">SIP</a>
|
||||||
|
is a system similar to SWIG, though seemingly more
|
||||||
|
C++-oriented. The author says that like Boost.Python, SIP supports overriding
|
||||||
|
extension class member functions in Python subclasses. It appears to
|
||||||
|
have been designed specifically to directly support some features of
|
||||||
|
PyQt/PyKDE, which is its primary client. Documentation is almost
|
||||||
|
entirely missing at the time of this writing, so a detailed comparison
|
||||||
|
is difficult.
|
||||||
|
|
||||||
|
<h2>ILU</h2>
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href="ftp://ftp.parc.xerox.com/pub/ilu/ilu.html">ILU</a>
|
||||||
|
is a very ambitious project which tries to describe a module's interface
|
||||||
|
(types and functions) in terms of an <a
|
||||||
|
href="ftp://ftp.parc.xerox.com/pub/ilu/2.0b1/manual-html/manual_2.html">Interface
|
||||||
|
Specification Language</a> (ISL) so that it can be uniformly interfaced
|
||||||
|
to a wide range of computer languages, including Common Lisp, C++, C,
|
||||||
|
Modula-3, and Python. ILU can parse the ISL to generate a C++ language
|
||||||
|
header file describing the interface, of which the user is expected to
|
||||||
|
provide an implementation. Unlike Boost.Python, this means that the system
|
||||||
|
imposes implementation details on your C++ code at the deepest level. It
|
||||||
|
is worth noting that some of the C++ names generated by ILU are supposed
|
||||||
|
to be reserved to the C++ implementation. It is unclear from the
|
||||||
|
documentation whether ILU supports overriding C++ virtual functions in Python.
|
||||||
|
|
||||||
|
<h2>GRAD</h2>
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href="http://www.python.org/workshops/1996-11/papers/GRAD/html/GRADcover.html">GRAD</a>
|
||||||
|
is another very ambitious project aimed at generating Python wrappers for
|
||||||
|
interfaces written in ``legacy languages'', among which C++ is the first one
|
||||||
|
implemented. Like SWIG, it aims to parse source code and automatically
|
||||||
|
generate wrappers, though it appears to take a more sophisticated approach
|
||||||
|
to parsing in general and C++ in particular, so it should do a much better
|
||||||
|
job with C++. It appears to support function overloading. The
|
||||||
|
documentation is missing a lot of information I'd like to see, so it is
|
||||||
|
difficult to give an accurate and fair assessment. I am left with the
|
||||||
|
following questions:
|
||||||
|
<ul>
|
||||||
|
<li>Does it support overriding of virtual functions?
|
||||||
|
<li>What about overriding private or protected virtual functions (the documentation indicates
|
||||||
|
that only public interfaces are supported)?
|
||||||
|
<li>Which C++ language constructs are supportd?
|
||||||
|
<li>Does it support implicit conversions between wrapped C++ classes that have
|
||||||
|
an inheritance relationship?
|
||||||
|
<li>Does it support smart pointers?
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Anyone in the possession of the answers to these questions will earn my
|
||||||
|
gratitude for a write-up <code>;-)</code>
|
||||||
|
|
||||||
|
<h2>Zope ExtensionClasses</h2>
|
||||||
|
<p>
|
||||||
|
<a href="http:http://www.digicool.com/releases/ExtensionClass">
|
||||||
|
ExtensionClasses in Zope</a> use the same underlying mechanism as Boost.Python
|
||||||
|
to support subclassing of extension types in Python, including
|
||||||
|
multiple-inheritance. Both systems support pickling/unpickling of
|
||||||
|
extension class instances in very similar ways. Both systems rely on the
|
||||||
|
same ``<a
|
||||||
|
href="http://www.python.org/workshops/1994-11/BuiltInClasses/Welcome.html">Don
|
||||||
|
Beaudry Hack</a>'' that also inspired Don's MESS System.
|
||||||
|
<p>
|
||||||
|
The major differences are:
|
||||||
|
<ul>
|
||||||
|
<li>Zope is entirely 'C' language-based. It doesn't require a C++
|
||||||
|
compiler, so it's much more portable than Boost.Python, which stresses
|
||||||
|
the limits of even some modern C++ implementations.
|
||||||
|
|
||||||
|
<li>
|
||||||
|
Boost.Python lifts the burden on the user to parse and convert function
|
||||||
|
argument types. Zope provides no such facility.
|
||||||
|
<li>
|
||||||
|
Boost.Python lifts the burden on the user to maintain Python
|
||||||
|
reference-counts.
|
||||||
|
<li>
|
||||||
|
Boost.Python supports function overloading; Zope does not.
|
||||||
|
<li>
|
||||||
|
Boost.Python supplies a simple mechanism for exposing read-only and
|
||||||
|
read/write access to data members of the wrapped C++ type as Python
|
||||||
|
attributes.
|
||||||
|
<li>
|
||||||
|
Writing a Zope ExtensionClass is significantly more complex than
|
||||||
|
exposing a C++ class to python using Boost.Python (mostly a summary of the
|
||||||
|
previous 4 items). <a href=
|
||||||
|
"http://www.digicool.com/releases/ExtensionClass/MultiMapping.html">A
|
||||||
|
Zope Example</a> illustrates the differences.
|
||||||
|
<li>
|
||||||
|
Zope's ExtensionClasses are specifically motivated by ``the need for a
|
||||||
|
C-based persistence mechanism''. Boost.Python's are motivated by the desire
|
||||||
|
to simply reflect a C++ API into Python with as little modification as
|
||||||
|
possible.
|
||||||
|
<li>
|
||||||
|
The following Zope restriction does not apply to Boost.Python: ``At most one
|
||||||
|
base extension direct or indirect super class may define C data
|
||||||
|
members. If an extension subclass inherits from multiple base
|
||||||
|
extension classes, then all but one must be mix-in classes that
|
||||||
|
provide extension methods but no data.''
|
||||||
|
<li>
|
||||||
|
Zope requires use of the somewhat funky inheritedAttribute (search for
|
||||||
|
``inheritedAttribute'' on <a
|
||||||
|
href="http://www.digicool.com/releases/ExtensionClass">this page</a>)
|
||||||
|
method to access base class methods. In Boost.Python, base class methods can
|
||||||
|
be accessed in the usual way by writing
|
||||||
|
``<code>BaseClass.method</code>''.
|
||||||
|
<li>
|
||||||
|
Zope supplies some creative but esoteric idioms such as <a href=
|
||||||
|
"http://www.digicool.com/releases/ExtensionClass/Acquisition.html">
|
||||||
|
Acquisition</a>. No specific support for this is built into Boost.Python.
|
||||||
|
<li>
|
||||||
|
Zope's ComputedAttribute support is designed to be used from Python.
|
||||||
|
<a href="special.html#getter_setter">The analogous feature of
|
||||||
|
Boost.Python</a> can be used from C++ or Python. The feature is arguably
|
||||||
|
easier to use in Boost.Python.
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Next: <a href="example1.html">A Simple Example Using Boost.Python</a>
|
||||||
|
Previous: <a href="extending.html">A Brief Introduction to writing Python Extension Modules</a>
|
||||||
|
Up: <a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2000. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Mar 6, 2001
|
||||||
|
</div>
|
||||||
|
|
||||||
336
doc/cross_module.html
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
|
||||||
|
<title>Cross-extension-module dependencies</title>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<img src="../../../c++boost.gif"
|
||||||
|
alt="c++boost.gif (8819 bytes)"
|
||||||
|
align="center"
|
||||||
|
width="277" height="86">
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h1>Cross-extension-module dependencies</h1>
|
||||||
|
|
||||||
|
It is good programming practice to organize large projects as modules
|
||||||
|
that interact with each other via well defined interfaces. With
|
||||||
|
Boost.Python it is possible to reflect this organization at the C++
|
||||||
|
level at the Python level. This is, each logical C++ module can be
|
||||||
|
organized as a separate Python extension module.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
At first sight this might seem natural and straightforward. However, it
|
||||||
|
is a fairly complex problem to establish cross-extension-module
|
||||||
|
dependencies while maintaining the same ease of use Boost.Python
|
||||||
|
provides for classes that are wrapped in the same extension module. To
|
||||||
|
a large extent this complexity can be hidden from the author of a
|
||||||
|
Boost.Python extension module, but not entirely.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>The recipe</h2>
|
||||||
|
|
||||||
|
Suppose there is an extension module that exposes certain instances of
|
||||||
|
the C++ <tt>std::vector</tt> template library such that it can be used
|
||||||
|
from Python in the following manner:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import std_vector
|
||||||
|
v = std_vector.double([1, 2, 3, 4])
|
||||||
|
v.push_back(5)
|
||||||
|
v.size()
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Suppose the <tt>std_vector</tt> module is done well and reflects all
|
||||||
|
C++ functions that are useful at the Python level, for all C++ built-in
|
||||||
|
data types (<tt>std_vector.int</tt>, <tt>std_vector.long</tt>, etc.).
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Suppose further that there is statistic module with a C++ class that
|
||||||
|
has constructors or member functions that use or return a
|
||||||
|
<tt>std::vector</tt>. For example:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
class xy {
|
||||||
|
public:
|
||||||
|
xy(const std::vector<double>& x, const std::vector<double>& y) : m_x(x), m_y(y) {}
|
||||||
|
const std::vector<double>& x() const { return m_x; }
|
||||||
|
const std::vector<double>& y() const { return m_y; }
|
||||||
|
double correlation();
|
||||||
|
private:
|
||||||
|
std::vector<double> m_x;
|
||||||
|
std::vector<double> m_y;
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
What is more natural than reusing the <tt>std_vector</tt> extension
|
||||||
|
module to expose these constructors or functions to Python?
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Unfortunately, what seems natural needs a little work in both the
|
||||||
|
<tt>std_vector</tt> and the <tt>statistics</tt> module.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In the <tt>std_vector</tt> extension module,
|
||||||
|
<tt>std::vector<double></tt> is exposed to Python in the usual
|
||||||
|
way with the <tt>class_builder<></tt> template. To also enable the
|
||||||
|
automatic conversion of <tt>std::vector<double></tt> function
|
||||||
|
arguments or return values in other Boost.Python C++ modules, the
|
||||||
|
converters that convert a <tt>std::vector<double></tt> C++ object
|
||||||
|
to a Python object and vice versa (i.e. the <tt>to_python()</tt> and
|
||||||
|
<tt>from_python()</tt> template functions) have to be exported. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
#include <boost/python/cross_module.hpp>
|
||||||
|
//...
|
||||||
|
class_builder<std::vector<double> > v_double(std_vector_module, "double");
|
||||||
|
export_converters(v_double);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
In the extension module that wraps <tt>class xy</tt> we can now import
|
||||||
|
these converters with the <tt>import_converters<></tt> template.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
#include <boost/python/cross_module.hpp>
|
||||||
|
//...
|
||||||
|
import_converters<std::vector<double> > v_double_converters("std_vector", "double");
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
That is all. All the attributes that are defined for
|
||||||
|
<tt>std_vector.double</tt> in the <tt>std_vector</tt> Boost.Python
|
||||||
|
module will be available for the returned objects of <tt>xy.x()</tt>
|
||||||
|
and <tt>xy.y()</tt>. Similarly, the constructor for <tt>xy</tt> will
|
||||||
|
accept objects that were created by the <tt>std_vector</tt>module.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>Placement of <tt>import_converters<></tt> template instantiations</h2>
|
||||||
|
|
||||||
|
<tt>import_converts<></tt> can be viewed as a drop-in replacement
|
||||||
|
for <tt>class_wrapper<></tt>, and the recommendations for the
|
||||||
|
placement of <tt>class_wrapper<></tt> template instantiations
|
||||||
|
also apply to to <tt>import_converts<></tt>. In particular, it is
|
||||||
|
important that an instantiation of <tt>class_wrapper<></tt> is
|
||||||
|
visible to any code which wraps a C++ function with a <tt>T</tt>,
|
||||||
|
<tt>T*</tt>, const <tt>T&</tt>, etc. parameter or return value.
|
||||||
|
Therefore you may want to group all <tt>class_wrapper<></tt> and
|
||||||
|
<tt>import_converts<></tt> instantiations at the top of your
|
||||||
|
module's init function, then <tt>def()</tt> the member functions later
|
||||||
|
to avoid problems with inter-class dependencies.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>Non-copyable types</h2>
|
||||||
|
|
||||||
|
<tt>export_converters()</tt> instantiates C++ template functions that
|
||||||
|
invoke the copy constructor of the wrapped type. For a type that is
|
||||||
|
non-copyable this will result in compile-time error messages. In such a
|
||||||
|
case, <tt>export_converters_noncopyable()</tt> can be used to export
|
||||||
|
the converters that do not involve the copy constructor of the wrapped
|
||||||
|
type. For example:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
class_builder<store> py_store(your_module, "store");
|
||||||
|
export_converters_noncopyable(py_store);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The corresponding <tt>import_converters<></tt> statement does not
|
||||||
|
need any special attention:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import_converters<store> py_store("noncopyable_export", "store");
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>Python module search path</h2>
|
||||||
|
|
||||||
|
The <tt>std_vector</tt> and <tt>statistics</tt> modules can now be used
|
||||||
|
in the following way:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import std_vector
|
||||||
|
import statistics
|
||||||
|
x = std_vector.double([1, 2, 3, 4])
|
||||||
|
y = std_vector.double([2, 4, 6, 8])
|
||||||
|
xy = statistics.xy(x, y)
|
||||||
|
xy.correlation()
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
In this example it is clear that Python has to be able to find both the
|
||||||
|
<tt>std_vector</tt> and the <tt>statistics</tt> extension module. In
|
||||||
|
other words, both extension modules need to be in the Python module
|
||||||
|
search path (<tt>sys.path</tt>).
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The situation is not always this obvious. Suppose the
|
||||||
|
<tt>statistics</tt> module has a <tt>random()</tt> function that
|
||||||
|
returns a vector of random numbers with a given length:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import statistics
|
||||||
|
x = statistics.random(5)
|
||||||
|
y = statistics.random(5)
|
||||||
|
xy = statistics.xy(x, y)
|
||||||
|
xy.correlation()
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
A naive user will not easily anticipate that the <tt>std_vector</tt>
|
||||||
|
module is used to pass the <tt>x</tt> and <tt>y</tt> vectors around. If
|
||||||
|
the <tt>std_vector</tt> module is in the Python module search path,
|
||||||
|
this form of ignorance is of no harm. On the contrary, we are glad
|
||||||
|
that we do not have to bother the user with details like this.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If the <tt>std_vector</tt> module is not in the Python module search
|
||||||
|
path, a Python exception will be raised:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
Traceback (innermost last):
|
||||||
|
File "foo.py", line 2, in ?
|
||||||
|
x = statistics.random(5)
|
||||||
|
ImportError: No module named std_vector
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
As is the case with any system of a non-trivial complexity, it is
|
||||||
|
important that the setup is consistent and complete.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>Two-way module dependencies</h2>
|
||||||
|
|
||||||
|
Boost.Python supports two-way module dependencies. This is best
|
||||||
|
illustrated by a simple example.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Suppose there is a module <tt>ivect</tt> that implements vectors of
|
||||||
|
integers, and a similar module <tt>dvect</tt> that implements vectors
|
||||||
|
of doubles. We want to be able do convert an integer vector to a double
|
||||||
|
vector and vice versa. For example:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import ivect
|
||||||
|
iv = ivect.ivect((1,2,3,4,5))
|
||||||
|
dv = iv.as_dvect()
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The last expression will implicitly import the <tt>dvect</tt> module in
|
||||||
|
order to enable the conversion of the C++ representation of
|
||||||
|
<tt>dvect</tt> to a Python object. The analogous is possible for a
|
||||||
|
<tt>dvect</tt>:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import dvect
|
||||||
|
dv = dvect.dvect((1,2,3,4,5))
|
||||||
|
iv = dv.as_ivect()
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Now the <tt>ivect</tt> module is imported implicitly.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note that the two-way dependencies are possible because the
|
||||||
|
dependencies are resolved only when needed. This is, the initialization
|
||||||
|
of the <tt>ivect</tt> module does not rely on the <tt>dvect</tt>
|
||||||
|
module, and vice versa. Only if <tt>as_dvect()</tt> or
|
||||||
|
<tt>as_ivect()</tt> is actually invoked will the corresponding module
|
||||||
|
be implicitly imported. This also means that, for example, the
|
||||||
|
<tt>dvect</tt> module does not have to be available at all if
|
||||||
|
<tt>as_dvect()</tt> is never used.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>Clarification of compile-time and link-time dependencies</h2>
|
||||||
|
|
||||||
|
Boost.Python's support for resolving cross-module dependencies at
|
||||||
|
runtime does not imply that compile-time dependencies are eliminated.
|
||||||
|
For example, the statistics extension module in the example above will
|
||||||
|
need to <tt>#include <vector></tt>. This is immediately obvious
|
||||||
|
from the definition of <tt>class xy</tt>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If a library is wrapped that consists of both header files and compiled
|
||||||
|
components (e.g. <tt>libdvect.a</tt>, <tt>dvect.lib</tt>, etc.), both
|
||||||
|
the Boost.Python extension module with the
|
||||||
|
<tt>export_converters()</tt> statement and the module with the
|
||||||
|
<tt>import_converters<></tt> statement need to be linked against
|
||||||
|
the object library. Ideally one would build a shared library (e.g.
|
||||||
|
<tt>libdvect.so</tt>, <tt>dvect.dll</tt>, etc.). However, this
|
||||||
|
introduces the issue of having to configure the search path for the
|
||||||
|
dynamic loading correctly. For small libraries it is therefore often
|
||||||
|
more convenient to ignore the fact that the object files are loaded
|
||||||
|
into memory more than once.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>Summary of motivation for cross-module support</h2>
|
||||||
|
|
||||||
|
The main purpose of Boost.Python's cross-module support is to allow for
|
||||||
|
a modular system layout. With this support it is straightforward to
|
||||||
|
reflect C++ code organization at the Python level. Without the
|
||||||
|
cross-module support, a multi-purpose module like <tt>std_vector</tt>
|
||||||
|
would be impractical because the entire wrapper code would somehow have
|
||||||
|
to be duplicated in all extension modules that use it, making them
|
||||||
|
harder to maintain and harder to build.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Another motivation for the cross-module support is that two extension
|
||||||
|
modules that wrap the same class cannot both be imported into Python.
|
||||||
|
For example, if there are two modules <tt>A</tt> and <tt>B</tt> that
|
||||||
|
both wrap a given <tt>class X</tt>, this will work:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import A
|
||||||
|
x = A.X()
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
This will also work:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import B
|
||||||
|
x = B.X()
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
However, this will fail:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
import A
|
||||||
|
import B
|
||||||
|
python: /net/cci/rwgk/boost/boost/python/detail/extension_class.hpp:866:
|
||||||
|
static void boost::python::detail::class_registry<X>::register_class(boost::python::detail::extension_class_base *):
|
||||||
|
Assertion `static_class_object == 0' failed.
|
||||||
|
Abort
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
A good solution is to wrap <tt>class X</tt> only once. Depending on the
|
||||||
|
situation, this could be done by module <tt>A</tt> or <tt>B</tt>, or an
|
||||||
|
additional small extension module that only wraps and exports
|
||||||
|
<tt>class X</tt>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Finally, there can be important psychological or political reasons for
|
||||||
|
using the cross-module support. If a group of classes is lumped
|
||||||
|
together with many others in a huge module, the authors will have
|
||||||
|
difficulties in being identified with their work. The situation is
|
||||||
|
much more transparent if the work is represented by a module with a
|
||||||
|
recognizable name. This is not just a question of strong egos, but also
|
||||||
|
of getting credit and funding.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2>Why not use <tt>export_converters()</tt> universally?</h2>
|
||||||
|
|
||||||
|
There is some overhead associated with the Boost.Python cross-module
|
||||||
|
support. Depending on the platform, the size of the code generated by
|
||||||
|
<tt>export_converters()</tt> is roughly 10%-20% of that generated
|
||||||
|
by <tt>class_builder<></tt>. For a large extension module with
|
||||||
|
many wrapped classes, this could mean a significant difference.
|
||||||
|
Therefore the general recommendation is to use
|
||||||
|
<tt>export_converters()</tt> only for classes that are likely to
|
||||||
|
be used as function arguments or return values in other modules.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
© Copyright Ralf W. Grosse-Kunstleve 2001. 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.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Updated: April 2001
|
||||||
|
|
||||||
|
</div>
|
||||||
192
doc/data_structures.txt
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
Given a real Python class 'A', a wrapped C++ class 'B', and this definition:
|
||||||
|
|
||||||
|
class C(A, B):
|
||||||
|
def __init__(self):
|
||||||
|
B.__init__(self)
|
||||||
|
self.x = 1
|
||||||
|
...
|
||||||
|
|
||||||
|
c = C()
|
||||||
|
|
||||||
|
this diagram describes the internal structure of an instance of 'C', including
|
||||||
|
its inheritance relationships. Note that ExtensionClass<B> is derived from
|
||||||
|
Class<ExtensionInstance>, and is in fact identical for all intents and purposes.
|
||||||
|
|
||||||
|
MetaClass<ExtensionInstance>
|
||||||
|
+---------+ +---------+
|
||||||
|
types.ClassType: | | | |
|
||||||
|
| | | |
|
||||||
|
| | | |
|
||||||
|
+---------+ +---------+
|
||||||
|
^ ^ ^
|
||||||
|
PyClassObject | ExtensionClass<B> | |
|
||||||
|
A: +------------+ | B: +------------+ | |
|
||||||
|
| ob_type -+-+ | ob_type -+-----+ |
|
||||||
|
| | ()<--+- __bases__ | |
|
||||||
|
| | | __dict__ -+->{...} |
|
||||||
|
| | 'B'<-+- __name__ | |
|
||||||
|
+------------+ +------------+ |
|
||||||
|
^ ^ |
|
||||||
|
| | |
|
||||||
|
+-----+ +-------------+ |
|
||||||
|
| | |
|
||||||
|
| | Class<ExtensionInstance> |
|
||||||
|
| | C: +------------+ |
|
||||||
|
| | | ob_type -+------------+
|
||||||
|
tuple:(*, *)<--+- __bases__ |
|
||||||
|
| __dict__ -+->{__module__, <methods, etc.>}
|
||||||
|
'C' <-+- __name__ |
|
||||||
|
+------------+
|
||||||
|
^ (in case of inheritance from more than one
|
||||||
|
| extension class, this vector would contain
|
||||||
|
+---------------+ a pointer to an instance holder for the data
|
||||||
|
| of each corresponding C++ class)
|
||||||
|
| ExtensionInstance
|
||||||
|
| c: +---------------------+ std::vector<InstanceHolderBase>
|
||||||
|
+----+- __class__ | +---+--
|
||||||
|
| m_wrapped_objects -+->| * | ...
|
||||||
|
{'x': 1}<-+- __dict__ | +-|-+--
|
||||||
|
+---------------------+ | InstanceValueHolder<B>
|
||||||
|
| +--------------------------------+
|
||||||
|
+-->| (contains a C++ instance of B) |
|
||||||
|
+--------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
In our inheritance test cases in extclass_demo.cpp/test_extclass.py, we have the
|
||||||
|
following C++ inheritance hierarchy:
|
||||||
|
|
||||||
|
+-----+ +----+
|
||||||
|
| A1 | | A2 |
|
||||||
|
+-----+ +----+
|
||||||
|
^ ^ ^ ^ ^
|
||||||
|
| | | | |
|
||||||
|
+-----+ | +---------+-----+
|
||||||
|
| | | |
|
||||||
|
| +---+----------+
|
||||||
|
.......!...... | |
|
||||||
|
: A_callback : +-+--+ +-+--+
|
||||||
|
:............: | B1 | | B2 |
|
||||||
|
+----+ +----+
|
||||||
|
^
|
||||||
|
|
|
||||||
|
+-------+---------+
|
||||||
|
| |
|
||||||
|
+-+-+ ......!.......
|
||||||
|
| C | : B_callback :
|
||||||
|
+---+ :............:
|
||||||
|
|
||||||
|
|
||||||
|
A_callback and B_callback are used as part of the wrapping mechanism but not
|
||||||
|
represented in Python. C is also not represented in Python but is delivered
|
||||||
|
there polymorphically through a smart pointer.
|
||||||
|
|
||||||
|
This is the data structure in Python.
|
||||||
|
|
||||||
|
ExtensionClass<A1>
|
||||||
|
A1: +------------+
|
||||||
|
()<--+- __bases__ |
|
||||||
|
| __dict__ -+->{...}
|
||||||
|
+------------+
|
||||||
|
^
|
||||||
|
| ExtensionInstance
|
||||||
|
| a1: +---------------------+ vec InstanceValueHolder<A1,A_callback>
|
||||||
|
+---------+- __class__ | +---+ +---------------------+
|
||||||
|
| | m_wrapped_objects -+->| *-+-->| contains A_callback |
|
||||||
|
| +---------------------+ +---+ +---------------------+
|
||||||
|
|
|
||||||
|
| ExtensionInstance
|
||||||
|
| pa1_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
|
||||||
|
+---------+- __class__ | +---+ +---+
|
||||||
|
| | m_wrapped_objects -+->| *-+-->| *-+-+ A1
|
||||||
|
| +---------------------+ +---+ +---+ | +---+
|
||||||
|
| +->| |
|
||||||
|
| ExtensionInstance +---+
|
||||||
|
| pb1_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
|
||||||
|
+---------+- __class__ | +---+ +---+
|
||||||
|
| | m_wrapped_objects -+->| *-+-->| *-+-+ B1
|
||||||
|
| +---------------------+ +---+ +---+ | +---+
|
||||||
|
| +->| |
|
||||||
|
| ExtensionInstance +---+
|
||||||
|
| pb2_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
|
||||||
|
+---------+- __class__ | +---+ +---+
|
||||||
|
| | m_wrapped_objects -+->| *-+-->| *-+-+ B2
|
||||||
|
| +---------------------+ +---+ +---+ | +---+
|
||||||
|
| +->| |
|
||||||
|
| +---+
|
||||||
|
| ExtensionClass<A1>
|
||||||
|
| A2: +------------+
|
||||||
|
| ()<--+- __bases__ |
|
||||||
|
| | __dict__ -+->{...}
|
||||||
|
| +------------+
|
||||||
|
| ^
|
||||||
|
| | ExtensionInstance
|
||||||
|
| a2: | +---------------------+ vec InstanceValueHolder<A2>
|
||||||
|
| +-+- __class__ | +---+ +-------------+
|
||||||
|
| | | m_wrapped_objects -+->| *-+-->| contains A2 |
|
||||||
|
| | +---------------------+ +---+ +-------------+
|
||||||
|
| |
|
||||||
|
| | ExtensionInstance
|
||||||
|
| pa2_a2: | +---------------------+ vec InstancePtrHolder<auto_ptr<A2>,A2>
|
||||||
|
| +-+- __class__ | +---+ +---+
|
||||||
|
| | | m_wrapped_objects -+->| *-+-->| *-+-+ A2
|
||||||
|
| | +---------------------+ +---+ +---+ | +---+
|
||||||
|
| | +->| |
|
||||||
|
| | ExtensionInstance +---+
|
||||||
|
| pb1_a2: | +---------------------+ vec InstancePtrHolder<auto_ptr<A2>,A2>
|
||||||
|
| +-+- __class__ | +---+ +---+
|
||||||
|
| | | m_wrapped_objects -+->| *-+-->| *-+-+ B1
|
||||||
|
| | +---------------------+ +---+ +---+ | +---+
|
||||||
|
| | +->| |
|
||||||
|
| | +---+
|
||||||
|
| |
|
||||||
|
| +---------------+------------------------------+
|
||||||
|
| | |
|
||||||
|
+------+-------------------------+-|----------------------------+ |
|
||||||
|
| | | | |
|
||||||
|
| Class<ExtensionInstance> | | ExtensionClass<B1> | | ExtensionClass<B1>
|
||||||
|
| DA1: +------------+ | | B1: +------------+ | | B2: +------------+
|
||||||
|
(*,)<---+- __bases__ | (*,*)<---+- __bases__ | (*,*)<---+- __bases__ |
|
||||||
|
| __dict__ -+->{...} | __dict__ -+->{...} | __dict__ -+->{...}
|
||||||
|
+------------+ +------------+ +------------+
|
||||||
|
^ ^ ^
|
||||||
|
| ExtensionInstance | |
|
||||||
|
| da1: +---------------------+ | vec InstanceValueHolder<A1,A_callback>
|
||||||
|
+-------+- __class__ | | +---+ +---------------------+ |
|
||||||
|
| m_wrapped_objects -+--|-->| *-+-->| contains A_callback | |
|
||||||
|
+---------------------+ | +---+ +---------------------+ |
|
||||||
|
+--------------------------------------+ |
|
||||||
|
| ExtensionInstance |
|
||||||
|
b1: | +---------------------+ vec InstanceValueHolder<B1,B_callback> |
|
||||||
|
+-+- __class__ | +---+ +---------------------+ |
|
||||||
|
| | m_wrapped_objects -+->| *-+-->| contains B_callback | |
|
||||||
|
| +---------------------+ +---+ +---------------------+ |
|
||||||
|
| |
|
||||||
|
| ExtensionInstance |
|
||||||
|
pb1_b1: | +---------------------+ vec InstancePtrHolder<auto_ptr<B1>,B1> |
|
||||||
|
+-+- __class__ | +---+ +---+ |
|
||||||
|
| | m_wrapped_objects -+->| *-+-->| *-+-+ B1 |
|
||||||
|
| +---------------------+ +---+ +---+ | +---+ |
|
||||||
|
| +->| | |
|
||||||
|
| ExtensionInstance +---+ |
|
||||||
|
pc_b1: | +---------------------+ vec InstancePtrHolder<auto_ptr<B1>,B1> |
|
||||||
|
+-+- __class__ | +---+ +---+ |
|
||||||
|
| | m_wrapped_objects -+->| *-+-->| *-+-+ C |
|
||||||
|
| +---------------------+ +---+ +---+ | +---+ |
|
||||||
|
| +->| | |
|
||||||
|
| +---+ |
|
||||||
|
| |
|
||||||
|
| Class<ExtensionInstance> +---------------------------------------+
|
||||||
|
| DB1: +------------+ | ExtensionInstance
|
||||||
|
(*,)<---+- __bases__ | a2: | +---------------------+ vec InstanceValueHolder<A2>
|
||||||
|
| __dict__ -+->{...} +-+- __class__ | +---+ +-------------+
|
||||||
|
+------------+ | m_wrapped_objects -+->| *-+-->| contains A2 |
|
||||||
|
^ +---------------------+ +---+ +-------------+
|
||||||
|
| ExtensionInstance
|
||||||
|
db1: | +---------------------+ vec InstanceValueHolder<B1,B_callback>
|
||||||
|
+-+- __class__ | +---+ +----------------------+
|
||||||
|
| m_wrapped_objects -+-->| *-+-->| contains B1_callback |
|
||||||
|
+---------------------+ +---+ +----------------------+
|
||||||
120
doc/enums.html
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<title>
|
||||||
|
Wrapping enums
|
||||||
|
</title>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<img width="277" height="86" id="_x0000_i1025" align="center"
|
||||||
|
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)"><br>
|
||||||
|
Wrapping enums
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p>Because there is in general no way to deduce that a value of arbitrary type T
|
||||||
|
is an enumeration constant, the Boost Python Library cannot automatically
|
||||||
|
convert enum values to and from Python. To handle this case, you need to decide
|
||||||
|
how you want the enum to show up in Python (since Python doesn't have
|
||||||
|
enums). Once you have done that, you can write some simple
|
||||||
|
<code>from_python()</code> and <code>to_python()</code> functions.
|
||||||
|
|
||||||
|
<p>If you are satisfied with a Python int as a way to represent your enum
|
||||||
|
values, we provide a shorthand for these functions. You just need to cause
|
||||||
|
<code>boost::python::enum_as_int_converters<EnumType></code> to be
|
||||||
|
instantiated, where
|
||||||
|
<code>EnumType</code> is your enumerated type. There are two convenient ways to do this:
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>Explicit instantiation:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
template class boost::python::enum_as_int_converters<my_enum>;
|
||||||
|
</blockquote></pre>
|
||||||
|
|
||||||
|
Some buggy C++ implementations require a class to be instantiated in the same
|
||||||
|
namespace in which it is defined. In that case, the simple incantation above becomes:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
...
|
||||||
|
} // close my_namespace
|
||||||
|
|
||||||
|
// drop into namespace python and explicitly instantiate
|
||||||
|
namespace boost { namespace python {
|
||||||
|
template class enum_as_int_converters<my_enum_type>;
|
||||||
|
}} // namespace boost::python
|
||||||
|
|
||||||
|
namespace my_namespace { // re-open my_namespace
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
|
||||||
|
<li>If you have such an implementation, you may find this technique more convenient
|
||||||
|
<blockquote><pre>
|
||||||
|
// instantiate as base class in any namespace
|
||||||
|
struct EnumTypeConverters
|
||||||
|
: boost::python::enum_as_int_converters<EnumType>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
</blockquote></pre>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Either of the above is equivalent to the following declarations:
|
||||||
|
<blockquote><pre>
|
||||||
|
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
|
||||||
|
|
||||||
|
MyEnumType from_python(PyObject* x, boost::python::type<MyEnumType>)
|
||||||
|
{
|
||||||
|
return static_cast<MyEnum>(
|
||||||
|
from_python(x, boost::python::type<long>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
MyEnumType from_python(PyObject* x, boost::python::type<const MyEnumType&>)
|
||||||
|
{
|
||||||
|
return static_cast<MyEnum>(
|
||||||
|
from_python(x, boost::python::type<long>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* to_python(MyEnumType x)
|
||||||
|
{
|
||||||
|
return to_python(static_cast<long>(x));
|
||||||
|
}
|
||||||
|
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>This technique defines the conversions of
|
||||||
|
<code>MyEnumType</code> in terms of the conversions for the built-in
|
||||||
|
<code>long</code> type.
|
||||||
|
|
||||||
|
You may also want to add a bunch of lines like this to your module
|
||||||
|
initialization. These bind the corresponding enum values to the appropriate
|
||||||
|
names so they can be used from Python:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
mymodule.add(boost::python::make_ref(enum_value_1), "enum_value_1");
|
||||||
|
mymodule.add(boost::python::make_ref(enum_value_2), "enum_value_2");
|
||||||
|
...
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
You can also add these to an extension class definition, if your enum happens to
|
||||||
|
be local to a class and you want the analogous interface in Python:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
my_class_builder.add(boost::python::to_python(enum_value_1), "enum_value_1");
|
||||||
|
my_class_builder.add(boost::python::to_python(enum_value_2), "enum_value_2");
|
||||||
|
...
|
||||||
|
</pre></blockquote>
|
||||||
|
<p>
|
||||||
|
Next: <a href="pointers.html">Pointers and Smart Pointers</a>
|
||||||
|
Previous: <a href="building.html">Building an Extension Module</a>
|
||||||
|
Up: <a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2000. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Mar 6, 2001
|
||||||
|
</div>
|
||||||
|
|
||||||
82
doc/example1.html
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<title>
|
||||||
|
A Simple Example
|
||||||
|
</title>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<img width="277" height="86" id="_x0000_i1025" src="../../../c++boost.gif" alt=
|
||||||
|
"c++boost.gif (8819 bytes)">
|
||||||
|
</h1>
|
||||||
|
<h1>
|
||||||
|
A Simple Example
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Suppose we have the following C++ API which we want to expose in
|
||||||
|
Python:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace { // Avoid cluttering the global namespace.
|
||||||
|
|
||||||
|
// A couple of simple C++ functions that we want to expose to Python.
|
||||||
|
std::string greet() { return "hello, world"; }
|
||||||
|
int square(int number) { return number * number; }
|
||||||
|
}
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<p>
|
||||||
|
Here is the C++ code for a python module called <tt>getting_started1</tt>
|
||||||
|
which exposes the API.
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
#include <boost/python/class_builder.hpp>
|
||||||
|
namespace python = boost::python;
|
||||||
|
|
||||||
|
BOOST_PYTHON_MODULE_INIT(getting_started1)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Create an object representing this extension module.
|
||||||
|
python::module_builder this_module("getting_started1");
|
||||||
|
|
||||||
|
// Add regular functions to the module.
|
||||||
|
this_module.def(greet, "greet");
|
||||||
|
this_module.def(square, "square");
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
python::handle_exception(); // Deal with the exception for Python
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<p>
|
||||||
|
That's it! If we build this shared library and put it on our <code>
|
||||||
|
PYTHONPATH</code> we can now access our C++ functions from
|
||||||
|
Python.
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> import getting_started1
|
||||||
|
>>> print getting_started1.greet()
|
||||||
|
hello, world
|
||||||
|
>>> number = 11
|
||||||
|
>>> print number, '*', number, '=', getting_started1.square(number)
|
||||||
|
11 * 11 = 121
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Next: <a href="exporting_classes.html">Exporting Classes</a>
|
||||||
|
Previous: <a href="comparisons.html">Comparisons with other systems</a> Up:
|
||||||
|
<a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2000. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Mar 6, 2000
|
||||||
|
</div>
|
||||||
|
|
||||||
144
doc/exporting_classes.html
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<title>
|
||||||
|
Exporting Classes
|
||||||
|
</title>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<img width="277" height="86" id="_x0000_i1025" src="../../../c++boost.gif" alt=
|
||||||
|
"c++boost.gif (8819 bytes)">
|
||||||
|
</h1>
|
||||||
|
<h1>
|
||||||
|
Exporting Classes
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Now let's expose a C++ class to Python:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace { // Avoid cluttering the global namespace.
|
||||||
|
|
||||||
|
// A friendly class.
|
||||||
|
class hello
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
hello(const std::string& country) { this->country = country; }
|
||||||
|
std::string greet() const { return "Hello from " + country; }
|
||||||
|
private:
|
||||||
|
std::string country;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A function taking a hello object as an argument.
|
||||||
|
std::string invite(const hello& w) {
|
||||||
|
return w.greet() + "! Please come soon!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</blockquote></pre> <p>
|
||||||
|
To expose the class, we use a <tt>class_builder</tt> in addition to the
|
||||||
|
<tt>module_builder</tt> from the previous example. Class member functions
|
||||||
|
are exposed by using the <tt>def()</tt> member function on the
|
||||||
|
<tt>class_builder</tt>:
|
||||||
|
<blockquote><pre>
|
||||||
|
#include <boost/python/class_builder.hpp>
|
||||||
|
namespace python = boost::python;
|
||||||
|
|
||||||
|
BOOST_PYTHON_MODULE_INIT(getting_started2)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Create an object representing this extension module.
|
||||||
|
python::module_builder this_module("getting_started2");
|
||||||
|
|
||||||
|
// Create the Python type object for our extension class.
|
||||||
|
python::class_builder<hello> hello_class(this_module, "hello");
|
||||||
|
|
||||||
|
// Add the __init__ function.
|
||||||
|
hello_class.def(python::constructor<std::string>());
|
||||||
|
// Add a regular member function.
|
||||||
|
hello_class.def(&hello::greet, "greet");
|
||||||
|
|
||||||
|
// Add invite() as a regular function to the module.
|
||||||
|
this_module.def(invite, "invite");
|
||||||
|
|
||||||
|
// Even better, invite() can also be made a member of hello_class!!!
|
||||||
|
hello_class.def(invite, "invite");
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
python::handle_exception(); // Deal with the exception for Python
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</blockquote></pre>
|
||||||
|
<p>
|
||||||
|
Now we can use the class normally from Python:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
>>> from getting_started2 import *
|
||||||
|
>>> hi = hello('California')
|
||||||
|
>>> hi.greet()
|
||||||
|
'Hello from California'
|
||||||
|
>>> invite(hi)
|
||||||
|
'Hello from California! Please come soon!'
|
||||||
|
>>> hi.invite()
|
||||||
|
'Hello from California! Please come soon!'
|
||||||
|
</blockquote></pre>
|
||||||
|
|
||||||
|
Notes:<ul>
|
||||||
|
<li> We expose the class' constructor by calling <tt>def()</tt> on the
|
||||||
|
<tt>class_builder</tt> with an argument whose type is
|
||||||
|
<tt>constructor<</tt><i>params</i><tt>></tt>, where <i>params</i>
|
||||||
|
matches the list of constructor argument types:
|
||||||
|
|
||||||
|
|
||||||
|
<li>Regular member functions are defined by calling <tt>def()</tt> with a
|
||||||
|
member function pointer and its Python name:
|
||||||
|
|
||||||
|
<li>Any function added to a class whose initial argument matches the class (or
|
||||||
|
any base) will act like a member function in Python.
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
We can even make a subclass of <code>hello.world</code>:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
>>> class wordy(hello):
|
||||||
|
... def greet(self):
|
||||||
|
... return hello.greet(self) + ', where the weather is fine'
|
||||||
|
...
|
||||||
|
>>> hi2 = wordy('Florida')
|
||||||
|
>>> hi2.greet()
|
||||||
|
'Hello from Florida, where the weather is fine'
|
||||||
|
>>> invite(hi2)
|
||||||
|
'Hello from Florida! Please come soon!'
|
||||||
|
</blockquote></pre>
|
||||||
|
<p>
|
||||||
|
Pretty cool! You can't do that with an ordinary Python extension type!
|
||||||
|
|
||||||
|
Of course, you may now have a slightly empty feeling in the pit of
|
||||||
|
your little pythonic stomach. Perhaps you wanted to see the following
|
||||||
|
<tt>wordy</tt> invitation:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
'Hello from Florida, where the weather is fine! Please come soon!'
|
||||||
|
</blockquote></pre>
|
||||||
|
|
||||||
|
After all, <tt>invite</tt> calls <tt>hello::greet()</tt>, and you
|
||||||
|
reimplemented that in your Python subclass, <tt>wordy</tt>. If so, <a
|
||||||
|
href= "overriding.html">read on</a>...
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Next: <a href="overriding.html">Overridable virtual functions</a>
|
||||||
|
Previous: <a href="example1.html">A Simple Example</a> Up:
|
||||||
|
<a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2000. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Mar 6, 2001
|
||||||
|
</div>
|
||||||
|
|
||||||
73
doc/extending.html
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
|
<title>
|
||||||
|
A Brief Introduction to writing Python extension modules
|
||||||
|
</title>
|
||||||
|
<h1>
|
||||||
|
<img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
||||||
|
width="277" height="86">
|
||||||
|
</h1>
|
||||||
|
<h1>
|
||||||
|
A Brief Introduction to writing Python extension modules
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Interfacing any language to Python involves building a module which can
|
||||||
|
be loaded by the Python interpreter, but which isn't written in Python.
|
||||||
|
This is known as an <em>extension module</em>. Many of the <a href=
|
||||||
|
"http://www.python.org/doc/current/lib/lib.html">built-in Python
|
||||||
|
libraries</a> are constructed in 'C' this way; Python even supplies its
|
||||||
|
<a href="http://www.python.org/doc/current/lib/types.html">fundamental
|
||||||
|
types</a> using the same mechanism. An extension module can be statically
|
||||||
|
linked with the Python interpreter, but it more commonly resides in a
|
||||||
|
shared library or DLL.
|
||||||
|
<p>
|
||||||
|
As you can see from <a href=
|
||||||
|
"http://www.python.org/doc/current/ext/ext.html"> The Python Extending
|
||||||
|
and Embedding Tutorial</a>, writing an extension module normally means
|
||||||
|
worrying about
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="http://www.python.org/doc/current/ext/refcounts.html">
|
||||||
|
maintaining reference counts</a>
|
||||||
|
<li>
|
||||||
|
<a href="http://www.python.org/doc/current/ext/callingPython.html"> how
|
||||||
|
to call back into Python</a>
|
||||||
|
<li>
|
||||||
|
<a href="http://www.python.org/doc/current/ext/parseTuple.html">
|
||||||
|
function argument parsing and typechecking</a>
|
||||||
|
</ul>
|
||||||
|
This last item typically occupies a great deal of code in an extension
|
||||||
|
module. Remember that Python is a completely dynamic language. A callable
|
||||||
|
object receives its arguments in a tuple; it is up to that object to extract
|
||||||
|
those arguments from the tuple, check their types, and raise appropriate
|
||||||
|
exceptions. There are numerous other tedious details that need to be
|
||||||
|
managed; too many to mention here. The Boost Python Library is designed to
|
||||||
|
lift most of that burden.<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Another obstacle that most people run into eventually when extending
|
||||||
|
Python is that there's no way to make a true Python class in an extension
|
||||||
|
module. The typical solution is to create a new Python type in the
|
||||||
|
extension module, and then write an additional module in 100% Python. The
|
||||||
|
Python module defines a Python class which dispatches to an instance of
|
||||||
|
the extension type, which it contains. This allows users to write
|
||||||
|
subclasses of the class in the Python module, almost as though they were
|
||||||
|
sublcassing the extension type. Aside from being tedious, it's not really
|
||||||
|
the same as having a true class, because there's no way for the user to
|
||||||
|
override a method of the extension type which is called from the
|
||||||
|
extension module. Boost.Python solves this problem by taking advantage of <a
|
||||||
|
href="http://www.python.org/doc/essays/metaclasses/">Python's metaclass
|
||||||
|
feature</a> to provide objects which look, walk, and hiss almost exactly
|
||||||
|
like regular Python classes. Boost.Python classes are actually cleaner than
|
||||||
|
Python classes in some subtle ways; a more detailed discussion will
|
||||||
|
follow (someday).</p>
|
||||||
|
<p>Next: <a href="comparisons.html">Comparisons with Other Systems</a> Up: <a
|
||||||
|
href="index.html">Top</a> </p>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2000. 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.</p>
|
||||||
|
|
||||||
247
doc/index.html
@@ -1,125 +1,166 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<title>
|
||||||
|
The Boost Python Library (Boost.Python)
|
||||||
|
</title>
|
||||||
|
<h1>
|
||||||
|
<img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277"
|
||||||
|
align="center" height="86"><br>The Boost Python Library (Boost.Python)
|
||||||
|
</h1>
|
||||||
|
|
||||||
<html>
|
<h2>Synopsis</h2>
|
||||||
<head>
|
<p>
|
||||||
<meta name="generator" content=
|
Use the Boost Python Library to quickly and easily export a C++ library to <a
|
||||||
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
|
href="http://www.python.org">Python</a> such that the Python interface is
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
very similar to the C++ interface. It is designed to be minimally
|
||||||
<link rel="stylesheet" type="text/css" href="boost.css">
|
intrusive on your C++ design. In most cases, you should not have to alter
|
||||||
|
your C++ classes in any way in order to use them with Boost.Python. The system
|
||||||
|
<em>should</em> simply ``reflect'' your C++ classes and functions into
|
||||||
|
Python. The major features of Boost.Python include support for:
|
||||||
|
<ul>
|
||||||
|
<li><a href="inheritance.html">Subclassing extension types in Python</a>
|
||||||
|
<li><a href="overriding.html">Overriding virtual functions in Python</a>
|
||||||
|
<li><a href="overloading.html">[Member] function Overloading</a>
|
||||||
|
<li><a href="special.html#numeric_auto">Automatic wrapping of numeric operators</a>
|
||||||
|
</ul>
|
||||||
|
among others.
|
||||||
|
|
||||||
<title>Boost.Python</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body link="#0000ff" vlink="#800080">
|
<h2>Supported Platforms</h2>
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
<p>Boost.Python is known to have been tested in the following configurations:
|
||||||
"header">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><a href="../../../index.htm"><img height="86" width="277" alt=
|
|
||||||
"C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
<ul>
|
||||||
<h1 align="center">Boost.Python</h1>
|
<li>Against Python 2.0 using the following compiler/library combinations:
|
||||||
|
<ul>
|
||||||
|
<li><a
|
||||||
|
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>
|
||||||
|
with the native library.
|
||||||
|
|
||||||
<h2 align="center">Index</h2>
|
<li>An upcoming release of <a
|
||||||
</td>
|
href="http://www.metrowerks.com/products/windows/">Metrowerks
|
||||||
</tr>
|
CodeWarrior Pro6 for Windows</a> with the native library (the first
|
||||||
</table>
|
release has a bug that's fatal to Boost.Python)
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Synopsis</h2>
|
<li><a
|
||||||
Welcome to version 2 of <b>Boost.Python</b>, a C++ library which enables
|
href="http://developer.intel.com/software/products/compilers/c50/">Intel
|
||||||
seamless interoperability between C++ and the <a href=
|
C++ 5.0</a>. Compilation succeeds, but tests <font
|
||||||
"http://www.python.org">Python</a> programming language. The new version
|
color="#FF0000"><b>FAILED at runtime</b></font> due to a bug in its
|
||||||
has been rewritten from the ground up, with a more convenient and
|
exception-handling implementation.
|
||||||
flexible interface, and many new capabilities, including support for:
|
</ul>
|
||||||
|
|
||||||
<ul>
|
<li>Against Python 1.5.2 using the following compiler/library:
|
||||||
<li>References and Pointers</li>
|
|
||||||
|
|
||||||
<li>Globally Registered Type Coercions</li>
|
<ul>
|
||||||
|
<li><a
|
||||||
|
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>
|
||||||
|
|
||||||
<li>Automatic Cross-Module Type Conversions</li>
|
<li><a
|
||||||
|
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>/<a
|
||||||
|
href="http://www.stlport.org">STLport 4.0</a>
|
||||||
|
|
||||||
<li>Efficient Function Overloading</li>
|
<li><a href="http://gcc.gnu.org/">GCC 2.95.2</a> [by <a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich
|
||||||
|
Koethe</a>]
|
||||||
|
|
||||||
<li>C++ to Python Exception Translation</li>
|
<li><a href="http://gcc.gnu.org/">GCC 2.95.2</a>/<a href="http://www.stlport.org">STLport 4.0</a>
|
||||||
|
|
||||||
<li>Default Arguments</li>
|
<li>Compaq C++ V6.2-024 for Digital UNIX V5.0 Rev. 910 (an <a
|
||||||
|
href="http://www.edg.com/">EDG</a>-based compiler) with <a
|
||||||
|
href="http://www.stlport.org/beta.html">STLport-4.1b3</a> [by <a
|
||||||
|
href="mailto:rwgk@cci.lbl.gov">Ralf W. Grosse-Kunstleve</a>]
|
||||||
|
|
||||||
<li>Keyword Arguments</li>
|
<li>An upcoming release of <a href="http://www.metrowerks.com/products/windows/">Metrowerks CodeWarrior
|
||||||
|
Pro6 for Windows</a> (the first release has a bug that's fatal to Boost.Python)
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<li>Manipulating Python objects in C++</li>
|
<h2>Credits</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../../../people/dave_abrahams.htm">David Abrahams</a> originated
|
||||||
|
and wrote most of the library, and continues to coordinate development.
|
||||||
|
|
||||||
<li>Exporting C++ Iterators as Python Iterators</li>
|
<li><a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich Koethe</a>
|
||||||
|
had independently developed a similar system. When he discovered Boost.Python,
|
||||||
<li>Documentation Strings</li>
|
he generously contributed countless hours of coding and much insight into
|
||||||
</ul>
|
improving it. He is responsible for an early version of the support for <a
|
||||||
The development of these features was funded in part by grants to <a
|
href="overloading.html">function overloading</a> and wrote the support for
|
||||||
href="http://www.boost-consulting.com">Boost Consulting</a> from the <a
|
<a href="inheritance.html#implicit_conversion">reflecting C++ inheritance
|
||||||
href="http://www.llnl.gov/">Lawrence Livermore National Laboratories</a>
|
relationships</a>. He has helped to improve error-reporting from both
|
||||||
and by the <a href="http://cci.lbl.gov/">Computational Crystallography
|
Python and C++, and has designed an extremely easy-to-use way of
|
||||||
Initiative</a> at Lawrence Berkeley National Laboratories.
|
exposing <a href="special.html#numeric">numeric operators</a>, including
|
||||||
<hr>
|
a way to avoid explicit coercion by means of overloading.
|
||||||
|
|
||||||
<h2>Note for Python 2.3 users</h2>
|
|
||||||
|
|
||||||
This is a bugfix release only, and is <b>not</b> compatible with
|
|
||||||
Python 2.3. Boost 1.31.0, which will be compatible with Python
|
|
||||||
2.3, is due out shortly. In the meantime, if you need Python 2.3
|
|
||||||
compatibility, we suggest you get a CVS snapshot, either from the
|
|
||||||
<a href="../../../more/download.html#CVS">SourceForge anonymous
|
|
||||||
CVS</a> or from our mirror, updated nightly:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
cvs -d :pserver:anonymous@boost-consulting.com:/boost login
|
|
||||||
<i>no password; just hit return</i>
|
|
||||||
|
|
||||||
cvs -d :pserver:anonymous@boost-consulting.com:/boost co boost
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<h2>Contents</h2>
|
|
||||||
|
|
||||||
<dl class="index">
|
|
||||||
<dt><a href="tutorial/index.html">Tutorial Introduction</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="building.html">Building and Testing</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="v2/reference.html">Reference Manual</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="v2/configuration.html">Configuration Information</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="v2/platforms.html">Known Working Platforms and
|
|
||||||
Compilers</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="v2/definitions.html">Definitions</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="projects.html">Projects using Boost.Python</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="support.html">Support Resources</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="v2/faq.html">Frequently Asked Questions (FAQs)</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="../pyste/index.html">Pyste (Boost.Python code generator)</a></dt>
|
<li><a href="http://cci.lbl.gov/staff/ralf_grosse-kunstleve.html">Ralf W.
|
||||||
|
Grosse-Kunstleve</a> contributed <a href="pickle.html">pickle support</a>
|
||||||
|
and numerous other small improvements. He's working on a way to allow
|
||||||
|
types exported by multiple modules to interact.
|
||||||
|
|
||||||
<dt><a href="news.html">News/Change Log</a></dt>
|
<li>The members of the boost mailing list and the Python community
|
||||||
|
supplied invaluable early feedback. In particular, Ron Clarke, Mark Evans,
|
||||||
|
Anton Gluck, Chuck Ingold, Prabhu Ramachandran, and Barry Scott took the
|
||||||
|
brave step of trying to use Boost.Python while it was still in early
|
||||||
|
stages of development.
|
||||||
|
|
||||||
<dt><a href="v2/progress_reports.html">LLNL Progress Reports</a></dt>
|
<li>The development of Boost.Python wouldn't have been possible without
|
||||||
|
the generous support of <a href="http://www.dragonsys.com/">Dragon
|
||||||
|
Systems/Lernout and Hauspie, Inc</a> who supported its development as an
|
||||||
|
open-source project.
|
||||||
|
</ul>
|
||||||
|
|
||||||
<dt><a href="v2/acknowledgments.html">Acknowledgments</a></dt>
|
<h2>Table of Contents</h2>
|
||||||
</dl>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
<ol>
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
<li><a href="extending.html">A Brief Introduction to writing Python
|
||||||
4 August, 2003
|
extension modules</a>
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="../../people/dave_abrahams.htm">Dave
|
<li><a href="comparisons.html">Comparisons between Boost.Python and other
|
||||||
Abrahams</a> 2002. All Rights Reserved.</i></p>
|
systems for extending Python</a>
|
||||||
</body>
|
|
||||||
</html>
|
<li><a href="example1.html">A Simple Example</a>
|
||||||
|
|
||||||
|
<li><a href="exporting_classes.html">Exporting Classes</a>
|
||||||
|
|
||||||
|
<li><a href="overriding.html">Overridable Virtual Functions</a>
|
||||||
|
|
||||||
|
<li><a href="overloading.html">Function Overloading</a>
|
||||||
|
|
||||||
|
<li><a href="inheritance.html">Inheritance</a>
|
||||||
|
|
||||||
|
<li><a href="special.html">Special Method and Operator Support</a>
|
||||||
|
|
||||||
|
<li><a href="under-the-hood.html">A Peek Under the Hood</a>
|
||||||
|
|
||||||
|
<li><a href="building.html">Building an Extension Module</a>
|
||||||
|
|
||||||
|
<li><a href="pickle.html">Pickle Support</a>
|
||||||
|
|
||||||
|
<li><a href="cross_module.html">Cross-Extension-Module Dependencies</a>
|
||||||
|
|
||||||
|
<li><a href="enums.html">Wrapping Enums</a>
|
||||||
|
|
||||||
|
<li><a href="pointers.html">Pointers and Smart Pointers</a>
|
||||||
|
|
||||||
|
<li><a href="data_structures.txt">Internal Data Structures</a>
|
||||||
|
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Documentation is a major ongoing project; assistance is greatly
|
||||||
|
appreciated! In the meantime, useful examples of every Boost.Python feature should
|
||||||
|
be evident in the regression test files <code>test/comprehensive.[<a
|
||||||
|
href="../test/comprehensive.py">py</a>/<a
|
||||||
|
href="../test/comprehensive.hpp">hpp</a>/<a
|
||||||
|
href="../test/comprehensive.cpp">cpp</a>]</code>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Questions should be directed to <a href=
|
||||||
|
"http://www.yahoogroups.com/list/boost">the boost mailing list</a>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2001. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Mar 6, 2001
|
||||||
|
|
||||||
|
|||||||
173
doc/inheritance.html
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<title>
|
||||||
|
Inheritance
|
||||||
|
</title>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<img width="277" height="86" id="_x0000_i1025" align="center"
|
||||||
|
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Inheritance
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<h2>Inheritance in Python</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Boost.Python extension classes support single and multiple-inheritance in
|
||||||
|
Python, just like regular Python classes. You can arbitrarily mix
|
||||||
|
built-in Python classes with extension classes in a derived class'
|
||||||
|
tuple of bases. Whenever a Boost.Python extension class is among the bases for a
|
||||||
|
new class in Python, the result is an extension class:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> class MyPythonClass:
|
||||||
|
... def f(): return 'MyPythonClass.f()'
|
||||||
|
...
|
||||||
|
>>> import my_extension_module
|
||||||
|
>>> class Derived(my_extension_module.MyExtensionClass, MyPythonClass):
|
||||||
|
... '''This is an extension class'''
|
||||||
|
... pass
|
||||||
|
...
|
||||||
|
>>> x = Derived()
|
||||||
|
>>> x.f()
|
||||||
|
'MyPythonClass.f()'
|
||||||
|
>>> x.g()
|
||||||
|
'MyExtensionClass.g()'
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<h2><a name="implicit_conversion">Reflecting C++ Inheritance Relationships</a></h2>
|
||||||
|
<p>
|
||||||
|
Boost.Python also allows us to represent C++ inheritance relationships so that
|
||||||
|
wrapped derived classes may be passed where values, pointers, or
|
||||||
|
references to a base class are expected as arguments. The
|
||||||
|
<code>declare_base</code> member function of
|
||||||
|
<code>class_builder<></code> is used to establish the relationship
|
||||||
|
between base and derived classes:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
#include <memory> // for std::auto_ptr<>
|
||||||
|
|
||||||
|
struct Base {
|
||||||
|
virtual ~Base() {}
|
||||||
|
virtual const char* name() const { return "Base"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Derived : Base {
|
||||||
|
Derived() : x(-1) {}
|
||||||
|
virtual const char* name() const { return "Derived"; }
|
||||||
|
int x;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::auto_ptr<Base> derived_as_base() {
|
||||||
|
return std::auto_ptr<Base>(new Derived);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* get_name(const Base& b) {
|
||||||
|
return b.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_derived_x(const Derived& d) {
|
||||||
|
return d.x;
|
||||||
|
}
|
||||||
|
<hr>
|
||||||
|
#include <boost/python/class_builder.hpp>
|
||||||
|
|
||||||
|
// namespace alias for code brevity
|
||||||
|
namespace python = boost::python;
|
||||||
|
|
||||||
|
BOOST_PYTHON_MODULE_INIT(my_module)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
python::module_builder my_module("my_module");
|
||||||
|
|
||||||
|
python::class_builder<Base> base_class(my_module, "Base");
|
||||||
|
base_class.def(python::constructor<void>());
|
||||||
|
|
||||||
|
python::class_builder<Derived> derived_class(my_module, "Derived");
|
||||||
|
derived_class.def(python::constructor<void>());
|
||||||
|
<b>// Establish the inheritance relationship between Base and Derived
|
||||||
|
derived_class.declare_base(base_class);</b>
|
||||||
|
|
||||||
|
my_module.def(derived_as_base, "derived_as_base");
|
||||||
|
my_module.def(get_name, "get_name");
|
||||||
|
my_module.def(get_derived_x, "get_derived_x");
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
python::handle_exception(); // Deal with the exception for Python
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Then, in Python:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> from my_module import *
|
||||||
|
>>> base = Base()
|
||||||
|
>>> derived = Derived()
|
||||||
|
>>> get_name(base)
|
||||||
|
'Base'
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<i>objects of wrapped class Derived may be passed where Base is expected</i>
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> get_name(derived)
|
||||||
|
'Derived'
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<i>objects of wrapped class Derived can be passed where Derived is
|
||||||
|
expected but where type information has been lost.</i>
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> get_derived_x(derived_as_base())
|
||||||
|
-1
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<h2>Inheritance Without Virtual Functions</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If for some reason your base class has no virtual functions but you still want
|
||||||
|
to represent the inheritance relationship between base and derived classes,
|
||||||
|
pass the special symbol <code>boost::python::without_downcast</code> as the 2nd parameter
|
||||||
|
to <code>declare_base</code>:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
struct Base2 {};
|
||||||
|
struct Derived2 { int f(); };
|
||||||
|
<hr>
|
||||||
|
...
|
||||||
|
python::class_builder<Base> base2_class(my_module, "Base2");
|
||||||
|
base2_class.def(python::constructor<void>());
|
||||||
|
|
||||||
|
python::class_builder<Derived2> derived2_class(my_module, "Derived2");
|
||||||
|
derived2_class.def(python::constructor<void>());
|
||||||
|
derived_class.declare_base(base_class, <b>python::without_downcast</b>);
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>This approach will allow <code>Derived2</code> objects to be passed where
|
||||||
|
<code>Base2</code> is expected, but does not attempt to implicitly convert (downcast)
|
||||||
|
smart-pointers to <code>Base2</code> into <code>Derived2</code> pointers,
|
||||||
|
references, or values.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Next: <a href="special.html">Special Method and Operator Support</a>
|
||||||
|
Previous: <a href="overloading.html">Function Overloading</a>
|
||||||
|
Up: <a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2000. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Nov 26, 2000
|
||||||
|
</div>
|
||||||
|
|
||||||
@@ -1,328 +0,0 @@
|
|||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
||||||
<title>A New Type Conversion Mechanism for Boost.Python</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" text="#000000">
|
|
||||||
|
|
||||||
<p><img border="0" src="../../../c++boost.gif" width="277" height="86"
|
|
||||||
alt="boost logo"></p>
|
|
||||||
|
|
||||||
<h1>A New Type Conversion Mechanism for Boost.Python</h1>
|
|
||||||
|
|
||||||
<p>By <a href="../../../people/dave_abrahams.htm">David Abrahams</a>.
|
|
||||||
|
|
||||||
<h2>Introduction</h2>
|
|
||||||
|
|
||||||
This document describes a redesign of the mechanism for automatically
|
|
||||||
converting objects between C++ and Python. The current implementation
|
|
||||||
uses two functions for any type <tt>T</tt>:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
U from_python(PyObject*, type<T>);
|
|
||||||
void to_python(V);
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
where U is convertible to T and T is convertible to V. These functions
|
|
||||||
are at the heart of C++/Python interoperability in Boost.Python, so
|
|
||||||
why would we want to change them? There are many reasons:
|
|
||||||
|
|
||||||
<h3>Bugs</h3>
|
|
||||||
<p>Firstly, the current mechanism relies on a common C++ compiler
|
|
||||||
bug. This is not just embarrassing: as compilers get to be more
|
|
||||||
conformant, the library stops working. The issue, in detail, is the
|
|
||||||
use of inline friend functions in templates to generate
|
|
||||||
conversions. It is a very powerful, and legal technique as long as
|
|
||||||
it's used correctly:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
template <class Derived>
|
|
||||||
struct add_some_functions
|
|
||||||
{
|
|
||||||
friend <i>return-type</i> some_function1(..., Derived <i>cv-*-&-opt</i>, ...);
|
|
||||||
friend <i>return-type</i> some_function2(..., Derived <i>cv-*-&-opt</i>, ...);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct some_template : add_some_functions<some_template<T> >
|
|
||||||
{
|
|
||||||
};
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
The <tt>add_some_functions</tt> template generates free functions
|
|
||||||
which operate on <tt>Derived</tt>, or on related types. Strictly
|
|
||||||
speaking the related types are not just cv-qualified <tt>Derived</tt>
|
|
||||||
values, pointers and/or references. Section 3.4.2 in the standard
|
|
||||||
describes exactly which types you must use as parameters to these
|
|
||||||
functions if you want the functions to be found
|
|
||||||
(there is also a less-technical description in section 11.5.1 of
|
|
||||||
C++PL3 <a href="#ref_1">[1]</a>). Suffice it to say that
|
|
||||||
with the current design, the <tt>from_python</tt> and
|
|
||||||
<tt>to_python</tt> functions are not supposed to be callable under any
|
|
||||||
conditions!
|
|
||||||
|
|
||||||
<h3>Compilation and Linking Time</h3>
|
|
||||||
|
|
||||||
The conversion functions generated for each wrapped class using the
|
|
||||||
above technique are not function templates, but regular functions. The
|
|
||||||
upshot is that they must <i>all</i> be generated regardless of whether
|
|
||||||
they are actually used. Generating all of those functions can slow
|
|
||||||
down module compilation, and resolving the references can slow down
|
|
||||||
linking.
|
|
||||||
|
|
||||||
<h3>Efficiency</h3>
|
|
||||||
|
|
||||||
The conversion functions are primarily used in (member) function
|
|
||||||
wrappers to convert the arguments and return values. Being functions,
|
|
||||||
converters have no interface which allows us to ask "will the
|
|
||||||
conversion succeed?" without calling the function. Since the
|
|
||||||
return value of the function must be the object to be passed as an
|
|
||||||
argument, Boost.Python currently uses C++ exception-handling to detect
|
|
||||||
an unsuccessful conversion. It's not a particularly good use of
|
|
||||||
exception-handling, since the failure is not handled very far from
|
|
||||||
where it occurred. More importantly, it means that C++ exceptions are
|
|
||||||
thrown during overload resolution as we seek an overload that matches
|
|
||||||
the arguments passed. Depending on the implementation, this approach
|
|
||||||
can result in significant slowdowns.
|
|
||||||
|
|
||||||
<p>It is also unclear that the current library generates a minimal
|
|
||||||
amount of code for any type conversion. Many of the conversion
|
|
||||||
functions are nontrivial, and partly because of compiler limitations,
|
|
||||||
they are declared <tt>inline</tt>. Also, we could have done a better
|
|
||||||
job separating the type-specific conversion code from the code which
|
|
||||||
is type-independent.
|
|
||||||
|
|
||||||
<h3>Cross-module Support</h3>
|
|
||||||
|
|
||||||
The current strategy requires every module to contain the definition
|
|
||||||
of conversions it uses. In general, a new module can never supply
|
|
||||||
conversion code which is used by another module. Ralf Grosse-Kunstleve
|
|
||||||
designed a clever system which imports conversions directly from one
|
|
||||||
library into another using some explicit declarations, but it has some
|
|
||||||
disadvantages also:
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>The system Ullrich Koethe designed for implicit conversion between
|
|
||||||
wrapped classes related through inheritance does not currently work if
|
|
||||||
the classes are defined in separate modules.
|
|
||||||
|
|
||||||
<li>The writer of the importing module is required to know the name of
|
|
||||||
the module supplying the imported conversions.
|
|
||||||
|
|
||||||
<li>There can be only one way to extract any given C++ type from a
|
|
||||||
Python object in a given module.
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
The first item might be addressed by moving Boost.Python into a shared
|
|
||||||
library, but the other two cannot. Ralf turned the limitation in item
|
|
||||||
two into a feature: the required module is loaded implicitly when a
|
|
||||||
conversion it defines is invoked. We will probably want to provide
|
|
||||||
that functionality anyway, but it's not clear that we should require
|
|
||||||
the declaration of all such conversions. The final item is a more
|
|
||||||
serious limitation. If, for example, new numeric types are defined in
|
|
||||||
separate modules, and these types can all be converted to
|
|
||||||
<tt>double</tt>s, we have to choose just one conversion method.
|
|
||||||
|
|
||||||
<h3>Ease-of-use</h3>
|
|
||||||
|
|
||||||
One persistent source of confusion for users of Boost.Python has been
|
|
||||||
the fact that conversions for a class are not be visible at
|
|
||||||
compile-time until the declaration of that class has been seen. When
|
|
||||||
the user tries to expose a (member) function operating on or returning
|
|
||||||
an instance of the class in question, compilation fails...even though
|
|
||||||
the user goes on to expose the class in the same translation unit!
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The new system lifts all compile-time checks for the existence of
|
|
||||||
particular type conversions and replaces them with runtime checks, in
|
|
||||||
true Pythonic style. While this might seem cavalier, the compile-time
|
|
||||||
checks are actually not much use in the current system if many classes
|
|
||||||
are wrapped in separate modules, since the checks are based only on
|
|
||||||
the user's declaration that the conversions exist.
|
|
||||||
|
|
||||||
<h2>The New Design</h2>
|
|
||||||
|
|
||||||
<h3>Motivation</h3>
|
|
||||||
|
|
||||||
The new design was heavily influenced by a desire to generate as
|
|
||||||
little code as possible in extension modules. Some of Boost.Python's
|
|
||||||
clients are enormous projects where link time is proportional to the
|
|
||||||
amount of object code, and there are many Python extension modules. As
|
|
||||||
such, we try to keep type-specific conversion code out of modules
|
|
||||||
other than the one the converters are defined in, and rely as much as
|
|
||||||
possible on centralized control through a shared library.
|
|
||||||
|
|
||||||
<h3>The Basics</h3>
|
|
||||||
|
|
||||||
The library contains a <tt>registry</tt> which maps runtime type
|
|
||||||
identifiers (actually an extension of <tt>std::type_info</tt> which
|
|
||||||
preserves references and constness) to entries containing type
|
|
||||||
converters. An <tt>entry</tt> can contain only one converter from C++ to Python
|
|
||||||
(<tt>wrapper</tt>), but many converters from Python to C++
|
|
||||||
(<tt>unwrapper</tt>s). <font color="#ff0000">What should happen if
|
|
||||||
multiple modules try to register wrappers for the same type?</font>. Wrappers
|
|
||||||
and unwrappers are known as <tt>body</tt> objects, and are accessed
|
|
||||||
by the user and the library (in its function-wrapping code) through
|
|
||||||
corresponding <tt>handle</tt> (<tt>wrap<T></tt> and
|
|
||||||
<tt>unwrap<T></tt>) objects. The <tt>handle</tt> objects are
|
|
||||||
extremely lightweight, and delegate <i>all</i> of their operations to
|
|
||||||
the corresponding <tt>body</tt>.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
When a <tt>handle</tt> object is constructed, it accesses the
|
|
||||||
registry to find a corresponding <tt>body</tt> that can convert the
|
|
||||||
handle's constructor argument. Actually the registry record for any
|
|
||||||
type
|
|
||||||
<tt>T</tt>used in a module is looked up only once and stored in a
|
|
||||||
static <tt>registration<T></tt> object for efficiency. For
|
|
||||||
example, if the handle is an <tt>unwrap<Foo&></tt> object,
|
|
||||||
the <tt>entry</tt> for <tt>Foo&</tt> is looked up in the
|
|
||||||
<tt>registry</tt>, and each <tt>unwrapper</tt> it contains is queried
|
|
||||||
to determine if it can convert the
|
|
||||||
<tt>PyObject*</tt> with which the <tt>unwrap</tt> was constructed. If
|
|
||||||
a body object which can perform the conversion is found, a pointer to
|
|
||||||
it is stored in the handle. A body object may at any point store
|
|
||||||
additional data in the handle to speed up the conversion process.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Now that the handle has been constructed, the user can ask it whether
|
|
||||||
the conversion can be performed. All handles can be tested as though
|
|
||||||
they were convertible to <tt>bool</tt>; a <tt>true</tt> value
|
|
||||||
indicates success. If the user forges ahead and tries to do the
|
|
||||||
conversion without checking when no conversion is possible, an
|
|
||||||
exception will be thrown as usual. The conversion itself is performed
|
|
||||||
by the body object.
|
|
||||||
|
|
||||||
<h3>Handling complex conversions</h3>
|
|
||||||
|
|
||||||
<p>Some conversions may require a dynamic allocation. For example,
|
|
||||||
when a Python tuple is converted to a <tt>std::vector<double>
|
|
||||||
const&</tt>, we need some storage into which to construct the
|
|
||||||
vector so that a reference to it can be formed. Furthermore, multiple
|
|
||||||
conversions of the same type may need to be "active"
|
|
||||||
simultaneously, so we can't keep a single copy of the storage
|
|
||||||
anywhere. We could keep the storage in the <tt>body</tt> object, and
|
|
||||||
have the body clone itself in case the storage is used, but in that
|
|
||||||
case the storage in the body which lives in the registry is never
|
|
||||||
used. If the storage was actually an object of the target type (the
|
|
||||||
safest way in C++), we'd have to find a way to construct one for the
|
|
||||||
body in the registry, since it may not have a default constructor.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The most obvious way out of this quagmire is to allocate the object using a
|
|
||||||
<i>new-expression</i>, and store a pointer to it in the handle. Since
|
|
||||||
the <tt>body</tt> object knows everything about the data it needs to
|
|
||||||
allocate (if any), it is also given responsibility for destroying that
|
|
||||||
data. When the <tt>handle</tt> is destroyed it asks the <tt>body</tt>
|
|
||||||
object to tear down any data it may have stored there. In many ways,
|
|
||||||
you can think of the <tt>body</tt> as a "dynamically-determined
|
|
||||||
vtable" for the handle.
|
|
||||||
|
|
||||||
<h3>Eliminating Redundancy</h3>
|
|
||||||
|
|
||||||
If you look at the current Boost.Python code, you'll see that there
|
|
||||||
are an enormous number of conversion functions generated for each
|
|
||||||
wrapped class. For a given class <tt>T</tt>, functions are generated
|
|
||||||
to extract the following types <tt>from_python</tt>:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
T*
|
|
||||||
T const*
|
|
||||||
T const* const&
|
|
||||||
T* const&
|
|
||||||
T&
|
|
||||||
T const&
|
|
||||||
T
|
|
||||||
std::auto_ptr<T>&
|
|
||||||
std::auto_ptr<T>
|
|
||||||
std::auto_ptr<T> const&
|
|
||||||
boost::shared_ptr<T>&
|
|
||||||
boost::shared_ptr<T>
|
|
||||||
boost::shared_ptr<T> const&
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
Most of these are implemented in terms of just a few conversions, and
|
|
||||||
<t>if you're lucky</t>, they will be inlined and cause no extra
|
|
||||||
overhead. In the new system, however, a significant amount of data
|
|
||||||
will be associated with each type that needs to be converted. We
|
|
||||||
certainly don't want to register a separate unwrapper object for all
|
|
||||||
of the above types.
|
|
||||||
|
|
||||||
<p>Fortunately, much of the redundancy can be eliminated. For example,
|
|
||||||
if we generate an unwrapper for <tt>T&</tt>, we don't need an
|
|
||||||
unwrapper for <tt>T const&</tt> or <tt>T</tt>. Accordingly, the user's
|
|
||||||
request to wrap/unwrap a given type is translated at compile-time into
|
|
||||||
a request which helps to eliminate redundancy. The rules used to
|
|
||||||
<tt>unwrap</tt> a type are:
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li> Treat built-in types specially: when unwrapping a value or
|
|
||||||
constant reference to one of these, use a value for the target
|
|
||||||
type. It will bind to a const reference if neccessary, and more
|
|
||||||
importantly, avoids having to dynamically allocate room for
|
|
||||||
an lvalue of types which can be cheaply copied.
|
|
||||||
<li>
|
|
||||||
Reduce everything else to a reference to an un-cv-qualified type
|
|
||||||
where possible. Since cv-qualification is lost on Python
|
|
||||||
anyway, there's no point in trying to convert to a
|
|
||||||
<tt>const&</tt>. <font color="#ff0000">What about conversions
|
|
||||||
to values like the tuple->vector example above? It seems to me
|
|
||||||
that we don't want to make a <tt>vector<double>&</tt>
|
|
||||||
(non-const) converter available for that case. We may need to
|
|
||||||
rethink this slightly.</font>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>To handle the problem described above in item 2, we modify the
|
|
||||||
procedure slightly. To unwrap any non-scalar <tt>T</tt>, we seek an
|
|
||||||
unwrapper for <tt>add_reference<T>::type</tt>. Unwrappers for
|
|
||||||
<tt>T const&</tt> always return <tt>T&</tt>, and are
|
|
||||||
registered under both <tt>T &</tt> and
|
|
||||||
<tt>T const&</tt>.
|
|
||||||
|
|
||||||
<p>For compilers not supporting partial specialization, unwrappers for
|
|
||||||
<tt>T const&</tt> must return <tt>T const&</tt>
|
|
||||||
(since constness can't be stripped), but a separate unwrapper object
|
|
||||||
need to be registered for <tt>T &</tt> and
|
|
||||||
<tt>T const&</tt> anyway, for the same reasons.
|
|
||||||
|
|
||||||
<font color="#ff0000">We may want to make it possible to compile as
|
|
||||||
though partial specialization were unavailable even on compilers where
|
|
||||||
it is available, in case modules could be compiled by different
|
|
||||||
compilers with compatible ABIs (e.g. Intel C++ and MSVC6).</font>
|
|
||||||
|
|
||||||
<h3>Efficient Argument Conversion</h3>
|
|
||||||
|
|
||||||
Since type conversions are primarily used in function wrappers, an
|
|
||||||
optimization is provided for the case where a group of conversions are
|
|
||||||
used together. Each <tt>handle</tt> class has a corresponding
|
|
||||||
"<tt>_more</tt>" class which does the same job, but has a
|
|
||||||
trivial destructor. Instead of asking each "<tt>_more</tt>"
|
|
||||||
handle to destroy its own body, it is linked into an endogenous list
|
|
||||||
managed by the first (ordinary) handle. The <tt>wrap</tt> and
|
|
||||||
<tt>unwrap</tt> destructors are responsible for traversing that list
|
|
||||||
and asking each <tt>body</tt> class to tear down its
|
|
||||||
<tt>handle</tt>. This mechanism is also used to determine if all of
|
|
||||||
the argument/return-value conversions can succeed with a single
|
|
||||||
function call in the function wrapping code. <font color="#ff0000">We
|
|
||||||
might need to handle return values in a separate step for Python
|
|
||||||
callbacks, since the availablility of a conversion won't be known
|
|
||||||
until the result object is retrieved.</font>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<hr>
|
|
||||||
<h2>References</h2>
|
|
||||||
|
|
||||||
<p><a name="ref_1">[1]</a>B. Stroustrup, The C++ Programming Language
|
|
||||||
Special Edition Addison-Wesley, ISBN 0-201-70073-5.
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B %Y" startspan -->
|
|
||||||
13 November, 2002
|
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="31283" --></p>
|
|
||||||
<p>© Copyright David Abrahams, 2001</p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
This hierarchy contains converter handle classes.
|
|
||||||
|
|
||||||
|
|
||||||
+-------------+
|
|
||||||
| noncopyable |
|
|
||||||
+-------------+
|
|
||||||
^
|
|
||||||
| A common base class used so that
|
|
||||||
+--------+--------+ conversions can be linked into a
|
|
||||||
| conversion_base | chain for efficient argument
|
|
||||||
+-----------------+ conversion
|
|
||||||
^
|
|
||||||
|
|
|
||||||
+---------+-----------+
|
|
||||||
| |
|
|
||||||
+-----------+----+ +------+-------+ only used for
|
|
||||||
| unwrap_more<T> | | wrap_more<T> | chaining, and don't manage any
|
|
||||||
+----------------+ +--------------+ resources.
|
|
||||||
^ ^
|
|
||||||
| |
|
|
||||||
+-----+-----+ +-------+-+ These converters are what users
|
|
||||||
| unwrap<T> | | wrap<T> | actually touch, but they do so
|
|
||||||
+-----------+ +---------+ through a type generator which
|
|
||||||
minimizes the number of converters
|
|
||||||
that must be generated, so they
|
|
||||||
|
|
||||||
|
|
||||||
Each unwrap<T>, unwrap_more<T>, wrap<T>, wrap_more<T> converter holds
|
|
||||||
a reference to an appropriate converter object
|
|
||||||
|
|
||||||
This hierarchy contains converter body classes
|
|
||||||
|
|
||||||
Exposes use/release which
|
|
||||||
are needed in case the converter
|
|
||||||
+-----------+ in the registry needs to be
|
|
||||||
| converter | cloned. That occurs when a
|
|
||||||
+-----------+ unwrap target type is not
|
|
||||||
^ contained within the Python object.
|
|
||||||
|
|
|
||||||
+------------------+-----+
|
|
||||||
| |
|
|
||||||
+--------+-------+ Exposes |
|
|
||||||
| unwrapper_base | convertible() |
|
|
||||||
+----------------+ |
|
|
||||||
^ |
|
|
||||||
| |
|
|
||||||
+--------+----+ +-----+-----+
|
|
||||||
| unwrapper<T>| | wrapper<T>|
|
|
||||||
+-------------+ +-----------+
|
|
||||||
Exposes T convert(PyObject*) Exposes PyObject* convert(T)
|
|
||||||
|
|
||||||
|
|
||||||
unwrap:
|
|
||||||
|
|
||||||
constructed with a PyObject*, whose reference count is
|
|
||||||
incremented.
|
|
||||||
|
|
||||||
find the registry entry for the target type
|
|
||||||
|
|
||||||
look in the collection of converters for one which claims to be
|
|
||||||
able to convert the PyObject to the target type.
|
|
||||||
|
|
||||||
stick a pointer to the unwrapper in the unwrap object
|
|
||||||
|
|
||||||
when unwrap is queried for convertibility, it checks to see
|
|
||||||
if it has a pointer to an unwrapper.
|
|
||||||
|
|
||||||
on conversion, the unwrapper is asked to allocate an
|
|
||||||
implementation if the unwrap object isn't already holding
|
|
||||||
one. The unwrap object "takes ownership" of the unwrapper's
|
|
||||||
implementation. No memory allocation will actually take place
|
|
||||||
unless this is a value conversion.
|
|
||||||
|
|
||||||
on destruction, the unwrapper is asked to free any implementation
|
|
||||||
held by the unwrap object. No memory deallocation actually
|
|
||||||
takes place unless this is a value conversion
|
|
||||||
|
|
||||||
on destruction, the reference count on the held PyObject is
|
|
||||||
decremented.
|
|
||||||
|
|
||||||
We need to make sure that by default, you can't instantiate
|
|
||||||
callback<> for reference and pointer return types: although the
|
|
||||||
unwrappers may exist, they may convert by-value, which would cause
|
|
||||||
the referent to be destroyed upon return.
|
|
||||||
|
|
||||||
wrap:
|
|
||||||
|
|
||||||
find the registry entry for the source type
|
|
||||||
|
|
||||||
see if there is a converter. If found, stick a pointer to it in
|
|
||||||
the wrap object.
|
|
||||||
|
|
||||||
when queried for convertibility, it checks to see if it has a
|
|
||||||
pointer to a converter.
|
|
||||||
|
|
||||||
on conversion, a reference to the target PyObject is held by the
|
|
||||||
converter. Generally, the PyObject will have been created by the
|
|
||||||
converter, but in certain cases it may be a pre-existing object,
|
|
||||||
whose reference count will have been incremented.
|
|
||||||
|
|
||||||
when a wrap<T> x is used to return from a C++ function,
|
|
||||||
x.release() is returned so that x no longer holds a reference to
|
|
||||||
the PyObject when destroyed.
|
|
||||||
|
|
||||||
Otherwise, on destruction, any PyObject still held has its
|
|
||||||
reference-count decremented.
|
|
||||||
|
|
||||||
|
|
||||||
When a converter is created by the user, the appropriate element must
|
|
||||||
be added to the registry; when it is destroyed, it must be removed
|
|
||||||
from the registry.
|
|
||||||
109
doc/news.html
@@ -1,109 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="generator" content=
|
|
||||||
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="boost.css">
|
|
||||||
|
|
||||||
<title>Boost.Python - News/Change Log</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body link="#0000ff" vlink="#800080">
|
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
|
||||||
"header">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><a href="../../../index.htm"><img height="86" width="277" alt=
|
|
||||||
"C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center"><a href="index.html">Boost.Python</a></h1>
|
|
||||||
|
|
||||||
<h2 align="center">News/Change Log</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<dl class="page-index">
|
|
||||||
<dt>24 February 2003</dt>
|
|
||||||
|
|
||||||
<dd>Finished improved support
|
|
||||||
for <code>boost::shared_ptr</code>. Now any wrapped object of
|
|
||||||
C++ class <code>X</code> can be converted automatically
|
|
||||||
to <code>shared_ptr<X></code>, regardless of how it was
|
|
||||||
wrapped. The <code>shared_ptr</code> will manage the lifetime
|
|
||||||
of the Python object which supplied the <code>X</code>, rather
|
|
||||||
than just the <code>X</code> object itself, and when such
|
|
||||||
a <code>shared_ptr</code> is converted back to Python, the
|
|
||||||
original Python object will be returned.</dd>
|
|
||||||
|
|
||||||
<dt>19 January 2003</dt>
|
|
||||||
|
|
||||||
<dd>Integrated <code>staticmethod</code> support from <a href=
|
|
||||||
"mailto:nickm-at-sitius.com">Nikolay Mladenov</a>. Thanks,
|
|
||||||
Nikolay!</dd>
|
|
||||||
|
|
||||||
<dt>29 December 2002</dt>
|
|
||||||
|
|
||||||
<dd>Added Visual Studio project file and instructions from Brett
|
|
||||||
Calcott. Thanks, Brett!</dd>
|
|
||||||
|
|
||||||
<dt>20 December 2002</dt>
|
|
||||||
|
|
||||||
<dd>Added automatic downcasting for pointers, references, and smart
|
|
||||||
pointers to polymorphic class types upon conversion to python</dd>
|
|
||||||
|
|
||||||
<dt>18 December 2002</dt>
|
|
||||||
|
|
||||||
<dd>Optimized from_python conversions for wrapped classes by putting
|
|
||||||
the conversion logic in the shared library instead of registering
|
|
||||||
separate converters for each class in each extension module</dd>
|
|
||||||
|
|
||||||
<dt>19 November 2002</dt>
|
|
||||||
|
|
||||||
<dd>Removed the need for users to cast base class member function
|
|
||||||
pointers when used as arguments to <a href=
|
|
||||||
"v2/class.html#class_-spec-modifiers">add_property</a></dd>
|
|
||||||
|
|
||||||
<dt>13 December 2002</dt>
|
|
||||||
|
|
||||||
<dd>Allow exporting of <a href=
|
|
||||||
"v2/enum.html#enum_-spec"><code>enum_</code></a> values into enclosing
|
|
||||||
<a href="v2/scope.html#scope-spec"><code>scope</code></a>.<br>
|
|
||||||
Fixed unsigned integer conversions to deal correctly with numbers that
|
|
||||||
are out-of-range of <code>signed long</code>.</dd>
|
|
||||||
|
|
||||||
<dt>14 November 2002</dt>
|
|
||||||
|
|
||||||
<dd>Auto-detection of class data members wrapped with <a href=
|
|
||||||
"v2/data_members.html#make_getter-spec"><code>make_getter</code></a></dd>
|
|
||||||
|
|
||||||
<dt>13 November 2002</dt>
|
|
||||||
|
|
||||||
<dd>Full Support for <code>std::auto_ptr<></code> added.</dd>
|
|
||||||
|
|
||||||
<dt>October 2002</dt>
|
|
||||||
|
|
||||||
<dd>Ongoing updates and improvements to tutorial documentation</dd>
|
|
||||||
|
|
||||||
<dt>10 October 2002</dt>
|
|
||||||
|
|
||||||
<dd>Boost.Python V2 is released!</dd>
|
|
||||||
</dl>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
|
||||||
20 December, 2002
|
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="../../../people/dave_abrahams.htm">Dave
|
|
||||||
Abrahams</a> 2002. All Rights Reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
155
doc/overloading.html
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<title>
|
||||||
|
Function Overloading
|
||||||
|
</title>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<img width="277" height="86" id="_x0000_i1025" align="center"
|
||||||
|
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Function Overloading
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<h2>An Example</h2>
|
||||||
|
<p>
|
||||||
|
To expose overloaded functions in Python, simply <code>def()</code> each
|
||||||
|
one with the same Python name:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
inline int f1() { return 3; }
|
||||||
|
inline int f2(int x) { return x + 1; }
|
||||||
|
|
||||||
|
class X {
|
||||||
|
public:
|
||||||
|
X() : m_value(0) {}
|
||||||
|
X(int n) : m_value(n) {}
|
||||||
|
int value() const { return m_value; }
|
||||||
|
void value(int v) { m_value = v; }
|
||||||
|
private:
|
||||||
|
int m_value;
|
||||||
|
};
|
||||||
|
...
|
||||||
|
|
||||||
|
BOOST_PYTHON_MODULE_INIT(overload_demo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
boost::python::module_builder overload_demo("overload_demo");
|
||||||
|
// Overloaded functions at module scope
|
||||||
|
overload_demo.def(f1, "f");
|
||||||
|
overload_demo.def(f2, "f");
|
||||||
|
|
||||||
|
boost::python::class_builder<X> x_class(overload_demo, "X");
|
||||||
|
// Overloaded constructors
|
||||||
|
x_class.def(boost::python::constructor<>());
|
||||||
|
x_class.def(boost::python::constructor<int>());
|
||||||
|
|
||||||
|
// Overloaded member functions
|
||||||
|
x_class.def((int (X::*)() const)&X::value, "value");
|
||||||
|
x_class.def((void (X::*)(int))&X::value, "value");
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Now in Python:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> from overload_demo import *
|
||||||
|
>>> x0 = X()
|
||||||
|
>>> x1 = X(1)
|
||||||
|
>>> x0.value()
|
||||||
|
0
|
||||||
|
>>> x1.value()
|
||||||
|
1
|
||||||
|
>>> x0.value(3)
|
||||||
|
>>> x0.value()
|
||||||
|
3
|
||||||
|
>>> X('hello')
|
||||||
|
TypeError: No overloaded functions match (X, string). Candidates are:
|
||||||
|
void (*)()
|
||||||
|
void (*)(int)
|
||||||
|
>>> f()
|
||||||
|
3
|
||||||
|
>>> f(4)
|
||||||
|
5
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<h2>Discussion</h2>
|
||||||
|
<p>
|
||||||
|
Notice that overloading in the Python module was produced three ways:<ol>
|
||||||
|
<li>by combining the non-overloaded C++ functions <code>int f1()</code>
|
||||||
|
and <code>int f2(int)</code> and exposing them as <code>f</code> in Python.
|
||||||
|
<li>by exposing the overloaded constructors of <code>class X</code>
|
||||||
|
<li>by exposing the overloaded member functions <code>X::value</code>.
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
Techniques 1. and 3. above are really alternatives. In case 3, you need
|
||||||
|
to form a pointer to each of the overloaded functions. The casting
|
||||||
|
syntax shown above is one way to do that in C++. Case 1 does not require
|
||||||
|
complicated-looking casts, but may not be viable if you can't change
|
||||||
|
your C++ interface. N.B. There's really nothing unsafe about casting an
|
||||||
|
overloaded (member) function address this way: the compiler won't let
|
||||||
|
you write it at all unless you get it right.
|
||||||
|
|
||||||
|
<h2>An Alternative to Casting</h2>
|
||||||
|
<p>
|
||||||
|
This approach is not neccessarily better, but may be preferable for some
|
||||||
|
people who have trouble writing out the types of (member) function
|
||||||
|
pointers or simply prefer to avoid all casts as a matter of principle:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
// Forwarding functions for X::value
|
||||||
|
inline void set_x_value(X& self, int v) { self.value(v); }
|
||||||
|
inline int get_x_value(X& self) { return self.value(); }
|
||||||
|
...
|
||||||
|
// Overloaded member functions
|
||||||
|
x_class.def(set_x_value, "value");
|
||||||
|
x_class.def(get_x_value, "value");
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<p>Here we are taking advantage of the ability to expose C++ functions at
|
||||||
|
namespace scope as Python member functions.
|
||||||
|
|
||||||
|
<h2>Overload Resolution</h2>
|
||||||
|
<p>
|
||||||
|
The function overload resolution mechanism works as follows:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>Attribute lookup for extension classes proceeds in <a
|
||||||
|
href="http://www.python.org/doc/current/tut/node11.html#SECTION0011510000000000000000">the
|
||||||
|
usual Python way</a> using a depth-first, left-to-right search. When a
|
||||||
|
class is found which has a matching attribute, only functions overloaded
|
||||||
|
in the context of that class are candidates for overload resolution. In
|
||||||
|
this sense, overload resolution mirrors the C++ mechanism, where a name
|
||||||
|
in a derived class ``hides'' all functions with the same name from a base
|
||||||
|
class.
|
||||||
|
<p>
|
||||||
|
|
||||||
|
<li>Within a name-space context (extension class or module), overloaded
|
||||||
|
functions are tried in the same order they were
|
||||||
|
<code>def()</code>ed. The first function whose signature can be made to
|
||||||
|
match each argument passed is the one which is ultimately called.
|
||||||
|
This means in particular that you cannot overload the same function on
|
||||||
|
both ``<code>int</code>'' and ``<code>float</code>'' because Python
|
||||||
|
automatically converts either of the two types into the other one.
|
||||||
|
If the ``<code>float</code>'' overload is found first, it is used
|
||||||
|
also used for arguments of type ``<code>int</code>'' as well, and the
|
||||||
|
``<code>int</code>'' version of the function is never invoked.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Next: <a href="inheritance.html">Inheritance</a>
|
||||||
|
Previous: <a href="overriding.html">Overridable Virtual Functions</a>
|
||||||
|
Up: <a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2001. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Mar 6, 2001
|
||||||
|
</div>
|
||||||
|
|
||||||
215
doc/overriding.html
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
|
|
||||||
|
<title>Overridable Virtual Functions</title>
|
||||||
|
|
||||||
|
<img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
||||||
|
width="277" height="86">
|
||||||
|
|
||||||
|
<h1>Overridable Virtual Functions</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In the <a href="exporting_classes.html">previous example</a> we exposed a simple
|
||||||
|
C++ class in Python and showed that we could write a subclass. We even
|
||||||
|
redefined one of the functions in our derived class. Now we will learn
|
||||||
|
how to make the function behave virtually <em>when called from C++</em>.
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="overriding_example">Example</a></h2>
|
||||||
|
|
||||||
|
<p>In this example, it is assumed that <code>hello::greet()</code> is a virtual
|
||||||
|
member function:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
class hello
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
hello(const std::string& country) { this->country = country; }
|
||||||
|
<b>virtual</b> std::string greet() const { return "Hello from " + country; }
|
||||||
|
virtual ~hello(); // Good practice
|
||||||
|
...
|
||||||
|
};
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
We'll need a derived class<a href="#why_derived">*</a> to help us
|
||||||
|
dispatch the call to Python. In our derived class, we need the following
|
||||||
|
elements:
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
|
||||||
|
<li><a name="derived_1">A</a> <code>PyObject*</code> data member (usually
|
||||||
|
called <tt>self</tt>) that holds a pointer to the Python object corresponding
|
||||||
|
to our C++ <tt>hello</tt> instance.
|
||||||
|
|
||||||
|
<li><a name="derived_2">For</a> each exposed constructor of the
|
||||||
|
base class <tt>T</tt>, a constructor which takes the same parameters preceded by an initial
|
||||||
|
<code>PyObject*</code> argument. The initial argument should be stored in the <tt>self</tt> data
|
||||||
|
member described above.
|
||||||
|
|
||||||
|
<li><a name="derived_3">If</a> the class being wrapped is ever returned <i>by
|
||||||
|
value</i> from a wrapped function, be sure you do the same for the
|
||||||
|
<tt>T</tt>'s copy constructor: you'll need a constructor taking arguments
|
||||||
|
<tt>(PyObject*, const T&)</tt>.
|
||||||
|
|
||||||
|
<li><a name="derived_4">An</a> implementation of each virtual function you may
|
||||||
|
wish to override in Python which uses
|
||||||
|
<tt>callback<</tt><i>return-type</i><tt>>::call_method(self, "</tt><i>name</i><tt>", </tt><i>args...</i><tt>)</tt> to call
|
||||||
|
the Python override.
|
||||||
|
|
||||||
|
<li><a name="derived_5">For</a> each non-pure virtual function meant to be
|
||||||
|
overridable from Python, a static member function (or a free function) taking
|
||||||
|
a reference or pointer to the <tt>T</tt> as the first parameter and which
|
||||||
|
forwards any additional parameters neccessary to the <i>default</i>
|
||||||
|
implementation of the virtual function. See also <a href="#private">this
|
||||||
|
note</a> if the base class virtual function is private.
|
||||||
|
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
struct hello_callback : hello
|
||||||
|
{
|
||||||
|
// hello constructor storing initial self_ parameter
|
||||||
|
hello_callback(PyObject* self_, const std::string& x) // <a href="#derived_2">2</a>
|
||||||
|
: hello(x), self(self_) {}
|
||||||
|
|
||||||
|
// In case hello is returned by-value from a wrapped function
|
||||||
|
hello_callback(PyObject* self_, const hello& x) // <a href="#derived_3">3</a>
|
||||||
|
: hello(x), self(self_) {}
|
||||||
|
|
||||||
|
// Override greet to call back into Python
|
||||||
|
std::string greet() const // <a href="#derived_4">4</a>
|
||||||
|
{ return boost::python::callback<std::string>::call_method(self, "greet"); }
|
||||||
|
|
||||||
|
// Supplies the default implementation of greet
|
||||||
|
static std::string <a name= "default_implementation">default_greet</a>(const hello& self_) const // <a href="#derived_5">5</a>
|
||||||
|
{ return self_.hello::greet(); }
|
||||||
|
private:
|
||||||
|
PyObject* self; // <a href="#derived_1">1</a>
|
||||||
|
};
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Finally, we add <tt>hello_callback</tt> to the <tt>
|
||||||
|
class_builder<></tt> declaration in our module initialization
|
||||||
|
function, and when we define the function, we must tell Boost.Python about the default
|
||||||
|
implementation:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
// Create the <a name=
|
||||||
|
"hello_class">Python type object</a> for our extension class
|
||||||
|
boost::python::class_builder<hello<strong>,hello_callback></strong> hello_class(hello, "hello");
|
||||||
|
// Add a virtual member function
|
||||||
|
hello_class.def(&hello::greet, "greet", &<b>hello_callback::default_greet</b>);
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Now our Python subclass of <tt>hello</tt> behaves as expected:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
>>> class wordy(hello):
|
||||||
|
... def greet(self):
|
||||||
|
... return hello.greet(self) + ', where the weather is fine'
|
||||||
|
...
|
||||||
|
>>> hi2 = wordy('Florida')
|
||||||
|
>>> hi2.greet()
|
||||||
|
'Hello from Florida, where the weather is fine'
|
||||||
|
>>> invite(hi2)
|
||||||
|
'Hello from Florida, where the weather is fine! Please come soon!'
|
||||||
|
</pre></blockquote>
|
||||||
|
<p>
|
||||||
|
<a name="why_derived">*</a>You may ask, "Why do we need this derived
|
||||||
|
class? This could have been designed so that everything gets done right
|
||||||
|
inside of <tt>hello</tt>." One of the goals of Boost.Python is to be
|
||||||
|
minimally intrusive on an existing C++ design. In principle, it should be
|
||||||
|
possible to expose the interface for a 3rd party library without changing
|
||||||
|
it. To unintrusively hook into the virtual functions so that a Python
|
||||||
|
override may be called, we must use a derived class.
|
||||||
|
|
||||||
|
<h2>Pure Virtual Functions</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A pure virtual function with no implementation is actually a lot easier to
|
||||||
|
deal with than a virtual function with a default implementation. First of
|
||||||
|
all, you obviously don't need to <a href="#default_implementation"> supply
|
||||||
|
a default implementation</a>. Secondly, you don't need to call
|
||||||
|
<tt>def()</tt> on the <tt>extension_class<></tt> instance
|
||||||
|
for the virtual function. In fact, you wouldn't <em>want</em> to: if the
|
||||||
|
corresponding attribute on the Python class stays undefined, you'll get an
|
||||||
|
<tt>AttributeError</tt> in Python when you try to call the function,
|
||||||
|
indicating that it should have been implemented. For example:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
struct baz {
|
||||||
|
<strong>virtual</strong> int pure(int) = 0;
|
||||||
|
int calls_pure(int x) { return pure(x) + 1000; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct baz_callback {
|
||||||
|
int pure(int x) { boost::python::callback<int>::call_method(m_self, "pure", x); }
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_PYTHON_MODULE_INIT(foobar)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
boost::python::module_builder foobar("foobar");
|
||||||
|
boost::python::class_builder<baz,baz_callback> baz_class("baz");
|
||||||
|
baz_class.def(&baz::calls_pure, "calls_pure");
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
boost::python::handle_exception(); // Deal with the exception for Python
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<p>
|
||||||
|
Now in Python:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> from foobar import baz
|
||||||
|
>>> x = baz()
|
||||||
|
>>> x.pure(1)
|
||||||
|
Traceback (innermost last):
|
||||||
|
File "<stdin>", line 1, in ?
|
||||||
|
AttributeError: pure
|
||||||
|
>>> x.calls_pure(1)
|
||||||
|
Traceback (innermost last):
|
||||||
|
File "<stdin>", line 1, in ?
|
||||||
|
AttributeError: pure
|
||||||
|
>>> class mumble(baz):
|
||||||
|
... def pure(self, x): return x + 1
|
||||||
|
...
|
||||||
|
>>> y = mumble()
|
||||||
|
>>> y.pure(99)
|
||||||
|
100
|
||||||
|
>>> y.calls_pure(99)
|
||||||
|
1100
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<a name="private"><h2>Private Non-Pure Virtual Functions</h2></a>
|
||||||
|
|
||||||
|
<p>This is one area where some minor intrusiveness on the wrapped library is
|
||||||
|
required. Once it has been overridden, the only way to call the base class
|
||||||
|
implementation of a private virtual function is to make the derived class a
|
||||||
|
friend of the base class. You didn't hear it from me, but most C++
|
||||||
|
implementations will allow you to change the declaration of the base class in
|
||||||
|
this limited way without breaking binary compatibility (though it will certainly
|
||||||
|
break the <a
|
||||||
|
href="http://cs.calvin.edu/c++/C++Standard-Nov97/basic.html#basic.def.odr">ODR</a>).
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<p>
|
||||||
|
Next: <a href="overloading.html">Function Overloading</a>
|
||||||
|
Previous: <a href="exporting_classes.html">Exporting Classes</a>
|
||||||
|
Up: <a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2001. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Mar 21, 2001
|
||||||
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<img src="../../../../c++boost.gif"
|
<img src="../../../c++boost.gif"
|
||||||
alt="c++boost.gif (8819 bytes)"
|
alt="c++boost.gif (8819 bytes)"
|
||||||
align="center"
|
align="center"
|
||||||
width="277" height="86">
|
width="277" height="86">
|
||||||
@@ -26,14 +26,16 @@ converts nearly arbitrary Python objects into a stream of bytes that
|
|||||||
can be written to a file.
|
can be written to a file.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The Boost Python Library supports the pickle module
|
The Boost Python Library supports the pickle module by emulating the
|
||||||
through the interface as described in detail in the
|
interface implemented by Jim Fulton's ExtensionClass module that is
|
||||||
|
included in the
|
||||||
|
<a href="http://www.zope.org/"
|
||||||
|
>ZOPE</a>
|
||||||
|
distribution.
|
||||||
|
This interface is similar to that for regular Python classes as
|
||||||
|
described in detail in the
|
||||||
<a href="http://www.python.org/doc/current/lib/module-pickle.html"
|
<a href="http://www.python.org/doc/current/lib/module-pickle.html"
|
||||||
>Python Library Reference for pickle.</a> This interface
|
>Python Library Reference for pickle.</a>
|
||||||
involves the special methods <tt>__getinitargs__</tt>,
|
|
||||||
<tt>__getstate__</tt> and <tt>__setstate__</tt> as described
|
|
||||||
in the following. Note that Boost.Python is also fully compatible
|
|
||||||
with Python's cPickle module.
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<h2>The Boost.Python Pickle Interface</h2>
|
<h2>The Boost.Python Pickle Interface</h2>
|
||||||
@@ -53,9 +55,8 @@ methods:
|
|||||||
the class constructor.
|
the class constructor.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
If <tt>__getinitargs__</tt> is not defined, <tt>pickle.load</tt>
|
If <tt>__getinitargs__</tt> is not defined, the class constructor
|
||||||
will call the constructor (<tt>__init__</tt>) without arguments;
|
will be called without arguments.
|
||||||
i.e., the object must be default-constructible.
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<dt>
|
<dt>
|
||||||
@@ -67,137 +68,94 @@ methods:
|
|||||||
This method should return a Python object representing the state of
|
This method should return a Python object representing the state of
|
||||||
the instance.
|
the instance.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If <tt>__getstate__</tt> is not defined, the instance's
|
||||||
|
<tt>__dict__</tt> is pickled (if it is not empty).
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<dt>
|
<dt>
|
||||||
<strong><tt>__setstate__</tt></strong>
|
<strong><tt>__setstate__</tt></strong>
|
||||||
|
|
||||||
<dd>
|
<dd>
|
||||||
When an instance of a Boost.Python extension class is restored by the
|
When an instance of a Boost.Python extension class is restored by the
|
||||||
unpickler (<tt>pickle.load</tt>), it is first constructed using the
|
unpickler, it is first constructed using the result of
|
||||||
result of <tt>__getinitargs__</tt> as arguments (see above). Subsequently
|
<tt>__getinitargs__</tt> as arguments (see above). Subsequently the
|
||||||
the unpickler tests if the new instance has a <tt>__setstate__</tt>
|
unpickler tests if the new instance has a <tt>__setstate__</tt>
|
||||||
method. If so, this method is called with the result of
|
method. If so, this method is called with the result of
|
||||||
<tt>__getstate__</tt> (a Python object) as the argument.
|
<tt>__getstate__</tt> (a Python object) as the argument.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If <tt>__setstate__</tt> is not defined, the result of
|
||||||
|
<tt>__getstate__</tt> must be a Python dictionary. The items of this
|
||||||
|
dictionary are added to the instance's <tt>__dict__</tt>.
|
||||||
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
The three special methods described above may be <tt>.def()</tt>'ed
|
If both <tt>__getstate__</tt> and <tt>__setstate__</tt> are defined,
|
||||||
individually by the user. However, Boost.Python provides an easy to use
|
the Python object returned by <tt>__getstate__</tt> need not be a
|
||||||
high-level interface via the
|
dictionary. The <tt>__getstate__</tt> and <tt>__setstate__</tt> methods
|
||||||
<strong><tt>boost::python::pickle_suite</tt></strong> class that also
|
can do what they want.
|
||||||
enforces consistency: <tt>__getstate__</tt> and <tt>__setstate__</tt>
|
|
||||||
must be defined as pairs. Use of this interface is demonstrated by the
|
|
||||||
following examples.
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<h2>Examples</h2>
|
<h2>Pitfalls and Safety Guards</h2>
|
||||||
|
|
||||||
There are three files in <a href="../../test/"
|
In Boost.Python extension modules with many extension classes,
|
||||||
><tt>boost/libs/python/test</tt></a> that show how to
|
providing complete pickle support for all classes would be a
|
||||||
provide pickle support.
|
significant overhead. In general complete pickle support should only be
|
||||||
|
implemented for extension classes that will eventually be pickled.
|
||||||
|
However, the author of a Boost.Python extension module might not
|
||||||
|
anticipate correctly which classes need support for pickle.
|
||||||
|
Unfortunately, the pickle protocol described above has two important
|
||||||
|
pitfalls that the end user of a Boost.Python extension module might not
|
||||||
|
be aware of:
|
||||||
|
|
||||||
<hr>
|
<dl>
|
||||||
<h3><a href="../../test/pickle1.cpp"><tt>pickle1.cpp</tt></a></h3>
|
<dt>
|
||||||
|
<strong>Pitfall 1:</strong>
|
||||||
|
Both <tt>__getinitargs__</tt> and <tt>__getstate__</tt> are not defined.
|
||||||
|
|
||||||
The C++ class in this example can be fully restored by passing the
|
<dd>
|
||||||
appropriate argument to the constructor. Therefore it is sufficient
|
In this situation the unpickler calls the class constructor without
|
||||||
to define the pickle interface method <tt>__getinitargs__</tt>.
|
arguments and then adds the <tt>__dict__</tt> that was pickled by
|
||||||
This is done in the following way:
|
default to that of the new instance.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
However, most C++ classes wrapped with Boost.Python will have member
|
||||||
|
data that are not restored correctly by this procedure. To alert the
|
||||||
|
user to this problem, a safety guard is provided. If both
|
||||||
|
<tt>__getinitargs__</tt> and <tt>__getstate__</tt> are not defined,
|
||||||
|
Boost.Python tests if the class has an attribute
|
||||||
|
<tt>__dict_defines_state__</tt>. An exception is raised if this
|
||||||
|
attribute is not defined:
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>1. Definition of the C++ pickle function:
|
|
||||||
<pre>
|
<pre>
|
||||||
struct world_pickle_suite : boost::python::pickle_suite
|
RuntimeError: Incomplete pickle support (__dict_defines_state__ not set)
|
||||||
{
|
|
||||||
static
|
|
||||||
boost::python::tuple
|
|
||||||
getinitargs(world const& w)
|
|
||||||
{
|
|
||||||
return boost::python::make_tuple(w.get_country());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</pre>
|
</pre>
|
||||||
<li>2. Establishing the Python binding:
|
|
||||||
|
In the rare cases where this is not the desired behavior, the safety
|
||||||
|
guard can deliberately be disabled. The corresponding C++ code for
|
||||||
|
this is, e.g.:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
class_<world>("world", args<const std::string&>())
|
class_builder<your_class> py_your_class(your_module, "your_class");
|
||||||
// ...
|
py_your_class.dict_defines_state();
|
||||||
.def_pickle(world_pickle_suite())
|
|
||||||
// ...
|
|
||||||
</pre>
|
</pre>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<hr>
|
It is also possible to override the safety guard at the Python level.
|
||||||
<h3><a href="../../test/pickle2.cpp"><tt>pickle2.cpp</tt></a></h3>
|
E.g.:
|
||||||
|
|
||||||
The C++ class in this example contains member data that cannot be
|
|
||||||
restored by any of the constructors. Therefore it is necessary to
|
|
||||||
provide the <tt>__getstate__</tt>/<tt>__setstate__</tt> pair of
|
|
||||||
pickle interface methods:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>1. Definition of the C++ pickle functions:
|
|
||||||
<pre>
|
<pre>
|
||||||
struct world_pickle_suite : boost::python::pickle_suite
|
import your_bpl_module
|
||||||
{
|
class your_class(your_bpl_module.your_class):
|
||||||
static
|
__dict_defines_state__ = 1
|
||||||
boost::python::tuple
|
|
||||||
getinitargs(const world& w)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
boost::python::tuple
|
|
||||||
getstate(const world& w)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
setstate(world& w, boost::python::tuple state)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</pre>
|
</pre>
|
||||||
<li>2. Establishing the Python bindings for the entire suite:
|
|
||||||
<pre>
|
|
||||||
class_<world>("world", args<const std::string&>())
|
|
||||||
// ...
|
|
||||||
.def_pickle(world_pickle_suite())
|
|
||||||
// ...
|
|
||||||
</pre>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For simplicity, the <tt>__dict__</tt> is not included in the result
|
|
||||||
of <tt>__getstate__</tt>. This is not generally recommended, but a
|
|
||||||
valid approach if it is anticipated that the object's
|
|
||||||
<tt>__dict__</tt> will always be empty. Note that the safety guard
|
|
||||||
described below will catch the cases where this assumption is violated.
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<h3><a href="../../test/pickle3.cpp"><tt>pickle3.cpp</tt></a></h3>
|
|
||||||
|
|
||||||
This example is similar to <a
|
|
||||||
href="../../test/pickle2.cpp"><tt>pickle2.cpp</tt></a>. However, the
|
|
||||||
object's <tt>__dict__</tt> is included in the result of
|
|
||||||
<tt>__getstate__</tt>. This requires a little more code but is
|
|
||||||
unavoidable if the object's <tt>__dict__</tt> is not always empty.
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<h2>Pitfall and Safety Guard</h2>
|
|
||||||
|
|
||||||
The pickle protocol described above has an important pitfall that the
|
|
||||||
end user of a Boost.Python extension module might not be aware of:
|
|
||||||
<p>
|
|
||||||
<strong>
|
|
||||||
<tt>__getstate__</tt> is defined and the instance's <tt>__dict__</tt>
|
|
||||||
is not empty.
|
|
||||||
</strong>
|
|
||||||
<p>
|
<p>
|
||||||
|
<dt>
|
||||||
|
<strong>Pitfall 2:</strong>
|
||||||
|
<tt>__getstate__</tt> is defined and the instance's <tt>__dict__</tt> is not empty.
|
||||||
|
|
||||||
|
<dd>
|
||||||
The author of a Boost.Python extension class might provide a
|
The author of a Boost.Python extension class might provide a
|
||||||
<tt>__getstate__</tt> method without considering the possibilities
|
<tt>__getstate__</tt> method without considering the possibilities
|
||||||
that:
|
that:
|
||||||
@@ -231,20 +189,15 @@ is not empty.
|
|||||||
To resolve this problem, it should first be established that the
|
To resolve this problem, it should first be established that the
|
||||||
<tt>__getstate__</tt> and <tt>__setstate__</tt> methods manage the
|
<tt>__getstate__</tt> and <tt>__setstate__</tt> methods manage the
|
||||||
instances's <tt>__dict__</tt> correctly. Note that this can be done
|
instances's <tt>__dict__</tt> correctly. Note that this can be done
|
||||||
either at the C++ or the Python level. Finally, the safety guard
|
both at the C++ and the Python level. Finally, the safety guard
|
||||||
should intentionally be overridden. E.g. in C++ (from
|
should intentionally be overridden. E.g. in C++:
|
||||||
<a href="../../test/pickle3.cpp"><tt>pickle3.cpp</tt></a>):
|
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
struct world_pickle_suite : boost::python::pickle_suite
|
class_builder<your_class> py_your_class(your_module, "your_class");
|
||||||
{
|
py_your_class.getstate_manages_dict();
|
||||||
// ...
|
|
||||||
|
|
||||||
static bool getstate_manages_dict() { return true; }
|
|
||||||
};
|
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Alternatively in Python:
|
In Python:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
import your_bpl_module
|
import your_bpl_module
|
||||||
@@ -255,23 +208,16 @@ is not empty.
|
|||||||
def __setstate__(self, state):
|
def __setstate__(self, state):
|
||||||
# your code here
|
# your code here
|
||||||
</pre>
|
</pre>
|
||||||
|
</dl>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<h2>Practical Advice</h2>
|
<h2>Practical Advice</h2>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
|
||||||
In Boost.Python extension modules with many extension classes,
|
|
||||||
providing complete pickle support for all classes would be a
|
|
||||||
significant overhead. In general complete pickle support should
|
|
||||||
only be implemented for extension classes that will eventually
|
|
||||||
be pickled.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<li>
|
<li>
|
||||||
Avoid using <tt>__getstate__</tt> if the instance can also be
|
Avoid using <tt>__getstate__</tt> if the instance can also be
|
||||||
reconstructed by way of <tt>__getinitargs__</tt>. This automatically
|
reconstructed by way of <tt>__getinitargs__</tt>. This automatically
|
||||||
avoids the pitfall described above.
|
avoids Pitfall 2.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<li>
|
<li>
|
||||||
@@ -281,13 +227,46 @@ is not empty.
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
<h2>Examples</h2>
|
||||||
|
|
||||||
© Copyright Ralf W. Grosse-Kunstleve 20012-2002. Permission to copy,
|
There are three files in <tt>boost/libs/python/example</tt> that
|
||||||
|
show how so provide pickle support.
|
||||||
|
|
||||||
|
<h3><a href="../example/pickle1.cpp"><tt>pickle1.cpp</tt></a></h3>
|
||||||
|
|
||||||
|
The C++ class in this example can be fully restored by passing the
|
||||||
|
appropriate argument to the constructor. Therefore it is sufficient
|
||||||
|
to define the pickle interface method <tt>__getinitargs__</tt>.
|
||||||
|
|
||||||
|
<h3><a href="../example/pickle2.cpp"><tt>pickle2.cpp</tt></a></h3>
|
||||||
|
|
||||||
|
The C++ class in this example contains member data that cannot be
|
||||||
|
restored by any of the constructors. Therefore it is necessary to
|
||||||
|
provide the <tt>__getstate__</tt>/<tt>__setstate__</tt> pair of
|
||||||
|
pickle interface methods.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For simplicity, the <tt>__dict__</tt> is not included in the result
|
||||||
|
of <tt>__getstate__</tt>. This is not generally recommended, but a
|
||||||
|
valid approach if it is anticipated that the object's
|
||||||
|
<tt>__dict__</tt> will always be empty. Note that the safety guards
|
||||||
|
will catch the cases where this assumption is violated.
|
||||||
|
|
||||||
|
<h3><a href="../example/pickle3.cpp"><tt>pickle3.cpp</tt></a></h3>
|
||||||
|
|
||||||
|
This example is similar to <a
|
||||||
|
href="../example/pickle2.cpp"><tt>pickle2.cpp</tt></a>. However, the
|
||||||
|
object's <tt>__dict__</tt> is included in the result of
|
||||||
|
<tt>__getstate__</tt>. This requires more code but is unavoidable
|
||||||
|
if the object's <tt>__dict__</tt> is not always empty.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
© Copyright Ralf W. Grosse-Kunstleve 2001. Permission to copy,
|
||||||
use, modify, sell and distribute this document is granted provided this
|
use, modify, sell and distribute this document is granted provided this
|
||||||
copyright notice appears in all copies. This document is provided "as
|
copyright notice appears in all copies. This document is provided "as
|
||||||
is" without express or implied warranty, and with no claim as to its
|
is" without express or implied warranty, and with no claim as to its
|
||||||
suitability for any purpose.
|
suitability for any purpose.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Updated: Aug 2002.
|
Updated: March 21, 2001
|
||||||
</div>
|
</div>
|
||||||
148
doc/pointers.html
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<title>
|
||||||
|
Pointers
|
||||||
|
</title>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<img width="277" height="86" id="_x0000_i1025" align="center"
|
||||||
|
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Pointers
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<h2><a name="problem">The Problem With Pointers</a></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In general, raw pointers passed to or returned from functions are problematic
|
||||||
|
for Boost.Python because pointers have too many potential meanings. Is it an iterator?
|
||||||
|
A pointer to a single element? An array? When used as a return value, is the
|
||||||
|
caller expected to manage (delete) the pointed-to object or is the pointer
|
||||||
|
really just a reference? If the latter, what happens to Python references to the
|
||||||
|
referent when some C++ code deletes it?
|
||||||
|
<p>
|
||||||
|
There are a few cases in which pointers are converted automatically:
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>Both const- and non-const pointers to wrapped class instances can be passed
|
||||||
|
<i>to</i> C++ functions.
|
||||||
|
|
||||||
|
<li>Values of type <code>const char*</code> are interpreted as
|
||||||
|
null-terminated 'C' strings and when passed to or returned from C++ functions are
|
||||||
|
converted from/to Python strings.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Can you avoid the problem?</h3>
|
||||||
|
|
||||||
|
<p>My first piece of advice to anyone with a case not covered above is
|
||||||
|
``find a way to avoid the problem.'' For example, if you have just one
|
||||||
|
or two functions that return a pointer to an individual <code>const
|
||||||
|
T</code>, and <code>T</code> is a wrapped class, you may be able to write a ``thin
|
||||||
|
converting wrapper'' over those two functions as follows:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
const Foo* f(); // original function
|
||||||
|
const Foo& f_wrapper() { return *f(); }
|
||||||
|
...
|
||||||
|
my_module.def(f_wrapper, "f");
|
||||||
|
</pre></blockquote>
|
||||||
|
<p>
|
||||||
|
Foo must have a public copy constructor for this technique to work, since Boost.Python
|
||||||
|
converts <code>const T&</code> values <code>to_python</code> by copying the <code>T</code>
|
||||||
|
value into a new extension instance.
|
||||||
|
|
||||||
|
<h2>Dealing with the problem</h2>
|
||||||
|
|
||||||
|
<p>The first step in handling the remaining cases is to figure out what the pointer
|
||||||
|
means. Several potential solutions are provided in the examples that follow:
|
||||||
|
|
||||||
|
<h3>Returning a pointer to a wrapped type</h3>
|
||||||
|
|
||||||
|
<h4>Returning a const pointer</h4>
|
||||||
|
|
||||||
|
<p>If you have lots of functions returning a <code>const T*</code> for some
|
||||||
|
wrapped <code>T</code>, you may want to provide an automatic
|
||||||
|
<code>to_python</code> conversion function so you don't have to write lots of
|
||||||
|
thin wrappers. You can do this simply as follows:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
|
||||||
|
PyObject* to_python(const Foo* p) {
|
||||||
|
return to_python(*p); // convert const Foo* in terms of const Foo&
|
||||||
|
}
|
||||||
|
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<h4>If you can't (afford to) copy the referent, or the pointer is non-const</h4>
|
||||||
|
|
||||||
|
<p>If the wrapped type doesn't have a public copy constructor, if copying is
|
||||||
|
<i>extremely</i> costly (remember, we're dealing with Python here), or if the
|
||||||
|
pointer is non-const and you really need to be able to modify the referent from
|
||||||
|
Python, you can use the following dangerous trick. Why dangerous? Because python
|
||||||
|
can not control the lifetime of the referent, so it may be destroyed by your C++
|
||||||
|
code before the last Python reference to it disappears:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
|
||||||
|
PyObject* to_python(Foo* p)
|
||||||
|
{
|
||||||
|
return boost::python::python_extension_class_converters<Foo>::smart_ptr_to_python(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* to_python(const Foo* p)
|
||||||
|
{
|
||||||
|
return to_python(const_cast<Foo*>(p));
|
||||||
|
}
|
||||||
|
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
This will cause the Foo* to be treated as though it were an owning smart
|
||||||
|
pointer, even though it's not. Be sure you don't use the reference for anything
|
||||||
|
from Python once the pointer becomes invalid, though. Don't worry too much about
|
||||||
|
the <code>const_cast<></code> above: Const-correctness is completely lost
|
||||||
|
to Python anyway!
|
||||||
|
|
||||||
|
<h3>[In/]Out Parameters and Immutable Types</h3>
|
||||||
|
|
||||||
|
<p>If you have an interface that uses non-const pointers (or references) as
|
||||||
|
in/out parameters to types which in Python are immutable (e.g. int, string),
|
||||||
|
there simply is <i>no way</i> to get the same interface in Python. You must
|
||||||
|
resort to transforming your interface with simple thin wrappers as shown below:
|
||||||
|
<blockquote><pre>
|
||||||
|
const void f(int* in_out_x); // original function
|
||||||
|
const int f_wrapper(int in_x) { f(in_x); return in_x; }
|
||||||
|
...
|
||||||
|
my_module.def(f_wrapper, "f");
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>Of course, [in/]out parameters commonly occur only when there is already a
|
||||||
|
return value. You can handle this case by returning a Python tuple:
|
||||||
|
<blockquote><pre>
|
||||||
|
typedef unsigned ErrorCode;
|
||||||
|
const char* f(int* in_out_x); // original function
|
||||||
|
...
|
||||||
|
#include <boost/python/objects.hpp>
|
||||||
|
const boost::python::tuple f_wrapper(int in_x) {
|
||||||
|
const char* s = f(in_x);
|
||||||
|
return boost::python::tuple(s, in_x);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
my_module.def(f_wrapper, "f");
|
||||||
|
</pre></blockquote>
|
||||||
|
<p>Now, in Python:
|
||||||
|
<blockquote><pre>
|
||||||
|
>>> str,out_x = f(3)
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Previous: <a href="enums.html">Enums</a>
|
||||||
|
Up: <a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2000. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Nov 26, 2000
|
||||||
|
</div>
|
||||||
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
How Runtime Polymorphism is expressed in Boost.Python:
|
|
||||||
-----------------------------------------------------
|
|
||||||
|
|
||||||
struct A { virtual std::string f(); virtual ~A(); };
|
|
||||||
|
|
||||||
std::string call_f(A& x) { return x.f(); }
|
|
||||||
|
|
||||||
struct B { virtual std::string f() { return "B"; } };
|
|
||||||
|
|
||||||
struct Bcb : B
|
|
||||||
{
|
|
||||||
Bcb(PyObject* self) : m_self(self) {}
|
|
||||||
|
|
||||||
virtual std::string f() { return call_method<std::string>(m_sef, "f"); }
|
|
||||||
static std::string f_default(B& b) { return b.B::f(); }
|
|
||||||
|
|
||||||
PyObject* m_self;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct C : B
|
|
||||||
{
|
|
||||||
virtual std::string f() { return "C"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
>>> class D(B):
|
|
||||||
... def f():
|
|
||||||
... return 'D'
|
|
||||||
...
|
|
||||||
>>> class E(B): pass
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
When we write, "invokes B::f non-virtually", we mean:
|
|
||||||
|
|
||||||
void g(B& x) { x.B::f(); }
|
|
||||||
|
|
||||||
This will call B::f() regardless of the dynamic type of x. Any other
|
|
||||||
way of invoking B::f, including through a function pointer, is a
|
|
||||||
"virtual invocation", and will call the most-derived override of f().
|
|
||||||
|
|
||||||
Case studies
|
|
||||||
|
|
||||||
C++\Python class
|
|
||||||
\___A_____B_____C_____D____E___
|
|
||||||
|
|
|
||||||
A | 1
|
|
||||||
|
|
|
||||||
B | 2 3
|
|
||||||
|
|
|
||||||
Bcb | 4 5 6
|
|
||||||
|
|
|
||||||
C | 7 8
|
|
||||||
|
|
|
||||||
|
|
||||||
|
|
||||||
1. Simple case
|
|
||||||
|
|
||||||
2. Python A holds a B*. Probably won't happen once we have forced
|
|
||||||
downcasting.
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
x.f() -> 'B'
|
|
||||||
call_f(x) -> 'B'
|
|
||||||
|
|
||||||
Implies: A.f invokes A::f() (virtually or otherwise)
|
|
||||||
|
|
||||||
3. Python B holds a B*.
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
x.f() -> 'B'
|
|
||||||
call_f(x) -> 'B'
|
|
||||||
|
|
||||||
Implies: B.f invokes B::f (virtually or otherwise)
|
|
||||||
|
|
||||||
|
|
||||||
4. B constructed from Python
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
|
|
||||||
x.f() -> 'B'
|
|
||||||
call_f(x) -> 'B'
|
|
||||||
|
|
||||||
Implies: B.f invokes B::f non-virtually. Bcb::f invokes B::f
|
|
||||||
non-virtually.
|
|
||||||
|
|
||||||
Question: Does it help if we arrange for Python B construction to
|
|
||||||
build a true B object? Then this case doesn't arise.
|
|
||||||
|
|
||||||
|
|
||||||
5. D is a Python class derived from B
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
|
|
||||||
x.f() -> 'D'
|
|
||||||
call_f(x) -> 'D'
|
|
||||||
|
|
||||||
Implies: Bcb::f must invoke call_method to look up the Python
|
|
||||||
method override, otherwise call_f wouldn't work.
|
|
||||||
|
|
||||||
6. E is like D, but doesn't override f
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
|
|
||||||
x.f() -> 'B'
|
|
||||||
call_f(x) -> 'B'
|
|
||||||
|
|
||||||
Implies: B.f invokes B::f non-virtually. If it were virtual, x.f()
|
|
||||||
would cause infinite recursion, because we've already
|
|
||||||
determined that Bcb::f must invoke call_method to look up
|
|
||||||
the Python method override.
|
|
||||||
|
|
||||||
7. Python B object holds a C*
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
|
|
||||||
x.f() -> 'C'
|
|
||||||
call_f(x) -> 'C'
|
|
||||||
|
|
||||||
Implies: B.f invokes B::f virtually.
|
|
||||||
|
|
||||||
8. C object constructed from Python
|
|
||||||
|
|
||||||
Requires:
|
|
||||||
|
|
||||||
x.f() -> 'C'
|
|
||||||
call_f(x) -> 'C'
|
|
||||||
|
|
||||||
Implies: nothing new.
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
Total implications:
|
|
||||||
|
|
||||||
2: A.f invokes A::f() (virtually or otherwise)
|
|
||||||
3: B.f invokes B::f (virtually or otherwise)
|
|
||||||
4: B.f invokes B::f non-virtually. Bcb::f invokes B::f non-virtually
|
|
||||||
6: B.f invokes B::f non-virtually.
|
|
||||||
7: B.f invokes B::f virtually.
|
|
||||||
|
|
||||||
5: Bcb::f invokes call_method to look up the Python method
|
|
||||||
|
|
||||||
Though (4) is avoidable, clearly 6 and 7 are not, and they
|
|
||||||
conflict. The implication is that B.f must choose its behavior
|
|
||||||
according to the type of the contained C++ object. If it is Bcb, a
|
|
||||||
non-virtual call to B::f must occur. Otherwise, a virtual call to B::f
|
|
||||||
must occur. This is essentially the same scheme we had with
|
|
||||||
Boost.Python v1.
|
|
||||||
|
|
||||||
Note: in early versions of Boost.Python v1, we solved this problem by
|
|
||||||
introducing a new Python class in the hierarchy, so that D and E
|
|
||||||
actually derive from a B', and B'.f invokes B::f non-virtually, while
|
|
||||||
B.f invokes B::f virtually. However, people complained about the
|
|
||||||
artificial class in the hierarchy, which was revealed when they tried
|
|
||||||
to do normal kinds of Python introspection.
|
|
||||||
|
|
||||||
-------
|
|
||||||
|
|
||||||
Assumption: we will have a function which builds a virtual function
|
|
||||||
dispatch callable Python object.
|
|
||||||
|
|
||||||
make_virtual_function(pvmf, default_impl, call_policies, dispatch_type)
|
|
||||||
|
|
||||||
Pseudocode:
|
|
||||||
|
|
||||||
Get first argument from Python arg tuple
|
|
||||||
if it contains dispatch_type
|
|
||||||
call default_impl
|
|
||||||
else
|
|
||||||
call through pvmf
|
|
||||||
|
|
||||||
|
|
||||||
Open questions:
|
|
||||||
|
|
||||||
1. What about Python multiple inheritance? Do we have the right
|
|
||||||
check in the if clause above?
|
|
||||||
|
|
||||||
A: Not quite. The correct test looks like:
|
|
||||||
|
|
||||||
Deduce target type of pvmf, i.e. T in R(T::*)(A1...AN).
|
|
||||||
Find holder in first argument which holds T
|
|
||||||
if it holds dispatch_type...
|
|
||||||
|
|
||||||
2. Can we make this more efficient?
|
|
||||||
|
|
||||||
The current "returning" mechanism will look up a holder for T
|
|
||||||
again. I don't know if we know how to avoid that.
|
|
||||||
|
|
||||||
|
|
||||||
OK, the solution involves reworking the call mechanism. This is
|
|
||||||
neccesary anyway in order to enable wrapping of function objects.
|
|
||||||
|
|
||||||
It can result in a reduction in the overall amount of source code,
|
|
||||||
because returning<> won't need to be specialized for every
|
|
||||||
combination of function and member function... though it will still
|
|
||||||
need a void specialization. We will still need a way to dispatch to
|
|
||||||
member functions through a regular function interface. mem_fn is
|
|
||||||
almost the right tool, but it only goes up to 8
|
|
||||||
arguments. Forwarding is tricky if you don't want to incur copies.
|
|
||||||
I think the trick is to use arg_from_python<T>::result_type for each
|
|
||||||
argument to the forwarder.
|
|
||||||
|
|
||||||
Another option would be to use separate function, function object,
|
|
||||||
and member function dispatchers. Once you know you have a member
|
|
||||||
function, you don't need cv-qualified overloads to call it.
|
|
||||||
|
|
||||||
Hmm, while we're at this, maybe we should solve the write-back
|
|
||||||
converter problem. Can we do it? Maybe not. Ralf doesn't want to
|
|
||||||
write special write-back functions here, does he? He wants the
|
|
||||||
converter to do the work automatically. We could add
|
|
||||||
cleanup/destructor registration. That would relieve the client from
|
|
||||||
having accessible destructors for types which are being converted by
|
|
||||||
rvalue. I'm not sure that this will really save any code,
|
|
||||||
however. It rather depends on the linker, doesn't it? I wonder if
|
|
||||||
this can be done in a backwards-compatible fashion by generating the
|
|
||||||
delete function when it's not supplied?
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="generator" content=
|
|
||||||
"HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="boost.css">
|
|
||||||
|
|
||||||
<title>Boost.Python - Projects using Boost.Python</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body link="#0000ff" vlink="#800080">
|
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
|
||||||
"header">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><a href="../../../index.htm"><img height="86" width="277" alt=
|
|
||||||
"C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center"><a href="index.html">Boost.Python</a></h1>
|
|
||||||
|
|
||||||
<h2 align="center">Projects using Boost.Python</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Introduction</h2>
|
|
||||||
|
|
||||||
<p>This is a partial list of projects using Boost.Python. If you are
|
|
||||||
using Boost.Python as your Python/C++ binding solution, we'd be proud to
|
|
||||||
list your project on this page. Just <a href=
|
|
||||||
"mailto:c++-sig@python.org">post</a> a short description of your project
|
|
||||||
and how Boost.Python helps you get the job done, and we'll add it to this
|
|
||||||
page .</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h3>Enterprise Software</h3>
|
|
||||||
|
|
||||||
<dl class="page-index">
|
|
||||||
<dt><b><a href="http://openwbem.sourceforge.net">OpenWBEM</a></b></dt>
|
|
||||||
|
|
||||||
<dd>
|
|
||||||
The OpenWBEM project is an effort to develop an open-source
|
|
||||||
implementation of Web Based Enterprise Management suitable for
|
|
||||||
commercial and non-commercial application
|
|
||||||
|
|
||||||
<p><a href="mailto:dnuffer@sco.com">Dan Nuffer</a> writes:</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
I'm using Boost.Python to wrap the client API of OpenWBEM.This will
|
|
||||||
make it easier to do rapid prototyping, testing, and scripting when
|
|
||||||
developing management solutions that use WBEM.
|
|
||||||
</blockquote>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<h3>Financial Analysis</h3>
|
|
||||||
|
|
||||||
<dl class="page-index">
|
|
||||||
<dt><b>TSLib</b> - <a href="http://www.fortressinv.com">Fortress
|
|
||||||
Investment Group LLC</a></dt>
|
|
||||||
|
|
||||||
<dd>
|
|
||||||
Fortress Investment Group has contracted <a href=
|
|
||||||
"http://www.boost-consulting.com">Boost Consulting</a> to develop
|
|
||||||
core internal financial analysis tools in C++ and to prepare Python
|
|
||||||
bindings for them using Boost.Python.
|
|
||||||
|
|
||||||
<p>Tom Barket of Fortress writes:</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
We have a large C++ analytical library specialized for research in
|
|
||||||
finance and economics, built for speed and mission critical
|
|
||||||
stability. Yet Python offers us the flexibility to test out new
|
|
||||||
ideas quickly and increase the productivity of our time versus
|
|
||||||
working in C++. There are several key features which make Python
|
|
||||||
stand out. Its elegance, stability, and breadth of resources on the
|
|
||||||
web are all valuable, but the most important is its extensibility,
|
|
||||||
due to its open source transparency. Boost.Python makes Python
|
|
||||||
extensibility extremely simple and straightforward, yet preserves a
|
|
||||||
great deal of power and control.
|
|
||||||
</blockquote>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<h3>Graphics</h3>
|
|
||||||
|
|
||||||
<dl class="page-index">
|
|
||||||
<dt><b><a href=
|
|
||||||
"http://www.openscenegraph.org">OpenSceneGraph</a></b></dt>
|
|
||||||
|
|
||||||
<dd><a href="mailto:gideon@computer.org">Gideon May</a> has created a
|
|
||||||
set of bindings for OpenSceneGraph, a cross-platform C++/OpenGL library
|
|
||||||
for the real-time visualization. You can read the release announcement
|
|
||||||
at <a href="http://www.hypereyes.com">www.hypereyes.com</a>. <a href=
|
|
||||||
"mailto:gideon@computer.org">Contact Gideon</a> for more
|
|
||||||
information.<br>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt><a href=
|
|
||||||
"http://pythonmagick.procoders.net/"><b>PythonMagick</b></a></dt>
|
|
||||||
|
|
||||||
<dd>PythonMagick binds the <a href=
|
|
||||||
"http://www.imagemagick.org">ImageMagick</a> image manipulation library
|
|
||||||
to Python.<br>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt><b><a href=
|
|
||||||
"http://www.slac.stanford.edu/grp/ek/hippodraw/index.html">HippoDraw</a></b></dt>
|
|
||||||
|
|
||||||
<dd>
|
|
||||||
HippoDraw is a data analysis environment consisting of a canvas upon
|
|
||||||
which graphs such as histograms, scattter plots, etc, are prsented.
|
|
||||||
It has a highly interactive GUI interface, but some things you need
|
|
||||||
to do with scripts. HippoDraw can be run as Python extension module
|
|
||||||
so that all the manipulation can be done from either Python or the
|
|
||||||
GUI.
|
|
||||||
|
|
||||||
<p>Before the web page came online, <a
|
|
||||||
href="mailto:Paul_Kunz@SLAC.Stanford.EDU">Paul F. Kunz</a>
|
|
||||||
wrote:</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
Don't have a web page for the project, but the organization's is <a
|
|
||||||
href=
|
|
||||||
"http://www.slac.stanford.edu">http://www.slac.stanford.edu</a>
|
|
||||||
(the first web server site in America, I installed it).
|
|
||||||
</blockquote>
|
|
||||||
Which was just too cool a piece of trivia to omit.<br>
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<h3>Scientific Computing</h3>
|
|
||||||
|
|
||||||
<dl class="page index">
|
|
||||||
<dt><a href="http://camfr.sourceforge.net"><b>CAMFR</b></a></dt>
|
|
||||||
|
|
||||||
<dd>
|
|
||||||
CAMFR is a photonics and electromagnetics modelling tool. Python is
|
|
||||||
used for computational steering.
|
|
||||||
|
|
||||||
<p><a href="mailto:Peter.Bienstman@rug.ac.be">Peter Bienstman</a>
|
|
||||||
writes:</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
Thanks for providing such a great tool!
|
|
||||||
</blockquote>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt><a href="http://cctbx.sourceforge.net"><b>cctbx - Computational
|
|
||||||
Crystallography Toolbox</b></a></dt>
|
|
||||||
|
|
||||||
<dd>
|
|
||||||
Computational Crystallography is concerned with the derivation of
|
|
||||||
atomic models of crystal structures, given experimental X-ray
|
|
||||||
diffraction data. The cctbx is an open-source library of fundamental
|
|
||||||
algorithms for crystallographic computations. The core algorithms are
|
|
||||||
implemented in C++ and accessed through higher-level Python
|
|
||||||
interfaces.
|
|
||||||
|
|
||||||
<p>The cctbx grew together with Boost.Python and is designed from the
|
|
||||||
ground up as a hybrid Python/C++ system. With one minor exception,
|
|
||||||
run-time polymorphism is completely handled by Python. C++
|
|
||||||
compile-time polymorphism is used to implement performance critical
|
|
||||||
algorithms. The Python and C++ layers are seamlessly integrated using
|
|
||||||
Boost.Python.</p>
|
|
||||||
|
|
||||||
<p>The SourceForge cctbx project is organized in modules to
|
|
||||||
facilitate use in non-crystallographic applications. The scitbx
|
|
||||||
module implements a general purpose array family for scientific
|
|
||||||
applications and pure C++ ports of FFTPACK and the LBFGS conjugate
|
|
||||||
gradient minimizer.</p>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt><a href="http://www.llnl.gov/CASC/emsolve"><b>EMSolve</b></a></dt>
|
|
||||||
|
|
||||||
<dd>EMSolve is a provably stable, charge conserving, and energy
|
|
||||||
conserving solver for Maxwell's equations.<br>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt><b><a href="http://cern.ch/gaudi">Gaudi</a></b> and <b><a href=
|
|
||||||
"http://cern.ch/Gaudi/RootPython/">RootPython</a></b></dt>
|
|
||||||
|
|
||||||
<dd>
|
|
||||||
Gaudi is a framework for particle physics collision data processing
|
|
||||||
applications developed in the context of the LHCb and ATLAS
|
|
||||||
experiments at CERN.
|
|
||||||
|
|
||||||
<p><a href="mailto:Pere.Mato@cern.ch">Pere Mato Vila</a> writes:</p>
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
We are using Boost.Python to provide scripting/interactive
|
|
||||||
capability to our framework. We have a module called "GaudiPython"
|
|
||||||
implemented using Boost.Python that allows the interaction with any
|
|
||||||
framework service or algorithm from python. RootPython also uses
|
|
||||||
Boost.Python to provide a generic "gateway" between the <a href=
|
|
||||||
"http://root.cern.ch">ROOT</a> framework and python
|
|
||||||
|
|
||||||
<p>Boost.Python is great. We managed very quickly to interface our
|
|
||||||
framework to python, which is great language. We are trying to
|
|
||||||
facilitate to our physicists (end-users) a rapid analysis
|
|
||||||
application development environment based on python. For that,
|
|
||||||
Boost.Python plays and essential role.</p>
|
|
||||||
</blockquote>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
|
||||||
22 March, 2003
|
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="../../../people/dave_abrahams.htm">Dave
|
|
||||||
Abrahams</a> 2002-2003. All Rights Reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
106
doc/richcmp.html
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
||||||
|
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
|
||||||
|
<title>Rich Comparisons</title>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<img src="../../../c++boost.gif"
|
||||||
|
alt="c++boost.gif (8819 bytes)"
|
||||||
|
align="center"
|
||||||
|
width="277" height="86">
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h1>Rich Comparisons</h1>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
In Python versions up to and including Python 2.0, support for
|
||||||
|
implementing comparisons on user-defined classes and extension types
|
||||||
|
was quite simple. Classes could implement a <tt>__cmp__</tt> method
|
||||||
|
that was given two instances of a class as arguments, and could only
|
||||||
|
return <tt>0</tt> if they were equal or <tt>+1</tt> or <tt>-1</tt> if
|
||||||
|
they were not. The method could not raise an exception or return
|
||||||
|
anything other than an integer value.
|
||||||
|
In Python 2.1, <b>Rich Comparisons</b> were added (see
|
||||||
|
<a href="http://python.sourceforge.net/peps/pep-0207.html">PEP 207</a>).
|
||||||
|
Python classes can now individually overload each of the <, <=,
|
||||||
|
>, >=, ==, and != operations.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For more detailed information, search for "rich comparison"
|
||||||
|
<a href="http://www.python.org/doc/current/ref/customization.html"
|
||||||
|
>here</a>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Boost.Python supports both automatic overloading and manual overloading
|
||||||
|
of the Rich Comparison operators. The <b>compile-time</b> support is
|
||||||
|
independent of the Python version that is used when compiling
|
||||||
|
Boost.Python extension modules. That is, <tt>op_lt</tt> for example can
|
||||||
|
always be used, and the C++ <tt>operator<</tt> will always be bound
|
||||||
|
to the Python method <tt>__lt__</tt>. However, the <b>run-time</b>
|
||||||
|
behavior will depend on the Python version.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
With Python versions before 2.1, the Rich Comparison operators will not
|
||||||
|
be called by Python when any of the six comparison operators
|
||||||
|
(<tt><</tt>, <tt><=</tt>, <tt>==</tt>, <tt>!=</tt>,
|
||||||
|
<tt>></tt>, <tt>>=</tt>) is used in an expression. The only way
|
||||||
|
to access the corresponding methods is to call them explicitly, e.g.
|
||||||
|
<tt>a.__lt__(b)</tt>. Only with Python versions 2.1 or higher will
|
||||||
|
expressions like <tt>a < b</tt> work as expected.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To support Rich Comparisions, the Python C API was modified between
|
||||||
|
Python versions 2.0 and 2.1. A new slot was introduced in the
|
||||||
|
<tt>PyTypeObject</tt> structure: <tt>tp_richcompare</tt>. For backwards
|
||||||
|
compatibility, a flag (<tt>Py_TPFLAGS_HAVE_RICHCOMPARE</tt>) has to be
|
||||||
|
set to signal to the Python interpreter that Rich Comparisions are
|
||||||
|
supported by a particular type.
|
||||||
|
There is only one flag for all the six comparison operators.
|
||||||
|
When any of the six operators is wrapped automatically or
|
||||||
|
manually, Boost.Python will set this flag. Attempts to use comparison
|
||||||
|
operators at the Python level that are not defined at the C++ level
|
||||||
|
will then lead to an <tt>AttributeError</tt> when the Python 2.1
|
||||||
|
(or higher) interpreter tries, e.g., <tt>a.__lt__(b)</tt>. That
|
||||||
|
is, in general all six operators should be supplied. Automatically
|
||||||
|
wrapped operators and manually wrapped operators can be mixed. For
|
||||||
|
example:<pre>
|
||||||
|
boost::python::class_builder<code> py_code(this_module, "code");
|
||||||
|
|
||||||
|
py_code.def(boost::python::constructor<>());
|
||||||
|
py_code.def(boost::python::constructor<int>());
|
||||||
|
py_code.def(boost::python::operators<( boost::python::op_eq
|
||||||
|
| boost::python::op_ne)>());
|
||||||
|
py_code.def(NotImplemented, "__lt__");
|
||||||
|
py_code.def(NotImplemented, "__le__");
|
||||||
|
py_code.def(NotImplemented, "__gt__");
|
||||||
|
py_code.def(NotImplemented, "__ge__");
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<tt>NotImplemented</tt> is a simple free function that (currently) has
|
||||||
|
to be provided by the user. For example:<pre>
|
||||||
|
boost::python::ref
|
||||||
|
NotImplemented(const code&, const code&) {
|
||||||
|
return
|
||||||
|
boost::python::ref(Py_NotImplemented, boost::python::ref::increment_count);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
See also:
|
||||||
|
<ul>
|
||||||
|
<li><a href="../example/richcmp1.cpp"><tt>../example/richcmp1.cpp</tt></a>
|
||||||
|
<li><a href="../example/richcmp2.cpp"><tt>../example/richcmp2.cpp</tt></a>
|
||||||
|
<li><a href="../example/richcmp3.cpp"><tt>../example/richcmp3.cpp</tt></a>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
© Copyright Nicholas K. Sauter & Ralf W. Grosse-Kunstleve 2001.
|
||||||
|
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.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Updated: July 2001
|
||||||
|
|
||||||
|
</div>
|
||||||
944
doc/special.html
Normal file
@@ -0,0 +1,944 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<title>
|
||||||
|
Special Method and Operator Support
|
||||||
|
</title>
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<img width="277" height="86" id="_x0000_i1025" align="middle" src=
|
||||||
|
"../../../c++boost.gif" alt="c++boost.gif (8819 bytes)">Special Method and
|
||||||
|
Operator Support
|
||||||
|
</h1>
|
||||||
|
<h2>
|
||||||
|
Overview
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Boost.Python supports all of the standard <a href=
|
||||||
|
"http://www.python.org/doc/current/ref/specialnames.html">
|
||||||
|
special method names</a> supported by real Python class instances <em>
|
||||||
|
except</em> <code>__complex__</code> (more on the reasons <a href=
|
||||||
|
"#reasons">below</a>). In addition, it can quickly and easily expose
|
||||||
|
suitable C++ functions and operators as Python operators. The following
|
||||||
|
categories of special method names are supported:
|
||||||
|
<ul>
|
||||||
|
<li><a href="#general">Basic Customization</a>
|
||||||
|
<li><a href="#numeric">Numeric Operators</a>
|
||||||
|
<li><a href="#sequence_and_mapping">Sequence and Mapping protocols</a>
|
||||||
|
<li><a href="#getter_setter">Attribute Getters and Setters</a>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="general">Basic Customization</a></h2>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Python provides a number of special operators for basic customization of a
|
||||||
|
class. Only a brief description is provided below; more complete
|
||||||
|
documentation can be found <a
|
||||||
|
href="http://www.python.org/doc/current/ref/customization.html">here</a>.
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__init__</tt></b>(<i>self</i>)
|
||||||
|
<dd>
|
||||||
|
Initialize the class instance. For extension classes not subclassed in
|
||||||
|
Python, <code> __init__</code> is defined by
|
||||||
|
|
||||||
|
<pre> my_class.def(boost::python::constructor<...>())</pre>
|
||||||
|
|
||||||
|
(see section <a href="example1.html">"A Simple Example Using Boost.Python"</a>).<p>
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__del__</tt></b>(<i>self</i>)
|
||||||
|
<dd>
|
||||||
|
Called when the extension instance is about to be destroyed. For extension classes
|
||||||
|
not subclassed in Python, <code> __del__</code> is always defined automatically by
|
||||||
|
means of the class' destructor.
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__repr__</tt></b>(<i>self</i>)
|
||||||
|
<dd>
|
||||||
|
Create a string representation from which the object can be
|
||||||
|
reconstructed.
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__str__</tt></b>(<i>self</i>)
|
||||||
|
<dd>
|
||||||
|
Create a string representation which is suitable for printing.
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__lt__</tt></b>(<i>self, other</i>)
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__le__</tt></b>(<i>self, other</i>)
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__eq__</tt></b>(<i>self, other</i>)
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__ne__</tt></b>(<i>self, other</i>)
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__gt__</tt></b>(<i>self, other</i>)
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__ge__</tt></b>(<i>self, other</i>)
|
||||||
|
<dd>
|
||||||
|
Rich Comparison methods.
|
||||||
|
New in Python 2.1.
|
||||||
|
See <a href="richcmp.html">Rich Comparisons</a>.
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__cmp__</tt></b>(<i>self, other</i>)
|
||||||
|
<dd>
|
||||||
|
Three-way compare function.
|
||||||
|
See <a href="richcmp.html">Rich Comparisons</a>.
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__hash__</tt></b>(<i>self</i>)
|
||||||
|
<dd>
|
||||||
|
Called for the key object for dictionary operations, and by the
|
||||||
|
built-in function hash(). Should return a 32-bit integer usable as a
|
||||||
|
hash value for dictionary operations (only allowed if __cmp__ is also
|
||||||
|
defined)
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__nonzero__</tt></b>(<i>self</i>)
|
||||||
|
<dd>
|
||||||
|
called if the object is used as a truth value (e.g. in an if
|
||||||
|
statement)
|
||||||
|
<dt>
|
||||||
|
<b><tt class='method'>__call__</tt></b> (<var>self</var><big>[</big><var>, args...</var><big>]</big>)
|
||||||
|
<dd>
|
||||||
|
Called when the instance is ``called'' as a function; if this method
|
||||||
|
is defined, <code><var>x</var>(arg1, arg2, ...)</code> is a shorthand for
|
||||||
|
<code><var>x</var>.__call__(arg1, arg2, ...)</code>.
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
If we have a suitable C++ function that supports any of these features,
|
||||||
|
we can export it like any other function, using its Python special name.
|
||||||
|
For example, suppose that class <code>Foo</code> provides a string
|
||||||
|
conversion function:
|
||||||
|
<blockquote><pre>
|
||||||
|
std::string to_string(Foo const& f)
|
||||||
|
{
|
||||||
|
std::ostringstream s;
|
||||||
|
s << f;
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
</pre></blockquote>
|
||||||
|
This function would be wrapped like this:
|
||||||
|
<blockquote><pre>
|
||||||
|
boost::python::class_builder<Foo> foo_class(my_module, "Foo");
|
||||||
|
foo_class.def(&to_string, "__str__");
|
||||||
|
</pre></blockquote>
|
||||||
|
Note that Boost.Python also supports <em>automatic wrapping</em> of
|
||||||
|
<code>__str__</code> and <code>__cmp__</code>. This is explained in the <a
|
||||||
|
href="#numeric">next section</a> and the <a href="#numeric_table">Table of
|
||||||
|
Automatically Wrapped Methods</a>.
|
||||||
|
|
||||||
|
<h2><a name="numeric">Numeric Operators</a></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Numeric operators can be exposed manually, by <code>def</code>ing C++
|
||||||
|
[member] functions that support the standard Python <a
|
||||||
|
href="http://www.python.org/doc/current/ref/numeric-types.html">numeric
|
||||||
|
protocols</a>. This is the same basic technique used to expose
|
||||||
|
<code>to_string()</code> as <code>__str__()</code> above, and is <a
|
||||||
|
href="#numeric_manual">covered in detail below</a>. Boost.Python also supports
|
||||||
|
<i>automatic wrapping</i> of numeric operators whenever they have already
|
||||||
|
been defined in C++.
|
||||||
|
|
||||||
|
<h3><a name="numeric_auto">Exposing C++ Operators Automatically</a></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Supose we wanted to expose a C++ class
|
||||||
|
<code>BigNum</code> which supports addition. That is, in C++ we can write:
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum a, b, c;
|
||||||
|
...
|
||||||
|
c = a + b;
|
||||||
|
</pre></blockquote>
|
||||||
|
<p>
|
||||||
|
To enable the same functionality in Python, we first wrap the <code>
|
||||||
|
BigNum</code> class as usual:
|
||||||
|
<blockquote><pre>
|
||||||
|
boost::python::class_builder<BigNum> bignum_class(my_module, "BigNum");
|
||||||
|
bignum_class.def(boost::python::constructor<>());
|
||||||
|
...
|
||||||
|
</pre></blockquote>
|
||||||
|
Then we export the addition operator like this:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
bignum_class.def(boost::python::operators<boost::python::op_add>());
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
Since BigNum also supports subtraction, multiplication, and division, we
|
||||||
|
want to export those also. This can be done in a single command by
|
||||||
|
``or''ing the operator identifiers together (a complete list of these
|
||||||
|
identifiers and the corresponding operators can be found in the <a href=
|
||||||
|
"#numeric_table">Table of Automatically Wrapped Methods</a>):
|
||||||
|
<blockquote><pre>
|
||||||
|
bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>());
|
||||||
|
</pre></blockquote>
|
||||||
|
[Note that the or-expression must be enclosed in parentheses.]
|
||||||
|
|
||||||
|
<p>This form of operator definition can be used to wrap unary and
|
||||||
|
homogeneous binary operators (a <i>homogeneous</i> operator has left and
|
||||||
|
right operands of the same type). Now suppose that our C++ library also
|
||||||
|
supports addition of BigNums and plain integers:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum a, b;
|
||||||
|
int i;
|
||||||
|
...
|
||||||
|
a = b + i;
|
||||||
|
a = i + b;
|
||||||
|
</pre></blockquote>
|
||||||
|
To wrap these heterogeneous operators, we need to specify a different type for
|
||||||
|
one of the operands. This is done using the <code>right_operand</code>
|
||||||
|
and <code>left_operand</code> templates:
|
||||||
|
<blockquote><pre>
|
||||||
|
bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::right_operand<int>());
|
||||||
|
bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::left_operand<int>());
|
||||||
|
</pre></blockquote>
|
||||||
|
Boost.Python uses overloading to register several variants of the same
|
||||||
|
operation (more on this in the context of <a href="#coercion">
|
||||||
|
coercion</a>). Again, several operators can be exported at once:
|
||||||
|
<blockquote><pre>
|
||||||
|
bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>(),
|
||||||
|
boost::python::right_operand<int>());
|
||||||
|
bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>(),
|
||||||
|
boost::python::left_operand<int>());
|
||||||
|
</pre></blockquote>
|
||||||
|
The type of the operand not mentioned is taken from the class being wrapped. In
|
||||||
|
our example, the class object is <code>bignum_class</code>, and thus the
|
||||||
|
other operand's type is ``<code>BigNum const&</code>''. You can override
|
||||||
|
this default by explicitly specifying a type in the <code>
|
||||||
|
operators</code> template:
|
||||||
|
<blockquote><pre>
|
||||||
|
bignum_class.def(boost::python::operators<boost::python::op_add, BigNum>(), boost::python::right_operand<int>());
|
||||||
|
</pre></blockquote>
|
||||||
|
<p>
|
||||||
|
Note that automatic wrapping uses the <em>expression</em>
|
||||||
|
``<code>left + right</code>'' and can be used uniformly
|
||||||
|
regardless of whether the C++ operators are supplied as free functions
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum operator+(BigNum, BigNum)
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
or as member functions
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum::operator+(BigNum).
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For the Python built-in functions <code>pow()</code> and
|
||||||
|
<code>abs()</code>, there is no corresponding C++ operator. Instead,
|
||||||
|
automatic wrapping attempts to wrap C++ functions of the same name. This
|
||||||
|
only works if those functions are known in namespace
|
||||||
|
<code>python</code>. On some compilers (e.g. MSVC) it might be
|
||||||
|
necessary to add a using declaration prior to wrapping:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
namespace boost { namespace python {
|
||||||
|
using my_namespace::pow;
|
||||||
|
using my_namespace::abs;
|
||||||
|
}
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<h3><a name="numeric_manual">Wrapping Numeric Operators Manually</a></h3>
|
||||||
|
<p>
|
||||||
|
In some cases, automatic wrapping of operators may be impossible or
|
||||||
|
undesirable. Suppose, for example, that the modulo operation for BigNums
|
||||||
|
is defined by a set of functions called <code>mod()</code>:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum mod(BigNum const& left, BigNum const& right);
|
||||||
|
BigNum mod(BigNum const& left, int right);
|
||||||
|
BigNum mod(int left, BigNum const& right);
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For automatic wrapping of the modulo function, <code>operator%()</code> would be needed.
|
||||||
|
Therefore, the <code>mod()</code>-functions must be wrapped manually. That is, we have
|
||||||
|
to export them explicitly with the Python special name "__mod__":
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
bignum_class.def((BigNum (*)(BigNum const&, BigNum const&))&mod, "__mod__");
|
||||||
|
bignum_class.def((BigNum (*)(BigNum const&, int))&mod, "__mod__");
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The third form of <code>mod()</code> (with <code>int</code> as left operand) cannot
|
||||||
|
be wrapped directly. We must first create a function <code>rmod()</code> with the
|
||||||
|
operands reversed:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum rmod(BigNum const& right, int left)
|
||||||
|
{
|
||||||
|
return mod(left, right);
|
||||||
|
}
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
This function must be wrapped under the name "__rmod__" (standing for "reverse mod"):
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
bignum_class.def(&rmod, "__rmod__");
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
Many of the possible operator names can be found in the <a href=
|
||||||
|
"#numeric_table">Table of Automatically Wrapped Methods</a>. Special treatment is
|
||||||
|
necessary to export the <a href="#ternary_pow">ternary pow</a> operator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Automatic and manual wrapping can be mixed arbitrarily. Note that you
|
||||||
|
cannot overload the same operator for a given extension class on both
|
||||||
|
``<code>int</code>'' and ``<code>float</code>'', because Python implicitly
|
||||||
|
converts these types into each other. Thus, the overloaded variant
|
||||||
|
found first (be it ``<code>int</code>`` or ``<code>float</code>'') will be
|
||||||
|
used for either of the two types.
|
||||||
|
|
||||||
|
<h3><a name="coercion">Coercion</a></h3>
|
||||||
|
|
||||||
|
|
||||||
|
Plain Python can only execute operators with identical types on the left
|
||||||
|
and right hand side. If it encounters an expression where the types of
|
||||||
|
the left and right operand differ, it tries to coerce these types to a
|
||||||
|
common type before invoking the actual operator. Implementing good
|
||||||
|
coercion functions can be difficult if many type combinations must be
|
||||||
|
supported.
|
||||||
|
<p>
|
||||||
|
Boost.Python solves this problem the same way that C++ does: with <em><a
|
||||||
|
href="overloading.html">overloading</a></em>. This technique drastically
|
||||||
|
simplifies the code neccessary to support operators: you just register
|
||||||
|
operators for all desired type combinations, and Boost.Python automatically
|
||||||
|
ensures that the correct function is called in each case; there is no
|
||||||
|
need for user-defined coercion functions. To enable operator
|
||||||
|
overloading, Boost.Python provides a standard coercion which is <em>implicitly
|
||||||
|
registered</em> whenever automatic operator wrapping is used.
|
||||||
|
<p>
|
||||||
|
If you wrap all operator functions manually, but still want to use
|
||||||
|
operator overloading, you have to register the standard coercion
|
||||||
|
function explicitly:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
// this is not necessary if automatic operator wrapping is used
|
||||||
|
bignum_class.def_standard_coerce();
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
If you encounter a situation where you absolutely need a customized
|
||||||
|
coercion, you can still define the "__coerce__" operator manually. The signature
|
||||||
|
of a coercion function should look like one of the following (the first is
|
||||||
|
the safest):
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
boost::python::tuple custom_coerce(boost::python::reference left, boost::python::reference right);
|
||||||
|
boost::python::tuple custom_coerce(PyObject* left, PyObject* right);
|
||||||
|
PyObject* custom_coerce(PyObject* left, PyObject* right);
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
The resulting <code>tuple</code> must contain two elements which
|
||||||
|
represent the values of <code>left</code> and <code>right</code>
|
||||||
|
converted to the same type. Such a function is wrapped as usual:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
// this must be called before any use of automatic operator
|
||||||
|
// wrapping or a call to some_class.def_standard_coerce()
|
||||||
|
some_class.def(&custom_coerce, "__coerce__");
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
Note that the standard coercion (defined by use of automatic
|
||||||
|
operator wrapping on a <code>class_builder</code> or a call to
|
||||||
|
<code>class_builder::def_standard_coerce()</code>) will never be applied if
|
||||||
|
a custom coercion function has been registered. Therefore, in
|
||||||
|
your coercion function you should call
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
boost::python::standard_coerce(left, right);
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
for all cases that you don't want to handle yourself.
|
||||||
|
|
||||||
|
<h3><a name="ternary_pow">The Ternary <code>pow()</code> Operator</a></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In addition to the usual binary <code>pow(x, y)</code> operator (meaning
|
||||||
|
<i>x<sup>y</sup></i>), Python also provides a ternary variant that implements
|
||||||
|
<i>x<sup>y</sup> <b>mod</b> z</i>, presumably using a more efficient algorithm than
|
||||||
|
concatenation of power and modulo operators. Automatic operator wrapping
|
||||||
|
can only be used with the binary variant. Ternary <code>pow()</code> must
|
||||||
|
always be wrapped manually. For a homgeneous ternary <code>pow()</code>,
|
||||||
|
this is done as usual:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum power(BigNum const& first, BigNum const& second, BigNum const& modulus);
|
||||||
|
typedef BigNum (ternary_function1)(const BigNum&, const BigNum&, const BigNum&);
|
||||||
|
...
|
||||||
|
bignum_class.def((ternary_function1)&power, "__pow__");
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
If you want to support this function with non-uniform argument
|
||||||
|
types, wrapping is a little more involved. Suppose you have to wrap:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum power(BigNum const& first, int second, int modulus);
|
||||||
|
BigNum power(int first, BigNum const& second, int modulus);
|
||||||
|
BigNum power(int first, int second, BigNum const& modulus);
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
The first variant can be wrapped as usual:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
typedef BigNum (ternary_function2)(const BigNum&, int, int);
|
||||||
|
bignum_class.def((ternary_function2)&power, "__pow__");
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
In the second variant, however, <code>BigNum</code> appears only as second
|
||||||
|
argument, and in the last one it's the third argument. These functions
|
||||||
|
must be presented to Boost.Python such that that the <code>BigNum</code>
|
||||||
|
argument appears in first position:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
BigNum rpower(BigNum const& second, int first, int modulus)
|
||||||
|
{
|
||||||
|
return power(first, second, modulus);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigNum rrpower(BigNum const& modulus, int first, int second)
|
||||||
|
{
|
||||||
|
return power(first, second, modulus);
|
||||||
|
}
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>These functions must be wrapped under the names "__rpow__" and "__rrpow__"
|
||||||
|
respectively:
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
bignum_class.def((ternary_function2)&rpower, "__rpow__");
|
||||||
|
bignum_class.def((ternary_function2)&rrpower, "__rrpow__");
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
Note that "__rrpow__" is an extension not present in plain Python.
|
||||||
|
|
||||||
|
<h2><a name="numeric_table">Table of Automatically Wrapped Methods</a></h2>
|
||||||
|
<p>
|
||||||
|
Boost.Python can automatically wrap the following <a href=
|
||||||
|
"http://www.python.org/doc/current/ref/specialnames.html">
|
||||||
|
special methods</a>:
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<table summary="special numeric methods" cellpadding="5" border="1"
|
||||||
|
width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<b>Python Operator Name</b>
|
||||||
|
<td align="center">
|
||||||
|
<b>Python Expression</b>
|
||||||
|
<td align="center">
|
||||||
|
<b>C++ Operator Id</b>
|
||||||
|
<td align="center">
|
||||||
|
<b>C++ Expression Used For Automatic Wrapping</b><br>
|
||||||
|
with <code>cpp_left = from_python(left,
|
||||||
|
type<Left>())</code>,<br>
|
||||||
|
<code>cpp_right = from_python(right,
|
||||||
|
type<Right>())</code>,<br>
|
||||||
|
and <code>cpp_oper = from_python(oper, type<Oper>())</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__add__, __radd__</code>
|
||||||
|
<td>
|
||||||
|
<code>left + right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_add</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left + cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__sub__, __rsub__</code>
|
||||||
|
<td>
|
||||||
|
<code>left - right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_sub</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left - cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__mul__, __rmul__</code>
|
||||||
|
<td>
|
||||||
|
<code>left * right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_mul</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left * cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__div__, __rdiv__</code>
|
||||||
|
<td>
|
||||||
|
<code>left / right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_div</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left / cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__mod__, __rmod__</code>
|
||||||
|
<td>
|
||||||
|
<code>left % right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_mod</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left % cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__divmod__, __rdivmod__</code>
|
||||||
|
<td>
|
||||||
|
<code>(quotient, remainder)<br>
|
||||||
|
= divmod(left, right)</code>
|
||||||
|
<td>
|
||||||
|
<code>op_divmod</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left / cpp_right</code>
|
||||||
|
<br><code>cpp_left % cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__pow__, __rpow__</code>
|
||||||
|
<td>
|
||||||
|
<code>pow(left, right)</code><br>
|
||||||
|
(binary power)
|
||||||
|
<td>
|
||||||
|
<code>op_pow</code>
|
||||||
|
<td>
|
||||||
|
<code>pow(cpp_left, cpp_right)</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__rrpow__</code>
|
||||||
|
<td>
|
||||||
|
<code>pow(left, right, modulo)</code><br>
|
||||||
|
(ternary power modulo)
|
||||||
|
<td colspan="2">
|
||||||
|
no automatic wrapping, <a href="#ternary_pow">special treatment</a>
|
||||||
|
required
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__lshift__, __rlshift__</code>
|
||||||
|
<td>
|
||||||
|
<code>left << right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_lshift</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left << cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__rshift__, __rrshift__</code>
|
||||||
|
<td>
|
||||||
|
<code>left >> right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_rshift</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left >> cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__and__, __rand__</code>
|
||||||
|
<td>
|
||||||
|
<code>left & right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_and</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left & cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__xor__, __rxor__</code>
|
||||||
|
<td>
|
||||||
|
<code>left ^ right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_xor</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left ^ cpp_right</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__or__, __ror__</code>
|
||||||
|
<td>
|
||||||
|
<code>left | right</code>
|
||||||
|
<td>
|
||||||
|
<code>op_or</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left | cpp_right</code>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__cmp__, __rcmp__</code>
|
||||||
|
<td>
|
||||||
|
<code>cmp(left, right)</code><br>
|
||||||
|
<br>See <a href="richcmp.html">Rich Comparisons</a>.
|
||||||
|
<td>
|
||||||
|
<code>op_cmp</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left < cpp_right </code>
|
||||||
|
<br><code>cpp_right < cpp_left</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__lt__</code>
|
||||||
|
<br><code>__le__</code>
|
||||||
|
<br><code>__eq__</code>
|
||||||
|
<br><code>__ne__</code>
|
||||||
|
<br><code>__gt__</code>
|
||||||
|
<br><code>__ge__</code>
|
||||||
|
<td>
|
||||||
|
<code>left < right</code>
|
||||||
|
<br><code>left <= right</code>
|
||||||
|
<br><code>left == right</code>
|
||||||
|
<br><code>left != right</code>
|
||||||
|
<br><code>left > right</code>
|
||||||
|
<br><code>left >= right</code>
|
||||||
|
<br>See <a href="richcmp.html">Rich Comparisons</a>
|
||||||
|
<td>
|
||||||
|
<code>op_lt</code>
|
||||||
|
<br><code>op_le</code>
|
||||||
|
<br><code>op_eq</code>
|
||||||
|
<br><code>op_ne</code>
|
||||||
|
<br><code>op_gt</code>
|
||||||
|
<br><code>op_ge</code>
|
||||||
|
<td>
|
||||||
|
<code>cpp_left < cpp_right </code>
|
||||||
|
<br><code>cpp_left <= cpp_right </code>
|
||||||
|
<br><code>cpp_left == cpp_right </code>
|
||||||
|
<br><code>cpp_left != cpp_right </code>
|
||||||
|
<br><code>cpp_left > cpp_right </code>
|
||||||
|
<br><code>cpp_left >= cpp_right </code>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__neg__</code>
|
||||||
|
<td>
|
||||||
|
<code>-oper </code> (unary negation)
|
||||||
|
<td>
|
||||||
|
<code>op_neg</code>
|
||||||
|
<td>
|
||||||
|
<code>-cpp_oper</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__pos__</code>
|
||||||
|
<td>
|
||||||
|
<code>+oper </code> (identity)
|
||||||
|
<td>
|
||||||
|
<code>op_pos</code>
|
||||||
|
<td>
|
||||||
|
<code>+cpp_oper</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__abs__</code>
|
||||||
|
<td>
|
||||||
|
<code>abs(oper) </code> (absolute value)
|
||||||
|
<td>
|
||||||
|
<code>op_abs</code>
|
||||||
|
<td>
|
||||||
|
<code>abs(cpp_oper)</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__invert__</code>
|
||||||
|
<td>
|
||||||
|
<code>~oper </code> (bitwise inversion)
|
||||||
|
<td>
|
||||||
|
<code>op_invert</code>
|
||||||
|
<td>
|
||||||
|
<code>~cpp_oper</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__int__</code>
|
||||||
|
<td>
|
||||||
|
<code>int(oper) </code> (integer conversion)
|
||||||
|
<td>
|
||||||
|
<code>op_int</code>
|
||||||
|
<td>
|
||||||
|
<code>long(cpp_oper)</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__long__</code>
|
||||||
|
<td>
|
||||||
|
<code>long(oper) </code><br>
|
||||||
|
(infinite precision integer conversion)
|
||||||
|
<td>
|
||||||
|
<code>op_long</code>
|
||||||
|
<td>
|
||||||
|
<code>PyLong_FromLong(cpp_oper)</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__float__</code>
|
||||||
|
<td>
|
||||||
|
<code>float(oper) </code> (float conversion)
|
||||||
|
<td>
|
||||||
|
<code>op_float</code>
|
||||||
|
<td>
|
||||||
|
<code>double(cpp_oper)</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__str__</code>
|
||||||
|
<td>
|
||||||
|
<code>str(oper) </code> (string conversion)
|
||||||
|
<td>
|
||||||
|
<code>op_str</code>
|
||||||
|
<td>
|
||||||
|
<code>std::ostringstream s; s << oper;</code>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>__coerce__</code>
|
||||||
|
<td>
|
||||||
|
<code>coerce(left, right)</code>
|
||||||
|
<td colspan="2">
|
||||||
|
usually defined automatically, otherwise <a href="#coercion">
|
||||||
|
special treatment</a> required
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><a name="sequence_and_mapping">Sequence and Mapping Operators</a></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Sequence and mapping operators let wrapped objects behave in accordance
|
||||||
|
to Python's iteration and access protocols. These protocols differ
|
||||||
|
considerably from the ones found in C++. For example, Python's typical
|
||||||
|
iteration idiom looks like
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
for i in S:
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
while in C++ one writes
|
||||||
|
|
||||||
|
<blockquote><pre>
|
||||||
|
for (iterator i = S.begin(), end = S.end(); i != end; ++i)
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>One could try to wrap C++ iterators in order to carry the C++ idiom into
|
||||||
|
Python. However, this does not work very well because
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>It leads to
|
||||||
|
non-uniform Python code (wrapped sequences support a usage different from
|
||||||
|
Python built-in sequences) and
|
||||||
|
|
||||||
|
<li>Iterators (e.g. <code>std::vector::iterator</code>) are often implemented as plain C++
|
||||||
|
pointers which are <a href="pointers.html#problem">problematic</a> for any automatic
|
||||||
|
wrapping system.
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
It is a better idea to support the standard <a
|
||||||
|
href="http://www.python.org/doc/current/ref/sequence-types.html">Python
|
||||||
|
sequence and mapping protocols</a> for your wrapped containers. These
|
||||||
|
operators have to be wrapped manually because there are no corresponding
|
||||||
|
C++ operators that could be used for automatic wrapping. The Python
|
||||||
|
documentation lists the relevant <a href=
|
||||||
|
"http://www.python.org/doc/current/ref/sequence-types.html">
|
||||||
|
container operators</a>. In particular, expose __getitem__, __setitem__
|
||||||
|
and remember to raise the appropriate Python exceptions
|
||||||
|
(<code>PyExc_IndexError</code> for sequences,
|
||||||
|
<code>PyExc_KeyError</code> for mappings) when the requested item is not
|
||||||
|
present.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In the following example, we expose <code>std::map<std::size_t,std::string></code>:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
typedef std::map<std::size_t, std::string> StringMap;
|
||||||
|
|
||||||
|
// A helper function for dealing with errors. Throw a Python exception
|
||||||
|
// if p == m.end().
|
||||||
|
void throw_key_error_if_end(
|
||||||
|
const StringMap& m,
|
||||||
|
StringMap::const_iterator p,
|
||||||
|
std::size_t key)
|
||||||
|
{
|
||||||
|
if (p == m.end())
|
||||||
|
{
|
||||||
|
PyErr_SetObject(PyExc_KeyError, boost::python::converters::to_python(key));
|
||||||
|
throw boost::python::error_already_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define some simple wrapper functions which match the Python protocol
|
||||||
|
// for __getitem__, __setitem__, and __delitem__. Just as in Python, a
|
||||||
|
// free function with a ``self'' first parameter makes a fine class method.
|
||||||
|
|
||||||
|
const std::string& get_item(const StringMap& self, std::size_t key)
|
||||||
|
{
|
||||||
|
const StringMap::const_iterator p = self.find(key);
|
||||||
|
throw_key_error_if_end(self, p, key);
|
||||||
|
return p->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the item corresponding to key in the map.
|
||||||
|
void StringMapPythonClass::set_item(StringMap& self, std::size_t key, const std::string& value)
|
||||||
|
{
|
||||||
|
self[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes the item corresponding to key from the map.
|
||||||
|
void StringMapPythonClass::del_item(StringMap& self, std::size_t key)
|
||||||
|
{
|
||||||
|
const StringMap::iterator p = self.find(key);
|
||||||
|
throw_key_error_if_end(self, p, key);
|
||||||
|
self.erase(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
class_builder<StringMap> string_map(my_module, "StringMap");
|
||||||
|
string_map.def(boost::python::constructor<>());
|
||||||
|
string_map.def(&StringMap::size, "__len__");
|
||||||
|
string_map.def(get_item, "__getitem__");
|
||||||
|
string_map.def(set_item, "__setitem__");
|
||||||
|
string_map.def(del_item, "__delitem__");
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<p>
|
||||||
|
Then in Python:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> m = StringMap()
|
||||||
|
>>> m[1]
|
||||||
|
Traceback (innermost last):
|
||||||
|
File "<stdin>", line 1, in ?
|
||||||
|
KeyError: 1
|
||||||
|
>>> m[1] = 'hello'
|
||||||
|
>>> m[1]
|
||||||
|
'hello'
|
||||||
|
>>> del m[1]
|
||||||
|
>>> m[1] # prove that it's gone
|
||||||
|
Traceback (innermost last):
|
||||||
|
File "<stdin>", line 1, in ?
|
||||||
|
KeyError: 1
|
||||||
|
>>> del m[2]
|
||||||
|
Traceback (innermost last):
|
||||||
|
File "<stdin>", line 1, in ?
|
||||||
|
KeyError: 2
|
||||||
|
>>> len(m)
|
||||||
|
0
|
||||||
|
>>> m[0] = 'zero'
|
||||||
|
>>> m[1] = 'one'
|
||||||
|
>>> m[2] = 'two'
|
||||||
|
>>> m[3] = 'three'
|
||||||
|
>>> len(m)
|
||||||
|
4
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<h2><a name="getter_setter">Customized Attribute Access</a></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Just like built-in Python classes, Boost.Python extension classes support <a
|
||||||
|
href="http://www.python.org/doc/current/ref/attribute-access.html">special
|
||||||
|
the usual attribute access methods</a> <code>__getattr__</code>,
|
||||||
|
<code>__setattr__</code>, and <code>__delattr__</code>.
|
||||||
|
Because writing these functions can
|
||||||
|
be tedious in the common case where the attributes being accessed are
|
||||||
|
known statically, Boost.Python checks the special names
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<code>__getattr__<em><name></em>__</code>
|
||||||
|
<li>
|
||||||
|
<code>__setattr__<em><name></em>__</code>
|
||||||
|
<li>
|
||||||
|
<code>__delattr__<em><name></em>__</code>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
to provide functional access to the attribute <em><name></em>. This
|
||||||
|
facility can be used from C++ or entirely from Python. For example, the
|
||||||
|
following shows how we can implement a ``computed attribute'' in Python:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> class Range(AnyBoost.PythonExtensionClass):
|
||||||
|
... def __init__(self, start, end):
|
||||||
|
... self.start = start
|
||||||
|
... self.end = end
|
||||||
|
... def __getattr__length__(self):
|
||||||
|
... return self.end - self.start
|
||||||
|
...
|
||||||
|
>>> x = Range(3, 9)
|
||||||
|
>>> x.length
|
||||||
|
6
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<h4>
|
||||||
|
Direct Access to Data Members
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
Boost.Python uses the special <code>
|
||||||
|
__xxxattr__<em><name></em>__</code> functionality described above
|
||||||
|
to allow direct access to data members through the following special
|
||||||
|
functions on <code>class_builder<></code> and <code>
|
||||||
|
extension_class<></code>:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<code>def_getter(<em>pointer-to-member</em>, <em>name</em>)</code> //
|
||||||
|
read access to the member via attribute <em>name</em>
|
||||||
|
<li>
|
||||||
|
<code>def_setter(<em>pointer-to-member</em>, <em>name</em>)</code> //
|
||||||
|
write access to the member via attribute <em>name</em>
|
||||||
|
<li>
|
||||||
|
<code>def_readonly(<em>pointer-to-member</em>, <em>name</em>)</code>
|
||||||
|
// read-only access to the member via attribute <em>name</em>
|
||||||
|
<li>
|
||||||
|
<code>def_read_write(<em>pointer-to-member</em>, <em>
|
||||||
|
name</em>)</code> // read/write access to the member via attribute
|
||||||
|
<em>name</em>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Note that the first two functions, used alone, may produce surprising
|
||||||
|
behavior. For example, when <code>def_getter()</code> is used, the
|
||||||
|
default functionality for <code>setattr()</code> and <code>
|
||||||
|
delattr()</code> remains in effect, operating on items in the extension
|
||||||
|
instance's name-space (i.e., its <code>__dict__</code>). For that
|
||||||
|
reason, you'll usually want to stick with <code>def_readonly</code> and
|
||||||
|
<code>def_read_write</code>.
|
||||||
|
<p>
|
||||||
|
For example, to expose a <code>std::pair<int,long></code> we
|
||||||
|
might write:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
typedef std::pair<int,long> Pil;
|
||||||
|
int first(const Pil& x) { return x.first; }
|
||||||
|
long second(const Pil& x) { return x.second; }
|
||||||
|
...
|
||||||
|
my_module.def(first, "first");
|
||||||
|
my_module.def(second, "second");
|
||||||
|
|
||||||
|
class_builder<Pil> pair_int_long(my_module, "Pair");
|
||||||
|
pair_int_long.def(boost::python::constructor<>());
|
||||||
|
pair_int_long.def(boost::python::constructor<int,long>());
|
||||||
|
pair_int_long.def_read_write(&Pil::first, "first");
|
||||||
|
pair_int_long.def_read_write(&Pil::second, "second");
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<p>
|
||||||
|
Now your Python class has attributes <code>first</code> and <code>
|
||||||
|
second</code> which, when accessed, actually modify or reflect the
|
||||||
|
values of corresponding data members of the underlying C++ object. Now
|
||||||
|
in Python:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
>>> x = Pair(3,5)
|
||||||
|
>>> x.first
|
||||||
|
3
|
||||||
|
>>> x.second
|
||||||
|
5
|
||||||
|
>>> x.second = 8
|
||||||
|
>>> x.second
|
||||||
|
8
|
||||||
|
>>> second(x) # Prove that we're not just changing the instance __dict__
|
||||||
|
8
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<h2>
|
||||||
|
<a name="reasons">And what about <code>__complex__</code>?</a>
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
That, dear reader, is one problem we don't know how to solve. The
|
||||||
|
Python source contains the following fragment, indicating the
|
||||||
|
special-case code really is hardwired:
|
||||||
|
<blockquote>
|
||||||
|
<pre>
|
||||||
|
/* XXX Hack to support classes with __complex__ method */
|
||||||
|
if (PyInstance_Check(r)) { ...
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
<p>
|
||||||
|
Next: <a href="under-the-hood.html">A Peek Under the Hood</a>
|
||||||
|
Previous: <a href="inheritance.html">Inheritance</a>
|
||||||
|
Up: <a href= "index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams and Ullrich Köthe 2000.
|
||||||
|
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.
|
||||||
|
<p>
|
||||||
|
Updated: Nov 26, 2000
|
||||||
|
</div>
|
||||||
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="generator" content=
|
|
||||||
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="boost.css">
|
|
||||||
|
|
||||||
<title>Boost.Python - Support Resources</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body link="#0000ff" vlink="#800080">
|
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
|
||||||
"header">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><a href="../../../index.htm"><img height="86" width="277" alt=
|
|
||||||
"C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center"><a href="index.html">Boost.Python</a></h1>
|
|
||||||
|
|
||||||
<h2 align="center">Support Resources</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Synopsis</h2>
|
|
||||||
|
|
||||||
<p>This is a list of available resources for support with Boost.Python
|
|
||||||
problems and feature requests.</p>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<dl class="page-index">
|
|
||||||
<dt><b><a href="http://www.boost-consulting.com">Boost
|
|
||||||
Consulting</a></b> - Commercial support, development, training, and
|
|
||||||
distribution for all the Boost libraries, from the people who brought
|
|
||||||
you Boost.Python.<br>
|
|
||||||
</dt>
|
|
||||||
|
|
||||||
<dt><b><a href="http://www.python.org/sigs/c++-sig/">The Python
|
|
||||||
C++-sig</a></b> mailing list is a forum for discussing Python/C++
|
|
||||||
interoperability, and Boost.Python in particular.<br>
|
|
||||||
</dt>
|
|
||||||
|
|
||||||
<dt>The <b>Boost.Python <a href=
|
|
||||||
"http://www.python.org/cgi-bin/moinmoin/boost_2epython">Wiki
|
|
||||||
Pages</a></b> established by Mike Rovner as part of the <a href=
|
|
||||||
"http://www.python.org/cgi-bin/moinmoin">PythonInfo Wiki</a> serves as
|
|
||||||
a forum to gather peoples' experience and as a cookbook.<br>
|
|
||||||
</dt>
|
|
||||||
</dl>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
|
||||||
17 November, 2002
|
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href="../../../people/dave_abrahams.htm">Dave
|
|
||||||
Abrahams</a> 2002. All Rights Reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Auto-Overloading</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="default_arguments.html">
|
|
||||||
<link rel="next" href="object_interface.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>Auto-Overloading</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="default_arguments.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="object_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
It was mentioned in passing in the previous section that
|
|
||||||
<tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt> and <tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt>
|
|
||||||
can also be used for overloaded functions and member functions with a
|
|
||||||
common sequence of initial arguments. Here is an example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>void </span><span class=identifier>foo</span><span class=special>()
|
|
||||||
{
|
|
||||||
/*...*/
|
|
||||||
}
|
|
||||||
|
|
||||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>)
|
|
||||||
{
|
|
||||||
/*...*/
|
|
||||||
}
|
|
||||||
|
|
||||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>b</span><span class=special>)
|
|
||||||
{
|
|
||||||
/*...*/
|
|
||||||
}
|
|
||||||
|
|
||||||
</span><span class=keyword>void </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>bool </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>b</span><span class=special>, </span><span class=keyword>char </span><span class=identifier>c</span><span class=special>)
|
|
||||||
{
|
|
||||||
/*...*/
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Like in the previous section, we can generate thin wrappers for these
|
|
||||||
overloaded functions in one-shot:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class=special>(</span><span class=identifier>foo_overloads</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=number>0</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Then...</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"foo"</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>foo_overloads</span><span class=special>());
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Notice though that we have a situation now where we have a minimum of zero
|
|
||||||
(0) arguments and a maximum of 3 arguments.</p>
|
|
||||||
<a name="manual_wrapping"></a><h2>Manual Wrapping</h2><p>
|
|
||||||
It is important to emphasize however that <b>the overloaded functions must
|
|
||||||
have a common sequence of initial arguments</b>. Otherwise, our scheme above
|
|
||||||
will not work. If this is not the case, we have to wrap our functions
|
|
||||||
<a href="overloading.html">
|
|
||||||
manually</a>.</p>
|
|
||||||
<p>
|
|
||||||
Actually, we can mix and match manual wrapping of overloaded functions and
|
|
||||||
automatic wrapping through <tt>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> and
|
|
||||||
its sister, <tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt>. Following up on our example
|
|
||||||
presented in the section <a href="overloading.html">
|
|
||||||
on overloading</a>, since the
|
|
||||||
first 4 overload functins have a common sequence of initial arguments, we
|
|
||||||
can use <tt>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> to automatically wrap the
|
|
||||||
first three of the <tt>def</tt>s and manually wrap just the last. Here's
|
|
||||||
how we'll do this:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class=special>(</span><span class=identifier>xf_overloads</span><span class=special>, </span><span class=identifier>f</span><span class=special>, </span><span class=number>1</span><span class=special>, </span><span class=number>4</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Create a member function pointers as above for both X::f overloads:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>bool </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx1</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double</span><span class=special>, </span><span class=keyword>char</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
|
||||||
</span><span class=keyword>int </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx2</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>int</span><span class=special>, </span><span class=keyword>int</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Then...</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>fx1</span><span class=special>, </span><span class=identifier>xf_overloads</span><span class=special>());
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>fx2</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<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="default_arguments.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="object_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Basic Interface</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="object_interface.html">
|
|
||||||
<link rel="next" href="derived_object_types.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>Basic Interface</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="object_interface.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="derived_object_types.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Class <tt>object</tt> wraps <tt>PyObject*</tt>. All the intricacies of dealing with
|
|
||||||
<tt>PyObject</tt>s such as managing reference counting are handled by the
|
|
||||||
<tt>object</tt> class. C++ object interoperability is seamless. Boost.Python C++
|
|
||||||
<tt>object</tt>s can in fact be explicitly constructed from any C++ object.</p>
|
|
||||||
<p>
|
|
||||||
To illustrate, this Python code snippet:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>def </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>x</span><span class=special>, </span><span class=identifier>y</span><span class=special>):
|
|
||||||
</span><span class=keyword>if </span><span class=special>(</span><span class=identifier>y </span><span class=special>== </span><span class=literal>'foo'</span><span class=special>):
|
|
||||||
</span><span class=identifier>x</span><span class=special>[</span><span class=number>3</span><span class=special>:</span><span class=number>7</span><span class=special>] = </span><span class=literal>'bar'
|
|
||||||
</span><span class=keyword>else</span><span class=special>:
|
|
||||||
</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>items </span><span class=special>+= </span><span class=identifier>y</span><span class=special>(</span><span class=number>3</span><span class=special>, </span><span class=identifier>x</span><span class=special>)
|
|
||||||
</span><span class=keyword>return </span><span class=identifier>x
|
|
||||||
|
|
||||||
</span><span class=identifier>def </span><span class=identifier>getfunc</span><span class=special>():
|
|
||||||
</span><span class=keyword>return </span><span class=identifier>f</span><span class=special>;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Can be rewritten in C++ using Boost.Python facilities this way:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>object </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>object </span><span class=identifier>x</span><span class=special>, </span><span class=identifier>object </span><span class=identifier>y</span><span class=special>) {
|
|
||||||
</span><span class=keyword>if </span><span class=special>(</span><span class=identifier>y </span><span class=special>== </span><span class=string>"foo"</span><span class=special>)
|
|
||||||
</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>slice</span><span class=special>(</span><span class=number>3</span><span class=special>,</span><span class=number>7</span><span class=special>) = </span><span class=string>"bar"</span><span class=special>;
|
|
||||||
</span><span class=keyword>else
|
|
||||||
</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>attr</span><span class=special>(</span><span class=string>"items"</span><span class=special>) += </span><span class=identifier>y</span><span class=special>(</span><span class=number>3</span><span class=special>, </span><span class=identifier>x</span><span class=special>);
|
|
||||||
</span><span class=keyword>return </span><span class=identifier>x</span><span class=special>;
|
|
||||||
}
|
|
||||||
</span><span class=identifier>object </span><span class=identifier>getfunc</span><span class=special>() {
|
|
||||||
</span><span class=keyword>return </span><span class=identifier>object</span><span class=special>(</span><span class=identifier>f</span><span class=special>);
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Apart from cosmetic differences due to the fact that we are writing the
|
|
||||||
code in C++, the look and feel should be immediately apparent to the Python
|
|
||||||
coder.</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="object_interface.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="derived_object_types.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Building Hello World</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="quickstart.html">
|
|
||||||
<link rel="next" href="exposing_classes.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>Building Hello World</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="quickstart.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="exposing_classes.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<a name="from_start_to_finish"></a><h2>From Start To Finish</h2><p>
|
|
||||||
Now the first thing you'd want to do is to build the Hello World module and
|
|
||||||
try it for yourself in Python. In this section, we shall outline the steps
|
|
||||||
necessary to achieve that. We shall use the build tool that comes bundled
|
|
||||||
with every boost distribution: <b>bjam</b>.</p>
|
|
||||||
<table width="80%" border="0" align="center">
|
|
||||||
<tr>
|
|
||||||
<td class="note_box">
|
|
||||||
<img src="theme/lens.gif"></img> <b>Building without bjam</b><br><br>
|
|
||||||
|
|
||||||
Besides bjam, there are of course other ways to get your module built.
|
|
||||||
What's written here should not be taken as "the one and only way".
|
|
||||||
There are of course other build tools apart from <tt>bjam</tt>.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
We shall skip over the details. Our objective will be to simply create the
|
|
||||||
hello world module and run it in Python. For a complete reference to
|
|
||||||
building Boost.Python, check out: <a href="../../building.html">
|
|
||||||
building.html</a>.
|
|
||||||
After this brief <i>bjam</i> tutorial, we should have built two DLLs:</p>
|
|
||||||
<ul><li>boost_python.dll</li><li>hello.pyd</li></ul><p>
|
|
||||||
if you are on Windows, and</p>
|
|
||||||
<ul><li>libboost_python.so</li><li>hello.so</li></ul><p>
|
|
||||||
if you are on Unix.</p>
|
|
||||||
<p>
|
|
||||||
The tutorial example can be found in the directory:
|
|
||||||
<tt>libs/python/example/tutorial</tt>. There, you can find:</p>
|
|
||||||
<ul><li>hello.cpp</li><li>Jamfile</li></ul><p>
|
|
||||||
The <tt>hello.cpp</tt> file is our C++ hello world example. The <tt>Jamfile</tt> is a
|
|
||||||
minimalist <i>bjam</i> script that builds the DLLs for us.</p>
|
|
||||||
<p>
|
|
||||||
Before anything else, you should have the bjam executable in your boost
|
|
||||||
directory or somewhere in your path such that <tt>bjam</tt> can be executed in
|
|
||||||
the command line. Pre-built Boost.Jam executables are available for most
|
|
||||||
platforms. For example, a pre-built Microsoft Windows bjam executable can
|
|
||||||
be downloaded <a href="http://boost.sourceforge.net/jam-executables/bin.ntx86/bjam.zip">
|
|
||||||
here</a>.
|
|
||||||
The complete list of bjam pre-built
|
|
||||||
executables can be found <a href="../../../../../tools/build/index.html#Jam">
|
|
||||||
here</a>.</p>
|
|
||||||
<a name="lets_jam_"></a><h2>Lets Jam!</h2><p>
|
|
||||||
<img src="theme/jam.png"></img></p>
|
|
||||||
<p>
|
|
||||||
Here is our minimalist Jamfile:</p>
|
|
||||||
<code><pre>
|
|
||||||
subproject libs/python/example/tutorial ;
|
|
||||||
|
|
||||||
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
|
|
||||||
include python.jam ;
|
|
||||||
|
|
||||||
extension hello # Declare a Python extension called hello
|
|
||||||
: hello.cpp # source
|
|
||||||
<dll>../../build/boost_python # dependencies
|
|
||||||
;
|
|
||||||
</pre></code><p>
|
|
||||||
First, we need to specify our location in the boost project hierarchy.
|
|
||||||
It so happens that the tutorial example is located in <tt>/libs/python/example/tutorial</tt>.
|
|
||||||
Thus:</p>
|
|
||||||
<code><pre>
|
|
||||||
subproject libs/python/example/tutorial ;
|
|
||||||
</pre></code><p>
|
|
||||||
Then we will include the definitions needed by Python modules:</p>
|
|
||||||
<code><pre>
|
|
||||||
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
|
|
||||||
include python.jam ;
|
|
||||||
</pre></code><p>
|
|
||||||
Finally we declare our <tt>hello</tt> extension:</p>
|
|
||||||
<code><pre>
|
|
||||||
extension hello # Declare a Python extension called hello
|
|
||||||
: hello.cpp # source
|
|
||||||
<dll>../../build/boost_python # dependencies
|
|
||||||
;
|
|
||||||
</pre></code><a name="running_bjam"></a><h2>Running bjam</h2><p>
|
|
||||||
<i>bjam</i> is run using your operating system's command line interpreter.</p>
|
|
||||||
<blockquote><p>Start it up.</p></blockquote><p>
|
|
||||||
Make sure that the environment is set so that we can invoke the C++
|
|
||||||
compiler. With MSVC, that would mean running the <tt>Vcvars32.bat</tt> batch
|
|
||||||
file. For instance:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>C</span><span class=special>:\</span><span class=identifier>Program </span><span class=identifier>Files</span><span class=special>\</span><span class=identifier>Microsoft </span><span class=identifier>Visual </span><span class=identifier>Studio</span><span class=special>\</span><span class=identifier>VC98</span><span class=special>\</span><span class=identifier>bin</span><span class=special>\</span><span class=identifier>Vcvars32</span><span class=special>.</span><span class=identifier>bat
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Some environment variables will have to be setup for proper building of our
|
|
||||||
Python modules. Example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>set </span><span class=identifier>PYTHON_ROOT</span><span class=special>=</span><span class=identifier>c</span><span class=special>:/</span><span class=identifier>dev</span><span class=special>/</span><span class=identifier>tools</span><span class=special>/</span><span class=identifier>python
|
|
||||||
</span><span class=identifier>set </span><span class=identifier>PYTHON_VERSION</span><span class=special>=</span><span class=number>2.2
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
The above assumes that the Python installation is in <tt>c:/dev/tools/python</tt>
|
|
||||||
and that we are using Python version 2.2. You'll have to tweak this path
|
|
||||||
appropriately. <img src="theme/note.gif"></img> Be sure not to include a third number, e.g. <b>not</b> "2.2.1",
|
|
||||||
even if that's the version you have.</p>
|
|
||||||
<p>
|
|
||||||
Now we are ready... Be sure to <tt>cd</tt> to <tt>libs/python/example/tutorial</tt>
|
|
||||||
where the tutorial <tt>"hello.cpp"</tt> and the <tt>"Jamfile"</tt> is situated.</p>
|
|
||||||
<p>
|
|
||||||
Finally:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>bjam </span><span class=special>-</span><span class=identifier>sTOOLS</span><span class=special>=</span><span class=identifier>msvc
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
We are again assuming that we are using Microsoft Visual C++ version 6. If
|
|
||||||
not, then you will have to specify the appropriate tool. See
|
|
||||||
<a href="../../../../../tools/build/index.html">
|
|
||||||
Building Boost Libraries</a> for
|
|
||||||
further details.</p>
|
|
||||||
<p>
|
|
||||||
It should be building now:</p>
|
|
||||||
<code><pre>
|
|
||||||
cd C:\dev\boost\libs\python\example\tutorial
|
|
||||||
bjam -sTOOLS=msvc
|
|
||||||
...patience...
|
|
||||||
...found 1703 targets...
|
|
||||||
...updating 40 targets...
|
|
||||||
</pre></code><p>
|
|
||||||
And so on... Finally:</p>
|
|
||||||
<code><pre>
|
|
||||||
vc-C++ ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\msvc\debug\
|
|
||||||
runtime-link-dynamic\hello.obj
|
|
||||||
hello.cpp
|
|
||||||
vc-Link ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\msvc\debug\
|
|
||||||
runtime-link-dynamic\hello.pyd ..\..\..\..\libs\python\example\tutorial\bin\
|
|
||||||
hello.pyd\msvc\debug\runtime-link-dynamic\hello.lib
|
|
||||||
Creating library ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\
|
|
||||||
msvc\debug\runtime-link-dynamic\hello.lib and object ..\..\..\..\libs\python\
|
|
||||||
example\tutorial\bin\hello.pyd\msvc\debug\runtime-link-dynamic\hello.exp
|
|
||||||
...updated 40 targets...
|
|
||||||
</pre></code><p>
|
|
||||||
If all is well, you should now have:</p>
|
|
||||||
<ul><li>boost_python.dll</li><li>hello.pyd</li></ul><p>
|
|
||||||
if you are on Windows, and</p>
|
|
||||||
<ul><li>libboost_python.so</li><li>hello.so</li></ul><p>
|
|
||||||
if you are on Unix.</p>
|
|
||||||
<p>
|
|
||||||
<tt>boost_python.dll</tt> can be found somewhere in <tt>libs\python\build\bin</tt>
|
|
||||||
while <tt>hello.pyd</tt> can be found somewhere in
|
|
||||||
<tt>libs\python\example\tutorial\bin</tt>. After a successful build, you can just
|
|
||||||
link in these DLLs with the Python interpreter. In Windows for example, you
|
|
||||||
can simply put these libraries inside the directory where the Python
|
|
||||||
executable is.</p>
|
|
||||||
<p>
|
|
||||||
You may now fire up Python and run our hello module:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>import </span><span class=identifier>hello
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>print </span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>greet</span><span class=special>()
|
|
||||||
</span><span class=identifier>hello</span><span class=special>, </span><span class=identifier>world
|
|
||||||
</span></pre></code>
|
|
||||||
<blockquote><p><b>There you go... Have fun!</b></p></blockquote><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="quickstart.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="exposing_classes.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Call Policies</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="functions.html">
|
|
||||||
<link rel="next" href="overloading.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>Call Policies</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="functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
In C++, we often deal with arguments and return types such as pointers
|
|
||||||
and references. Such primitive types are rather, ummmm, low level and
|
|
||||||
they really don't tell us much. At the very least, we don't know the
|
|
||||||
owner of the pointer or the referenced object. No wonder languages
|
|
||||||
such as Java and Python never deal with such low level entities. In
|
|
||||||
C++, it's usually considered a good practice to use smart pointers
|
|
||||||
which exactly describe ownership semantics. Still, even good C++
|
|
||||||
interfaces use raw references and pointers sometimes, so Boost.Python
|
|
||||||
must deal with them. To do this, it may need your help. Consider the
|
|
||||||
following C++ function:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>X</span><span class=special>& </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>Y</span><span class=special>& </span><span class=identifier>y</span><span class=special>, </span><span class=identifier>Z</span><span class=special>* </span><span class=identifier>z</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
How should the library wrap this function? A naive approach builds a
|
|
||||||
Python X object around result reference. This strategy might or might
|
|
||||||
not work out. Here's an example where it didn't</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>x </span><span class=special>= </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>y</span><span class=special>, </span><span class=identifier>z</span><span class=special>) </span>##<span class=identifier>x </span><span class=identifier>refers </span><span class=identifier>to </span><span class=identifier>some </span><span class=identifier>C</span><span class=special>++ </span><span class=identifier>X
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>del </span><span class=identifier>y
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>some_method</span><span class=special>() </span>##<span class=identifier>CRASH</span><span class=special>!
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
What's the problem?</p>
|
|
||||||
<p>
|
|
||||||
Well, what if f() was implemented as shown below:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>X</span><span class=special>& </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>Y</span><span class=special>& </span><span class=identifier>y</span><span class=special>, </span><span class=identifier>Z</span><span class=special>* </span><span class=identifier>z</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>z </span><span class=special>= </span><span class=identifier>z</span><span class=special>;
|
|
||||||
</span><span class=keyword>return </span><span class=identifier>y</span><span class=special>.</span><span class=identifier>x</span><span class=special>;
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
The problem is that the lifetime of result X& is tied to the lifetime
|
|
||||||
of y, because the f() returns a reference to a member of the y
|
|
||||||
object. This idiom is is not uncommon and perfectly acceptable in the
|
|
||||||
context of C++. However, Python users should not be able to crash the
|
|
||||||
system just by using our C++ interface. In this case deleting y will
|
|
||||||
invalidate the reference to X. We have a dangling reference.</p>
|
|
||||||
<p>
|
|
||||||
Here's what's happening:</p>
|
|
||||||
<ol><li><tt>f</tt> is called passing in a reference to <tt>y</tt> and a pointer to <tt>z</tt></li><li>A reference to <tt>y.x</tt> is returned</li><li><tt>y</tt> is deleted. <tt>x</tt> is a dangling reference</li><li><tt>x.some_method()</tt> is called</li><li><b>BOOM!</b></li></ol><p>
|
|
||||||
We could copy result into a new object:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>y</span><span class=special>, </span><span class=identifier>z</span><span class=special>).</span><span class=identifier>set</span><span class=special>(</span><span class=number>42</span><span class=special>) </span>##<span class=identifier>Result </span><span class=identifier>disappears
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>y</span><span class=special>.</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>get</span><span class=special>() </span>##<span class=identifier>No </span><span class=identifier>crash</span><span class=special>, </span><span class=identifier>but </span><span class=identifier>still </span><span class=identifier>bad
|
|
||||||
</span><span class=number>3.14
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
This is not really our intent of our C++ interface. We've broken our
|
|
||||||
promise that the Python interface should reflect the C++ interface as
|
|
||||||
closely as possible.</p>
|
|
||||||
<p>
|
|
||||||
Our problems do not end there. Suppose Y is implemented as follows:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>Y
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=identifier>X </span><span class=identifier>x</span><span class=special>; </span><span class=identifier>Z</span><span class=special>* </span><span class=identifier>z</span><span class=special>;
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>z_value</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>z</span><span class=special>-></span><span class=identifier>value</span><span class=special>(); }
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Notice that the data member <tt>z</tt> is held by class Y using a raw
|
|
||||||
pointer. Now we have a potential dangling pointer problem inside Y:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>x </span><span class=special>= </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>y</span><span class=special>, </span><span class=identifier>z</span><span class=special>) </span>##<span class=identifier>y </span><span class=identifier>refers </span><span class=identifier>to </span><span class=identifier>z
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>del </span><span class=identifier>z </span>##<span class=identifier>Kill </span><span class=identifier>the </span><span class=identifier>z </span><span class=identifier>object
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>y</span><span class=special>.</span><span class=identifier>z_value</span><span class=special>() </span>##<span class=identifier>CRASH</span><span class=special>!
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
For reference, here's the implementation of <tt>f</tt> again:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>X</span><span class=special>& </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>Y</span><span class=special>& </span><span class=identifier>y</span><span class=special>, </span><span class=identifier>Z</span><span class=special>* </span><span class=identifier>z</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=identifier>y</span><span class=special>.</span><span class=identifier>z </span><span class=special>= </span><span class=identifier>z</span><span class=special>;
|
|
||||||
</span><span class=keyword>return </span><span class=identifier>y</span><span class=special>.</span><span class=identifier>x</span><span class=special>;
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Here's what's happening:</p>
|
|
||||||
<ol><li><tt>f</tt> is called passing in a reference to <tt>y</tt> and a pointer to <tt>z</tt></li><li>A pointer to <tt>z</tt> is held by <tt>y</tt></li><li>A reference to <tt>y.x</tt> is returned</li><li><tt>z</tt> is deleted. <tt>y.z</tt> is a dangling pointer</li><li><tt>y.z_value()</tt> is called</li><li><tt>z->value()</tt> is called</li><li><b>BOOM!</b></li></ol><a name="call_policies"></a><h2>Call Policies</h2><p>
|
|
||||||
Call Policies may be used in situations such as the example detailed above.
|
|
||||||
In our example, <tt>return_internal_reference</tt> and <tt>with_custodian_and_ward</tt>
|
|
||||||
are our friends:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>f</span><span class=special>,
|
|
||||||
</span><span class=identifier>return_internal_reference</span><span class=special><</span><span class=number>1</span><span class=special>,
|
|
||||||
</span><span class=identifier>with_custodian_and_ward</span><span class=special><</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>> >());
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
What are the <tt>1</tt> and <tt>2</tt> parameters, you ask?</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>return_internal_reference</span><span class=special><</span><span class=number>1
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Informs Boost.Python that the first argument, in our case <tt>Y& y</tt>, is the
|
|
||||||
owner of the returned reference: <tt>X&</tt>. The "<tt>1</tt>" simply specifies the
|
|
||||||
first argument. In short: "return an internal reference <tt>X&</tt> owned by the
|
|
||||||
1st argument <tt>Y& y</tt>".</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>with_custodian_and_ward</span><span class=special><</span><span class=number>1</span><span class=special>, </span><span class=number>2</span><span class=special>>
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Informs Boost.Python that the lifetime of the argument indicated by ward
|
|
||||||
(i.e. the 2nd argument: <tt>Z* z</tt>) is dependent on the lifetime of the
|
|
||||||
argument indicated by custodian (i.e. the 1st argument: <tt>Y& y</tt>).</p>
|
|
||||||
<p>
|
|
||||||
It is also important to note that we have defined two policies above. Two
|
|
||||||
or more policies can be composed by chaining. Here's the general syntax:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>policy1</span><span class=special><</span><span class=identifier>args</span><span class=special>...,
|
|
||||||
</span><span class=identifier>policy2</span><span class=special><</span><span class=identifier>args</span><span class=special>...,
|
|
||||||
</span><span class=identifier>policy3</span><span class=special><</span><span class=identifier>args</span><span class=special>...> > >
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Here is the list of predefined call policies. A complete reference detailing
|
|
||||||
these can be found <a href="../../v2/reference.html#models_of_call_policies">
|
|
||||||
here</a>.</p>
|
|
||||||
<ul><li><b>with_custodian_and_ward</b><br> Ties lifetimes of the arguments</li><li><b>with_custodian_and_ward_postcall</b><br> Ties lifetimes of the arguments and results</li><li><b>return_internal_reference</b><br> Ties lifetime of one argument to that of result</li><li><b>return_value_policy<T> with T one of:</b><br></li><li><b>reference_existing_object</b><br>naïve (dangerous) approach</li><li><b>copy_const_reference</b><br>Boost.Python v1 approach</li><li><b>copy_non_const_reference</b><br></li><li><b>manage_new_object</b><br> Adopt a pointer and hold the instance</li></ul><table width="80%" border="0" align="center">
|
|
||||||
<tr>
|
|
||||||
<td class="note_box">
|
|
||||||
<img src="theme/smiley.gif"></img> <b>Remember the Zen, Luke:</b><br><br>
|
|
||||||
"Explicit is better than implicit"<br>
|
|
||||||
"In the face of ambiguity, refuse the temptation to guess"<br> </td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<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="functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Class Data Members</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="constructors.html">
|
|
||||||
<link rel="next" href="class_properties.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>Class Data Members</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="constructors.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="class_properties.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Data members may also be exposed to Python so that they can be
|
|
||||||
accessed as attributes of the corresponding Python class. Each data
|
|
||||||
member that we wish to be exposed may be regarded as <b>read-only</b> or
|
|
||||||
<b>read-write</b>. Consider this class <tt>Var</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>Var
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=identifier>Var</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>name</span><span class=special>) : </span><span class=identifier>name</span><span class=special>(</span><span class=identifier>name</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>string </span><span class=keyword>const </span><span class=identifier>name</span><span class=special>;
|
|
||||||
</span><span class=keyword>float </span><span class=identifier>value</span><span class=special>;
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Our C++ <tt>Var</tt> class and its data members can be exposed to Python:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>Var</span><span class=special>>(</span><span class=string>"Var"</span><span class=special>, </span><span class=identifier>init</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>def_readonly</span><span class=special>(</span><span class=string>"name"</span><span class=special>, &</span><span class=identifier>Var</span><span class=special>::</span><span class=identifier>name</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def_readwrite</span><span class=special>(</span><span class=string>"value"</span><span class=special>, &</span><span class=identifier>Var</span><span class=special>::</span><span class=identifier>value</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Then, in Python, assuming we have placed our Var class inside the namespace
|
|
||||||
hello as we did before:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>x </span><span class=special>= </span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>Var</span><span class=special>(</span><span class=literal>'pi'</span><span class=special>)
|
|
||||||
>>> </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>value </span><span class=special>= </span><span class=number>3.14
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>print </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>name</span><span class=special>, </span><span class=literal>'is around'</span><span class=special>, </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>value
|
|
||||||
</span><span class=identifier>pi </span><span class=identifier>is </span><span class=identifier>around </span><span class=number>3.14
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Note that <tt>name</tt> is exposed as <b>read-only</b> while <tt>value</tt> is exposed
|
|
||||||
as <b>read-write</b>.</p>
|
|
||||||
<code><pre>
|
|
||||||
>>> x.name = 'e' # can't change name
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "<stdin>", line 1, in ?
|
|
||||||
AttributeError: can't set attribute
|
|
||||||
</pre></code><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="constructors.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="class_properties.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Class Operators/Special Functions</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="virtual_functions_with_default_implementations.html">
|
|
||||||
<link rel="next" href="functions.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>Class Operators/Special Functions</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="virtual_functions_with_default_implementations.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<a name="python_operators"></a><h2>Python Operators</h2><p>
|
|
||||||
C is well known for the abundance of operators. C++ extends this to the
|
|
||||||
extremes by allowing operator overloading. Boost.Python takes advantage of
|
|
||||||
this and makes it easy to wrap C++ operator-powered classes.</p>
|
|
||||||
<p>
|
|
||||||
Consider a file position class <tt>FilePos</tt> and a set of operators that take
|
|
||||||
on FilePos instances:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>class </span><span class=identifier>FilePos </span><span class=special>{ /*...*/ };
|
|
||||||
|
|
||||||
</span><span class=identifier>FilePos </span><span class=keyword>operator</span><span class=special>+(</span><span class=identifier>FilePos</span><span class=special>, </span><span class=keyword>int</span><span class=special>);
|
|
||||||
</span><span class=identifier>FilePos </span><span class=keyword>operator</span><span class=special>+(</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>FilePos</span><span class=special>);
|
|
||||||
</span><span class=keyword>int </span><span class=keyword>operator</span><span class=special>-(</span><span class=identifier>FilePos</span><span class=special>, </span><span class=identifier>FilePos</span><span class=special>);
|
|
||||||
</span><span class=identifier>FilePos </span><span class=keyword>operator</span><span class=special>-(</span><span class=identifier>FilePos</span><span class=special>, </span><span class=keyword>int</span><span class=special>);
|
|
||||||
</span><span class=identifier>FilePos</span><span class=special>& </span><span class=keyword>operator</span><span class=special>+=(</span><span class=identifier>FilePos</span><span class=special>&, </span><span class=keyword>int</span><span class=special>);
|
|
||||||
</span><span class=identifier>FilePos</span><span class=special>& </span><span class=keyword>operator</span><span class=special>-=(</span><span class=identifier>FilePos</span><span class=special>&, </span><span class=keyword>int</span><span class=special>);
|
|
||||||
</span><span class=keyword>bool </span><span class=keyword>operator</span><span class=special><(</span><span class=identifier>FilePos</span><span class=special>, </span><span class=identifier>FilePos</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
The class and the various operators can be mapped to Python rather easily
|
|
||||||
and intuitively:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>FilePos</span><span class=special>>(</span><span class=string>"FilePos"</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>self </span><span class=special>+ </span><span class=keyword>int</span><span class=special>()) // </span><span class=identifier>__add__
|
|
||||||
</span><span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=keyword>int</span><span class=special>() + </span><span class=identifier>self</span><span class=special>) // </span><span class=identifier>__radd__
|
|
||||||
</span><span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>self </span><span class=special>- </span><span class=identifier>self</span><span class=special>) // </span><span class=identifier>__sub__
|
|
||||||
</span><span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>self </span><span class=special>- </span><span class=keyword>int</span><span class=special>()) // </span><span class=identifier>__sub__
|
|
||||||
</span><span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>self </span><span class=special>+= </span><span class=keyword>int</span><span class=special>()) // </span><span class=identifier>__iadd__
|
|
||||||
</span><span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>self </span><span class=special>-= </span><span class=identifier>other</span><span class=special><</span><span class=keyword>int</span><span class=special>>())
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>self </span><span class=special>< </span><span class=identifier>self</span><span class=special>); // </span><span class=identifier>__lt__
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
The code snippet above is very clear and needs almost no explanation at
|
|
||||||
all. It is virtually the same as the operators' signatures. Just take
|
|
||||||
note that <tt>self</tt> refers to FilePos object. Also, not every class <tt>T</tt> that
|
|
||||||
you might need to interact with in an operator expression is (cheaply)
|
|
||||||
default-constructible. You can use <tt>other<T>()</tt> in place of an actual
|
|
||||||
<tt>T</tt> instance when writing "self expressions".</p>
|
|
||||||
<a name="special_methods"></a><h2>Special Methods</h2><p>
|
|
||||||
Python has a few more <i>Special Methods</i>. Boost.Python supports all of the
|
|
||||||
standard special method names supported by real Python class instances. A
|
|
||||||
similar set of intuitive interfaces can also be used to wrap C++ functions
|
|
||||||
that correspond to these Python <i>special functions</i>. Example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>class </span><span class=identifier>Rational
|
|
||||||
</span><span class=special>{ </span><span class=keyword>operator </span><span class=keyword>double</span><span class=special>() </span><span class=keyword>const</span><span class=special>; };
|
|
||||||
|
|
||||||
</span><span class=identifier>Rational </span><span class=identifier>pow</span><span class=special>(</span><span class=identifier>Rational</span><span class=special>, </span><span class=identifier>Rational</span><span class=special>);
|
|
||||||
</span><span class=identifier>Rational </span><span class=identifier>abs</span><span class=special>(</span><span class=identifier>Rational</span><span class=special>);
|
|
||||||
</span><span class=identifier>ostream</span><span class=special>& </span><span class=keyword>operator</span><span class=special><<(</span><span class=identifier>ostream</span><span class=special>&,</span><span class=identifier>Rational</span><span class=special>);
|
|
||||||
|
|
||||||
</span><span class=identifier>class_</span><span class=special><</span><span class=identifier>Rational</span><span class=special>>()
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>float_</span><span class=special>(</span><span class=identifier>self</span><span class=special>)) // </span><span class=identifier>__float__
|
|
||||||
</span><span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>pow</span><span class=special>(</span><span class=identifier>self</span><span class=special>, </span><span class=identifier>other</span><span class=special><</span><span class=identifier>Rational</span><span class=special>>)) // </span><span class=identifier>__pow__
|
|
||||||
</span><span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>abs</span><span class=special>(</span><span class=identifier>self</span><span class=special>)) // </span><span class=identifier>__abs__
|
|
||||||
</span><span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>str</span><span class=special>(</span><span class=identifier>self</span><span class=special>)) // </span><span class=identifier>__str__
|
|
||||||
</span><span class=special>;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Need we say more?</p>
|
|
||||||
<table width="80%" border="0" align="center">
|
|
||||||
<tr>
|
|
||||||
<td class="note_box">
|
|
||||||
<img src="theme/lens.gif"></img> What is the business of <tt>operator<<</tt> <tt>.def(str(self))</tt>?
|
|
||||||
Well, the method <tt>str</tt> requires the <tt>operator<<</tt> to do its work (i.e.
|
|
||||||
<tt>operator<<</tt> is used by the method defined by def(str(self)). </td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<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="virtual_functions_with_default_implementations.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Class Properties</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="class_data_members.html">
|
|
||||||
<link rel="next" href="inheritance.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>Class Properties</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="class_data_members.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="inheritance.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
In C++, classes with public data members are usually frowned
|
|
||||||
upon. Well designed classes that take advantage of encapsulation hide
|
|
||||||
the class' data members. The only way to access the class' data is
|
|
||||||
through access (getter/setter) functions. Access functions expose class
|
|
||||||
properties. Here's an example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>Num
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=identifier>Num</span><span class=special>();
|
|
||||||
</span><span class=keyword>float </span><span class=identifier>get</span><span class=special>() </span><span class=keyword>const</span><span class=special>;
|
|
||||||
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=keyword>float </span><span class=identifier>value</span><span class=special>);
|
|
||||||
...
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
However, in Python attribute access is fine; it doesn't neccessarily break
|
|
||||||
encapsulation to let users handle attributes directly, because the
|
|
||||||
attributes can just be a different syntax for a method call. Wrapping our
|
|
||||||
<tt>Num</tt> class using Boost.Python:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>Num</span><span class=special>>(</span><span class=string>"Num"</span><span class=special>)
|
|
||||||
.</span><span class=identifier>add_property</span><span class=special>(</span><span class=string>"rovalue"</span><span class=special>, &</span><span class=identifier>Num</span><span class=special>::</span><span class=identifier>get</span><span class=special>)
|
|
||||||
.</span><span class=identifier>add_property</span><span class=special>(</span><span class=string>"value"</span><span class=special>, &</span><span class=identifier>Num</span><span class=special>::</span><span class=identifier>get</span><span class=special>, &</span><span class=identifier>Num</span><span class=special>::</span><span class=identifier>set</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
And at last, in Python:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>x </span><span class=special>= </span><span class=identifier>Num</span><span class=special>()
|
|
||||||
>>> </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>value </span><span class=special>= </span><span class=number>3.14
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>value</span><span class=special>, </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>rovalue
|
|
||||||
</span><span class=special>(</span><span class=number>3.14</span><span class=special>, </span><span class=number>3.14</span><span class=special>)
|
|
||||||
>>> </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>rovalue </span><span class=special>= </span><span class=number>2.17 </span>##<span class=identifier>error</span><span class=special>!
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Take note that the class property <tt>rovalue</tt> is exposed as <b>read-only</b>
|
|
||||||
since the <tt>rovalue</tt> setter member function is not passed in:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>.</span><span class=identifier>add_property</span><span class=special>(</span><span class=string>"rovalue"</span><span class=special>, &</span><span class=identifier>Num</span><span class=special>::</span><span class=identifier>get</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<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="class_data_members.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="inheritance.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Class Virtual Functions</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="inheritance.html">
|
|
||||||
<link rel="next" href="deriving_a_python_class.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>Class Virtual Functions</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="inheritance.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="deriving_a_python_class.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
In this section, we shall learn how to make functions behave
|
|
||||||
polymorphically through virtual functions. Continuing our example, let us
|
|
||||||
add a virtual function to our <tt>Base</tt> class:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>Base
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=keyword>virtual </span><span class=keyword>int </span><span class=identifier>f</span><span class=special>() = </span><span class=number>0</span><span class=special>;
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Since <tt>f</tt> is a pure virtual function, <tt>Base</tt> is now an abstract
|
|
||||||
class. Given an instance of our class, the free function <tt>call_f</tt>
|
|
||||||
calls some implementation of this virtual function in a concrete
|
|
||||||
derived class:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>int </span><span class=identifier>call_f</span><span class=special>(</span><span class=identifier>Base</span><span class=special>& </span><span class=identifier>b</span><span class=special>) { </span><span class=keyword>return </span><span class=identifier>b</span><span class=special>.</span><span class=identifier>f</span><span class=special>(); }
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
To allow this function to be implemented in a Python derived class, we
|
|
||||||
need to create a class wrapper:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>BaseWrap </span><span class=special>: </span><span class=identifier>Base
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=identifier>BaseWrap</span><span class=special>(</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self_</span><span class=special>)
|
|
||||||
: </span><span class=identifier>self</span><span class=special>(</span><span class=identifier>self_</span><span class=special>) {}
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>f</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>call_method</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>self</span><span class=special>, </span><span class=string>"f"</span><span class=special>); }
|
|
||||||
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self</span><span class=special>;
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<table width="80%" border="0" align="center">
|
|
||||||
<tr>
|
|
||||||
<td class="note_box">
|
|
||||||
<img src="theme/lens.gif"></img> <b>member function and methods</b><br><br> Python, like
|
|
||||||
many object oriented languages uses the term <b>methods</b>. Methods
|
|
||||||
correspond roughly to C++'s <b>member functions</b> </td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Our class wrapper <tt>BaseWrap</tt> is derived from <tt>Base</tt>. Its overridden
|
|
||||||
virtual member function <tt>f</tt> in effect calls the corresponding method
|
|
||||||
of the Python object <tt>self</tt>, which is a pointer back to the Python
|
|
||||||
<tt>Base</tt> object holding our <tt>BaseWrap</tt> instance.</p>
|
|
||||||
<table width="80%" border="0" align="center">
|
|
||||||
<tr>
|
|
||||||
<td class="note_box">
|
|
||||||
<img src="theme/note.gif"></img> <b>Why do we need BaseWrap?</b><br><br>
|
|
||||||
|
|
||||||
<i>You may ask</i>, "Why do we need the <tt>BaseWrap</tt> derived class? This could
|
|
||||||
have been designed so that everything gets done right inside of
|
|
||||||
Base."<br><br>
|
|
||||||
|
|
||||||
One of the goals of Boost.Python is to be minimally intrusive on an
|
|
||||||
existing C++ design. In principle, it should be possible to expose the
|
|
||||||
interface for a 3rd party library without changing it. To unintrusively
|
|
||||||
hook into the virtual functions so that a Python override may be called, we
|
|
||||||
must use a derived class.<br><br>
|
|
||||||
|
|
||||||
Note however that you don't need to do this to get methods overridden
|
|
||||||
in Python to behave virtually when called <i>from</i> <b>Python</b>. The only
|
|
||||||
time you need to do the <tt>BaseWrap</tt> dance is when you have a virtual
|
|
||||||
function that's going to be overridden in Python and called
|
|
||||||
polymorphically <i>from</i> <b>C++</b>. </td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Wrapping <tt>Base</tt> and the free function <tt>call_f</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>Base</span><span class=special>, </span><span class=identifier>BaseWrap</span><span class=special>, </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>noncopyable</span><span class=special>>(</span><span class=string>"Base"</span><span class=special>, </span><span class=identifier>no_init</span><span class=special>)
|
|
||||||
;
|
|
||||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"call_f"</span><span class=special>, </span><span class=identifier>call_f</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Notice that we parameterized the <tt>class_</tt> template with <tt>BaseWrap</tt> as the
|
|
||||||
second parameter. What is <tt>noncopyable</tt>? Without it, the library will try
|
|
||||||
to create code for converting Base return values of wrapped functions to
|
|
||||||
Python. To do that, it needs Base's copy constructor... which isn't
|
|
||||||
available, since Base is an abstract class.</p>
|
|
||||||
<p>
|
|
||||||
In Python, let us try to instantiate our <tt>Base</tt> class:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>base </span><span class=special>= </span><span class=identifier>Base</span><span class=special>()
|
|
||||||
</span><span class=identifier>RuntimeError</span><span class=special>: </span><span class=identifier>This </span><span class=keyword>class </span><span class=identifier>cannot </span><span class=identifier>be </span><span class=identifier>instantiated </span><span class=identifier>from </span><span class=identifier>Python
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Why is it an error? <tt>Base</tt> is an abstract class. As such it is advisable
|
|
||||||
to define the Python wrapper with <tt>no_init</tt> as we have done above. Doing
|
|
||||||
so will disallow abstract base classes such as <tt>Base</tt> to be instantiated.</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="inheritance.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="deriving_a_python_class.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Constructors</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="exposing_classes.html">
|
|
||||||
<link rel="next" href="class_data_members.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>Constructors</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="exposing_classes.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="class_data_members.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Our previous example didn't have any explicit constructors.
|
|
||||||
Since <tt>World</tt> is declared as a plain struct, it has an implicit default
|
|
||||||
constructor. Boost.Python exposes the default constructor by default,
|
|
||||||
which is why we were able to write</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>planet </span><span class=special>= </span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>()
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
We may wish to wrap a class with a non-default constructor. Let us
|
|
||||||
build on our previous example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>World
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=identifier>World</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>): </span><span class=identifier>msg</span><span class=special>(</span><span class=identifier>msg</span><span class=special>) {} // </span><span class=identifier>added </span><span class=identifier>constructor
|
|
||||||
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; }
|
|
||||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; }
|
|
||||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>;
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
This time <tt>World</tt> has no default constructor; our previous
|
|
||||||
wrapping code would fail to compile when the library tried to expose
|
|
||||||
it. We have to tell <tt>class_<World></tt> about the constructor we want to
|
|
||||||
expose instead.</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=preprocessor>#include </span><span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>python</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>>
|
|
||||||
</span><span class=keyword>using </span><span class=keyword>namespace </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>python</span><span class=special>;
|
|
||||||
|
|
||||||
</span><span class=identifier>BOOST_PYTHON_MODULE</span><span class=special>(</span><span class=identifier>hello</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=identifier>class_</span><span class=special><</span><span class=identifier>World</span><span class=special>>(</span><span class=string>"World"</span><span class=special>, </span><span class=identifier>init</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>def</span><span class=special>(</span><span class=string>"greet"</span><span class=special>, &</span><span class=identifier>World</span><span class=special>::</span><span class=identifier>greet</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"set"</span><span class=special>, &</span><span class=identifier>World</span><span class=special>::</span><span class=identifier>set</span><span class=special>)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
<tt>init<std::string>()</tt> exposes the constructor taking in a
|
|
||||||
<tt>std::string</tt> (in Python, constructors are spelled
|
|
||||||
"<tt>"__init__"</tt>").</p>
|
|
||||||
<p>
|
|
||||||
We can expose additional constructors by passing more <tt>init<...></tt>s to
|
|
||||||
the <tt>def()</tt> member function. Say for example we have another World
|
|
||||||
constructor taking in two doubles:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>World</span><span class=special>>(</span><span class=string>"World"</span><span class=special>, </span><span class=identifier>init</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>def</span><span class=special>(</span><span class=identifier>init</span><span class=special><</span><span class=keyword>double</span><span class=special>, </span><span class=keyword>double</span><span class=special>>())
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"greet"</span><span class=special>, &</span><span class=identifier>World</span><span class=special>::</span><span class=identifier>greet</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"set"</span><span class=special>, &</span><span class=identifier>World</span><span class=special>::</span><span class=identifier>set</span><span class=special>)
|
|
||||||
;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
On the other hand, if we do not wish to expose any constructors at
|
|
||||||
all, we may use <tt>no_init</tt> instead:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>Abstract</span><span class=special>>(</span><span class=string>"Abstract"</span><span class=special>, </span><span class=identifier>no_init</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
This actually adds an <tt>__init__</tt> method which always raises a
|
|
||||||
Python RuntimeError exception.</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="exposing_classes.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="class_data_members.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Default Arguments</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="overloading.html">
|
|
||||||
<link rel="next" href="auto_overloading.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>Default Arguments</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="overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="auto_overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Boost.Python wraps (member) function pointers. Unfortunately, C++ function
|
|
||||||
pointers carry no default argument info. Take a function <tt>f</tt> with default
|
|
||||||
arguments:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>int </span><span class=identifier>f</span><span class=special>(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double </span><span class=special>= </span><span class=number>3.14</span><span class=special>, </span><span class=keyword>char </span><span class=keyword>const</span><span class=special>* = </span><span class=string>"hello"</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
But the type of a pointer to the function <tt>f</tt> has no information
|
|
||||||
about its default arguments:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>int</span><span class=special>(*</span><span class=identifier>g</span><span class=special>)(</span><span class=keyword>int</span><span class=special>,</span><span class=keyword>double</span><span class=special>,</span><span class=keyword>char </span><span class=keyword>const</span><span class=special>*) = </span><span class=identifier>f</span><span class=special>; // </span><span class=identifier>defaults </span><span class=identifier>lost</span><span class=special>!
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
When we pass this function pointer to the <tt>def</tt> function, there is no way
|
|
||||||
to retrieve the default arguments:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>f</span><span class=special>); // </span><span class=identifier>defaults </span><span class=identifier>lost</span><span class=special>!
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Because of this, when wrapping C++ code, we had to resort to manual
|
|
||||||
wrapping as outlined in the <a href="overloading.html">
|
|
||||||
previous section</a>, or
|
|
||||||
writing thin wrappers:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=comment>// write "thin wrappers"
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>f1</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>x</span><span class=special>) { </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>x</span><span class=special>); }
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>f2</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>x</span><span class=special>, </span><span class=keyword>double </span><span class=identifier>y</span><span class=special>) { </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>x</span><span class=special>,</span><span class=identifier>y</span><span class=special>); }
|
|
||||||
|
|
||||||
/*...*/
|
|
||||||
|
|
||||||
// </span><span class=identifier>in </span><span class=identifier>module </span><span class=identifier>init
|
|
||||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>f</span><span class=special>); // </span><span class=identifier>all </span><span class=identifier>arguments
|
|
||||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>f2</span><span class=special>); // </span><span class=identifier>two </span><span class=identifier>arguments
|
|
||||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>f1</span><span class=special>); // </span><span class=identifier>one </span><span class=identifier>argument
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
When you want to wrap functions (or member functions) that either:</p>
|
|
||||||
<ul><li>have default arguments, or</li><li>are overloaded with a common sequence of initial arguments</li></ul><a name="boost_python_function_overloads"></a><h2>BOOST_PYTHON_FUNCTION_OVERLOADS</h2><p>
|
|
||||||
Boost.Python now has a way to make it easier. For instance, given a function:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>int </span><span class=identifier>foo</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>char </span><span class=identifier>b </span><span class=special>= </span><span class=number>1</span><span class=special>, </span><span class=keyword>unsigned </span><span class=identifier>c </span><span class=special>= </span><span class=number>2</span><span class=special>, </span><span class=keyword>double </span><span class=identifier>d </span><span class=special>= </span><span class=number>3</span><span class=special>)
|
|
||||||
{
|
|
||||||
/*...*/
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
The macro invocation:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class=special>(</span><span class=identifier>foo_overloads</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=number>1</span><span class=special>, </span><span class=number>4</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
will automatically create the thin wrappers for us. This macro will create
|
|
||||||
a class <tt>foo_overloads</tt> that can be passed on to <tt>def(...)</tt>. The third
|
|
||||||
and fourth macro argument are the minimum arguments and maximum arguments,
|
|
||||||
respectively. In our <tt>foo</tt> function the minimum number of arguments is 1
|
|
||||||
and the maximum number of arguments is 4. The <tt>def(...)</tt> function will
|
|
||||||
automatically add all the foo variants for us:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"foo"</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>foo_overloads</span><span class=special>());
|
|
||||||
</span></pre></code>
|
|
||||||
<a name="boost_python_member_function_overloads"></a><h2>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</h2><p>
|
|
||||||
Objects here, objects there, objects here there everywhere. More frequently
|
|
||||||
than anything else, we need to expose member functions of our classes to
|
|
||||||
Python. Then again, we have the same inconveniences as before when default
|
|
||||||
arguments or overloads with a common sequence of initial arguments come
|
|
||||||
into play. Another macro is provided to make this a breeze.</p>
|
|
||||||
<p>
|
|
||||||
Like <tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt>,
|
|
||||||
<tt>BOOST_PYTHON_FUNCTION_OVERLOADS</tt> may be used to automatically create
|
|
||||||
the thin wrappers for wrapping member functions. Let's have an example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>george
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=keyword>void
|
|
||||||
</span><span class=identifier>wack_em</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>b </span><span class=special>= </span><span class=number>0</span><span class=special>, </span><span class=keyword>char </span><span class=identifier>c </span><span class=special>= </span><span class=literal>'x'</span><span class=special>)
|
|
||||||
{
|
|
||||||
/*...*/
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
The macro invocation:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class=special>(</span><span class=identifier>george_overloads</span><span class=special>, </span><span class=identifier>wack_em</span><span class=special>, </span><span class=number>1</span><span class=special>, </span><span class=number>3</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
will generate a set of thin wrappers for george's <tt>wack_em</tt> member function
|
|
||||||
accepting a minimum of 1 and a maximum of 3 arguments (i.e. the third and
|
|
||||||
fourth macro argument). The thin wrappers are all enclosed in a class named
|
|
||||||
<tt>george_overloads</tt> that can then be used as an argument to <tt>def(...)</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"wack_em"</span><span class=special>, &</span><span class=identifier>george</span><span class=special>::</span><span class=identifier>wack_em</span><span class=special>, </span><span class=identifier>george_overloads</span><span class=special>());
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
See the <a href="../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec">
|
|
||||||
overloads reference</a>
|
|
||||||
for details.</p>
|
|
||||||
<a name="init_and_optional"></a><h2>init and optional</h2><p>
|
|
||||||
A similar facility is provided for class constructors, again, with
|
|
||||||
default arguments or a sequence of overloads. Remember <tt>init<...></tt>? For example,
|
|
||||||
given a class X with a constructor:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>X
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=identifier>X</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>char </span><span class=identifier>b </span><span class=special>= </span><span class=literal>'D'</span><span class=special>, </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>c </span><span class=special>= </span><span class=string>"constructor"</span><span class=special>, </span><span class=keyword>double </span><span class=identifier>d </span><span class=special>= </span><span class=number>0.0</span><span class=special>);
|
|
||||||
/*...*/
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
You can easily add this constructor to Boost.Python in one shot:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=identifier>init</span><span class=special><</span><span class=keyword>int</span><span class=special>, </span><span class=identifier>optional</span><span class=special><</span><span class=keyword>char</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=keyword>double</span><span class=special>> >())
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Notice the use of <tt>init<...></tt> and <tt>optional<...></tt> to signify the default
|
|
||||||
(optional arguments).</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="overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="auto_overloading.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Derived Object types</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="basic_interface.html">
|
|
||||||
<link rel="next" href="extracting_c___objects.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>Derived Object types</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="basic_interface.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="extracting_c___objects.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Boost.Python comes with a set of derived <tt>object</tt> types corresponding to
|
|
||||||
that of Python's:</p>
|
|
||||||
<ul><li>list</li><li>dict</li><li>tuple</li><li>str</li><li>long_</li><li>enum</li></ul><p>
|
|
||||||
These derived <tt>object</tt> types act like real Python types. For instance:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>str</span><span class=special>(</span><span class=number>1</span><span class=special>) ==> </span><span class=string>"1"
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Wherever appropriate, a particular derived <tt>object</tt> has corresponding
|
|
||||||
Python type's methods. For instance, <tt>dict</tt> has a <tt>keys()</tt> method:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>d</span><span class=special>.</span><span class=identifier>keys</span><span class=special>()
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
<tt>make_tuple</tt> is provided for declaring <i>tuple literals</i>. Example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>make_tuple</span><span class=special>(</span><span class=number>123</span><span class=special>, </span><span class=literal>'D'</span><span class=special>, </span><span class=string>"Hello, World"</span><span class=special>, </span><span class=number>0.0</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
In C++, when Boost.Python <tt>object</tt>s are used as arguments to functions,
|
|
||||||
subtype matching is required. For example, when a function <tt>f</tt>, as
|
|
||||||
declared below, is wrapped, it will only accept instances of Python's
|
|
||||||
<tt>str</tt> type and subtypes.</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>void </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>str </span><span class=identifier>name</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=identifier>object </span><span class=identifier>n2 </span><span class=special>= </span><span class=identifier>name</span><span class=special>.</span><span class=identifier>attr</span><span class=special>(</span><span class=string>"upper"</span><span class=special>)(); // </span><span class=identifier>NAME </span><span class=special>= </span><span class=identifier>name</span><span class=special>.</span><span class=identifier>upper</span><span class=special>()
|
|
||||||
</span><span class=identifier>str </span><span class=identifier>NAME </span><span class=special>= </span><span class=identifier>name</span><span class=special>.</span><span class=identifier>upper</span><span class=special>(); // </span><span class=identifier>better
|
|
||||||
</span><span class=identifier>object </span><span class=identifier>msg </span><span class=special>= </span><span class=string>"%s is bigger than %s" </span><span class=special>% </span><span class=identifier>make_tuple</span><span class=special>(</span><span class=identifier>NAME</span><span class=special>,</span><span class=identifier>name</span><span class=special>);
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
In finer detail:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>str </span><span class=identifier>NAME </span><span class=special>= </span><span class=identifier>name</span><span class=special>.</span><span class=identifier>upper</span><span class=special>();
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Illustrates that we provide versions of the str type's methods as C++
|
|
||||||
member functions.</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>object </span><span class=identifier>msg </span><span class=special>= </span><span class=string>"%s is bigger than %s" </span><span class=special>% </span><span class=identifier>make_tuple</span><span class=special>(</span><span class=identifier>NAME</span><span class=special>,</span><span class=identifier>name</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Demonstrates that you can write the C++ equivalent of <tt>"format" % x,y,z</tt>
|
|
||||||
in Python, which is useful since there's no easy way to do that in std C++.</p>
|
|
||||||
<p>
|
|
||||||
<img src="theme/alert.gif"></img> <b>Beware</b> the common pitfall of forgetting that the constructors
|
|
||||||
of most of Python's mutable types make copies, just as in Python.</p>
|
|
||||||
<p>
|
|
||||||
Python:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>d </span><span class=special>= </span><span class=identifier>dict</span><span class=special>(</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>__dict__</span><span class=special>) </span>##<span class=identifier>copies </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>__dict__
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>d</span><span class=special>[</span><span class=literal>'whatever'</span><span class=special>] </span>##<span class=identifier>modifies </span><span class=identifier>the </span><span class=identifier>copy
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
C++:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>dict </span><span class=identifier>d</span><span class=special>(</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>attr</span><span class=special>(</span><span class=string>"__dict__"</span><span class=special>)); </span>##<span class=identifier>copies </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>__dict__
|
|
||||||
</span><span class=identifier>d</span><span class=special>[</span><span class=literal>'whatever'</span><span class=special>] = </span><span class=number>3</span><span class=special>; </span>##<span class=identifier>modifies </span><span class=identifier>the </span><span class=identifier>copy
|
|
||||||
</span></pre></code>
|
|
||||||
<a name="class__lt_t_gt__as_objects"></a><h2>class_<T> as objects</h2><p>
|
|
||||||
Due to the dynamic nature of Boost.Python objects, any <tt>class_<T></tt> may
|
|
||||||
also be one of these types! The following code snippet wraps the class
|
|
||||||
(type) object.</p>
|
|
||||||
<p>
|
|
||||||
We can use this to create wrapped instances. Example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>object </span><span class=identifier>vec345 </span><span class=special>= (
|
|
||||||
</span><span class=identifier>class_</span><span class=special><</span><span class=identifier>Vec2</span><span class=special>>(</span><span class=string>"Vec2"</span><span class=special>, </span><span class=identifier>init</span><span class=special><</span><span class=keyword>double</span><span class=special>, </span><span class=keyword>double</span><span class=special>>())
|
|
||||||
.</span><span class=identifier>def_readonly</span><span class=special>(</span><span class=string>"length"</span><span class=special>, &</span><span class=identifier>Point</span><span class=special>::</span><span class=identifier>length</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def_readonly</span><span class=special>(</span><span class=string>"angle"</span><span class=special>, &</span><span class=identifier>Point</span><span class=special>::</span><span class=identifier>angle</span><span class=special>)
|
|
||||||
)(</span><span class=number>3.0</span><span class=special>, </span><span class=number>4.0</span><span class=special>);
|
|
||||||
|
|
||||||
</span><span class=identifier>assert</span><span class=special>(</span><span class=identifier>vec345</span><span class=special>.</span><span class=identifier>attr</span><span class=special>(</span><span class=string>"length"</span><span class=special>) == </span><span class=number>5.0</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<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="basic_interface.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="extracting_c___objects.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Deriving a Python Class</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="class_virtual_functions.html">
|
|
||||||
<link rel="next" href="virtual_functions_with_default_implementations.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>Deriving a Python Class</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="class_virtual_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="virtual_functions_with_default_implementations.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Continuing, we can derive from our base class Base in Python and override
|
|
||||||
the virtual function in Python. Before we can do that, we have to set up
|
|
||||||
our <tt>class_</tt> wrapper as:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>Base</span><span class=special>, </span><span class=identifier>BaseWrap</span><span class=special>, </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>noncopyable</span><span class=special>>(</span><span class=string>"Base"</span><span class=special>)
|
|
||||||
;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Otherwise, we have to suppress the Base class' <tt>no_init</tt> by adding an
|
|
||||||
<tt>__init__()</tt> method to all our derived classes. <tt>no_init</tt> actually adds
|
|
||||||
an <tt>__init__</tt> method that raises a Python RuntimeError exception.</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=keyword>class </span><span class=identifier>Derived</span><span class=special>(</span><span class=identifier>Base</span><span class=special>):
|
|
||||||
... </span><span class=identifier>def </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>self</span><span class=special>):
|
|
||||||
... </span><span class=keyword>return </span><span class=number>42
|
|
||||||
</span><span class=special>...
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Cool eh? A Python class deriving from a C++ class!</p>
|
|
||||||
<p>
|
|
||||||
Let's now make an instance of our Python class <tt>Derived</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>derived </span><span class=special>= </span><span class=identifier>Derived</span><span class=special>()
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Calling <tt>derived.f()</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>derived</span><span class=special>.</span><span class=identifier>f</span><span class=special>()
|
|
||||||
</span><span class=number>42
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Will yield the expected result. Finally, calling calling the free function
|
|
||||||
<tt>call_f</tt> with <tt>derived</tt> as argument:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>call_f</span><span class=special>(</span><span class=identifier>derived</span><span class=special>)
|
|
||||||
</span><span class=number>42
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Will also yield the expected result.</p>
|
|
||||||
<p>
|
|
||||||
Here's what's happening:</p>
|
|
||||||
<ol><li><tt>call_f(derived)</tt> is called in Python</li><li>This corresponds to <tt>def("call_f", call_f);</tt>. Boost.Python dispatches this call.</li><li><tt>int call_f(Base& b) { return b.f(); }</tt> accepts the call.</li><li>The overridden virtual function <tt>f</tt> of <tt>BaseWrap</tt> is called.</li><li><tt>call_method<int>(self, "f");</tt> dispatches the call back to Python.</li><li><tt>def f(self): return 42</tt> is finally called.</li></ol><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="class_virtual_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="virtual_functions_with_default_implementations.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Embedding</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="enums.html">
|
|
||||||
<link rel="next" href="using_the_interpreter.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>Embedding</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="enums.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="using_the_interpreter.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
By now you should know how to use Boost.Python to call your C++ code from
|
|
||||||
Python. However, sometimes you may need to do the reverse: call Python code
|
|
||||||
from the C++-side. This requires you to <i>embed</i> the Python interpreter
|
|
||||||
into your C++ program.</p>
|
|
||||||
<p>
|
|
||||||
Currently, Boost.Python does not directly support everything you'll need
|
|
||||||
when embedding. Therefore you'll need to use the
|
|
||||||
<a href="http://www.python.org/doc/current/api/api.html">
|
|
||||||
Python/C API</a> to fill in
|
|
||||||
the gaps. However, Boost.Python already makes embedding a lot easier and,
|
|
||||||
in a future version, it may become unnecessary to touch the Python/C API at
|
|
||||||
all. So stay tuned... <img src="theme/smiley.gif"></img></p>
|
|
||||||
<a name="building_embedded_programs"></a><h2>Building embedded programs</h2><p>
|
|
||||||
To be able to use embedding in your programs, they have to be linked to
|
|
||||||
both Boost.Python's and Python's static link library.</p>
|
|
||||||
<p>
|
|
||||||
Boost.Python's static link library comes in two variants. Both are located
|
|
||||||
in Boost's <tt>/libs/python/build/bin-stage</tt> subdirectory. On Windows, the
|
|
||||||
variants are called <tt>boost_python.lib</tt> (for release builds) and
|
|
||||||
<tt>boost_python_debug.lib</tt> (for debugging). If you can't find the
|
|
||||||
libraries, you probably haven't built Boost.Python yet. See <a
|
|
||||||
href="../../building.html">Building and Testing</a> on how to do
|
|
||||||
this.</p>
|
|
||||||
<p>
|
|
||||||
Python's static link library can be found in the <tt>/libs</tt> subdirectory of
|
|
||||||
your Python directory. On Windows it is called pythonXY.lib where X.Y is
|
|
||||||
your major Python version number.</p>
|
|
||||||
<p>
|
|
||||||
Additionally, Python's <tt>/include</tt> subdirectory has to be added to your
|
|
||||||
include path.</p>
|
|
||||||
<p>
|
|
||||||
In a Jamfile, all the above boils down to:</p>
|
|
||||||
<code><pre>
|
|
||||||
projectroot c:\projects\embedded_program ; # location of the program
|
|
||||||
|
|
||||||
# bring in the rules for python
|
|
||||||
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
|
|
||||||
include python.jam ;
|
|
||||||
|
|
||||||
exe embedded_program # name of the executable
|
|
||||||
: #sources
|
|
||||||
embedded_program.cpp
|
|
||||||
: # requirements
|
|
||||||
<find-library>boost_python <library-path>c:\boost\libs\python
|
|
||||||
$(PYTHON_PROPERTIES)
|
|
||||||
<library-path>$(PYTHON_LIB_PATH)
|
|
||||||
<find-library>$(PYTHON_EMBEDDED_LIBRARY) ;
|
|
||||||
</pre></code><a name="getting_started"></a><h2>Getting started</h2><p>
|
|
||||||
Being able to build is nice, but there is nothing to build yet. Embedding
|
|
||||||
the Python interpreter into one of your C++ programs requires these 4
|
|
||||||
steps:</p>
|
|
||||||
<ol><li>#include <tt><boost/python.hpp></tt><br><br></li><li>Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-652">
|
|
||||||
Py_Initialize</a>() to start the interpreter and create the <tt>__main__</tt> module.<br><br></li><li>Call other Python C API routines to use the interpreter.<br><br></li><li>Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656">
|
|
||||||
Py_Finalize</a>() to stop the interpreter and release its resources.</li></ol><p>
|
|
||||||
(Of course, there can be other C++ code between all of these steps.)</p>
|
|
||||||
<blockquote><p><i><b>Now that we can embed the interpreter in our programs, lets see how to put it to use...</b></i></p></blockquote><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="enums.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="using_the_interpreter.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 Dirk Gerrits<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>
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Enums</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="extracting_c___objects.html">
|
|
||||||
<link rel="next" href="embedding.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>Enums</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="extracting_c___objects.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="embedding.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Boost.Python has a nifty facility to capture and wrap C++ enums. While
|
|
||||||
Python has no <tt>enum</tt> type, we'll often want to expose our C++ enums to
|
|
||||||
Python as an <tt>int</tt>. Boost.Python's enum facility makes this easy while
|
|
||||||
taking care of the proper conversions from Python's dynamic typing to C++'s
|
|
||||||
strong static typing (in C++, ints cannot be implicitly converted to
|
|
||||||
enums). To illustrate, given a C++ enum:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>enum </span><span class=identifier>choice </span><span class=special>{ </span><span class=identifier>red</span><span class=special>, </span><span class=identifier>blue </span><span class=special>};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
the construct:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>enum_</span><span class=special><</span><span class=identifier>choice</span><span class=special>>(</span><span class=string>"choice"</span><span class=special>)
|
|
||||||
.</span><span class=identifier>value</span><span class=special>(</span><span class=string>"red"</span><span class=special>, </span><span class=identifier>red</span><span class=special>)
|
|
||||||
.</span><span class=identifier>value</span><span class=special>(</span><span class=string>"blue"</span><span class=special>, </span><span class=identifier>blue</span><span class=special>)
|
|
||||||
;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
can be used to expose to Python. The new enum type is created in the
|
|
||||||
current <tt>scope()</tt>, which is usually the current module. The snippet above
|
|
||||||
creates a Python class derived from Python's <tt>int</tt> type which is
|
|
||||||
associated with the C++ type passed as its first parameter.</p>
|
|
||||||
<table width="80%" border="0" align="center">
|
|
||||||
<tr>
|
|
||||||
<td class="note_box">
|
|
||||||
<img src="theme/lens.gif"></img> <b>what is a scope?</b><br><br> The scope is a class that has an
|
|
||||||
associated global Python object which controls the Python namespace in
|
|
||||||
which new extension classes and wrapped functions will be defined as
|
|
||||||
attributes. Details can be found <a href="../../v2/scope.html">
|
|
||||||
here</a>. </td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
You can access those values in Python as</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>my_module</span><span class=special>.</span><span class=identifier>choice</span><span class=special>.</span><span class=identifier>red
|
|
||||||
</span><span class=identifier>my_module</span><span class=special>.</span><span class=identifier>choice</span><span class=special>.</span><span class=identifier>red
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
where my_module is the module where the enum is declared. You can also
|
|
||||||
create a new scope around a class:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>scope </span><span class=identifier>in_X </span><span class=special>= </span><span class=identifier>class_</span><span class=special><</span><span class=identifier>X</span><span class=special>>(</span><span class=string>"X"</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>( ... )
|
|
||||||
.</span><span class=identifier>def</span><span class=special>( ... )
|
|
||||||
;
|
|
||||||
|
|
||||||
// </span><span class=identifier>Expose </span><span class=identifier>X</span><span class=special>::</span><span class=identifier>nested </span><span class=identifier>as </span><span class=identifier>X</span><span class=special>.</span><span class=identifier>nested
|
|
||||||
</span><span class=identifier>enum_</span><span class=special><</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>nested</span><span class=special>>(</span><span class=string>"nested"</span><span class=special>)
|
|
||||||
.</span><span class=identifier>value</span><span class=special>(</span><span class=string>"red"</span><span class=special>, </span><span class=identifier>red</span><span class=special>)
|
|
||||||
.</span><span class=identifier>value</span><span class=special>(</span><span class=string>"blue"</span><span class=special>, </span><span class=identifier>blue</span><span class=special>)
|
|
||||||
;
|
|
||||||
</span></pre></code>
|
|
||||||
<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="extracting_c___objects.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="embedding.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Exception Translation</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="iterators.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>Exception Translation</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="iterators.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>
|
|
||||||
All C++ exceptions must be caught at the boundary with Python code. This
|
|
||||||
boundary is the point where C++ meets Python. Boost.Python provides a
|
|
||||||
default exception handler that translates selected standard exceptions,
|
|
||||||
then gives up:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>raise </span><span class=identifier>RuntimeError</span><span class=special>, </span><span class=literal>'unidentifiable C++ Exception'
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Users may provide custom translation. Here's an example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>PodBayDoorException</span><span class=special>;
|
|
||||||
</span><span class=keyword>void </span><span class=identifier>translator</span><span class=special>(</span><span class=identifier>PodBayDoorException </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>x</span><span class=special>) {
|
|
||||||
</span><span class=identifier>PyErr_SetString</span><span class=special>(</span><span class=identifier>PyExc_UserWarning</span><span class=special>, </span><span class=string>"I'm sorry Dave..."</span><span class=special>);
|
|
||||||
}
|
|
||||||
</span><span class=identifier>BOOST_PYTHON_MODULE</span><span class=special>(</span><span class=identifier>kubrick</span><span class=special>) {
|
|
||||||
</span><span class=identifier>register_exception_translator</span><span class=special><
|
|
||||||
</span><span class=identifier>PodBayDoorException</span><span class=special>>(</span><span class=identifier>translator</span><span class=special>);
|
|
||||||
...
|
|
||||||
</span></pre></code>
|
|
||||||
<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="iterators.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 © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Exposing Classes</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="building_hello_world.html">
|
|
||||||
<link rel="next" href="constructors.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>Exposing Classes</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="building_hello_world.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="constructors.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Now let's expose a C++ class to Python.</p>
|
|
||||||
<p>
|
|
||||||
Consider a C++ class/struct that we want to expose to Python:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>World
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-></span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; }
|
|
||||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>msg</span><span class=special>; }
|
|
||||||
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>;
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
We can expose this to Python by writing a corresponding Boost.Python
|
|
||||||
C++ Wrapper:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=preprocessor>#include </span><span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>python</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>>
|
|
||||||
</span><span class=keyword>using </span><span class=keyword>namespace </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>python</span><span class=special>;
|
|
||||||
|
|
||||||
</span><span class=identifier>BOOST_PYTHON_MODULE</span><span class=special>(</span><span class=identifier>hello</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=identifier>class_</span><span class=special><</span><span class=identifier>World</span><span class=special>>(</span><span class=string>"World"</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"greet"</span><span class=special>, &</span><span class=identifier>World</span><span class=special>::</span><span class=identifier>greet</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"set"</span><span class=special>, &</span><span class=identifier>World</span><span class=special>::</span><span class=identifier>set</span><span class=special>)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Here, we wrote a C++ class wrapper that exposes the member functions
|
|
||||||
<tt>greet</tt> and <tt>set</tt>. Now, after building our module as a shared library, we
|
|
||||||
may use our class <tt>World</tt> in Python. Here's a sample Python session:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>import </span><span class=identifier>hello
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>planet </span><span class=special>= </span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>()
|
|
||||||
>>> </span><span class=identifier>planet</span><span class=special>.</span><span class=identifier>set</span><span class=special>(</span><span class=literal>'howdy'</span><span class=special>)
|
|
||||||
>>> </span><span class=identifier>planet</span><span class=special>.</span><span class=identifier>greet</span><span class=special>()
|
|
||||||
</span><span class=literal>'howdy'
|
|
||||||
</span></pre></code>
|
|
||||||
<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="building_hello_world.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="constructors.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Extracting C++ objects</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="derived_object_types.html">
|
|
||||||
<link rel="next" href="enums.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>Extracting C++ objects</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="derived_object_types.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="enums.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
At some point, we will need to get C++ values out of object instances. This
|
|
||||||
can be achieved with the <tt>extract<T></tt> function. Consider the following:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>double </span><span class=identifier>x </span><span class=special>= </span><span class=identifier>o</span><span class=special>.</span><span class=identifier>attr</span><span class=special>(</span><span class=string>"length"</span><span class=special>); // </span><span class=identifier>compile </span><span class=identifier>error
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
In the code above, we got a compiler error because Boost.Python
|
|
||||||
<tt>object</tt> can't be implicitly converted to <tt>double</tt>s. Instead, what
|
|
||||||
we wanted to do above can be achieved by writing:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>double </span><span class=identifier>l </span><span class=special>= </span><span class=identifier>extract</span><span class=special><</span><span class=keyword>double</span><span class=special>>(</span><span class=identifier>o</span><span class=special>.</span><span class=identifier>attr</span><span class=special>(</span><span class=string>"length"</span><span class=special>));
|
|
||||||
</span><span class=identifier>Vec2</span><span class=special>& </span><span class=identifier>v </span><span class=special>= </span><span class=identifier>extract</span><span class=special><</span><span class=identifier>Vec2</span><span class=special>&>(</span><span class=identifier>o</span><span class=special>);
|
|
||||||
</span><span class=identifier>assert</span><span class=special>(</span><span class=identifier>l </span><span class=special>== </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>length</span><span class=special>());
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
The first line attempts to extract the "length" attribute of the
|
|
||||||
Boost.Python <tt>object</tt> <tt>o</tt>. The second line attempts to <i>extract</i> the
|
|
||||||
<tt>Vec2</tt> object from held by the Boost.Python <tt>object</tt> <tt>o</tt>.</p>
|
|
||||||
<p>
|
|
||||||
Take note that we said "attempt to" above. What if the Boost.Python
|
|
||||||
<tt>object</tt> <tt>o</tt> does not really hold a <tt>Vec2</tt> type? This is certainly
|
|
||||||
a possibility considering the dynamic nature of Python <tt>object</tt>s. To
|
|
||||||
be on the safe side, if the C++ type can't be extracted, an
|
|
||||||
appropriate exception is thrown. To avoid an exception, we need to
|
|
||||||
test for extractibility:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>extract</span><span class=special><</span><span class=identifier>Vec2</span><span class=special>&> </span><span class=identifier>x</span><span class=special>(</span><span class=identifier>o</span><span class=special>);
|
|
||||||
</span><span class=keyword>if </span><span class=special>(</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>check</span><span class=special>()) {
|
|
||||||
</span><span class=identifier>Vec2</span><span class=special>& </span><span class=identifier>v </span><span class=special>= </span><span class=identifier>x</span><span class=special>(); ...
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
<img src="theme/bulb.gif"></img> The astute reader might have noticed that the <tt>extract<T></tt>
|
|
||||||
facility in fact solves the mutable copying problem:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>dict </span><span class=identifier>d </span><span class=special>= </span><span class=identifier>extract</span><span class=special><</span><span class=identifier>dict</span><span class=special>>(</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>attr</span><span class=special>(</span><span class=string>"__dict__"</span><span class=special>));
|
|
||||||
</span><span class=identifier>d</span><span class=special>[</span><span class=literal>'whatever'</span><span class=special>] = </span><span class=number>3</span><span class=special>; </span>##<span class=identifier>modifies </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>__dict__ </span><span class=special>!
|
|
||||||
</span></pre></code>
|
|
||||||
<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="derived_object_types.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="enums.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Functions</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="class_operators_special_functions.html">
|
|
||||||
<link rel="next" href="call_policies.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>Functions</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="class_operators_special_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="call_policies.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
In this chapter, we'll look at Boost.Python powered functions in closer
|
|
||||||
detail. We shall see some facilities to make exposing C++ functions to
|
|
||||||
Python safe from potential pifalls such as dangling pointers and
|
|
||||||
references. We shall also see facilities that will make it even easier for
|
|
||||||
us to expose C++ functions that take advantage of C++ features such as
|
|
||||||
overloading and default arguments.</p>
|
|
||||||
<blockquote><p><i>Read on...</i></p></blockquote><p>
|
|
||||||
But before you do, you might want to fire up Python 2.2 or later and type
|
|
||||||
<tt>>>> import this</tt>.</p>
|
|
||||||
<code><pre>
|
|
||||||
>>> import this
|
|
||||||
The Zen of Python, by Tim Peters
|
|
||||||
Beautiful is better than ugly.
|
|
||||||
Explicit is better than implicit.
|
|
||||||
Simple is better than complex.
|
|
||||||
Complex is better than complicated.
|
|
||||||
Flat is better than nested.
|
|
||||||
Sparse is better than dense.
|
|
||||||
Readability counts.
|
|
||||||
Special cases aren't special enough to break the rules.
|
|
||||||
Although practicality beats purity.
|
|
||||||
Errors should never pass silently.
|
|
||||||
Unless explicitly silenced.
|
|
||||||
In the face of ambiguity, refuse the temptation to guess.
|
|
||||||
There should be one-- and preferably only one --obvious way to do it
|
|
||||||
Although that way may not be obvious at first unless you're Dutch.
|
|
||||||
Now is better than never.
|
|
||||||
Although never is often better than *right* now.
|
|
||||||
If the implementation is hard to explain, it's a bad idea.
|
|
||||||
If the implementation is easy to explain, it may be a good idea.
|
|
||||||
Namespaces are one honking great idea -- let's do more of those!
|
|
||||||
</pre></code><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="class_operators_special_functions.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="call_policies.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Inheritance</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="class_properties.html">
|
|
||||||
<link rel="next" href="class_virtual_functions.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>Inheritance</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="class_properties.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="class_virtual_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
In the previous examples, we dealt with classes that are not polymorphic.
|
|
||||||
This is not often the case. Much of the time, we will be wrapping
|
|
||||||
polymorphic classes and class hierarchies related by inheritance. We will
|
|
||||||
often have to write Boost.Python wrappers for classes that are derived from
|
|
||||||
abstract base classes.</p>
|
|
||||||
<p>
|
|
||||||
Consider this trivial inheritance structure:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>Base </span><span class=special>{ </span><span class=keyword>virtual </span><span class=special>~</span><span class=identifier>Base</span><span class=special>(); };
|
|
||||||
</span><span class=keyword>struct </span><span class=identifier>Derived </span><span class=special>: </span><span class=identifier>Base </span><span class=special>{};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
And a set of C++ functions operating on <tt>Base</tt> and <tt>Derived</tt> object
|
|
||||||
instances:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>void </span><span class=identifier>b</span><span class=special>(</span><span class=identifier>Base</span><span class=special>*);
|
|
||||||
</span><span class=keyword>void </span><span class=identifier>d</span><span class=special>(</span><span class=identifier>Derived</span><span class=special>*);
|
|
||||||
</span><span class=identifier>Base</span><span class=special>* </span><span class=identifier>factory</span><span class=special>() { </span><span class=keyword>return </span><span class=keyword>new </span><span class=identifier>Derived</span><span class=special>; }
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
We've seen how we can wrap the base class <tt>Base</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>Base</span><span class=special>>(</span><span class=string>"Base"</span><span class=special>)
|
|
||||||
/*...*/
|
|
||||||
;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Now we can inform Boost.Python of the inheritance relationship between
|
|
||||||
<tt>Derived</tt> and its base class <tt>Base</tt>. Thus:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>Derived</span><span class=special>, </span><span class=identifier>bases</span><span class=special><</span><span class=identifier>Base</span><span class=special>> >(</span><span class=string>"Derived"</span><span class=special>)
|
|
||||||
/*...*/
|
|
||||||
;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Doing so, we get some things for free:</p>
|
|
||||||
<ol><li>Derived automatically inherits all of Base's Python methods (wrapped C++ member functions)</li><li><b>If</b> Base is polymorphic, <tt>Derived</tt> objects which have been passed to Python via a pointer or reference to <tt>Base</tt> can be passed where a pointer or reference to <tt>Derived</tt> is expected.</li></ol><p>
|
|
||||||
Now, we shall expose the C++ free functions <tt>b</tt> and <tt>d</tt> and <tt>factory</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>def</span><span class=special>(</span><span class=string>"b"</span><span class=special>, </span><span class=identifier>b</span><span class=special>);
|
|
||||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"d"</span><span class=special>, </span><span class=identifier>d</span><span class=special>);
|
|
||||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"factory"</span><span class=special>, </span><span class=identifier>factory</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Note that free function <tt>factory</tt> is being used to generate new
|
|
||||||
instances of class <tt>Derived</tt>. In such cases, we use
|
|
||||||
<tt>return_value_policy<manage_new_object></tt> to instruct Python to adopt
|
|
||||||
the pointer to <tt>Base</tt> and hold the instance in a new Python <tt>Base</tt>
|
|
||||||
object until the the Python object is destroyed. We shall see more of
|
|
||||||
Boost.Python <a href="call_policies.html">
|
|
||||||
call policies</a> later.</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=comment>// Tell Python to take ownership of factory's result
|
|
||||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"factory"</span><span class=special>, </span><span class=identifier>factory</span><span class=special>,
|
|
||||||
</span><span class=identifier>return_value_policy</span><span class=special><</span><span class=identifier>manage_new_object</span><span class=special>>());
|
|
||||||
</span></pre></code>
|
|
||||||
<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="class_properties.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="class_virtual_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Iterators</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="using_the_interpreter.html">
|
|
||||||
<link rel="next" href="exception_translation.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>Iterators</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="using_the_interpreter.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="exception_translation.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
In C++, and STL in particular, we see iterators everywhere. Python also has
|
|
||||||
iterators, but these are two very different beasts.</p>
|
|
||||||
<p>
|
|
||||||
<b>C++ iterators:</b></p>
|
|
||||||
<ul><li>C++ has 5 type categories (random-access, bidirectional, forward, input, output)</li><li>There are 2 Operation categories: reposition, access</li><li>A pair of iterators is needed to represent a (first/last) range.</li></ul><p>
|
|
||||||
<b>Python Iterators:</b></p>
|
|
||||||
<ul><li>1 category (forward)</li><li>1 operation category (next())</li><li>Raises StopIteration exception at end</li></ul><p>
|
|
||||||
The typical Python iteration protocol: <tt><b>for y in x...</b></tt> is as follows:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>iter </span><span class=special>= </span><span class=identifier>x</span><span class=special>.</span><span class=identifier>__iter__</span><span class=special>() </span>##<span class=identifier>get </span><span class=identifier>iterator
|
|
||||||
</span><span class=keyword>try</span><span class=special>:
|
|
||||||
</span><span class=keyword>while </span><span class=number>1</span><span class=special>:
|
|
||||||
</span><span class=identifier>y </span><span class=special>= </span><span class=identifier>iter</span><span class=special>.</span><span class=identifier>next</span><span class=special>() </span>##<span class=identifier>get </span><span class=identifier>each </span><span class=identifier>item
|
|
||||||
</span><span class=special>... </span>##<span class=identifier>process </span><span class=identifier>y
|
|
||||||
</span><span class=identifier>except </span><span class=identifier>StopIteration</span><span class=special>: </span><span class=identifier>pass </span>##<span class=identifier>iterator </span><span class=identifier>exhausted
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Boost.Python provides some mechanisms to make C++ iterators play along
|
|
||||||
nicely as Python iterators. What we need to do is to produce
|
|
||||||
appropriate __iter__ function from C++ iterators that is compatible
|
|
||||||
with the Python iteration protocol. For example:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>object </span><span class=identifier>get_iterator </span><span class=special>= </span><span class=identifier>iterator</span><span class=special><</span><span class=identifier>vector</span><span class=special><</span><span class=keyword>int</span><span class=special>> >();
|
|
||||||
</span><span class=identifier>object </span><span class=identifier>iter </span><span class=special>= </span><span class=identifier>get_iterator</span><span class=special>(</span><span class=identifier>v</span><span class=special>);
|
|
||||||
</span><span class=identifier>object </span><span class=identifier>first </span><span class=special>= </span><span class=identifier>iter</span><span class=special>.</span><span class=identifier>next</span><span class=special>();
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Or for use in class_<>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"__iter__"</span><span class=special>, </span><span class=identifier>iterator</span><span class=special><</span><span class=identifier>vector</span><span class=special><</span><span class=keyword>int</span><span class=special>> >())
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
<b>range</b></p>
|
|
||||||
<p>
|
|
||||||
We can create a Python savvy iterator using the range function:</p>
|
|
||||||
<ul><li>range(start, finish)</li><li>range<Policies,Target>(start, finish)</li></ul><p>
|
|
||||||
Here, start/finish may be one of:</p>
|
|
||||||
<ul><li>member data pointers</li><li>member function pointers</li><li>adaptable function object (use Target parameter)</li></ul><p>
|
|
||||||
<b>iterator</b></p>
|
|
||||||
<ul><li>iterator<T, Policies>()</li></ul><p>
|
|
||||||
Given a container <tt>T</tt>, iterator is a shortcut that simply calls <tt>range</tt>
|
|
||||||
with &T::begin, &T::end.</p>
|
|
||||||
<p>
|
|
||||||
Let's put this into action... Here's an example from some hypothetical
|
|
||||||
bogon Particle accelerator code:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>f </span><span class=special>= </span><span class=identifier>Field</span><span class=special>()
|
|
||||||
</span><span class=keyword>for </span><span class=identifier>x </span><span class=identifier>in </span><span class=identifier>f</span><span class=special>.</span><span class=identifier>pions</span><span class=special>:
|
|
||||||
</span><span class=identifier>smash</span><span class=special>(</span><span class=identifier>x</span><span class=special>)
|
|
||||||
</span><span class=keyword>for </span><span class=identifier>y </span><span class=identifier>in </span><span class=identifier>f</span><span class=special>.</span><span class=identifier>bogons</span><span class=special>:
|
|
||||||
</span><span class=identifier>count</span><span class=special>(</span><span class=identifier>y</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Now, our C++ Wrapper:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>F</span><span class=special>>(</span><span class=string>"Field"</span><span class=special>)
|
|
||||||
.</span><span class=identifier>property</span><span class=special>(</span><span class=string>"pions"</span><span class=special>, </span><span class=identifier>range</span><span class=special>(&</span><span class=identifier>F</span><span class=special>::</span><span class=identifier>p_begin</span><span class=special>, &</span><span class=identifier>F</span><span class=special>::</span><span class=identifier>p_end</span><span class=special>))
|
|
||||||
.</span><span class=identifier>property</span><span class=special>(</span><span class=string>"bogons"</span><span class=special>, </span><span class=identifier>range</span><span class=special>(&</span><span class=identifier>F</span><span class=special>::</span><span class=identifier>b_begin</span><span class=special>, &</span><span class=identifier>F</span><span class=special>::</span><span class=identifier>b_end</span><span class=special>));
|
|
||||||
</span></pre></code>
|
|
||||||
<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="using_the_interpreter.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="exception_translation.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Object Interface</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="auto_overloading.html">
|
|
||||||
<link rel="next" href="basic_interface.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>Object Interface</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="auto_overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="basic_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Python is dynamically typed, unlike C++ which is statically typed. Python
|
|
||||||
variables may hold an integer, a float, list, dict, tuple, str, long etc.,
|
|
||||||
among other things. In the viewpoint of Boost.Python and C++, these
|
|
||||||
Pythonic variables are just instances of class <tt>object</tt>. We shall see in
|
|
||||||
this chapter how to deal with Python objects.</p>
|
|
||||||
<p>
|
|
||||||
As mentioned, one of the goals of Boost.Python is to provide a
|
|
||||||
bidirectional mapping between C++ and Python while maintaining the Python
|
|
||||||
feel. Boost.Python C++ <tt>object</tt>s are as close as possible to Python. This
|
|
||||||
should minimize the learning curve significantly.</p>
|
|
||||||
<p>
|
|
||||||
<img src="theme/python.png"></img></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="auto_overloading.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="basic_interface.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Overloading</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="call_policies.html">
|
|
||||||
<link rel="next" href="default_arguments.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>Overloading</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="call_policies.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="default_arguments.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
The following illustrates a scheme for manually wrapping an overloaded
|
|
||||||
member functions. Of course, the same technique can be applied to wrapping
|
|
||||||
overloaded non-member functions.</p>
|
|
||||||
<p>
|
|
||||||
We have here our C++ class:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>X
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=keyword>bool </span><span class=identifier>f</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>a</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=keyword>return </span><span class=keyword>true</span><span class=special>;
|
|
||||||
}
|
|
||||||
|
|
||||||
</span><span class=keyword>bool </span><span class=identifier>f</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>double </span><span class=identifier>b</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=keyword>return </span><span class=keyword>true</span><span class=special>;
|
|
||||||
}
|
|
||||||
|
|
||||||
</span><span class=keyword>bool </span><span class=identifier>f</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>double </span><span class=identifier>b</span><span class=special>, </span><span class=keyword>char </span><span class=identifier>c</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=keyword>return </span><span class=keyword>true</span><span class=special>;
|
|
||||||
}
|
|
||||||
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>f</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>a</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>b</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>c</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=keyword>return </span><span class=identifier>a </span><span class=special>+ </span><span class=identifier>b </span><span class=special>+ </span><span class=identifier>c</span><span class=special>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Class X has 4 overloaded functions. We shall start by introducing some
|
|
||||||
member function pointer variables:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>bool </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx1</span><span class=special>)(</span><span class=keyword>int</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
|
||||||
</span><span class=keyword>bool </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx2</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
|
||||||
</span><span class=keyword>bool </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx3</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>double</span><span class=special>, </span><span class=keyword>char</span><span class=special>)= &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
|
||||||
</span><span class=keyword>int </span><span class=special>(</span><span class=identifier>X</span><span class=special>::*</span><span class=identifier>fx4</span><span class=special>)(</span><span class=keyword>int</span><span class=special>, </span><span class=keyword>int</span><span class=special>, </span><span class=keyword>int</span><span class=special>) = &</span><span class=identifier>X</span><span class=special>::</span><span class=identifier>f</span><span class=special>;
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
With these in hand, we can proceed to define and wrap this for Python:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>fx1</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>fx2</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>fx3</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, </span><span class=identifier>fx4</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<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="call_policies.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="default_arguments.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>QuickStart</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="next" href="building_hello_world.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>QuickStart</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"><img src="theme/l_arr_disabled.gif" border="0"></td>
|
|
||||||
<td width="20"><a href="building_hello_world.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
The Boost Python Library is a framework for interfacing Python and
|
|
||||||
C++. It allows you to quickly and seamlessly expose C++ classes
|
|
||||||
functions and objects to Python, and vice-versa, using no special
|
|
||||||
tools -- just your C++ compiler. It is designed to wrap C++ interfaces
|
|
||||||
non-intrusively, so that you should not have to change the C++ code at
|
|
||||||
all in order to wrap it, making Boost.Python ideal for exposing
|
|
||||||
3rd-party libraries to Python. The library's use of advanced
|
|
||||||
metaprogramming techniques simplifies its syntax for users, so that
|
|
||||||
wrapping code takes on the look of a kind of declarative interface
|
|
||||||
definition language (IDL).</p>
|
|
||||||
<a name="hello_world"></a><h2>Hello World</h2><p>
|
|
||||||
Following C/C++ tradition, let's start with the "hello, world". A C++
|
|
||||||
Function:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>char </span><span class=keyword>const</span><span class=special>* </span><span class=identifier>greet</span><span class=special>()
|
|
||||||
{
|
|
||||||
</span><span class=keyword>return </span><span class=string>"hello, world"</span><span class=special>;
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
can be exposed to Python by writing a Boost.Python wrapper:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=preprocessor>#include </span><span class=special><</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>python</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>>
|
|
||||||
</span><span class=keyword>using </span><span class=keyword>namespace </span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>python</span><span class=special>;
|
|
||||||
|
|
||||||
</span><span class=identifier>BOOST_PYTHON_MODULE</span><span class=special>(</span><span class=identifier>hello</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=identifier>def</span><span class=special>(</span><span class=string>"greet"</span><span class=special>, </span><span class=identifier>greet</span><span class=special>);
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
That's it. We're done. We can now build this as a shared library. The
|
|
||||||
resulting DLL is now visible to Python. Here's a sample Python session:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>import </span><span class=identifier>hello
|
|
||||||
</span><span class=special>>>> </span><span class=identifier>print </span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>greet</span><span class=special>()
|
|
||||||
</span><span class=identifier>hello</span><span class=special>, </span><span class=identifier>world
|
|
||||||
</span></pre></code>
|
|
||||||
<blockquote><p><i><b>Next stop... Building your Hello World module from start to finish...</b></i></p></blockquote><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>
|
|
||||||
<td width="20"><a href="building_hello_world.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
BIN
doc/tutorial/doc/theme/alert.gif
vendored
|
Before Width: | Height: | Size: 577 B |
BIN
doc/tutorial/doc/theme/arrow.gif
vendored
|
Before Width: | Height: | Size: 70 B |
BIN
doc/tutorial/doc/theme/bkd.gif
vendored
|
Before Width: | Height: | Size: 1.3 KiB |
BIN
doc/tutorial/doc/theme/bkd2.gif
vendored
|
Before Width: | Height: | Size: 2.5 KiB |
BIN
doc/tutorial/doc/theme/bulb.gif
vendored
|
Before Width: | Height: | Size: 944 B |
BIN
doc/tutorial/doc/theme/bullet.gif
vendored
|
Before Width: | Height: | Size: 152 B |
BIN
doc/tutorial/doc/theme/c++boost.gif
vendored
|
Before Width: | Height: | Size: 8.6 KiB |
BIN
doc/tutorial/doc/theme/jam.png
vendored
|
Before Width: | Height: | Size: 3.8 KiB |
BIN
doc/tutorial/doc/theme/l_arr.gif
vendored
|
Before Width: | Height: | Size: 147 B |
BIN
doc/tutorial/doc/theme/l_arr_disabled.gif
vendored
|
Before Width: | Height: | Size: 91 B |
BIN
doc/tutorial/doc/theme/lens.gif
vendored
|
Before Width: | Height: | Size: 897 B |
BIN
doc/tutorial/doc/theme/note.gif
vendored
|
Before Width: | Height: | Size: 151 B |
BIN
doc/tutorial/doc/theme/python.png
vendored
|
Before Width: | Height: | Size: 14 KiB |
BIN
doc/tutorial/doc/theme/r_arr.gif
vendored
|
Before Width: | Height: | Size: 147 B |
BIN
doc/tutorial/doc/theme/r_arr_disabled.gif
vendored
|
Before Width: | Height: | Size: 91 B |
BIN
doc/tutorial/doc/theme/smiley.gif
vendored
|
Before Width: | Height: | Size: 879 B |
170
doc/tutorial/doc/theme/style.css
vendored
@@ -1,170 +0,0 @@
|
|||||||
body
|
|
||||||
{
|
|
||||||
background-image: url(bkd.gif);
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
margin: 1em 2em 1em 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; text-align: left; }
|
|
||||||
h2 { font: 140% sans-serif; font-weight: bold; text-align: left; }
|
|
||||||
h3 { font: 120% sans-serif; font-weight: bold; text-align: left; }
|
|
||||||
h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left; }
|
|
||||||
h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left; }
|
|
||||||
h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left; }
|
|
||||||
|
|
||||||
pre
|
|
||||||
{
|
|
||||||
border-top: gray 1pt solid;
|
|
||||||
border-right: gray 1pt solid;
|
|
||||||
border-left: gray 1pt solid;
|
|
||||||
border-bottom: gray 1pt solid;
|
|
||||||
|
|
||||||
padding-top: 2pt;
|
|
||||||
padding-right: 2pt;
|
|
||||||
padding-left: 2pt;
|
|
||||||
padding-bottom: 2pt;
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
font-family: "courier new", courier, mono;
|
|
||||||
background-color: #eeeeee; font-size: small
|
|
||||||
}
|
|
||||||
|
|
||||||
code
|
|
||||||
{
|
|
||||||
font-family: "Courier New", Courier, mono;
|
|
||||||
font-size: small
|
|
||||||
}
|
|
||||||
|
|
||||||
tt
|
|
||||||
{
|
|
||||||
display: inline;
|
|
||||||
font-family: "Courier New", Courier, mono;
|
|
||||||
color: #000099;
|
|
||||||
font-size: small
|
|
||||||
}
|
|
||||||
|
|
||||||
p
|
|
||||||
{
|
|
||||||
text-align: justify;
|
|
||||||
font-family: Georgia, "Times New Roman", Times, serif
|
|
||||||
}
|
|
||||||
|
|
||||||
ul
|
|
||||||
{
|
|
||||||
list-style-image: url(bullet.gif);
|
|
||||||
font-family: Georgia, "Times New Roman", Times, serif
|
|
||||||
}
|
|
||||||
|
|
||||||
ol
|
|
||||||
{
|
|
||||||
font-family: Georgia, "Times New Roman", Times, serif
|
|
||||||
}
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
font-weight: bold;
|
|
||||||
color: #003366;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover { color: #8080FF; }
|
|
||||||
|
|
||||||
.literal { color: #666666; font-style: italic}
|
|
||||||
.keyword { color: #000099}
|
|
||||||
.identifier {}
|
|
||||||
.comment { font-style: italic; color: #990000}
|
|
||||||
.special { color: #800040}
|
|
||||||
.preprocessor { color: #FF0000}
|
|
||||||
.string { font-style: italic; color: #666666}
|
|
||||||
.copyright { color: #666666; font-size: small}
|
|
||||||
.white_bkd { background-color: #FFFFFF}
|
|
||||||
.dk_grey_bkd { background-color: #999999}
|
|
||||||
.quotes { color: #666666; font-style: italic; font-weight: bold}
|
|
||||||
|
|
||||||
.note_box
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
border-top: gray 1pt solid;
|
|
||||||
border-right: gray 1pt solid;
|
|
||||||
border-left: gray 1pt solid;
|
|
||||||
border-bottom: gray 1pt solid;
|
|
||||||
|
|
||||||
padding-right: 12pt;
|
|
||||||
padding-left: 12pt;
|
|
||||||
padding-bottom: 12pt;
|
|
||||||
padding-top: 12pt;
|
|
||||||
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
background-color: #E2E9EF;
|
|
||||||
font-size: small; text-align: justify
|
|
||||||
}
|
|
||||||
|
|
||||||
.table_title
|
|
||||||
{
|
|
||||||
background-color: #648CCA;
|
|
||||||
|
|
||||||
font-family: Verdana, Arial, Helvetica, sans-serif; color: #FFFFFF;
|
|
||||||
font-weight: bold
|
|
||||||
; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px
|
|
||||||
}
|
|
||||||
|
|
||||||
.table_cells
|
|
||||||
{
|
|
||||||
background-color: #E2E9EF;
|
|
||||||
|
|
||||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
|
||||||
font-size: small
|
|
||||||
; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px
|
|
||||||
}
|
|
||||||
|
|
||||||
.toc
|
|
||||||
{
|
|
||||||
DISPLAY: block;
|
|
||||||
background-color: #E2E9EF
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
|
|
||||||
border-top: gray 1pt solid;
|
|
||||||
border-left: gray 1pt solid;
|
|
||||||
border-bottom: gray 1pt solid;
|
|
||||||
border-right: gray 1pt solid;
|
|
||||||
|
|
||||||
padding-top: 24pt;
|
|
||||||
padding-right: 24pt;
|
|
||||||
padding-left: 24pt;
|
|
||||||
padding-bottom: 24pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toc_title
|
|
||||||
{
|
|
||||||
background-color: #648CCA;
|
|
||||||
padding-top: 4px;
|
|
||||||
padding-right: 4px;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
padding-left: 4px;
|
|
||||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
|
||||||
color: #FFFFFF;
|
|
||||||
font-weight: bold
|
|
||||||
}
|
|
||||||
|
|
||||||
.toc_cells
|
|
||||||
{
|
|
||||||
background-color: #E2E9EF;
|
|
||||||
padding-top: 4px;
|
|
||||||
padding-right: 4px;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
padding-left: 4px;
|
|
||||||
font-family: Geneva, Arial, Helvetica, san-serif;
|
|
||||||
font-size: small
|
|
||||||
}
|
|
||||||
|
|
||||||
div.logo
|
|
||||||
{
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toc_cells_L0 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
|
||||||
.toc_cells_L1 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 44px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
|
||||||
.toc_cells_L2 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 88px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
|
||||||
.toc_cells_L3 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 122px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
|
||||||
.toc_cells_L4 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 166px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small }
|
|
||||||
BIN
doc/tutorial/doc/theme/u_arr.gif
vendored
|
Before Width: | Height: | Size: 170 B |
@@ -1,236 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Using the interpreter</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="embedding.html">
|
|
||||||
<link rel="next" href="iterators.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>Using the interpreter</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="embedding.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="iterators.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
As you probably already know, objects in Python are reference-counted.
|
|
||||||
Naturally, the <tt>PyObject</tt>s of the Python/C API are also reference-counted.
|
|
||||||
There is a difference however. While the reference-counting is fully
|
|
||||||
automatic in Python, the Python/C API requires you to do it
|
|
||||||
<a href="http://www.python.org/doc/current/api/refcounts.html">
|
|
||||||
by hand</a>. This is
|
|
||||||
messy and especially hard to get right in the presence of C++ exceptions.
|
|
||||||
Fortunately Boost.Python provides the <a href="../../v2/handle.html">
|
|
||||||
handle</a> class
|
|
||||||
template to automate the process.</p>
|
|
||||||
<a name="reference_counting_handles"></a><h2>Reference-counting handles</h2><p>
|
|
||||||
There are two ways in which a function in the Python/C API can return a
|
|
||||||
<tt>PyObject*</tt>: as a <i>borrowed reference</i> or as a <i>new reference</i>. Which of
|
|
||||||
these a function uses, is listed in that function's documentation. The two
|
|
||||||
require slightely different approaches to reference-counting but both can
|
|
||||||
be 'handled' by Boost.Python.</p>
|
|
||||||
<p>
|
|
||||||
For a function returning a <i>borrowed reference</i> we'll have to tell the
|
|
||||||
<tt>handle</tt> that the <tt>PyObject*</tt> is borrowed with the aptly named
|
|
||||||
<a href="../../v2/handle.html#borrowed-spec">
|
|
||||||
borrowed</a> function. Two functions
|
|
||||||
returning borrowed references are <a href="http://www.python.org/doc/current/api/importing.html#l2h-125">
|
|
||||||
PyImport_AddModule</a> and <a href="http://www.python.org/doc/current/api/moduleObjects.html#l2h-594">
|
|
||||||
PyModule_GetDict</a>.
|
|
||||||
The former returns a reference to an already imported module, the latter
|
|
||||||
retrieves a module's namespace dictionary. Let's use them to retrieve the
|
|
||||||
namespace of the <tt>__main__</tt> module:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_module</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>"__main__"</span><span class=special>) ));
|
|
||||||
</span><span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_namespace</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) ));
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Because the Python/C API doesn't know anything about <tt>handle</tt>s, we used
|
|
||||||
the <a href="../../v2/handle.html#handle-spec-observers">
|
|
||||||
get</a> member function to
|
|
||||||
retrieve the <tt>PyObject*</tt> from which the <tt>handle</tt> was constructed.</p>
|
|
||||||
<p>
|
|
||||||
For a function returning a <i>new reference</i> we can just create a <tt>handle</tt>
|
|
||||||
out of the raw <tt>PyObject*</tt> without wrapping it in a call to borrowed. One
|
|
||||||
such function that returns a new reference is <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
||||||
PyRun_String</a> which we'll
|
|
||||||
discuss in the next section.</p>
|
|
||||||
<table width="80%" border="0" align="center">
|
|
||||||
<tr>
|
|
||||||
<td class="note_box">
|
|
||||||
<img src="theme/lens.gif"></img> <b>Handle is a class <i>template</i>, so why haven't we been using any template parameters?</b><br>
|
|
||||||
<br>
|
|
||||||
<tt>handle</tt> has a single template parameter specifying the type of the managed object. This type is <tt>PyObject</tt> 99% of the time, so the parameter was defaulted to <tt>PyObject</tt> for convenience. Therefore we can use the shorthand <tt>handle<></tt> instead of the longer, but equivalent, <tt>handle<PyObject></tt>.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<a name="running_python_code"></a><h2>Running Python code</h2><p>
|
|
||||||
To run Python code from C++ there is a family of functions in the API
|
|
||||||
starting with the PyRun prefix. You can find the full list of these
|
|
||||||
functions <a href="http://www.python.org/doc/current/api/veryhigh.html">
|
|
||||||
here</a>. They
|
|
||||||
all work similarly so we will look at only one of them, namely:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=keyword>char </span><span class=special>*</span><span class=identifier>str</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>start</span><span class=special>, </span><span class=identifier>PyObject </span><span class=special>*</span><span class=identifier>globals</span><span class=special>, </span><span class=identifier>PyObject </span><span class=special>*</span><span class=identifier>locals</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
||||||
PyRun_String</a> takes the code to execute as a null-terminated (C-style)
|
|
||||||
string in its <tt>str</tt> parameter. The function returns a new reference to a
|
|
||||||
Python object. Which object is returned depends on the <tt>start</tt> paramater.</p>
|
|
||||||
<p>
|
|
||||||
The <tt>start</tt> parameter is the start symbol from the Python grammar to use
|
|
||||||
for interpreting the code. The possible values are:</p>
|
|
||||||
<table width="90%" border="0" align="center"> <tr>
|
|
||||||
<td class="table_title" colspan="6">
|
|
||||||
Start symbols </td>
|
|
||||||
</tr>
|
|
||||||
<tr><tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58">
|
|
||||||
Py_eval_input</a></td><td class="table_cells">for interpreting isolated expressions</td></tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59">
|
|
||||||
Py_file_input</a></td><td class="table_cells">for interpreting sequences of statements</td></tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60">
|
|
||||||
Py_single_input</a></td><td class="table_cells">for interpreting a single statement</td></tr></table>
|
|
||||||
<p>
|
|
||||||
When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58">
|
|
||||||
Py_eval_input</a>, the input string must contain a single expression
|
|
||||||
and its result is returned. When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59">
|
|
||||||
Py_file_input</a>, the string can
|
|
||||||
contain an abitrary number of statements and None is returned.
|
|
||||||
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60">
|
|
||||||
Py_single_input</a> works in the same way as <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59">
|
|
||||||
Py_file_input</a> but only accepts a
|
|
||||||
single statement.</p>
|
|
||||||
<p>
|
|
||||||
Lastly, the <tt>globals</tt> and <tt>locals</tt> parameters are Python dictionaries
|
|
||||||
containing the globals and locals of the context in which to run the code.
|
|
||||||
For most intents and purposes you can use the namespace dictionary of the
|
|
||||||
<tt>__main__</tt> module for both parameters.</p>
|
|
||||||
<p>
|
|
||||||
We have already seen how to get the <tt>__main__</tt> module's namespace so let's
|
|
||||||
run some Python code in it:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_module</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>"__main__"</span><span class=special>) ));
|
|
||||||
</span><span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_namespace</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) ));
|
|
||||||
</span><span class=identifier>handle</span><span class=special><>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"hello = file('hello.txt', 'w')\n"
|
|
||||||
</span><span class=string>"hello.write('Hello world!')\n"
|
|
||||||
</span><span class=string>"hello.close()"</span><span class=special>, </span><span class=identifier>Py_file_input</span><span class=special>,
|
|
||||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>get</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) );
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
This should create a file called 'hello.txt' in the current directory
|
|
||||||
containing a phrase that is well-known in programming circles.</p>
|
|
||||||
<p>
|
|
||||||
<img src="theme/note.gif"></img> <b>Note</b> that we wrap the return value of <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
||||||
PyRun_String</a> in a
|
|
||||||
(nameless) <tt>handle</tt> even though we are not interested in it. If we didn't
|
|
||||||
do this, the the returned object would be kept alive unnecessarily. Unless
|
|
||||||
you want to be a Dr. Frankenstein, always wrap <tt>PyObject*</tt>s in <tt>handle</tt>s.</p>
|
|
||||||
<a name="beyond_handles"></a><h2>Beyond handles</h2><p>
|
|
||||||
It's nice that <tt>handle</tt> manages the reference counting details for us, but
|
|
||||||
other than that it doesn't do much. Often we'd like to have a more useful
|
|
||||||
class to manipulate Python objects. But we have already seen such a class
|
|
||||||
in the <a href="object_interface.html">
|
|
||||||
previous section</a>: the aptly named <tt>object</tt>
|
|
||||||
class and it's derivatives. What we haven't seen, is that they can be
|
|
||||||
constructed from a <tt>handle</tt>. The following examples should illustrate this
|
|
||||||
fact:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_module</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>"__main__"</span><span class=special>) ));
|
|
||||||
</span><span class=identifier>main_namespace </span><span class=identifier>dict</span><span class=special>(</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) )));
|
|
||||||
</span><span class=identifier>handle</span><span class=special><>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"result = 5 ** 2"</span><span class=special>, </span><span class=identifier>Py_file_input</span><span class=special>,
|
|
||||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()) );
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>five_squared </span><span class=special>= </span><span class=identifier>extract</span><span class=special><</span><span class=keyword>int</span><span class=special>>( </span><span class=identifier>main_namespace</span><span class=special>[</span><span class=string>"result"</span><span class=special>] );
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Here we create a dictionary object for the <tt>__main__</tt> module's namespace.
|
|
||||||
Then we assign 5 squared to the result variable and read this variable from
|
|
||||||
the dictionary. Another way to achieve the same result is to let
|
|
||||||
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
||||||
PyRun_String</a> return the result directly with <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58">
|
|
||||||
Py_eval_input</a>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>object </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>handle</span><span class=special><>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"5 ** 2"</span><span class=special>, </span><span class=identifier>Py_eval_input</span><span class=special>,
|
|
||||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()) ));
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>five_squared </span><span class=special>= </span><span class=identifier>extract</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>result</span><span class=special>);
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
<img src="theme/note.gif"></img> <b>Note</b> that <tt>object</tt>'s member function to return the wrapped
|
|
||||||
<tt>PyObject*</tt> is called <tt>ptr</tt> instead of <tt>get</tt>. This makes sense if you
|
|
||||||
take into account the different functions that <tt>object</tt> and <tt>handle</tt>
|
|
||||||
perform.</p>
|
|
||||||
<a name="exception_handling"></a><h2>Exception handling</h2><p>
|
|
||||||
If an exception occurs in the execution of some Python code, the <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
||||||
PyRun_String</a> function returns a null pointer. Constructing a <tt>handle</tt> out of this null pointer throws <a href="../../v2/errors.html#error_already_set-spec">
|
|
||||||
error_already_set</a>, so basically, the Python exception is automatically translated into a C++ exception when using <tt>handle</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>try
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=identifier>object </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>handle</span><span class=special><>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"5/0"</span><span class=special>, </span><span class=identifier>Py_eval_input</span><span class=special>,
|
|
||||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()) ));
|
|
||||||
// </span><span class=identifier>execution </span><span class=identifier>will </span><span class=identifier>never </span><span class=identifier>get </span><span class=identifier>here</span><span class=special>:
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>five_divided_by_zero </span><span class=special>= </span><span class=identifier>extract</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>result</span><span class=special>);
|
|
||||||
}
|
|
||||||
</span><span class=keyword>catch</span><span class=special>(</span><span class=identifier>error_already_set</span><span class=special>)
|
|
||||||
{
|
|
||||||
// </span><span class=identifier>handle </span><span class=identifier>the </span><span class=identifier>exception </span><span class=identifier>in </span><span class=identifier>some </span><span class=identifier>way
|
|
||||||
</span><span class=special>}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
The <tt>error_already_set</tt> exception class doesn't carry any information in itself. To find out more about the Python exception that occurred, you need to use the <a href="http://www.python.org/doc/api/exceptionHandling.html">
|
|
||||||
exception handling functions</a> of the Python/C API in your catch-statement. This can be as simple as calling <a href="http://www.python.org/doc/api/exceptionHandling.html#l2h-70">
|
|
||||||
PyErr_Print()</a> to print the exception's traceback to the console, or comparing the type of the exception with those of the <a href="http://www.python.org/doc/api/standardExceptions.html">
|
|
||||||
standard exceptions</a>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>catch</span><span class=special>(</span><span class=identifier>error_already_set</span><span class=special>)
|
|
||||||
{
|
|
||||||
</span><span class=keyword>if </span><span class=special>(</span><span class=identifier>PyErr_ExceptionMatches</span><span class=special>(</span><span class=identifier>PyExc_ZeroDivisionError</span><span class=special>))
|
|
||||||
{
|
|
||||||
// </span><span class=identifier>handle </span><span class=identifier>ZeroDivisionError </span><span class=identifier>specially
|
|
||||||
</span><span class=special>}
|
|
||||||
</span><span class=keyword>else
|
|
||||||
</span><span class=special>{
|
|
||||||
// </span><span class=identifier>print </span><span class=identifier>all </span><span class=identifier>other </span><span class=identifier>errors </span><span class=identifier>to </span><span class=identifier>stderr
|
|
||||||
</span><span class=identifier>PyErr_Print</span><span class=special>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
(To retrieve even more information from the exception you can use some of the other exception handling functions listed <a href="http://www.python.org/doc/api/exceptionHandling.html">
|
|
||||||
here</a>.)</p>
|
|
||||||
<p>
|
|
||||||
If you'd rather not have <tt>handle</tt> throw a C++ exception when it is constructed, you can use the <a href="../../v2/handle.html#allow_null-spec">
|
|
||||||
allow_null</a> function in the same way you'd use borrowed:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>allow_null</span><span class=special>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"5/0"</span><span class=special>, </span><span class=identifier>Py_eval_input</span><span class=special>,
|
|
||||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()) ));
|
|
||||||
</span><span class=keyword>if </span><span class=special>(!</span><span class=identifier>result</span><span class=special>)
|
|
||||||
// </span><span class=identifier>Python </span><span class=identifier>exception </span><span class=identifier>occurred
|
|
||||||
</span><span class=keyword>else
|
|
||||||
</span><span class=comment>// everything went okay, it's safe to use the result
|
|
||||||
</span></pre></code>
|
|
||||||
<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="embedding.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="iterators.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 Dirk Gerrits<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>
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Virtual Functions with Default Implementations</title>
|
|
||||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
||||||
<link rel="prev" href="deriving_a_python_class.html">
|
|
||||||
<link rel="next" href="class_operators_special_functions.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>Virtual Functions with Default Implementations</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="deriving_a_python_class.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="class_operators_special_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
Recall that in the <a href="class_virtual_functions.html">
|
|
||||||
previous section</a>, we
|
|
||||||
wrapped a class with a pure virtual function that we then implemented in
|
|
||||||
C++ or Python classes derived from it. Our base class:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>Base
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=keyword>virtual </span><span class=keyword>int </span><span class=identifier>f</span><span class=special>() = </span><span class=number>0</span><span class=special>;
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
had a pure virtual function <tt>f</tt>. If, however, its member function <tt>f</tt> was
|
|
||||||
not declared as pure virtual:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>Base
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=keyword>virtual </span><span class=keyword>int </span><span class=identifier>f</span><span class=special>() { </span><span class=keyword>return </span><span class=number>0</span><span class=special>; }
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
and instead had a default implementation that returns <tt>0</tt>, as shown above,
|
|
||||||
we need to add a forwarding function that calls the <tt>Base</tt> default virtual
|
|
||||||
function <tt>f</tt> implementation:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=keyword>struct </span><span class=identifier>BaseWrap </span><span class=special>: </span><span class=identifier>Base
|
|
||||||
</span><span class=special>{
|
|
||||||
</span><span class=identifier>BaseWrap</span><span class=special>(</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self_</span><span class=special>)
|
|
||||||
: </span><span class=identifier>self</span><span class=special>(</span><span class=identifier>self_</span><span class=special>) {}
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>f</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>call_method</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>self</span><span class=special>, </span><span class=string>"f"</span><span class=special>); }
|
|
||||||
</span><span class=keyword>int </span><span class=identifier>default_f</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>Base</span><span class=special>::</span><span class=identifier>f</span><span class=special>(); } // <<=== ***</span><span class=identifier>ADDED</span><span class=special>***
|
|
||||||
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self</span><span class=special>;
|
|
||||||
};
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Then, Boost.Python needs to keep track of 1) the dispatch function <tt>f</tt> and
|
|
||||||
2) the forwarding function to its default implementation <tt>default_f</tt>.
|
|
||||||
There's a special <tt>def</tt> function for this purpose. Here's how it is
|
|
||||||
applied to our example above:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=identifier>class_</span><span class=special><</span><span class=identifier>Base</span><span class=special>, </span><span class=identifier>BaseWrap</span><span class=special>>(</span><span class=string>"Base"</span><span class=special>)
|
|
||||||
.</span><span class=identifier>def</span><span class=special>(</span><span class=string>"f"</span><span class=special>, &</span><span class=identifier>Base</span><span class=special>::</span><span class=identifier>f</span><span class=special>, &</span><span class=identifier>BaseWrap</span><span class=special>::</span><span class=identifier>default_f</span><span class=special>)
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Note that we are allowing <tt>Base</tt> objects to be instantiated this time,
|
|
||||||
unlike before where we specifically defined the <tt>class_<Base></tt> with
|
|
||||||
<tt>no_init</tt>.</p>
|
|
||||||
<p>
|
|
||||||
In Python, the results would be as expected:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>base </span><span class=special>= </span><span class=identifier>Base</span><span class=special>()
|
|
||||||
>>> </span><span class=keyword>class </span><span class=identifier>Derived</span><span class=special>(</span><span class=identifier>Base</span><span class=special>):
|
|
||||||
... </span><span class=identifier>def </span><span class=identifier>f</span><span class=special>(</span><span class=identifier>self</span><span class=special>):
|
|
||||||
... </span><span class=keyword>return </span><span class=number>42
|
|
||||||
</span><span class=special>...
|
|
||||||
>>> </span><span class=identifier>derived </span><span class=special>= </span><span class=identifier>Derived</span><span class=special>()
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Calling <tt>base.f()</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>base</span><span class=special>.</span><span class=identifier>f</span><span class=special>()
|
|
||||||
</span><span class=number>0
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Calling <tt>derived.f()</tt>:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>derived</span><span class=special>.</span><span class=identifier>f</span><span class=special>()
|
|
||||||
</span><span class=number>42
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Calling <tt>call_f</tt>, passing in a <tt>base</tt> object:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>call_f</span><span class=special>(</span><span class=identifier>base</span><span class=special>)
|
|
||||||
</span><span class=number>0
|
|
||||||
</span></pre></code>
|
|
||||||
<p>
|
|
||||||
Calling <tt>call_f</tt>, passing in a <tt>derived</tt> object:</p>
|
|
||||||
<code><pre>
|
|
||||||
<span class=special>>>> </span><span class=identifier>call_f</span><span class=special>(</span><span class=identifier>derived</span><span class=special>)
|
|
||||||
</span><span class=number>42
|
|
||||||
</span></pre></code>
|
|
||||||
<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="deriving_a_python_class.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
||||||
<td width="20"><a href="class_operators_special_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
||||||
<title>Boost Python Tutorial</title>
|
|
||||||
<link rel="stylesheet" href="doc/theme/style.css" type="text/css">
|
|
||||||
<link rel="next" href="quickstart.html">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table width="100%" height="48" border="0" cellspacing="2">
|
|
||||||
<tr>
|
|
||||||
<td><img src="doc/theme/c%2B%2Bboost.gif">
|
|
||||||
</td>
|
|
||||||
<td width="85%">
|
|
||||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Boost Python Tutorial</b></font>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<table width="80%" border="0" align="center">
|
|
||||||
<tr>
|
|
||||||
<td class="toc_title">Table of contents</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L0">
|
|
||||||
<a href="doc/quickstart.html">QuickStart</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L0">
|
|
||||||
<a href="doc/building_hello_world.html">Building Hello World</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L0">
|
|
||||||
<a href="doc/exposing_classes.html">Exposing Classes</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/constructors.html">Constructors</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/class_data_members.html">Class Data Members</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/class_properties.html">Class Properties</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/inheritance.html">Inheritance</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/class_virtual_functions.html">Class Virtual Functions</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/deriving_a_python_class.html">Deriving a Python Class</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/virtual_functions_with_default_implementations.html">Virtual Functions with Default Implementations</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/class_operators_special_functions.html">Class Operators/Special Functions</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L0">
|
|
||||||
<a href="doc/functions.html">Functions</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/call_policies.html">Call Policies</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/overloading.html">Overloading</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/default_arguments.html">Default Arguments</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/auto_overloading.html">Auto-Overloading</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L0">
|
|
||||||
<a href="doc/object_interface.html">Object Interface</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/basic_interface.html">Basic Interface</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/derived_object_types.html">Derived Object types</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/extracting_c___objects.html">Extracting C++ objects</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/enums.html">Enums</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L0">
|
|
||||||
<a href="doc/embedding.html">Embedding</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L1">
|
|
||||||
<a href="doc/using_the_interpreter.html">Using the interpreter</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L0">
|
|
||||||
<a href="doc/iterators.html">Iterators</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="toc_cells_L0">
|
|
||||||
<a href="doc/exception_translation.html">Exception Translation</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br>
|
|
||||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<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>
|
|
||||||
62
doc/under-the-hood.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
|
<title>
|
||||||
|
A Peek Under the Hood
|
||||||
|
</title>
|
||||||
|
<h1>
|
||||||
|
<img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
||||||
|
width="277" height="86">
|
||||||
|
</h1>
|
||||||
|
<h1>
|
||||||
|
A Peek Under the Hood
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Declaring a <code>class_builder<T></code> causes the instantiation
|
||||||
|
of an <code>extension_class<T></code> to which it forwards all
|
||||||
|
member function calls and which is doing most of the real work.
|
||||||
|
<code>extension_class<T></code> is a subclass of <code>
|
||||||
|
PyTypeObject</code>, the <code> struct</code> which Python's 'C' API uses
|
||||||
|
to describe a type. <a href="example1.html#world_class">An instance of the
|
||||||
|
<code>extension_class<></code></a> becomes the Python type object
|
||||||
|
corresponding to <code>hello::world</code>. When we <a href=
|
||||||
|
"example1.html#add_world_class">add it to the module</a> it goes into the
|
||||||
|
module's dictionary to be looked up under the name "world".
|
||||||
|
<p>
|
||||||
|
Boost.Python uses C++'s template argument deduction mechanism to determine the
|
||||||
|
types of arguments to functions (except constructors, for which we must
|
||||||
|
<a href="example1.html#Constructor_example">provide an argument list</a>
|
||||||
|
because they can't be named in C++). Then, it calls the appropriate
|
||||||
|
overloaded functions <code>PyObject*
|
||||||
|
to_python(</code><em>S</em><code>)</code> and <em>
|
||||||
|
S'</em><code>from_python(PyObject*,
|
||||||
|
type<</code><em>S</em><code>>)</code> which convert between any C++
|
||||||
|
type <em>S</em> and a <code>PyObject*</code>, the type which represents a
|
||||||
|
reference to any Python object in its 'C' API. The <a href=
|
||||||
|
"example1.html#world_class"><code>extension_class<T></code></a>
|
||||||
|
template defines a whole raft of these conversions (for <code>T, T*,
|
||||||
|
T&, std::auto_ptr<T></code>, etc.), using the same inline
|
||||||
|
friend function technique employed by <a href=
|
||||||
|
"file:///c:/boost/site/libs/utility/operators.htm">the boost operators
|
||||||
|
library</a>.
|
||||||
|
<p>
|
||||||
|
Because the <code>to_python</code> and <code>from_python</code> functions
|
||||||
|
for a user-defined class are defined by <code>
|
||||||
|
extension_class<T></code>, it is important that an instantiation of
|
||||||
|
<code> extension_class<T></code> is visible to any code which wraps
|
||||||
|
a C++ function with a <code>T, T*, const T&</code>, etc. parameter or
|
||||||
|
return value. In particular, you may want to create all of the classes at
|
||||||
|
the top of your module's init function, then <code>def</code> the member
|
||||||
|
functions later to avoid problems with inter-class dependencies.
|
||||||
|
<p>
|
||||||
|
Next: <a href="building.html">Building a Module with Boost.Python</a>
|
||||||
|
Previous: <a href="special.html">Special Method and Operator Support</a>
|
||||||
|
Up: <a href="index.html">Top</a>
|
||||||
|
<p>
|
||||||
|
© Copyright David Abrahams 2000. 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.
|
||||||
|
<p>
|
||||||
|
Updated: Nov 26, 2000
|
||||||
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href="../boost.css">
|
|
||||||
<title>Boost.Python - April 2002 Progress Report</title>
|
|
||||||
</head>
|
|
||||||
<body link="#0000ff" vlink="#800080">
|
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
|
||||||
"header">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><a href="../../../../index.htm"><img height="86" width="277" alt=
|
|
||||||
"C++ Boost" src="../../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
|
|
||||||
<h2 align="center">April 2002 Progress Report</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
<h2>Contents</h2>
|
|
||||||
<dl class="index">
|
|
||||||
<dt><a href="#accomplishments">Accomplishments</a></dt>
|
|
||||||
<dl class="index">
|
|
||||||
<dt><a href="#arity">Arbitrary Arity Support</a></dt>
|
|
||||||
<dt><a href="#callbacks">New Callback Interface</a></dt>
|
|
||||||
<dt><a href="#policies">Call Policies for Construtors</a></dt>
|
|
||||||
<dt><a href="#bugs">Real Users, Real Bugs</a></dt>
|
|
||||||
<dt><a href="#insights">New Insights</a></dt>
|
|
||||||
<dt><a href="#v1">Boost.Python V1 Maintenance</a></dt>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<dt><a href="#missing">What's Missing</a></dt>
|
|
||||||
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<h2><a name="accomplishments">Accomplishments</a></h2>
|
|
||||||
|
|
||||||
April was a short month as far as Boost.Python was concerned, since
|
|
||||||
the spring ISO C++ Committee Meeting (and associated vacation)
|
|
||||||
occupied me for the 2nd half of the month. However, a suprising amount
|
|
||||||
of work got done...
|
|
||||||
|
|
||||||
<h3><a name="arity">Arbitrary Arity Support</a></h3>
|
|
||||||
|
|
||||||
I began using the <a
|
|
||||||
href="../../../preprocessor/doc/index.htm">Boost.Preprocessor</a>
|
|
||||||
metaprogramming library to generate support for functions and member
|
|
||||||
functions of arbitrary arity, which was, to say the least, quite an
|
|
||||||
adventure. The feedback cycle resulting from my foray into
|
|
||||||
Boost.Preprocessor resulted in several improvements to the library,
|
|
||||||
most notably in its documentation.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
Boost.Python now supports calls of up to 17 arguments on most
|
|
||||||
compilers. Because most EDG-based compilers have dismal preprocessor
|
|
||||||
performance, I had to "manually" expand the metaprograms for
|
|
||||||
arities from zero to fifteen arguments, and EDG-based compilers with
|
|
||||||
<code>__EDG_VERSION__ <= 245</code> only support 15
|
|
||||||
arguments by default. If some crazy program finds a need for more than
|
|
||||||
the default arity support, users can increase the base support by
|
|
||||||
setting the <code>BOOST_PYTHON_MAX_ARITY</code> preprocessor symbol.
|
|
||||||
|
|
||||||
<h3><a name="callbacks">New Callback Interface</a></h3>
|
|
||||||
|
|
||||||
I mentioned in <a href="Mar2002.html">last month's report</a> that I
|
|
||||||
wasn't pleased with the interface for the interface for calling into
|
|
||||||
Python, so now it has been redesigned. The new interface is outlined
|
|
||||||
in <a
|
|
||||||
href="http://mail.python.org/pipermail/c++-sig/2002-April/000953.html">this
|
|
||||||
message</a> (though the GCC 2.95.3 bugs have been fixed).
|
|
||||||
|
|
||||||
<h3><a name="policies">Call Policies for Constructors</a></h3>
|
|
||||||
|
|
||||||
On April 2nd, I <a
|
|
||||||
href="http://mail.python.org/pipermail/c++-sig/2002-April/000916.html">announced</a>
|
|
||||||
support for the use of call policies with constructors.
|
|
||||||
|
|
||||||
<h3><a name="bugs">Real Users, Real Bugs</a></h3>
|
|
||||||
|
|
||||||
At least two people outside of Kull began actually using Boost.Python
|
|
||||||
v2 in earnest this month. Peter Bienstman and Pearu Pearson both
|
|
||||||
provided valuable real-world bug reports that helped me to improve the
|
|
||||||
library's robustness.
|
|
||||||
|
|
||||||
<h3><a name="insights">New Insights</a></h3>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="http://mail.python.org/pipermail/c++-sig/2002-May/001010.html"
|
|
||||||
>Answering some of Pearu's questions</a> about explicitly converting
|
|
||||||
objects between Python and C++ actually led me to a new understanding
|
|
||||||
of the role of the current conversion facilities. In Boost.Python v1,
|
|
||||||
all conversions between Python and C++ were handled by a single family
|
|
||||||
of functions, called <code>to_python()</code> and
|
|
||||||
<code>from_python()</code>. Since the primary role of Boost.Python is
|
|
||||||
to wrap C++ functions in Python, I used these names for the first kind
|
|
||||||
of converters I needed: those that extract C++ objects to be used as
|
|
||||||
function arguments and which C++ function return values to
|
|
||||||
Python. The better-considered approach in Boost.Python v2 uses a
|
|
||||||
completely different mechanism for conversions used when calling
|
|
||||||
Python from C++, as in wrapped virtual function implementations. I
|
|
||||||
usually think of this as a "callback", as in "calling
|
|
||||||
back into Python", and I named the converters used in callbacks
|
|
||||||
accordingly: <code>to_python_callback</code> and
|
|
||||||
<code>from_python_callback</code>. However, as it turns out, the
|
|
||||||
behavior of the "callback" converters is the appropriate one
|
|
||||||
for users who want to explicitly extract a C++ value from a Python
|
|
||||||
object, or create a Python object from a C++ value. The upshot is that
|
|
||||||
it probably makes sense to change the name of the existing <code>to_python</code> and
|
|
||||||
<code>from_python</code> so those names are available for the
|
|
||||||
user-friendly explicit converters.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
href="http://mail.python.org/pipermail/c++-sig/2002-May/001013.html">Another
|
|
||||||
of Pearu's questions</a> pushes momentum further in the direction of a
|
|
||||||
more-sophisticated overloading mechanism than the current
|
|
||||||
simple-minded "first match" approach, as I suggested <a
|
|
||||||
href="Mar2002.html#implicit_conversions">last month</a>.
|
|
||||||
|
|
||||||
<h3><a name="v1">Boost.Python V1 Maintenance</a></h3>
|
|
||||||
|
|
||||||
As much as I'm looking forward to retiring Boost.Python v1, a
|
|
||||||
significant amount of effort has been being spent dealing with support
|
|
||||||
problems; the saying that code rots when left alone is true, and
|
|
||||||
Boost.Python is no exception. Eventually it became obvious to me that
|
|
||||||
we were going to have to invest some effort in keeping V1 healthy
|
|
||||||
while working on V2. Ralf and I have expanded support for various
|
|
||||||
compilers and stabilized the V1 codebase considerably. We discarded
|
|
||||||
the obsolete Visual Studio projects which were causing so much
|
|
||||||
confusion. Still to do before the next Boost release:
|
|
||||||
<ol>
|
|
||||||
<li>Update the build/test documentation with detailed instructions for
|
|
||||||
configuring various toolsets.
|
|
||||||
<li>Provide some links to Boost.Python v2 to let people know what's
|
|
||||||
coming.
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
|
|
||||||
<h2><a name="missing">What's Missing</a></h2>
|
|
||||||
|
|
||||||
Last month I announced that I would implement the following which are
|
|
||||||
not yet complete:
|
|
||||||
<ol>
|
|
||||||
<li>Document all implemented features
|
|
||||||
<li>Implement conversions for <code>char</code> types. This is
|
|
||||||
implemented but not tested, so we have to assume it doesn't work.
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
These are my first priority for this month (especially the
|
|
||||||
documentation).
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
|
||||||
13 November, 2002
|
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
<p><i>© Copyright <a href="../../../../people/dave_abrahams.htm">Dave Abrahams</a>
|
|
||||||
2002. All Rights Reserved.</i></p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="generator" content=
|
|
||||||
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
<link rel="stylesheet" type="text/css" href=../../../../boost.css>
|
|
||||||
|
|
||||||
<title>Boost.Python - CallPolicies Concept</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body link="#0000ff" vlink="#800080">
|
|
||||||
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
|
|
||||||
"header">
|
|
||||||
<tr>
|
|
||||||
<td valign="top" width="300">
|
|
||||||
<h3><a href="../../../../index.htm"><img height="86" width="277"
|
|
||||||
alt="C++ Boost" src="../../../../c++boost.gif" border="0"></a></h3>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td valign="top">
|
|
||||||
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
|
|
||||||
|
|
||||||
<h2 align="center">CallPolicies Concept</h2>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<dl class="page-index">
|
|
||||||
<dt><a href="#introduction">Introduction</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="#composition">CallPolicies Composition</a></dt>
|
|
||||||
|
|
||||||
<dt><a href="#concept-requirements">Concept Requirements</a></dt>
|
|
||||||
|
|
||||||
<dd>
|
|
||||||
<dl class="page-index">
|
|
||||||
<dt><a href="#CallPolicies-concept">CallPolicies Concept</a></dt>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<h2><a name="introduction"></a>Introduction</h2>
|
|
||||||
|
|
||||||
<p>Models of the CallPolicies concept are used to specialize the behavior
|
|
||||||
of Python callable objects generated by Boost.Python to wrapped C++
|
|
||||||
objects like function and member function pointers, providing three
|
|
||||||
behaviors:</p>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li><code>precall</code> - Python argument tuple management before the
|
|
||||||
wrapped object is invoked</li>
|
|
||||||
|
|
||||||
<li><code>result_converter</code> - C++ return value handling</li>
|
|
||||||
|
|
||||||
<li><code>postcall</code> - Python argument tuple and result management
|
|
||||||
after the wrapped object is invoked</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<h2><a name="composition"></a>CallPolicies Composition</h2>
|
|
||||||
In order to allow the use of multiple models of CallPolicies in the same
|
|
||||||
callable object, Boost.Python's CallPolicies class templates provide a
|
|
||||||
chaining interface which allows them to be recursively composed. This
|
|
||||||
interface takes the form of an optional template parameter,
|
|
||||||
<code>Base</code> which defaults to <a href=
|
|
||||||
"default_call_policies.html#default_call_policies-spec"><code>default_call_policies</code></a>.
|
|
||||||
By convention, the <code>precall</code> function of the <code>Base</code>
|
|
||||||
is invoked <i>after</i> the <code>precall</code> function supplied by the
|
|
||||||
outer template, and the <code>postcall</code> function of the
|
|
||||||
<code>Base</code> is invoked <i>before</i> the <code>postcall</code>
|
|
||||||
function of the outer template. If a <code>result_converter</code> is
|
|
||||||
supplied by the outer template, it <i>replaces</i> any
|
|
||||||
<code>result_converter</code> supplied by the <code>Base</code>. For an
|
|
||||||
example, see <a href=
|
|
||||||
"return_internal_reference.html#return_internal_reference-spec"><code>return_internal_reference</code></a>.
|
|
||||||
|
|
||||||
|
|
||||||
<h2><a name="concept-requirements"></a>Concept Requirements</h2>
|
|
||||||
|
|
||||||
<h3><a name="CallPolicies-concept"></a>CallPolicies Concept</h3>
|
|
||||||
|
|
||||||
<p>In the table below, <code><b>x</b></code> denotes an object whose type
|
|
||||||
<code><b>P</b></code> is a model of CallPolicies, <code><b>a</b></code>
|
|
||||||
denotes a <code>PyObject*</code> pointing to a Python argument tuple
|
|
||||||
object, and <code><b>r</b></code> denotes a <code>PyObject*</code>
|
|
||||||
referring to a "preliminary" result object.</p>
|
|
||||||
|
|
||||||
<table summary="CallPolicies expressions" border="1" cellpadding="5">
|
|
||||||
<tr>
|
|
||||||
<td><b>Expression</b></td>
|
|
||||||
|
|
||||||
<td><b>Type</b></td>
|
|
||||||
|
|
||||||
<td><b>Result/Semantics</b></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>x.precall(a)</code></td>
|
|
||||||
|
|
||||||
<td>convertible to <code>bool</code></td>
|
|
||||||
|
|
||||||
<td>returns <code>false</code> and <code><a href=
|
|
||||||
"http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71">PyErr_Occurred</a>() != 0</code>
|
|
||||||
upon failure, <code>true</code> otherwise.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>P::result_converter</code></td>
|
|
||||||
|
|
||||||
<td>A model of <a href=
|
|
||||||
"ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a>.</td>
|
|
||||||
|
|
||||||
<td>An MPL unary <a href=
|
|
||||||
"../../../mpl/doc/paper/html/usage.html#metafunctions.classes">Metafunction
|
|
||||||
Class</a> used produce the "preliminary" result object.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td valign="top"><code>x.postcall(a, r)</code></td>
|
|
||||||
|
|
||||||
<td>convertible to <code>PyObject*</code></td>
|
|
||||||
|
|
||||||
<td>0 <code>0</code> and <code><a href=
|
|
||||||
"http://www.python.org/doc/2.2/api/exceptionHandling.html#l2h-71">PyErr_Occurred</a>() != 0</code>
|
|
||||||
upon failure. Must "conserve references" even in the event of an
|
|
||||||
exception. In other words, if <code>r</code> is not returned, its
|
|
||||||
reference count must be decremented; if another existing object is
|
|
||||||
returned, its reference count must be incremented.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
Models of CallPolicies are required to be <a href=
|
|
||||||
"../../../utility/CopyConstructible.html">CopyConstructible</a>.
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<p>Revised
|
|
||||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
|
|
||||||
13 November, 2002
|
|
||||||
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p><i>© Copyright <a href=
|
|
||||||
"../../../../people/dave_abrahams.htm">Dave Abrahams</a> 2002. All Rights
|
|
||||||
Reserved.</i></p>
|
|
||||||
|
|
||||||
<p>Permission to copy, use, modify, sell and distribute this software is
|
|
||||||
granted provided this copyright notice appears in all copies. This
|
|
||||||
software is provided "as is" without express or implied warranty, and
|
|
||||||
with no claim as to its suitability for any purpose.</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||