[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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:
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.
28.1 Running the binding generator 28.2 Generating bindings for C++ headers 28.3 Switches
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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.
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] | [ ? ] |
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] | [ ? ] |
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |