![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Interfacing with Other Languages In Ada, a subprogram written in another language can be called from an Ada program (Ada83 LRM 13.10.2, Ada95 LRM 13.9).
The LRM does not provide for calling Ada routines from other languages; this can be done with Rational Ada.
When writing a program that contains source code in both Ada and another language, you must follow certain restrictions and methodologies. This chapter discusses:
If you are using Apex Duo, additional information on including C/C++ code in an Ada program can be found in the Programmer's Guide.
General InformationWhen writing a multilanguage program (one that contains code written in other languages as well as Ada) using Apex, you cannot:
- Import an Ada view into a C/C++ view
When writing a multilanguage program (one that contains code written in other languages as well as Ada) using Apex, you can:
- Import a C/C++ view into an Ada view
- Place non-Ada program units in subsystems and put them under version control as you would treat any other text files.
- Edit non-Ada program units using the Apex text editor.
- Debug C code in a limited manner if the -g argument is used on the cc command. Note that for Sun Solaris the -xs argument is needed and that on Digital Unix 4.0, the -oldc argument is needed in addition to the -g argument. For example:
cc -g hello.c -- SunOS, HP, RS/6000, SGI, PowerPC cc -g -xs hello.c -- Sun Solaris cc -g -oldc hello.c -- Digital Unix 4.0
For additional information, see the Using The Apex Debugger Guide.
Program StructureThis section discusses the following topics:
- Non-Ada Subsystems
- Structuring the Main Program
- Code Restrictions
- Parameter Passing
- Ada and Assembly Language
Non-Ada Subsystems
In general, place non-Ada code into a separate subsystem from the Ada code that interfaces with it. This provides a logical separation of code with different requirements.
Structuring the Main Program
Elaboration code is not generated automatically in a multilanguage program for non-Ada units. The code to elaborate all the compilation units in the closure of a program is generated only for a main Ada procedure.
Warning: Because of this, the main entry point for any mixed-language program must be in Ada.
Construct your program as follows:
- 1 . Create a set of Ada packages to contain the declarations for all non-Ada routines to be called from the main program.
package C_Specs is -- Type declarations here if needed -- Procedure or function declarations here end C_Specs;
- 2 . Create an Ada procedure to serve as the main entry point for the program.
In this Ada main program, with the Ada closure of any non-Ada routines (that is, any Ada called from the non-Ada routine), include the packages created in step 1 . For example:
with C_Specs; procedure Ada_Main is begin -- Calls go here end Ada_Main;
You might have several layers similar to this. For example, another Ada package Ada_X that is linked with the main Ada procedure would with an associated Ada_X_C_Specs package containing the interface declarations for C routines used in Ada_X.
- 3 . Code the Ada main program and any other Ada units in its closure as you normally would.
- 4 . Link the Ada main program as described in Linking.
Code Restrictions
Warning: Your program must observe the following restrictions.
- Ada and non-Ada portions of the program must follow the restrictions described in UNIX Restrictions.
- C does not support nested procedures, so Ada subprograms exported to C routines must be declared in static scope.
- If output is generated for stdout from both the Ada and C portions of the program, all Ada output will precede C output unless the C output buffer is flushed before returning from the C code in which output is generated.
Interfacing Pragmas
For the import or export of non-Ada procedures, functions, and variables, Apex Ada supports the following pragmas the following Interfacing pragmas (AARM B.1) for both Ada83 and Ada95:
pragma Import
This pragma allows an entity from a foreign language to be imported by an Ada program, so that a foreign-language subprogram can be called or a foreign-language object accessed from Ada.
pragma Import( [Convention =>] convention_ID, [Entity =>] local_name [,[External_Name =>] string_expression [,[Link_Name => string_expression)];
convention_ID ::= C | Ada | Asm local_name ::= (the Ada identifier of the entity)
Required Parameters
Convention -- Apex Ada allows one the following calling conventions:
- C – To incorporate C and C++ routines in Ada code; for example, functions from C math libraries, functions specially coded in C to use certain C features, or functions used to interface with C runtime.
Note that it is possible to import C++ code but the exported interfaces from the C++ code must be standard C. Apex only understands the C function naming conventions. C++ mangled names are not supported. If C++ objects are to be linked with an Ada main program the interfaces to the C++ code must be in standard C. Use the extern "C" {...} syntax to provide this interface. For example here is a C++ example that works with the Apex C++ compiler:
extern "C" { extern int c_function_called_from_ada(); } void arbitrary_cpp_function() { return; } int c_function_called_from_ada() { arbitrary_cpp_function(); return 1; }
- Ada – To use Ada code from runtime routines. This convention may also used (with great care) to integrate ada83 and ada95 code.
- ASM – To import assembly language routines.
Entity – The identifier Ada uses for the object or subprogram imported from the foreign language.
Optional Parameters
External_Name – The entity's identifier in the foreign code. The default is the entity_ID. For C, the default is the entity_ID converted to lower case.
For example, the identifier "sqrt" of this C function
double sqrt (double x) { . . . } is the external name of the function when it is imported to Ada:
function Sqrt (X:Interfaces.C.Double) return Interfaces.C.Double; pragma Import (C, Sqrt); -- This is line is equivalent to: -- pragma Import (C, Sqrt, External_Name => "sqrt");
If upper and lower case letters appear in the identifier in foreign code where case is significant (C or Asm), you must supply the external name explicitly.
In the following example, Ada imports the abs function from the standard C math library but must change the name (to Absolute_Value, in the example) because abs is a reserved word in Ada.
int abs (int i);
function Absolute_Value (I:Interfaces.C.int) return Interfaces.C.int; pragma Import (C, Absolute_Value, "abs");
The syntax of the pragma in this example shows parameters passed by position. If they were passed by name, the syntax would be:
pragma Import (Convention => C, Entity => Absolute_Value, External_Name => "abs");
Link_Name – The link name in the external code of the entity to be imported. By default, the compiler generates the link name from the external name using the convention of the compiler for the foreign language. In the example above, on a Sun platform, the compiler would construct a link name using Solaris conventions: "_abs"
Importing Objects
The examples given above are of entities that are subprograms. Here is an example of applying pragma Import to an entity which is an object, C's errno variable. Ada imports it to be a part of a package of UNIX interface entities:
int errno;
package Unix_Interface is . . . Errno : Interfaces.C.Int; pragma Import (C, Errno); . . . end Unix_Interface;
pragma Export
This pragma allows Ada subprograms to be called and Ada objects accessed by foreign-language programs.
pragma Export( [Convention =>] convention_ID, [Entity =>] local_name [,[External_Name =>] string_expression [,[Link_Name => string_expression)];
convention_ID ::= C | Ada | Asm local_name ::= (the Ada identifier of the entity)
Required Parameters pragma Export
pragma Export uses the same required parameters as pragma Import.
Convention – Can be C, Ada, or Asm. C is the version of the C or C++ language that was used to compile the operating system of the current platform.
Entity – The local (Ada) name of the object or subprogram to be exported to the foreign language.
Optional Parameters for pragma Export
External_Name -- The foreign code identifier of the entity being exported from Ada. The default is the Ada entity_ID in lower-case. If a different identifier, including one using upper-case letters is required in the foreign code, it must be entered explicitly.
Link_Name – The link name to use in the external code of the entity to be exported. By default, the link name is generated from the external name by the convention used on the foreign platform.Example of exporting a function from Ada to C:
function Square_Root (X:Interfaces.C.Double) return Interfaces.C.Double; pragma Export (C, Sqare_Root, External_Name => "sqrt");
double sqrt (double x) { . . . }
Exporting Objects
As with pragma Inline, the examples given above are of subprograms; pragma Export handles objects similarly to pragma Import.
package P is Status: Interfaces.C.Int; pragma Export (C, Status); end P;
extern int status;
pragma Convention
This pragma is used for specifying that an Ada subprogram or type should use the conventions of another language. It is useful for defining subprograms for callback operations.
pragma Convention( [Convention =>] convention_ID, [Entity =>] local_name);
convention_ID ::= Ada | C | Asm
local_name ::= The name of the entity in the Ada code.
For example, it is frequently convenient to call a C routine that has a callback as a parameter:
void procedure_with_callback_parameter (int *callback());
In Ada, the routine that has the callback parameter must have its calling convention specified as C:
procedure Example_Of_Interfacing_To_C_With_Callbacks is type T is access function (return Interfaces.C.Int); procedure Procedure_With_Callback_Parameter(X:T); pragma Import (C, Procedure_With_Callback_Parameter); function Callback return Interfaces.C.Int is begin return 17; end Callback; pragma Convention (C, Callback) begin Procedure_With_Callback_Parameter(Callback'Access); end Example_Of_Interfacing_To_C_With_Callbacks;
When a convention of C is specified for a record type, the layout of the record is C-compatible (i.e., the same layout as would be generated by the C compiler for a corresponding C struct). In particular, the compiler does not reorder fields in this case. See "Record Types" in the Ada Runtime Guide for more information.
pragma Calling_Convention
Pragma Calling_Convention is always used in conjunction with pragma Import or pragma Export. Additional information on, and Apex specific extensions to, pragma Calling_Convention can be found in implementation dependent Pragma Calling_Convention (also available in Pragma Calling_Convention).
Pragmas Import and Export tell the compiler that a certain subprogram is imported from or exported to another language. Pragma Calling_Convention gives additional instructions to the compiler about specific calling conventions to be used. This affects the code generated by the compiler for the subprogram call (if imported) or for the subprogram prologue and epilog (when exported). The syntax is:
pragma Calling_Convention( [Entity =>]local_name
[,attribute1
=>value1
,] [,attribute2
=>value2
,] ...)
Pragma Calling_Convention can be used to enable the running of different IEEE floating point models within the same program. For example, a project's C/C++ code uses the extended IEEE programming mathematics "model". That is, instead of exceptions occurring on overflows, underflows, or erroneous computations (such as divide by zero or square root of a negative number), the C/C++ code expects IEEE NaN and Inf values to be produced, with the intent that somewhere within C/C++ there will be a test for these values with appropriate actions at that point.
The existing Ada code depends on a finite-values-only IEEE model, in which any of the above occurrences cause an exception to be raised.
There is a fundamental incompatibility between the two models. Code can be written for either model in either language, but once written, running the code with the opposite model leads to faulty execution. What is needed is a way to run both models within the same program, switching back and forth as appropriate.
The Apex compiler has support for exactly this situation, but does require the application code to make it clear when the model is to be changed. Specifically, any calls out to C/C++ and any callbacks into Ada from C/C++ must use the appropriate pragma to indicate that the FP control state is to be changed.
For C/C++ procedures that are "imported" via a pragma Import, there must be a pragma Calling_Convention with Floating_Point_Control_Preserve set to True (the name of the pragma feature is an anachronistic misnomer; the effect is backwards from what you might expect from the name). For Ada procedures that are called from C/C++ the same calling convention must be applied. For example:
pragma Import (C, <subprogram>); pragma Calling_Convention (<subprogram>, Floating_Point_Status_Preserve => True);
pragma Export( C, <Ada_procedure> ); pragma Calling_Convention (<Ada_procedure>, Floating_Point_Status_Preserve => True);
Applied to an Import, this causes the "calling code" to save the FP control state, change it to the value of the symbol __FP_CONTROL_FOR_C, call the routine, and upon return from the routine, restore the FP control state.
Applied to an Export, this generates subroutine preamble code to save the FP control state and change it to the value of the symbol __FP_CONTROL_FOR_ADA. It also generates subroutine post-amble code that restores the FP control state on exit from the subroutine.
The value of __FP_CONTROL_FOR_C is initialized during startup from the C_FLOATING_POINT_CONTROL field in the user's configuration table (in file v_usr_conf.2.ada).
The value for __FP_CONTROL_FOR_ADA is initialized during startup from the FLOATING_POINT_CONTROL in the user's configuration table (in file v_usr_conf.2.ada). Currently, this item must be identical to the same item in the kernel configuration table (in file v_krn_conf.2.ada).
Warning: The values in FP data registers are NOT affected by this pragma or the generated code. Only the FP control status register, which controls what to do when abnormal values are generated, is affected.
Parameter Passing
- See LRM Annex section B.3(63-75) for details of the correspondence between the Ada and C/C++ parameter-passing conventions.
- The Apex Ada compiler always passes array and record parameters by reference.
Ada and Assembly Language
When mixing Ada code and assembly-language routines, you need to specify a language convention of Asm for the Export pragmas.
When specifying the external name for an imported assembler program or an Ada subprogram exported to an assembler program, match the name that you give to your assembler routine.
When providing this name, avoid the following naming prefixes:
- Period (.) under AIX or underscore (_) under SunOS, which could conflict with C-compiler-generated names
- Double underscore (__), which could conflict with Rational Ada runtime names
Compiling the C CodeTo compile the C (or C++) routines that will be linked with the Ada main program, use the cc command with the following arguments:
- Use the -c argument. Because the C code will not be the main entry point, this argument generates a .o file and avoids an unnecessary message that says this is not a main program.
- Use the -g argument if you need to do partial debugging on this code using the Apex debugger. Remember that on Sun Solaris, you must also use the -xs argument, and on Digital Unix 4.0, the -oldc argument must be used in addition to the -g argument.
Linking
Warning: For all platforms except SunOS and AIX, external archives and object files linked with Apex Ada must not define the symbol "main". For SunOS, external archives must not define "_main". For AIX, external archives must not define ".main".
To link an Ada main program named Ada_Main that includes non-Ada routines:
- 1 . Set the NON_ADA_LINKAGE context switch (or use the corresponding command-line option) in the view from which you will link your Ada main program.
Its value is a string that contains linker arguments. At a minimum, specify:
- The pathnames of any non-Ada .o files to link with the Ada main program.
- Linker options to apply to the cc command as needed. This might include additional non-Ada object files and archive libraries to link.
Note: cc automatically includes libc.a and modules to do C-library initialization. If the Profiling switch or command option is used, profiling support libraries are also included.
pragma Linker_Options
Passes arguments to the target linker. The syntax is:
pragma Linker_Options (manifest_string_expression)
Usage
This pragma can appear in any package specification or declarative part. Its argument is passed as a command line argument to the target linker whenever the unit containing the pragma is in the closure of the main program being linked.
In constructing the target linker command line argument, the Link_With argument is first divided into tokens. Tokens are delimited by white-space.
Tokens are then passed to the linker command line. Tokens beginning with "+" and "-" tokens are interpreted as linker switches. Tokens beginning with "/" tokens are interpreted as rooted filenames. If a token begins with "-", "+", or "/", it is left untouched.
If a token begins with neither "-" nor "+" nor "/", then it is assumed to name a file and is prefixed with pathname of the directory containing the Ada unit in which the pragma appears. (This behavior is different from VADS, in which unqualified names are interpreted in the context of the main program being linked).
If a main program's closure contains more than one pragma Linker_Options, their contents will be separated by blanks on the linker command line. The order in which the arguments appear is not defined.
If pragma Linker_Options appears in the implementation of an API, that is, in a unit that also contains pragma Api, its contents are passed to the linker when the API is used in the closure of a main program, not when the API itself is linked.
Note that pragma Linker_Options is feature-identical with, and replaces, the obsolete pragma Link_With.
Rational Software Corporation http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2004, Rational Software Corporation. All rights reserved. |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |