========================
Multi-module development
========================

.. contents:: Table of contents

------------
Introduction
------------

It is a common practices to construct final program or a package from few
different dependent or independent C++ libraries. Many time these libraries
reuse classes\\functions defined in some other library. I think this is a must
requirement from a code generator to be able to expose these libraries to `Python`_ ,
without "re-exposing" the class\\functions definition twice.

This functionality is new in version "0.8.6".

---------------------
Use case introduction
---------------------

Lets say that you have to expose few libraries, which deal with image processing:

* ``core`` library - defines base class for all image classes - ``image_i``

* ``png`` library - defines class ``png_image_t``, which derives from
  ``core::image_i`` and implements functionality for "png" image format.

The code:

.. code-block:: C++

  namespace core{
      class image_i{
          ...
          virtual void load() = 0;
      };
  } //core

  namespace png{
      class png_image_t : public core::image_i{
          ...
          virtual void load();
      };
  }


The desired goal is to expose every class in its own package.

-------------------
``already_exposed``
-------------------

Every `Py++`_ declaration has ``already_exposed`` property. This property says
to `Py++`_ that the declaration is already exposed in another module:

.. code-block:: Python

  #generate_code.py script

  mb_core = module_builder_t( ... )
  mb_core.class_( 'image_i' ).include()
  mb_core.build_code_creator( 'core' )
  mb.write_module( 'core.cpp' )

  mb_png = module_builder_t( ... )
  mb_png.class_( '::core::image_i' ).already_exposed = True
  mb_png.class_( '::png::png_image_t' ).include()
  mb_core.build_code_creator( 'png' )
  mb.write_module( 'png.cpp' )

`Py++`_ will generate code very similar to the the following one:

.. code-block:: C++

  //file core.cpp
  namespace bp = boost::python;

  struct image_i_wrapper : core::image_i, bp::wrapper< core::image_i > {
      image_i_wrapper()
      : core::image_i(), bp::wrapper< core::image_i >()
      {}

      virtual void load(  ){
          bp::override func_load = this->get_override( "load" );
          func_load(  );
      }
      ...
  };

  BOOST_PYTHON_MODULE(core){
      bp::class_< image_i_wrapper, boost::noncopyable >( "image_i" )
          ...
          .def( "load", bp::pure_virtual( &::core::image_i::load ) );
  }

.. code-block:: C++

  //file png.cpp
  struct png_image_t_wrapper : png::png_image_t, bp::wrapper< png::png_image_t > {

      png_image_t_wrapper()
      : png::png_image_t(), bp::wrapper< png::png_image_t >()
      {}

      virtual void load(  ) {
          if( bp::override func_load = this->get_override( "load" ) )
              func_load(  );
          else
              this->png::png_image_t::load(  );
      }

      void default_load(  ) {
          png::png_image_t::load( );
      }
  };

  BOOST_PYTHON_MODULE(pyplusplus){
      bp::class_< png_image_t_wrapper, bp::bases< core::image_i > >( "png_image_t" )
      //-------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^
        ...
        .def( "load", &::png::png_image_t::load, &png_image_t_wrapper::default_load );
  }

As you can see "png.cpp" file doesn't contains code, which exposes ``core::image_i``
class.


-----------------------
Semi-automatic solution
-----------------------

``already_exposed`` solution is pretty good when you mix hand-written modules with
the Py++ generated ones. It doesn't work/scale for "true" multi-module development. 
This is exactly the reason why `Py++`_ offers "semi automatic" solution.

For every exposed module, `Py++`_ generates "exposed_decl.pypp.txt" file. This
file contains the list of all parsed declarations and whether they were included
or excluded. Later, when you work on another module, you can tell `Py++`_ that 
the current module depends on the previously generated one. `Py++`_ will load 
"exposed_decl.pypp.txt" file and update the declarations.

Usage example:

.. code-block:: Python

   mb = module_builder_t( ... )   
   mb.register_module_dependency( <<<other module generated code directory>>> )


------
Caveat
------

You should import module "core", before "png". `Boost.Python`_ requires definition
of any base class to be exposed\\registered before a derive one.


.. _`Py++` : ./../pyplusplus.html
.. _`Boost.Python`: http://www.boost.org/libs/python/doc/index.html
.. _`Python`: http://www.python.org
.. _`GCC-XML`: http://www.gccxml.org

