GNAT GPL User's Guide: Generating Ada Bindings for C and C++ headers

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

# 29. Generating Ada Bindings for C and C++ headers

GNAT now comes with a binding generator for C and C++ headers which is intended to do 95% of the tedious work of generating Ada specs from C or C++ header files.

Note that this capability is not intended to generate 100% correct Ada specs, and will is some cases require manual adjustments, although it can often be used out of the box in practice.

Some of the known limitations include:

- only very simple character constant macros are translated into Ada constants. Function macros (macros with arguments) are partially translated as comments, to be completed manually if needed.
- some extensions (e.g. vector types) are not supported
- pointers to pointers or complex structures are mapped to System.Address
- identifiers with identical name (except casing) will generate compilation errors (e.g. `shm_get` vs `SHM_GET`).

The code generated is using the Ada 2005 syntax, which makes it easier to interface with other languages than previous versions of Ada.

> 29.1 Running the binding generator |  |
> 29.2 Generating bindings for C++ headers |  |
> 29.3 Switches |  |

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 29.1 Running the binding generator

The binding generator is part of the `gcc` compiler and can be invoked via the ``-fdump-ada-spec'` switch, which will generate Ada spec files for the header files specified on the command line, and all header files needed by these files transitively. For example:

    $ g++ -c -fdump-ada-spec -C /usr/include/time.h
    $ gcc -c -gnat05 *.ads

will generate, under GNU/Linux, the following files: ``time_h.ads'`, ``bits_time_h.ads'`, ``stddef_h.ads'`, ``bits_types_h.ads'` which correspond to the files ``/usr/include/time.h'`, ``/usr/include/bits/time.h'`, etc..., and will then compile in Ada 2005 mode these Ada specs.

The `-C` switch tells `gcc` to extract comments from headers, and will attempt to generate corresponding Ada comments.

If you want to generate a single Ada file and not the transitive closure, you can use instead the ``-fdump-ada-spec-slim'` switch.

You can optionally specify a parent unit, of which all generated units will be children, using `-fada-spec-parent=`unit.

Note that we recommend when possible to use the `g++` driver to generate bindings, even for most C headers, since this will in general generate better Ada specs. For generating bindings for C++ headers, it is mandatory to use the `g++` command, or `gcc -x c++` which is equivalent in this case. If `g++` cannot work on your C headers because of incompatibilities between C and C++, then you can fallback to `gcc` instead.

For an example of better bindings generated from the C++ front-end, the name of the parameters (when available) are actually ignored by the C front-end. Consider the following C header:

    extern void foo (int variable);

with the C front-end, `variable` is ignored, and the above is handled as:

    extern void foo (int);

generating a generic:

    procedure foo (param1 : int);

with the C++ front-end, the name is available, and we generate:

    procedure foo (variable : int);

In some cases, the generated bindings will be more complete or more meaningful when defining some macros, which you can do via the ``-D'` switch. This is for example the case with ``Xlib.h'` under GNU/Linux:

    g++ -c -fdump-ada-spec -DXLIB_ILLEGAL_ACCESS -C /usr/include/X11/Xlib.h

The above will generate more complete bindings than a straight call without the ``-DXLIB_ILLEGAL_ACCESS'` switch.

In other cases, it is not possible to parse a header file in a stand-alone manner, because other include files need to be included first. In this case, the solution is to create a small header file including the needed `#include` and possible `#define` directives. For example, to generate Ada bindings for ``readline/readline.h'`, you need to first include ``stdio.h'`, so you can create a file with the following two lines in e.g. ``readline1.h'`:

    #include <stdio.h>
    #include <readline/readline.h>

and then generate Ada bindings from this file:

    $ g++ -c -fdump-ada-spec readline1.h

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 29.2 Generating bindings for C++ headers

Generating bindings for C++ headers is done using the same options, always with the `g++` compiler.

In this mode, C++ classes will be mapped to Ada tagged types, constructors will be mapped using the `CPP_Constructor` pragma, and when possible, multiple inheritance of abstract classes will be mapped to Ada interfaces (See section `Interfacing to C++' in GNAT Reference Manual, for additional information on interfacing to C++).

For example, given the following C++ header file:

    class Carnivore {
    public:
       virtual int Number_Of_Teeth () = 0;
    };

    class Domestic {
    public:
       virtual void Set_Owner (char* Name) = 0;
    };

    class Animal {
    public:
      int Age_Count;
      virtual void Set_Age (int New_Age);
    };

    class Dog : Animal, Carnivore, Domestic {
     public:
      int  Tooth_Count;
      char *Owner;

      virtual int  Number_Of_Teeth ();
      virtual void Set_Owner (char* Name);

      Dog();
    };

The corresponding Ada code is generated:

      package Class_Carnivore is
        type Carnivore is limited interface;
        pragma Import (CPP, Carnivore);

        function Number_Of_Teeth (this : access Carnivore) return int is abstract;
      end;
      use Class_Carnivore;

      package Class_Domestic is
        type Domestic is limited interface;
        pragma Import (CPP, Domestic);

        procedure Set_Owner
          (this : access Domestic;
           Name : Interfaces.C.Strings.chars_ptr) is abstract;
      end;
      use Class_Domestic;

      package Class_Animal is
        type Animal is tagged limited record
          Age_Count : aliased int;
        end record;
        pragma Import (CPP, Animal);

        procedure Set_Age (this : access Animal; New_Age : int);
        pragma Import (CPP, Set_Age, "_ZN6Animal7Set_AgeEi");
      end;
      use Class_Animal;

      package Class_Dog is
        type Dog is new Animal and Carnivore and Domestic with record
          Tooth_Count : aliased int;
          Owner : Interfaces.C.Strings.chars_ptr;
        end record;
        pragma Import (CPP, Dog);

        function Number_Of_Teeth (this : access Dog) return int;
        pragma Import (CPP, Number_Of_Teeth, "_ZN3Dog15Number_Of_TeethEv");

        procedure Set_Owner
          (this : access Dog; Name : Interfaces.C.Strings.chars_ptr);
        pragma Import (CPP, Set_Owner, "_ZN3Dog9Set_OwnerEPc");

        function New_Dog return Dog;
        pragma CPP_Constructor (New_Dog);
        pragma Import (CPP, New_Dog, "_ZN3DogC1Ev");
      end;
      use Class_Dog;

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

## 29.3 Switches

``-fdump-ada-spec'`
  Generate Ada spec files for the given header files transitively (including all header files that these headers depend upon).

``-fdump-ada-spec-slim'`
  Generate Ada spec files for the header files specified on the command line only.

``-fada-spec-parent=unit'`
  Specifies that all files generated by ``-fdump-ada-spec*'` are to be child units of the specified parent unit.

``-C'`
  Extract comments from headers and generate Ada comments in the Ada spec files.

[ << ] | [ >> ] |  |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

This document was generated by GNAT Mailserver on April, 17 2014 using texi2html