Provided by: cppgir_0~git20230606.960fe05-1_amd64 bug

NAME

       cppgir - GObject-Introspection C++ binding wrapper generator

SYNOPSIS

       cppgir [OPTION...] --output DIRECTORY GIR...

DESCRIPTION

       cppgir  reads  each  of  the  specified GIR and converts these (and any dependencies) into
       C++11 wrapper code that collectively then make up a  'binding'  (in  GObject-Introspection
       https://wiki.gnome.org/Projects/GObjectIntrospection   terminology).   Each   GIR  can  be
       specified as a full pathname to the .gir file or simply by the basename (i.e. no  path  or
       .gir  suffix), with or without version. Of course, in the latter case, the .gir must be in
       a standard location, or other options must specify additional whereabouts.

OPTIONS

       See BACKGROUND later on for further details on some of the concepts used in the  following
       descriptions.

       --output DIRECTORY
              Specifies  the top-level directory in which to generate code. It will be created if
              it does not yet exist.

       --gir-path PATHS
              Adds a colon-separated list of additional directories within which to (recursively)
              search for a .gir file (if not specified by full pathname).

       --debug LEVEL
              Debug level or level of verbosity, higher numbers are more verbose.

       --ignore FILES
              Adds a colon-separated list of so-called ignore files.

       --suppression FILES
              Adds a colon-separated list of so-called suppression files.

       --gen-suppression FILE
              Specifies a suppression file to generate during this run.

       --class
              Requests generation of implementation class code needed for subclassing.

       --expected
              Use an error return type based on std::expected http://wg21.link/p0323 proposal (as
              opposed to throwing exception).

BACKGROUND

   API
       The generated code provides a  straight  binding  as  specified  by  the  annotations,  so
       everything  is  pretty  much where expected, such as methods within classes in turn within
       namespaces. For example, all GObject types are within  namespace  gi::repository::GObject.
       With  that  in  mind,  it should be easy to use and navigate in generated code, along with
       following comments:

       ○   As customary, anything within a detail or internal namespace is not meant  for  public
           use  and  subject to change. The top-level gi namespace defines a few things that make
           up public API which is meant to be stable (though at this stage of  maturity  no  full
           guarantee is provided).

       ○   Some  generated  code  may have _ (underscore) appended to it simply to avoid clashing
           with a reserved keyword (or a preprocessor definition). It has no  special  (reserved)
           meaning otherwise.

       ○   However,  anything  with  leading  underscore (if encountered) should be considered as
           internal (and not meant for public API).

       In overall, the generated code is very lightweight and clear, easily understood  and  with
       little  runtime  overhead.  For  instance,  a GObject is still a single pointer along with
       class code for easily handling it around and managing  refcount  (including  cleanup  upon
       destruction).  Similarly, a boxed GType is handled by a std::shared_ptr (with g_boxed_free
       deleter) and suitable helper methods. Various enum, (static)  method,  functions,  typedef
       (for callback) fill in the rest.

       Functions  that  involve the usual GError return pattern are wrapped in a few ways. On the
       one hand, in a straight way, where the  error  is  a  (wrapped  error)  output  parameter.
       Alternatively,  the  error  parameter  is  removed  from the signature. In that case it is
       "returned" by either  throwing  the  (wrapped)  error  (which  is  also  a  std::exception
       subclasss), or by returning a suitable expected type (with the wrapped error type as error
       type). While throwing is default behaviour, the latter can be requested  using  --expected
       option.

       Some  additional specifications on how subclasses and interfaces are mapped may also be in
       order. A subclass in the GObject world is  directly  mapped  as  a  subclass  in  the  C++
       binding.  However,  if  a  GObject  implements  an interface, the generated class does not
       inherit  from  the  interface's  (generated)  class.  This  is  mostly  of  a  matter   of
       implementation  choice  (and  to ensure its lightweight simplicity). However, knowledge of
       implemented interfaces  is  not  always  available  at  compile  time,  e.g.  in  case  of
       dynamically loaded GStreamer elements (though it is more likely in case of Gtk hierarchy).
       Since there would be no inheritance in the dynamic case, a consistent  choice  is  not  to
       have  it  at  any  time.  However,  for ease of use, some helper code is generated when an
       implemented interface is known at generation/compile time, as illustrated in the following
       snippet from an example

       c++   //  use  a  cast  if  not  known,  either  to  a  class  or  interface  auto  bin  =
       gi::object_cast<Gst::Bin>(playbin_); //  known  at  compile  time;  overloaded  interface_
       method auto cp = bin.interface_ (gi::interface_tag<Gst::ChildProxy>());

       There  may  be  times when one would want to make a custom subclass of GObject, or of some
       Gtk widget. In the same vein, (current) implementation choices imply that one  should  not
       simply  inherit  from  Gtk::Window.  Part  of the motivation here is that such subclassing
       depends on style and setting, i.e. it is rather rare when in a GStreamer setting, but less
       so in e.g. Gtk. As such, the possibly rare cases should not burden or complicate the basic
       wrapping usecase.

       So, how to subclass then? By a slight twist by using the impl namespace variations, as  in
       following excerpt from an example:

       c++   class   TreeViewFilterWindow   :  public  Gtk::impl::WindowImpl  {  //  ...  public:
       TreeViewFilterWindow () : Gtk::impl::WindowImpl (typeid (*this)) {  //  ...  }  };  Parent
       (class  or  interface)  methods  can then be overridden or implemented in the usual way by
       simply defining them in the subclass. It is also possible  to  define  custom  signal  and
       properties in the subclass, as illustrated in the gobject.cpp example.

       Since this is considered an optional feature, the impl parts are not generated by default,
       but only if the --class option is specified.

   CODE LAYOUT AND BUILD SETUP
       The generated code is written to  the  top-level  with  the  following  layout.  Each  GIR
       namespace   has   a  corresponding  subdirectory,  say  ns  (and  also  a  C++  namespace,
       cppgir::repository::ns). The top-levels headers for a namespace are then:

       ns.hpp a regular header providing the namespace's declarations. It will also  include  the
              dependent  namespaces' top headers. If the macro GI_INLINE is defined, then it will
              also include ...

       ns_impl.hpp
              contains the definitions corresponding to the declarations. Normally, this would be
              a  .cpp  file, but as they might be included directly in the inline case, they have
              been named xxx_impl.hpp instead.

       ns.cpp this merely includes ns_impl.hpp and is as  such  no  different  than  the  latter,
              except  for  more  traditional  naming.  Compiling this file in the non-inline case
              provides all the definitions for the namespace in the resulting object file.

       So, in summary, it comes down to setting  up  the  build  system  to  build  each  of  the
       namespaces'  .cpp,  as  is  also done in this repo's CMake build setup. There is one other
       shortcut build setup that is illustrated by the gtk-obj.cpp example file,  which  includes
       all definitions (recursively):

       c++ #define GI_INCLUDE_IMPL 1 #include <gtk/gtk.hpp>

       Note,  however,  this is only possible if there is exactly 1 top-level namespace, as doing
       this for several namespaces will lead to duplicate definitions.

       Some items (functions, types) may be marked as deprecated (in source  code).  while  still
       present  in  GIR  data.  Wrappers  will  still be generated and pragma are issued to avoid
       warnings that might otherwise occur. Generic gi support tries to  avoid  using  deprecated
       code.  There  is,  however,  one  exception  regarding  the use of g_object_newv, which is
       deprecated but may have to be used if support for an older GLib is required. This  can  be
       arranged  by  defining GI_OBJECT_NEWV (and the deprecation warning should also be silenced
       when dealing with newer version).

       If you have specified the --class option, then the generated code  will  possibly  contain
       classes  that  inherit  from  several  classes  (representing  interfaces).  Since various
       interfaces may have overlapping member names, this  might  trigger  compilation  warnings.
       These are not suppressed by default, as you may need to be made aware of this. However, if
       it does no harm in you particular case, then defining GI_CLASS_IMPL_PRAGMA should  arrange
       for proper suppression.

   OVERRIDING OR EXTENDING
       It  is  possible to add functions or methods or override existing names (by effect of name
       hiding). To this end, the generated code contains various 'optional include  hooks'  using
       the  __has_include directive. This way, code in externally supplied (include) files can be
       inserted into the class definition chain. There are roughly 3 such 'hook points':

       initial setup
              this part  is  (conditionally)  included  before  the  namespace's  C  headers  are
              included.  This  allows  specifying  define's to tweak subsequent headers or to add
              headers that also need to be include'd, and which may not have  been  specified  in
              the GIR.

       class definition
              these hooks allow extending the wrapped class with new or tweaked methods

       global extra definitions
              these  are  included  after  all  generated code, and supports adding of new global
              functions, typedef's, type trait helper declarations, ...

       The reader is invited to examine the default  overrides  in  this  repo  as  well  as  the
       generated  code  to  see how this fits together based on a simple naming scheme and use of
       macros. In particular, see the provided GLib overrides. Suffice it to add  that  the  _def
       suffix  refers to 'default' as supplied by this repo and which are installed alongside the
       common headers. The  corresponding  non-suffixed  filenames  should  be  used  by  project
       specific custom additions.

   CODE GENERATION
       It might be necessary to exclude a GIR entry from processing, either because it is a basic
       type handled by custom code (e.g. GObject, GValue, ...) or because of a faulty annotation.
       The  latter  can  be  a  glitch in the annotation itself, or one that actually refers to a
       symbol in a non-included private header. The exclusion can be directed by so-called ignore
       files,  and  at least one such is supplied as a system default ignore containing known and
       essential cases to exclude (and without which code  generation  would  not  produce  valid
       code).  Such  a  file  consists  of  lines  of  regular expressions (# commented lines are
       ignored).    At    generation    time,    each     symbol     is     turned     into     a
       <NAMESPACE>:<SYMBOLKIND>:<SYMBOL>  string,  and  excluded  if it matches one of the lines'
       regular expression. So, for instance, GObject:record:Value prevents processing of  GValue,
       since  there  is  already  special-case  code  for that in the common header code. Further
       expression examples are found  in  the  default  ignore  file.  Additional  files  can  be
       specified by the --ignore option.

       As  each  entry  is  processed,  some  notification  may  be  given  regarding a perceived
       inconsistency in an annotation or an unsupported case (see  also  BUGS  AND  LIMITATIONS).
       When  the  reported  cases  have  been  (manually)  checked  and  considered harmless, the
       corresponding notices can be suppressed by specifying suppression files to  --suppression.
       The  format  of  such  files  is the same as ignore files, except that a match then simply
       serves to decrease reporting verbosity. Such a file could be hand-crafted, but it can also
       be auto-generated by a run when specifying --gen-suppression.

BUGS AND LIMITATIONS

       The  generated code's coverage is pretty good and comfortably serves most cases that arise
       in practice as also illustrated by the examples. Nevertheless,  the  following  should  be
       mentioned:

       Callback  types.  Only  callback  types  that  have  an  explicit  user_data parameter are
       supported. That includes (fortunately)  cases  such  as  connecting  to  a  signal,  or  a
       GstPadProbeCallback,  though  a GstPadChainFunction is excluded. The reason is a technical
       one; the user_data parameter is used to pass data used by callback wrapper code. A typical
       (script)  runtime  binding  handles  this  using libffi https://github.com/libffi/libffi's
       closure API. In effect, a little bit of executable code is then generated at runtime,  and
       the  address  of  that  code then essentially serves as surrogate user_data that can carry
       extra meta-data for use by the runtime. This could also  be  employed  here  to  lift  the
       user_data limitation, it would take a bit extra work, but would more importantly then also
       incur an additional dependency.

       Callback handling. Even if user_data is present, other aspects of a callback signature may
       not be supported (at this time). Most notably, output parameters or container (e.g. array)
       parameters are not supported. This limitation  is  currently  due  to  a  plain-and-simple
       implementation of callback wrapping. Some additional work could remove these restrictions,
       though as it stands the simple approach likely covers most interesting cases.

       const handling. In C++, this is a Bigger Thing. For instance,  a  simple  'getter'  should
       preferably  be  marked const. However, on the original C-side of things, only very limited
       consideration is given to this. Even if there is some const, it is not  treated  with  all
       that  much respect, e.g. g_value_take_boxed starts const but it is merrily cast away along
       the way. As such, there is not much to find on const-ness in annotation data,  and  so  no
       point  in  inventing any. Rather, the focus is simply on getting the proper function calls
       done along with automagic refcount and resource management (much as  any  runtime  binding
       would do, with no regard for const whatsoever in that case).

ENVIRONMENT

       In  stead  of command-line options, environment variables can also be used. Note, however,
       that options are still taken into account even when variables have been set. The following
       environment  variables  are  considered,  and  have  the same meaning as the corresponding
       command-line option:

       GI_DEBUG, GI_IGNORE, GI_SUPPRESSION, GI_GEN_SUPPRESSION, GI_OUTPUT, GI_CLASS, GI_EXPECTED,
       GI_GIR_PATH

       In addition to the above, GI_GIR can specify a colon-separated lists of GIRs (specified as
       on command-line). XDG_DATA_DIRS is also used as additional source of directories to search
       for GIRs (within a gir-1.0 subdirectory).

SEE ALSO

       g-ir-scanner(1)

                                            June 2023                                   CPPGIR(1)