Author: Maciej Fijalkowski <fij...@gmail.com> Branch: Changeset: r55494:f3ae32f79e96 Date: 2012-06-08 11:03 +0200 http://bitbucket.org/pypy/pypy/changeset/f3ae32f79e96/
Log: merge diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -71,10 +71,14 @@ .. _`recent snapshot`: http://cern.ch/wlav/reflex-2012-05-02.tar.bz2 .. _`gccxml`: http://www.gccxml.org -Next, get the `PyPy sources`_, select the reflex-support branch, and build -pypy-c. +Next, get the `PyPy sources`_, select the reflex-support branch, and build. For the build to succeed, the ``$ROOTSYS`` environment variable must point to -the location of your ROOT (or standalone Reflex) installation:: +the location of your ROOT (or standalone Reflex) installation, or the +``root-config`` utility must be accessible through ``PATH`` (e.g. by adding +``$ROOTSYS/bin`` to ``PATH``). +In case of the former, include files are expected under ``$ROOTSYS/include`` +and libraries under ``$ROOTSYS/lib``. +Then run the translation to build ``pypy-c``:: $ hg clone https://bitbucket.org/pypy/pypy $ cd pypy @@ -115,7 +119,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 +143,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 +220,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 +262,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 +286,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 +483,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 +496,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 +519,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 +530,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 +605,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, diff --git a/pypy/doc/release-1.9.0.rst b/pypy/doc/release-1.9.0.rst --- a/pypy/doc/release-1.9.0.rst +++ b/pypy/doc/release-1.9.0.rst @@ -64,7 +64,7 @@ functionality to test the validity of file descriptors; and correct handling of the calling convensions for ctypes. (Still not much progress on Win64.) A lot of work on this has been done by Matti Picus - and Amaury Forgeot D'Arc. + and Amaury Forgeot d'Arc. * Improvements in ``cpyext``, our emulator for CPython C extension modules. For example PyOpenSSL should now work. diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py @@ -82,7 +82,7 @@ # if os.name == 'nt': from _ffi import WinDLL, types - libc = WinDLL(libc_name) + libc = WinDLL('Kernel32.dll') sleep = libc.getfunc('Sleep', [types.uint], types.uint) delays = [0]*n + [1000] else: diff --git a/pypy/test_all.py b/pypy/test_all.py --- a/pypy/test_all.py +++ b/pypy/test_all.py @@ -3,9 +3,16 @@ PyPy Test runner interface -------------------------- -Running test_all.py is equivalent to running py.test -which you independently install, see -http://pytest.org/getting-started.html +Running pytest.py starts py.test, the testing tool +we use in PyPy. It is distributed along with PyPy, +but you may get more information about it at +http://pytest.org/. + +Note that it makes no sense to run all tests at once. +You need to pick a particular subdirectory and run + + cd pypy/.../test + ../../../pytest.py [options] For more information, use test_all.py -h. """ diff --git a/pytest.py b/pytest.py --- a/pytest.py +++ b/pytest.py @@ -1,6 +1,20 @@ #!/usr/bin/env python """ -unit and functional testing with Python. +PyPy Test runner interface +-------------------------- + +Running pytest.py starts py.test, the testing tool +we use in PyPy. It is distributed along with PyPy, +but you may get more information about it at +http://pytest.org/. + +Note that it makes no sense to run all tests at once. +You need to pick a particular subdirectory and run + + cd pypy/.../test + ../../../pytest.py [options] + +For more information, use pytest.py -h. """ __all__ = ['main'] @@ -23,6 +37,11 @@ from _pytest import __version__ if __name__ == '__main__': # if run as a script or by 'python -m pytest' + import os + if len(sys.argv) == 1 and os.path.dirname(sys.argv[0]) in '.': + print >> sys.stderr, __doc__ + sys.exit(2) + #XXX: sync to upstream later import pytest_cov raise SystemExit(main(plugins=[pytest_cov])) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit