GNAT User's Guide Supplement for the .NET Platform


Next: , Previous: (dir), Up: (dir)


Next: , Previous: Top, Up: (dir)

About This Guide

This guide describes the features and the use of GNAT, the Ada development environment for the .NET platform. This guide also explains how to use the .NET API from Ada and how to interface Ada and the .NET framework.

Before reading this manual you should be familiar with the GNAT User's Guide as a thorough understanding of the concepts and notions explained there is needed to use GNAT effectively.


Next: , Previous: About This Guide, Up: About This Guide

What This Guide Contains

This guide contains the following chapters:


Next: , Previous: What This Guide Contains, Up: About This Guide

What You Should Know Before Reading This Guide

Before reading this document readers should be familiar with the GNAT User's Guide and have a conceptual understanding of the .NET technology.


Next: , Previous: What you should know before reading this guide, Up: About This Guide

Related Information

For further information about GNAT, Ada, and the .NET technology, we recommend consulting the following documents:


Previous: Related Information, Up: About This Guide

Conventions

Following are examples of the typographical and graphic conventions used in this guide:

Commands that are entered by the user are preceded in this manual by the “$ ” characters (dollar sign followed by space). If your system uses this sequence as a prompt, then the commands will appear exactly as you see them in the manual. If your system uses some other prompt, then the command will appear with the $ replaced by whatever prompt character you are using.


Next: , Previous: About This Guide, Up: (dir)

1 Getting Started with GNAT for .NET


Next: , Previous: Getting Started with GNAT for .NET, Up: Getting Started with GNAT for .NET

1.1 Overview

The .NET technology, introduced by Microsoft, is a paradigm whose goal is to add platform-independent programming flexibility to applications and embedded devices such as consumer electronics, smart cards, etc.

The .NET technology consists of a comprehensive set of libraries (.NET API), and a virtual execution environment offering the same object code interface on all platforms (bytecode).

The GNAT system offers an Ada programming environment for the .NET platform. In addition to a bytecode compiler, binder and linker, GNAT contains a .NET-to-Ada-2005 binding generator that produces the Ada 2005 specs of the services contained in any .NET .class file or API.

Furthermore, because the .dll files generated by the GNAT compiler are fully compliant with the CIL standard, the user can employ any .NET debugger to debug Ada code, and can use any of the .NET tools that operate on .dll files (e.g. ildasm, gacutil, etc.).

As a side note, the GNAT system is implemented in Ada 2005 and its sources are available under the GPL.


Next: , Previous: Overview, Up: Getting Started with GNAT for .NET

1.2 GNAT Tools

Most tools are regular GNAT tools that have been slightly adapted for use with .NET. They are used in the same fashion as their corresponding GNAT equivalent. These tools are:

The following GNAT tools have been specifically developed for .NET:


Next: , Previous: GNAT Tools, Up: Getting Started with GNAT for .NET

1.3 .NET Development Kits compatible with GNAT

GNAT has been tested with the .NET 2.0 framework. It may also be compatible with other frameworks, e.g. mono under GNU/Linux.

In order to use the GNAT toolset for .NET, you first need to install the .NET run-time and SDK (e.g. dotnetfx.exe and setup.exe under Windows). The run-time should come with any recent Windows version, while the SDK can generally be found either as a standalone installer or as part of Microsoft Visual Studio or Microsoft Visual Studio Express.


Previous: .NET Development Kits that you can use with GNAT, Up: Getting Started with GNAT for .NET

1.4 Compiling Your First Application with GNAT for .NET

To compile the following “Hello .NET” program put the following in file hello.adb:

     with Ada.Text_IO; use Ada.Text_IO;
     procedure Hello is
     begin
        Put_Line ("Hello .NET!");
     end Hello;

then type:

     $ dotnet-gnatmake hello

This command will generate file hello.exe. To run it, just type

     $ hello

To compile more complex Ada applications use dotnet-gnatmake as usual. If you want to use the GNAT compiler, binder, and linker separately, you will need to individually invoke the appropriate dotnet-gnatcompile, dotnet-gnatbind and dotnet-gnatlink commands.


Next: , Previous: Getting Started with GNAT for .NET, Up: (dir)

2 Ada and .NET Interoperability

An attractive aspect of .NET is its growing set of API classes. It is therefore fundamental that the API be made available to the Ada programmer transparently. It is also important for the Ada programmer to be able to write libraries or APIs for the .NET platform in Ada, and that these libraries be easily usable in any .NET application. GNAT provides full interoperability between Ada and .NET.

To achieve this goal, constructs that can appear in a .NET class at the specification level are mapped to Ada either by means of a corresponding Ada feature or by using an implementation-defined Ada pragma.

In addition, the mapping from .NET to Ada is completely automated. GNAT does not include any Ada bindings for the .NET API, but instead provides a tool (see Using the .NET API with cil2ada) that can produce Ada specifications from any .NET DLL.


Next: , Previous: Ada & .NET Interoperability, Up: Ada & .NET Interoperability

2.1 Importing .NET Services to Ada

To access the services provided by the .NET API or by any set of .dll files, you should proceed as follows:

  1. If your .NET code is in source form (e.g. C#), compile it using any .NET compiler.
  2. If you just want to import a variable or a subprogram from a .NET class, use pragma Import (see Pragma Import CIL) in the Ada code where you want to import the .NET service.
  3. More generally, you can use the cil2ada utility to produce the Ada specs (containing the appropriate .NET-specific pragmas) for the .dll, files containing the .NET services you would like to use from Ada (see Using the .NET API with cil2ada). Note that cil2ada preserves, in the generated Ada specs, the names of the original .NET services.
  4. with the needed Ada specs and use their services as usual.

You can see an example of an Ada program using the .NET framework to display a window with menus and callbacks at <GNAT Pro installation dir>/share/examples/dotnet/CompactFramework.


Previous: Importing .NET Services to Ada, Up: Ada & .NET Interoperability

2.2 Exporting Ada Services to .NET

To export a set of Ada services to .NET you should:

  1. Use pragma Export and other CIL interfacing pragmas inside the Ada code (see .NET-Specific Pragmas). This gives you complete control of what is being generated and allows you to decide very precisely what the exported services look like on the .NET side.
  2. Create a library containing you compiled Ada code.

    Note that there is for now no direct support of .NET libraries generation in the project files. Instead, you need to specify:

    The project must be built using gprbuild since it has no main procedure (for example, gprbuild --target=dotnet).

    For example, here is a simple project file to generate a library from all the sources used by library.adb:

              project Library1 is
                 for Main use ("library.adb");
                 for Object_Dir use "obj";
              
                 package Builder is
                    for Executable_Suffix use ".dll";
                 end Builder;
              
                 package Binder is
                    for Default_Switches ("ada") use ("-n");
                 end Binder;
              
                 package Linker is
                    for Default_Switches ("ada") use ("/DLL");
                 end Linker;
              
              end Library1;
    

    You can automatically create such a project from Visual Studio, by creating a new project using the 'library Ada Project' template, or you can look at the <GNAT Pro installation dir>/share/examples/dotnet/MixedLanguages/ example where the AdaLib subdirectory contains a project creating an Ada library.

  3. Add a reference to this library from the .NET project, and call the library elaboration routine before calling any of its services. The elaboration routine is contained in a special namespace ada_<library_name_in_lowercase>_pkg and is called adainit, e.g: ada_lib1_pkg::adainit. After using the library, you may also need to manually call adafinal to finalize any objects created on the Ada side.
  4. Call the ada methods contained in the library using their underlying CIL naming scheme: all Ada names are translated to lower case, and the last package name receives a _pkg suffix (for example, the package Foo.Adapackage will be named in CIL foo.adapackage_pkg). You can easily verify the naming scheme by looking at the compiled files (with .il extension) located in the object directory: these are text files that can be read by any text editor or IDE.

You can see an example of C# program using Ada services in <GNAT Pro installation dir>/share/examples/dotnet/MixedLanguages/


Next: , Previous: Ada & .NET Interoperability, Up: (dir)

3 Using the .NET API with cil2ada

The cil2ada tool takes .dll files as input and generates Ada specs as output.


Next: , Previous: Using the .NET API with cil2ada, Up: Using the .NET API with cil2ada

3.1 Running cil2ada

The form of the cil2ada command is

     cil2ada [options] file

Where file is either a DLL containing .NET APIs, or an assembly name (e.g. System.Windows.Form, mscorlib, etc.). File names may be prefixed with directory information.

The output of cil2ada is an Ada source file for each class processed. The Ada source file contains a package spec giving the Ada declaration for the services exported by the corresponding class.

The Ada files generated are placed in the directory where the cil2ada command is invoked, or in the subdiretory specified via the -o option.


Next: , Previous: Running cil2ada, Up: Using the .NET API with cil2ada

3.2 Switches for cil2ada

The following switches are available with the cil2ada utility:

-compact
Search assemblies from the .NET compact framework repository
-h
Displays the help message and exits
-o name
Create the files in the specified output directory.
-q, -quiet
Quiet mode
-r
Perform also the analysis of the referenced assemblies.
-V, --version
Displays the tool's version and exits


Previous: Switches for cil2ada, Up: Using the .NET API with cil2ada

3.3 Running cil2ada on the .NET API

To be able to access the .NET API you need to use cil2ada to generate an Ada package spec for each public class in the API.

     $ cd some-dir
     $ cil2ada mscorlib -o bindings

This will create, in directory some-dir/bindings, an Ada package spec for each public .NET class included in mscorlib (the default .NET library).


Next: , Previous: Using the .NET API with cil2ada, Up: (dir)

4 .NET-Specific Pragmas

The simplest way to import services from .NET classes is to use the cil2ada tool to automatically generate the specification of the corresponding .class file. The resulting specification contains the appropriate .NET-specific pragmas.

Sometimes, however, interfacing between .NET and Ada requires more fine-grained control. For example;

This chapter explains the features and pragmas that are needed for full support of interfacing between .NET and Ada.


Next: , Previous: .NET-Specific Pragmas, Up: .NET-Specific Pragmas

4.1 The CIL_Constructor Pragma


Next: , Previous: The CIL_Constructor Pragma, Up: The CIL_Constructor Pragma

4.1.1 Background on .NET Constructors

A .NET constructor is a special method that must be invoked immediately after allocating an object, in order to initialize the object. Given the following .NET class:

     public class C {
        public int field;
        public C ()      { field = 3; }
        public C (int i) { field = i; }
     }

then the statement C obj = new C (3) accomplishes two things:

  1. It allocates a new instance of class C in the .NET heap and sets obj to point to this object;
  2. It then calls the constructor that takes an int parameter, passing obj to it as a hidden parameter and the value 3 for its int parameter.

If no constructor is provided, as in the following class:

     class D extends C {
        float f;
     }

then a default constructor

     public D () {
        super ();
     }

is automatically generated for class D. The call of super() inside this default constructor (known as a no-arg constructor) invokes the no-arg constructor of the superclass of D, that is, the constructor of class C.

Generally speaking, the first statement of every constructor must either be a call to another constructor of the class, or a call to a constructor of the superclass. For instance, given a constructor

     public C (int i, int j) { this (i + j); }

The call this (i + j) invokes the constructor in class C that takes an int as its parameter. As another example, consider:

     public D (int k) { super (k); }

Here super (k) invokes the constructor from D's superclass that takes an int as its parameter.

Note that in both of the original constructors of class C, there are no calls to either this (...) or super (...). When no such call is explicitly given, the .NET compiler automatically inserts a call to the no-arg constructor of the superclass. If (as will be explained below) the superclass does not have an accessible no-arg constructor then you must explicitly insert a call to a constructor from either the same class or its superclass.

As just noted, a class might not have an accessible no-arg constructor. This can occur only when explicit constructors are defined in the class. In this case, the no-arg constructor is not automatically generated for the class, and if a no-arg constructor is desired, you must add it explicitly. For instance, in the following class:

     public class A {
        int ival;
        public A (int i) { ival = i; }
     }
     
     public class B extends A {
        float fval;
        public B (float f) { fval = f; }
     }

the .NET compiler will issue a compile-time error reporting that no constructor matching A () was found in class A, because the compiler tries to insert such a call at the beginning of B. To correct this problem the .NET programmer must either add a no-arg constructor A () in class A, or else change the definition of B's constructor to contain an explicit constructor, e.g., as follows:

     public B (float f) {
       super (0);
       fval = f;
     }

A similar situation may arise when the superclass contains a no-arg constructor that is not accessible in the subclass. For example:

     public class A {
        int ival;
        public A (int i) { ival = i; }
        private A () { ival = 0; }
     }
     
     public class B extends A {
        float fval;
        public B (float f) { fval = f; }
     }

This will generate the same error as above: the private no-arg constructor from A cannot be legally invoked from B, and thus the compiler's attempt to implicitly place the call super() as the first statement in B's constructor will fail.


Next: , Previous: Background on .NET Constructors, Up: The CIL_Constructor Pragma

4.1.2 Using .NET Constructors in Ada

To map an Ada function function-name to a .NET constructor for some Ada tagged-type, GNAT provides the CIL_Constructor pragma. Its syntax is as follows:

     pragma CIL_Constructor (function-name);

where function-name is the name of a function declared immediately within the same declarative part where the pragma occurs. The function must satisfy the following requirements:

The effect of a CIL_Constructor pragma is to compile function-name into a constructor for the class corresponding to tagged-type. In addition, whenever function-name is invoked with a null value for parameter This, the compiler calls the tagged-type object allocator and passes in the pointer to the newly allocated object instead of the value null.

A CIL_Constructor pragma is a program unit pragma. It can appear in the same places where an Inline pragma for function-name can appear. The CIL_Constructor pragma applies to all the overloaded function-name subprograms declared immediately within the declarative region containing the pragma.

For examples of use of this pragma, see the packages generated by cil2ada.


Previous: Using .NET Constructors in Ada, Up: The CIL_Constructor Pragma

4.1.3 .NET Constructors and Ada Allocators

If an Ada function has been defined as a no-arg constructor (via pragma CIL_Constructor) then it is implicitly invoked during the evaluation of an Ada allocator. For instance a client of package C given in the previous section could write:

     with C;
     procedure Client is
        Obj_1 : C.Ref := new_C;
        Obj_2 : C.Ref := new C.Typ;  -- allocator

In compiling new C.Typ, GNAT generates a call of the no-arg constructor if present (in the example new_C (This : Ref := null)). If there is no no-arg constructor then GNAT reports an error. (This last check is not supported as of September 2007, and an exception is raised at run time).


Next: , Previous: The CIL_Constructor Pragma, Up: .NET-Specific Pragmas

4.2 Pragma Import CIL

For convention CIL, pragma Import has the following syntax:

     pragma Import ([Convention    =>] CIL,
                    [Entity        =>] Local_Name
                  [,[External_Name =>] String_Expression]);

where Local_Name is the name of an object, subprogram, record component, exception, or package, while String_Expression is a string giving the .NET name of the imported entity. If String_Expression is missing it is taken to be the Local_Name, folded to lower case.


Next: , Previous: Pragma Import CIL, Up: Pragma Import CIL

4.2.1 Importing Packages

If the Local_Name of an Import pragma is the name of a package spec P, then all the entities declared in P must be explicitly imported from .NET. The String_Expression of such an Import pragma gives the name of the .NET class corresponding to P and can be a simple class name or it can have the form namespace.class_name.

The following rules apply when importing a package P:

The following example illustrates these rules:

     package MSSyst.Object is
        pragma Preelaborate;
     
        type Typ (<>) is tagged limited private;
     
        type Ref       is access all Typ;
        type Ref_Class is access all Typ'Class;
     
        function new_Object (This : Ref := null) return Ref;
        function Equals
          (This : access Typ;
           obj  : access MSSyst.Object.Typ'Class) return Standard.Boolean;
     
     private
        type Typ is tagged limited null record;
        pragma Convention (CIL, Typ);
     
        pragma Cil_Constructor (new_Object);
        pragma Import (CIL, Equals, "Equals");
     
     end MSSyst.Object;
     pragma Import (CIL, Object, "[mscorlib]System.Object");


Next: , Previous: Importing Packages, Up: Pragma Import CIL

4.2.2 Importing Exceptions

If the Local_Name of an Import pragma is the name of an exception E, the String_Expression of such an Import pragma gives the name of the class corresponding to E. This can be a simple class name or it can have the form namespace_name.class_name (which says that the class class_name corresponding to E belongs to the namespace namespace_name).

When importing an exception you should make sure that the imported class is indeed a .NET exception, i.e. it derives from System.SystemException.


Next: , Previous: Importing Exceptions, Up: Pragma Import CIL

4.2.3 Importing Record Components

If the Local_Name of an Import pragma is the name of a record field, then the record field must be declared in a record whose convention is CIL and the record must be declared in a package specification which is itself imported. In this case String_Expression must be a simple name (i.e. contains no dots) giving the name of the imported field.


Next: , Previous: Importing Record Components, Up: Pragma Import CIL

4.2.4 Importing Dispatching Subprograms

If the Local_Name of an Import pragma is the name of a dispatching subprogram (i.e., a primitive operation of a tagged type), then the subprogram must be declared in a package specification which is itself imported. In this case String_Expression must be a simple name (i.e. contains no dots) giving the name of the imported subprogram.


Next: , Previous: Importing Dispatching Subprograms, Up: Pragma Import CIL

4.2.5 Importing Objects

If the Local_Name of an Import pragma is the name of an object and the object is declared in a package specification which is itself imported, then the String_Expression must be a simple name (i.e. contains no dots) giving the name of the imported .NET static field.

An Import pragma for an object can be given even though such an entity does not occur in a package spec with an Import pragma. In this case the String_Expression of the Import pragma must give the complete .NET name of the imported entity, as shown in the following example:

     procedure Foo is
        Var : Integer;
        pragma Import (CIL, Var, "pack.Foo.the_var");
     begin
        Var := 3;
     end Foo;


Next: , Previous: Importing Objects, Up: Pragma Import CIL

4.2.6 Importing Non-Dispatching Subprograms

If the Local_Name of an Import pragma is the name of a non-dispatching subprogram and the subprogram is declared in a package specification which is itself imported, then the String_Expression must be a simple name (i.e. contains no dots) giving the name of the imported .NET static method.

An Import pragma for a non-dispatching subprogram can be given even though such an entity does not occur in a package spec with an Import pragma. In this case the String_Expression of the Import pragma must give the complete .NET name of the imported entity as shown in the following example:

     procedure Foo is
        X : Integer;
        function Compute (I : Integer) return Integer;
        pragma Import (CIL, Compute, "pack.Bar.calc");
     begin
        X := Compute (3);
     end Foo;


Previous: Importing Non-Dispatching Subprograms, Up: Pragma Import CIL

4.2.7 Importing Delegates

Starting with GNAT 6.2, access-to-subprograms Ada types and .NET delegates now perfectly match. As a result, an access-to-subprogram type can now be directly imported from a .NET delegate.

An Import pragma for an access-to-subprogram can be given even though such an entity does not occur in a package spec with an Import pragma. In this case the String_Expression of the Import pragma must give the complete .NET name of the imported entity as shown in the following example:

     procedure Foo is
        --  This defines the delegate type, that matches pack.Bar.some_delegate_type
        type CB_Type is access procedure (Arg : Integer);
        pragma Import (CIL, CB, "pack.Bar.some_delegate_type");
     
        --  Let's import a method asking for such delegate as input.
        procedure Fn_Using_Delegate (CB : CB_Type);
        pragma Import (CIL, Fn_Using_Delegate, "pack.Bar.some_method");
     
        --  Our actual callback, full Ada
        procedure Bar (Arg : Integer);
     begin
        --  We can now call the external .NET method with our full Ada Bar callback.
        Fn_Using_Delegate (Bar'Access);
     end Foo;

Note that this behavior changed in GNAT 6.2. In previous versions, .NET delegates were treated as objects, and could only be imported as such.


Previous: Pragma Import CIL, Up: .NET-Specific Pragmas

4.3 Pragma Export CIL

In the absence of pragma Export, the name of any Ada object, field, or subprogram compiled into a class file is the name of the corresponding Ada entity folded to lower-case.

For exceptions, record types, and packages, the names of the generated class files are all folded to lower case.

By using pragma Export you can change the default name that is generated by the GNAT compiler. In addition, for Ada packages the pragma can also specify which .NET package they belong to. For convention CIL, the pragma Export has the following syntax:

     pragma Export ([Convention    =>] CIL,
                    [Entity        =>] Local_Name
                  [,[External_Name =>] String_Expression]);

where Local_Name is the name of an object, subprogram, record component, record type, exception, or package, and String_Expression is a string giving the CIL name of the exported entity. If String_Expression is missing it is taken to be the Local_Name, folded to lower-case.


Next: , Previous: Pragma Export CIL, Up: Pragma Export CIL

4.3.1 Exporting Objects, Subprograms, and Record Components

NOTE: Exporting of record components is not yet supported.

If the Local_Name of an Export pragma is the name of an object, record component, or subprogram (but not a top-level subprogram), String_Expression must be a simple name (i.e., it contains no dots), giving the name of the corresponding entity at the CIL level. Here is an example:

     package C is
        type Typ is tagged record
           Field : Integer;
           pragma Export(CIL, Field, "THE_FIELD");
        end record;
     
        function Instance_Op (This : access Typ; I : Integer) return Integer;
     
        Var : Integer;
        function Op (J : Integer) return Integer;
     
     private
        pragma Export (CIL, Instance_Op, "dispatch_op");
        pragma Export (CIL, Var, "the_var");
     end C;

This is interpreted as the following two class specifications at the CIL level:

     public class c {
        public static int the_var;
        public static int op (int j);
     }
     public class c$typ {
        public int THE_FIELD;
        public int dispatch_op (int i) {...}
     }

Note that when exporting an object, subprogram, or record component you cannot specify its class, as this is determined by the compiler.


Next: , Previous: Exporting Objects Subprograms and Record Components, Up: Pragma Export CIL

4.3.2 Exporting Exceptions

If the Local_Name of an Export pragma is the name of an exception E, then the String_Expression of such an Export pragma gives the name of the generated class for the Ada exception, overriding the name that would have been given by the compiler. String_Expression can be a simple class name, or it can have the form

     namespace_name.class_name

indicating that the generated class belongs to .NET package namespace_name.

Care must be taken not to use the same class name for two Ada exceptions, packages or record types when they belong to different source files located in the same directory, since one .class file would overwrite the other.


Previous: Exporting Exceptions, Up: Pragma Export CIL

4.3.3 Exporting Record Types

If the Local_Name of an Export pragma is the name of a record type P, then the String_Expression of such an Export pragma gives the name of the generated .NET class, overriding the name that would have been given by the compiler. String_Expression can be a simple class name, or it can have the form namespace_name.class_name.

Care must be taken not to use the same class name for two Ada exceptions or record types when they belong to different source files located in the same directory.


Next: , Previous: .NET-Specific Pragmas, Up: (dir)

5 Debugging Ada Programs

Because GNAT generates DLLs and executables that are fully compliant with the .NET framework, you can use any .NET debugger (e.g. Visual Studio), with GNAT. However, in order to use such a debugger on Ada constructs that are not directly available in CIL (e.g. attributes), you need to know how GNAT compiles these into bytecode.

This chapter explains the correspondence between Ada features and bytecode. It is not a complete description; if you need to understand the output of the GNAT compiler for a particular Ada construct that is not documented below, you can inspect the assembly code generated by GNAT (.il file).


Next: , Previous: Debugging Ada Programs, Up: Debugging Ada Programs

5.1 Ada Compilation Units

Unless pragma Export is used (see Pragma Export CIL), the names of all classes generated from the compilation of an Ada unit are folded to lower case. Similarly for the names of all of the entities generated inside a class file.

The compilation of a nongeneric Ada library unit P always generates an assembly file p.il containing a p_pkg class.

A package Q nested inside an Ada unit P does not result in a separate class. Entities declared within the nested package will generally be associated as members of the containing library package's class. However, the names of the corresponding fields and methods resulting from the nested package will be given expanded names that include the name of the outermost library package followed by the names of any enclosing nested packages. Adjacent pairs of simple names in the expansion are separated by an underscore (e.g., p_q_proc).

A child unit P.Q is compiled into a .NET class p.q_pkg. All the rules described here are applied recursively with respect to Q's contents.

A generic package instantiation R nested inside an Ada unit P is treated exactly like a nested package.

A generic subprogram instantiation S nested inside an Ada unit P treated exactly like a nested subprogram.

A subprogram N nested inside another subprogram P will be treated as a static method of the enclosing library unit's class and will be given an expanded name that includes the names of any enclosing subprograms (e.g., pkg_p_n). In addition, a special class will be generated for the nested subprogram's enclosing subprogram to contain fields for any objects of the enclosing subprogram that are referenced by the nested subprogram. The name of this special Activation Record class is constructed by appending the prefix __AR_ to the name of the enclosing subprogram (e.g., __AR_pkg_p).


Next: , Previous: Ada Compilation Units, Up: Debugging Ada Programs

5.2 Lexical Elements

Letters in all Ada identifiers in user code are folded into lower case when generating symbolic references for .NET, unless pragma Export is used. However, certain names corresponding to internal entities generated by the GNAT front end may include upper-case letters. These can be seen using the -gnatG or -gnatD switches.


Next: , Previous: Lexical Elements, Up: Debugging Ada Programs

5.3 Enumeration Types

An Ada enumeration type is converted into a .NET 1-byte, 2-byte, 4-byte or 8-byte integer whose size best matches the value of the largest enumeration literal.

Character types are treated like regular Ada enumeration types. More specifically, the Ada Character type is mapped to a .NET byte, and the Ada Wide_Character type is mapped to the equivalent 2-byte .NET char type.

An Ada Boolean type is treated like a standard Ada enumeration type with 2 values and is consequently mapped into a .NET byte.


Next: , Previous: Enumeration Types, Up: Debugging Ada Programs

5.4 Integer Types

Each signed integer type is mapped to the smallest corresponding .NET integer type whose size is able to represent all required integer values:

Ada type .NET type
Short_Short_Integer byte (1 byte)
Short_Integer short (2 bytes)
Integer int (4 bytes)
Long_Integer long (8 bytes)
Long_Long_Integer long (8 bytes)

Each modular type is also mapped to the smallest corresponding .NET integer type whose size is able to represent all required modular values.


Previous: Integer Types, Up: Debugging Ada Programs

5.5 Floating Point Types

The Ada predefined floating point types map very naturally onto .NET's IEEE 32-bit float and IEEE 64-bit double:

Ada type .NET type
Short_Float float (4 bytes)
Float float (4 bytes)
Long_Float double (8 bytes)
Long_Long_Float double (8 bytes)

User-defined floating point types are mapped into Float where possible, and Long_Float otherwise.


Previous: Debugging Ada Programs, Up: (dir)

6 Limitations

Due to constraints of the .NET environment, or to implementation limitations, GNAT for .NET only supports a subset of the Ada language and GNAT run-time.

Language constructs not supported (where noted, partial support is provided):

Switches not supported:

Run-time units not supported yet, which will be available in the future:

Run-time units not supported:

Table of Contents