diff --git a/docs/changelog.rst b/docs/changelog.rst index 92b23670b..d14dad862 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,7 +5,7 @@ Changelog 1.5 (not yet released) ---------------------- -* For polymorphic types, use RTTI to try to return the closest type registered with pybind11. +* For polymorphic types, use RTTI to try to return the closest type registered with pybind11 * Pickling support for serializing and unserializing C++ instances to a byte stream in Python * Added a convenience routine ``make_iterator()`` which turns a range indicated by a pair of C++ iterators into a iterable Python object diff --git a/docs/faq.rst b/docs/faq.rst index 12d28375e..7e45b8c9a 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -97,3 +97,101 @@ that that were ``malloc()``-ed in another shared library, using data structures with incompatible ABIs, and so on. pybind11 is very careful not to make these types of mistakes. +How can I reduce the build time? +================================ + +It's good practice to split binding code over multiple files, as is done in +the included file :file:`example/example.cpp`. + +.. code-block:: cpp + + void init_ex1(py::module &); + void init_ex2(py::module &); + /* ... */ + + PYBIND11_PLUGIN(example) { + py::module m("example", "pybind example plugin"); + + init_ex1(m); + init_ex2(m); + + /* ... */ + + return m.ptr(); + } + +The various ``init_ex`` functions are contained in separate files that can be +compiled independently from another. Following this approach will + +1. enable parallel builds (if desired). + +2. allow for faster incremental builds (e.g. if a single class definiton is + changed, only a subset of the binding code may need to be recompiled). + +3. reduce memory requirements. + +How can I create smaller binaries? +================================== + +To do its job, pybind11 extensively relies on a programming technique known as +*template metaprogramming*, which is a way of performing computation at compile +time using type information. Template metaprogamming usually instantiates code +involving significant numbers of deeply nested types that are either completely +removed or reduced to just a few instrutions during the compiler's optimization +phase. However, due to the nested nature of these types, the resulting symbol +names in the compiled extension library can be extremely long. For instance, +the included test suite contains the following symbol: + +.. code-block:: cpp + + __ZN8pybind1112cpp_functionC1Iv8Example2JRNSt3__16vectorINS3_12basic_stringIwNS3_11char_traitsIwEENS3_9allocatorIwEEEENS8_ISA_EEEEEJNS_4nameENS_7siblingENS_9is_methodEA28_cEEEMT0_FT_DpT1_EDpRKT2_ + +which is the mangled form of the following function type: + +.. code-block:: cpp + + pybind11::cpp_function::cpp_function, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >&, pybind11::name, pybind11::sibling, pybind11::is_method, char [28]>(void (Example2::*)(std::__1::vector, std::__1::allocator >, std::__1::allocator, std::__1::allocator > > >&), pybind11::name const&, pybind11::sibling const&, pybind11::is_method const&, char const (&) [28]) + +The memory needed to store just the name of this function (196 bytes) is larger +than the actual piece of code (111 bytes) it represents! On the other hand, +it's silly to even give this function a name -- after all, it's just a tiny +cog in a bigger piece of machinery that is not exposed to the outside world. +So we'll generally only want to export symbols for those functions which are +actually called from the outside. + +This can be achieved by specifying the parameter ``-fvisibility=hidden`` to GCC +and Clang, which sets the default symbol visibility to *hidden*. It's best to +do this only for release builds, since the symbol names can be helpful in +debugging sessions. On Visual Studio, symbols are already hidden by default, so +nothing needs to be done there. Needless to say, this has a tremendous impact +on the final binary size of the resulting extension library. + +Another aspect that can require a fair bit of code are function signature +descriptions. pybind11 automatically generates human-readable function +signatures for docstrings, e.g.: + +.. code-block:: none + + | __init__(...) + | __init__(*args, **kwargs) + | Overloaded function. + | + | 1. __init__(example.Example1) -> NoneType + | + | Docstring for overload #1 goes here + | + | 2. __init__(example.Example1, int) -> NoneType + | + | Docstring for overload #2 goes here + | + | 3. __init__(example.Example1, example.Example1) -> NoneType + | + | Docstring for overload #3 goes here + + +In C++11 mode, these are generated at run time using string concatenation, +which can amount to 10-20% of the size of the resulting binary. If you can, +enable C++14 language features (using ``-std=c++14`` for GCC/Clang), in which +case signatures are efficiently pre-generated at compile time. Unfortunately, +Visual Studio's C++14 support (``constexpr``) is not good enough as of April +2016, so it always uses the more expensive run-time approach.