.. _cmake_interface:

CMake interface
===============

CMake fragments are provided for an Automated generation of an end-user
bindings package from a CMake-based project build.
The bindings generated by rootcling, are 'raw' in the sense that:

* The .cpp file be compiled. The required compilation steps are
  platform-dependent.
* The bindings are not packaged for distribution. Typically, users expect
  to have a pip-compatible package.
* The binding are in the 'cppyy.gbl' namespace. This is an inconvenience at
  best for users who might expect C++ code from KF5::Config to appear in
  Python via "import KF5.Config".
* The bindings are loaded lazily, which limits the discoverability of the
  content of the bindings.
* ``cppyy`` supports customization of the bindings via 'Pythonization' but
  there is no automated way to load them.

These issues are addressed by the CMake support. This is a blend of Python
packaging and CMake where CMake provides:

* Platform-independent scripting of the creation of a Python 'wheel' package
  for the bindings.
* An facility for CMake-based projects to automate the entire bindings
  generation process, including basic automated tests.

.. note::

    The JIT needs to resolve linker symbols in order to call them through
    generated wrappers.
    Thus, any classes, functions, and data that will be used in Python need
    to be exported.
    This is the default behavior on Mac and Linux, but not on Windows.
    On that platform, use ``__declspec(dllexport)`` to explicitly export the
    classes and function you expect to call.
    CMake has simple `support for exporting all`_ C++ symbols.


Python packaging
----------------

Modern Python packaging usage is based on the 'wheel'. This is places the onus
on the creation of binary artifacts in the package on the distributor. In this
case, this includes the platform-dependent steps necessary to compile the .cpp
file.

The generated package also takes advantage of the __init__.py load-time
mechanism to enhance the bindings:

* The bindings are rehosted in a "native" namespace so that C++ code from
  KF5::Config appears in Python via "import KF5.Config".
* (TBD) Load Pythonizations.

Both of these need/can use the output of the
:ref:`cppyy-generator <cppyy-generator>` (included in the package) as well as
other runtime support included in ``cppyy``.


CMake usage
-----------

The CMake usage is via two modules:

* FindLibClang.cmake provides some bootstrap support needed to locate clang.
  This is provided mostly as a temporary measure; hopefully upstream support
  will allow this to be eliminated in due course.
* FindCppyy.cmake provides the interface described further here.

Details of the usage of these modules is within the modules themselves, but
here is a summary of the usage. ``FindLibClang.cmake`` sets the following
variables:

::

    LibClang_FOUND             - True if libclang is found.
    LibClang_LIBRARY           - Clang library to link against.
    LibClang_VERSION           - Version number as a string (e.g. "3.9").
    LibClang_PYTHON_EXECUTABLE - Compatible python version.


``FindCppyy.cmake`` sets the following variables:

::

    Cppyy_FOUND - set to true if Cppyy is found
    Cppyy_DIR - the directory where Cppyy is installed
    Cppyy_EXECUTABLE - the path to the Cppyy executable
    Cppyy_INCLUDE_DIRS - Where to find the Cppyy header files.
    Cppyy_VERSION - the version number of the Cppyy backend.

and also defines the following functions::

    cppyy_add_bindings - Generate a set of bindings from a set of header files.
    cppyy_find_pips - Return a list of available pip programs.

cppyy_add_bindings
^^^^^^^^^^^^^^^^^^

Generate a set of bindings from a set of header files. Somewhat like CMake's
add_library(), the output is a compiler target. In addition ancillary files
are also generated to allow a complete set of bindings to be compiled,
packaged and installed::

  cppyy_add_bindings(
      pkg
      pkg_version
      author
      author_email
      [URL url]
      [LICENSE license]
      [LANGUAGE_STANDARD std]
      [LINKDEFS linkdef...]
      [IMPORTS pcm...]
      [GENERATE_OPTIONS option...]
      [COMPILE_OPTIONS option...]
      [INCLUDE_DIRS dir...]
      [LINK_LIBRARIES library...]
      [H_DIRS H_DIRSectory]
      H_FILES h_file...)

The bindings are based on https://cppyy.readthedocs.io/en/latest/, and can be
used as per the documentation provided via the cppyy.gbl namespace. First add
the directory of the <pkg>.rootmap file to the LD_LIBRARY_PATH environment
variable, then "import cppyy; from cppyy.gbl import <some-C++-entity>".

Alternatively, use "import <pkg>". This convenience wrapper supports
"discovery" of the available C++ entities using, for example Python 3's command
line completion support.

The bindings are complete with a setup.py, supporting Wheel-based
packaging, and a test.py supporting pytest/nosetest sanity test of the bindings.

The bindings are generated/built/packaged using 3 environments:

- One compatible with the header files being bound. This is used to
  generate the generic C++ binding code (and some ancillary files) using
  a modified C++ compiler. The needed options must be compatible with the
  normal build environment of the header files.
- One to compile the generated, generic C++ binding code using a standard
  C++ compiler. The resulting library code is "universal" in that it is
  compatible with both Python2 and Python3.
- One to package the library and ancillary files into standard Python2/3
  wheel format. The packaging is done using native Python tooling.

+----------------------+---------------------------------------------------------------------------------------------+
|Arguments and options | Description                                                                                 |
+======================+=============================================================================================+
|pkg                   | The name of the package to generate. This can be either                                     |
|                      | of the form "simplename" (e.g. "Akonadi"), or of the                                        |
|                      | form "namespace.simplename" (e.g. "KF5.Akonadi").                                           |
+----------------------+---------------------------------------------------------------------------------------------+
|pkg_version           | The version of the package.                                                                 |
+----------------------+---------------------------------------------------------------------------------------------+
|author                | The name of the library author.                                                             |
+----------------------+---------------------------------------------------------------------------------------------+
|author_email          | The email address of the library author.                                                    |
+----------------------+---------------------------------------------------------------------------------------------+
|URL url               | The home page for the library. Default is                                                   |
|                      | "https://pypi.python.org/pypi/<pkg>".                                                       |
+----------------------+---------------------------------------------------------------------------------------------+
|LICENSE license       | The license, default is "LGPL 2.0".                                                         |
+----------------------+---------------------------------------------------------------------------------------------+
|LANGUAGE_STANDARD std | The version of C++ in use, "14" by default.                                                 |
+----------------------+---------------------------------------------------------------------------------------------+
|IMPORTS pcm           | Files which contain previously-generated bindings                                           |
|                      | which pkg depends on.                                                                       |
+----------------------+---------------------------------------------------------------------------------------------+
|GENERATE_OPTIONS optio| Options which are to be passed into the rootcling                                           |
|                      | command. For example, bindings which depend on Qt                                           |
|                      | may need "-D__PIC__;-Wno-macro-redefined".                                                  |
+----------------------+---------------------------------------------------------------------------------------------+
|LINKDEFS def          | Files or lines which contain extra #pragma content                                          |
|                      | for the linkdef.h file used by rootcling. See                                               |
|                      | https://root.cern.ch/root/html/guides/users-guide/AddingaClass.html#the-linkdef.h-file.     |
|                      |                                                                                             |
|                      | In lines, literal semi-colons must be escaped: "\;".                                        |
+----------------------+---------------------------------------------------------------------------------------------+
|EXTRA_CODES code      | Files which contain extra code needed by the bindings.                                      |
|                      | Customization is by routines named "c13n_<something>";                                      |
|                      | each such routine is passed the module for <pkg>:                                           |
|                      |                                                                                             |
|                      | :: code-block python                                                                        |
|                      |                                                                                             |
|                      |     def c13n_doit(pkg_module):                                                              |
|                      |         print(pkg_module.__dict__)                                                          |
|                      |                                                                                             |
|                      | The files and individual routines within files are                                          |
|                      | processed in alphabetical order.                                                            |
+----------------------+---------------------------------------------------------------------------------------------+
|EXTRA_HEADERS hdr     | Files which contain extra headers needed by the bindings.                                   |
+----------------------+---------------------------------------------------------------------------------------------+
|EXTRA_PYTHONS py      | Files which contain extra Python code needed by the bindings.                               |
+----------------------+---------------------------------------------------------------------------------------------+
|COMPILE_OPTIONS option| Options which are to be passed into the compile/link                                        |
|                      | command.                                                                                    |
+----------------------+---------------------------------------------------------------------------------------------+
|INCLUDE_DIRS dir      | Include directories.                                                                        |
+----------------------+---------------------------------------------------------------------------------------------+
|LINK_LIBRARIES library| Libraries to link against.                                                                  |
+----------------------+---------------------------------------------------------------------------------------------+
|H_DIRS directory      | Base directories for H_FILES.                                                               |
+----------------------+---------------------------------------------------------------------------------------------+
|H_FILES h_file        | Header files for which to generate bindings in pkg.                                         |
|                      | Absolute filenames, or filenames relative to H_DIRS. All                                    |
|                      | definitions found directly in these files will contribute                                   |
|                      | to the bindings. (NOTE: This means that if "forwarding                                      |
|                      | headers" are present, the real "legacy" headers must be                                     |
|                      | specified as H_FILES).                                                                      |
|                      | All header files which contribute to a given C++ namespace                                  |
|                      | should be grouped into a single pkg to ensure a 1-to-1                                      |
|                      | mapping with the implementing Python class.                                                 |
+----------------------+---------------------------------------------------------------------------------------------+

Returns via PARENT_SCOPE variables::

  target              The CMake target used to build.
  setup_py            The setup.py script used to build or install pkg.

Examples::

  find_package(Qt5Core NO_MODULE)
  find_package(KF5KDcraw NO_MODULE)
  get_target_property(_H_DIRS KF5::KDcraw INTERFACE_INCLUDE_DIRECTORIES)
  get_target_property(_LINK_LIBRARIES KF5::KDcraw INTERFACE_LINK_LIBRARIES)
  set(_LINK_LIBRARIES KF5::KDcraw ${_LINK_LIBRARIES})
  include(${KF5KDcraw_DIR}/KF5KDcrawConfigVersion.cmake)

  cppyy_add_bindings(
      "KDCRAW" "${PACKAGE_VERSION}" "Shaheed" "srhaque@theiet.org"
      LANGUAGE_STANDARD "14"
      LINKDEFS "../linkdef_overrides.h"
      GENERATE_OPTIONS "-D__PIC__;-Wno-macro-redefined"
      INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS}
      LINK_LIBRARIES ${_LINK_LIBRARIES}
      H_DIRS ${_H_DIRS}
      H_FILES "dcrawinfocontainer.h;kdcraw.h;rawdecodingsettings.h;rawfiles.h")


cppyy_find_pips
^^^^^^^^^^^^^^^

Return a list of available pip programs.


.. _`support for exporting all`: https://cmake.org/cmake/help/latest/prop_tgt/WINDOWS_EXPORT_ALL_SYMBOLS.html
