Author: Wim Lavrijsen <[email protected]>
Branch:
Changeset: r55486:5f515c20c98a
Date: 2012-06-07 13:48 -0700
http://bitbucket.org/pypy/pypy/changeset/5f515c20c98a/
Log: o) explain class loader usage o) fix a few typos o) incorporate
feedback from Alex Pyattaev
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -115,7 +115,7 @@
code::
$ genreflex MyClass.h
- $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o
libMyClassDict.so
+ $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o
libMyClassDict.so -L$ROOTSYS/lib -lReflex
Now you're ready to use the bindings.
Since the bindings are designed to look pythonistic, it should be
@@ -139,6 +139,51 @@
That's all there is to it!
+Automatic class loader
+======================
+There is one big problem in the code above, that prevents its use in a (large
+scale) production setting: the explicit loading of the reflection library.
+Clearly, if explicit load statements such as these show up in code downstream
+from the ``MyClass`` package, then that prevents the ``MyClass`` author from
+repackaging or even simply renaming the dictionary library.
+
+The solution is to make use of an automatic class loader, so that downstream
+code never has to call ``load_reflection_info()`` directly.
+The class loader makes use of so-called rootmap files, which ``genreflex``
+can produce.
+These files contain the list of available C++ classes and specify the library
+that needs to be loaded for their use.
+By convention, the rootmap files should be located next to the reflection info
+libraries, so that they can be found through the normal shared library search
+path.
+They can be concatenated together, or consist of a single rootmap file per
+library.
+For example::
+
+ $ genreflex MyClass.h --rootmap=libMyClassDict.rootmap
--rootmap-lib=libMyClassDict.so
+ $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o
libMyClassDict.so -L$ROOTSYS/lib -lReflex
+
+where the first option (``--rootmap``) specifies the output file name, and the
+second option (``--rootmap-lib``) the name of the reflection library where
+``MyClass`` will live.
+It is necessary to provide that name explicitly, since it is only in the
+separate linking step where this name is fixed.
+If the second option is not given, the library is assumed to be libMyClass.so,
+a name that is derived from the name of the header file.
+
+With the rootmap file in place, the above example can be rerun without explicit
+loading of the reflection info library::
+
+ $ pypy-c
+ >>>> import cppyy
+ >>>> myinst = cppyy.gbl.MyClass(42)
+ >>>> print myinst.GetMyInt()
+ 42
+ >>>> # etc. ...
+
+As a caveat, note that the class loader is currently limited to classes only.
+
+
Advanced example
================
The following snippet of C++ is very contrived, to allow showing that such
@@ -171,7 +216,7 @@
std::string m_name;
};
- Base1* BaseFactory(const std::string& name, int i, double d) {
+ Base2* BaseFactory(const std::string& name, int i, double d) {
return new Derived(name, i, d);
}
@@ -213,7 +258,7 @@
Now the reflection info can be generated and compiled::
$ genreflex MyAdvanced.h --selection=MyAdvanced.xml
- $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp
-o libAdvExDict.so
+ $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp
-o libAdvExDict.so -L$ROOTSYS/lib -lReflex
and subsequently be used from PyPy::
@@ -237,7 +282,7 @@
A couple of things to note, though.
If you look back at the C++ definition of the ``BaseFactory`` function,
-you will see that it declares the return type to be a ``Base1``, yet the
+you will see that it declares the return type to be a ``Base2``, yet the
bindings return an object of the actual type ``Derived``?
This choice is made for a couple of reasons.
First, it makes method dispatching easier: if bound objects are always their
@@ -434,7 +479,9 @@
int m_i;
};
- template class std::vector<MyClass>;
+ #ifdef __GCCXML__
+ template class std::vector<MyClass>; // explicit instantiation
+ #endif
If you know for certain that all symbols will be linked in from other sources,
you can also declare the explicit template instantiation ``extern``.
@@ -445,8 +492,9 @@
internal namespace, rather than in the iterator classes.
One way to handle this, is to deal with this once in a macro, then reuse that
macro for all ``vector`` classes.
-Thus, the header above needs this, instead of just the explicit instantiation
-of the ``vector<MyClass>``::
+Thus, the header above needs this (again protected with
+``#ifdef __GCCXML__``), instead of just the explicit instantiation of the
+``vector<MyClass>``::
#define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE)
\
template class std::STLTYPE< TTYPE >;
\
@@ -467,11 +515,9 @@
$ cat MyTemplate.xml
<lcgdict>
<class pattern="std::vector<*>" />
- <class pattern="__gnu_cxx::__normal_iterator<*>" />
- <class pattern="__gnu_cxx::new_allocator<*>" />
+ <class pattern="std::vector<*>::iterator" />
<class pattern="std::_Vector_base<*>" />
<class pattern="std::_Vector_base<*>::_Vector_impl" />
- <class pattern="std::allocator<*>" />
<function name="__gnu_cxx::operator=="/>
<function name="__gnu_cxx::operator!="/>
@@ -480,8 +526,8 @@
Run the normal ``genreflex`` and compilation steps::
- $ genreflex MyTemplate.h --selection=MyTemplate.xm
- $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp
-o libTemplateDict.so
+ $ genreflex MyTemplate.h --selection=MyTemplate.xml
+ $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp
-o libTemplateDict.so -L$ROOTSYS/lib -lReflex
Note: this is a dirty corner that clearly could do with some automation,
even if the macro already helps.
@@ -555,7 +601,9 @@
There are a couple of minor differences between PyCintex and cppyy, most to do
with naming.
The one that you will run into directly, is that PyCintex uses a function
-called ``loadDictionary`` rather than ``load_reflection_info``.
+called ``loadDictionary`` rather than ``load_reflection_info`` (it has the
+same rootmap-based class loader functionality, though, making this point
+somewhat moot).
The reason for this is that Reflex calls the shared libraries that contain
reflection info "dictionaries."
However, in python, the name `dictionary` already has a well-defined meaning,
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit