PowerAda Linking With Foreign Object Code

From OC Systems Wiki!
< PowerAda:Interface to Other Languages
Revision as of 00:36, 25 April 2019 by imported>WikiVisor (Text replacement - """ to """)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search


The use of the -m or -b option with the ada (or aprojbuild or abuild) commands specifies that an executable program is to be bound. This consists primarily of using the linker command to link together all the object code associated with the program and resolve all symbol references.

If your Ada program references symbols in non-Ada code by the use of pragma Import, you will need to specify where to find the object code in which these symbols are defined, except that you do not need to specify the library libc.a as part of the compilation; that library is always included when an Ada program is linked.

There are several ways to identify additional object code to be included in an Ada program:

  1. Simply name the object or archive file name on the ada (or aprojbuild or abuild) command line if the file name has an extension of .o or .a.
  2. Precede the object or archive file name with the -i option on the command line.
  3. Name the file in a linker directive in a sublibrary imports file associated with the object file.
  4. Specify the object or archive filename in a .adalinks file in one of the Ada sublibrary directories.
  5. Specify the object or archive filename with pragma Linker_Options.

If the foreign code includes C++ code and you are linking on AIX, you must specify -q xlCbind when linking. This option tells Ada to use the xlC (or xlC_r) command to link the object code instead of the AIX ld command. This extra step is necessary, because C++, like Ada, needs to perform certain initialization/finalization actions prior to running a program that contains C++ and by binding with the C++ compiler, these actions will be done.

If any of the foreign code uses AIX threads or was compiled using the "_r" version of the compiler (e.g., xlC_r), you should add the -t option to the Ada bind command (which specifies to the Ada compiler that the program should be bound against the reentrant thread libraries).

The -i Compiler Option

The -i option must be used if the object file does not end in .o (the standard UNIX suffix indicating an unlinked object file) or .a (indicating an object archive file created with the AIX ar command). To specify multiple files, use -i once for each one, for instance:

ada -m -i asm_functions -i a.out ada_program.ada

The -i option also is the only way to force an object module to be included before the object code associated with the Ada sublibraries (see "Object Module Ordering" below).

The linker Imports Directive

The sublibrary imports file adalib.imports is used within a PowerAda project to indicate which other sublibraries are imported. It may also contain directives indicating foreign object code and other options that are to be appended to the ld command that is generated by the PowerAda compiler. This is useful for associating with a sublibrary the foreign object files needed by the Ada code in that sublibrary. The naming of an object module in a linker directive allows others to link programs which reference the sublibrary without knowing about the dependency on that object module.

The syntax of this directive is:

linker: [ object_file | ld_options ]

You can put as many directives as necessary, one per line, in an adalib.imports file, but only one object_file should be named per directive. This allows the powerada tools to correctly determine the fully-qualified path for this file. The ld_options (such as -lX11) are copied verbatim to the ld command

The absolute location of the object file to be used is as follows: if an absolute pathname is provided (after expanding environment variables), that path is used. If a simple name is provided, (e.g., fred.o), and the object file exists in the same directory as the adalib.imports file itself, then the project-relative name of that directory is used to qualify the object file name.; otherwise (if the file does not exist there or has slashes in it) the path provided is assumed to be a project-relative name. When the link script is being built by the command, the project-relative names are resolved to absolute names, and duplicate occurrences are removed.

When building within a project, this is the recommended way to recording object files and linker directives, because it gives the right behavior in the presence of delta projects.

The .adalinks File

If the hidden file .adalinks is found in a sublibrary, its contents are included in the ld command that is generated by the PowerAda compiler. This feature should only be used outside of a PowerAda project, since the linker directive described above is clearly superior when within a project.

The naming of an object module in a .adalinks file allows others to link programs which reference the sublibrary without knowing about the dependency on that object module.

The syntax of the file is simple but rigid: everything up to the first blank on each line is added to the link command, followed by a shell continuation character. Everything after the first blank on a line is ignored.

Any ld option, object file name or archive name may be specified, as long as there are no blanks in it. For example, a shared library of the form libName.a may be designated -lName so that it is found by searching the library path recorded in the executable or specified by the LIBPATH environment variable. See the AIX Commands Reference or Linux documentation for a complete description of the ld command.

Warning: the alibinit command will destroy the .adalinks file in an existing sublibrary: the newly initialized sublibrary will not contain a .adalinks file. The following example illustrates how this might be used.

1. Create a math package C_MATH in file cmaths.ada that uses a function in /usr/lib/libm.a: <syntaxhighlighht lang="Ada"> package C_MATH is function SIN(X : in LONG_FLOAT) return LONG_FLOAT; pragma Import(C, sin); end C_MATH; </syntaxhighlight> 2. Create a library to compile cmaths.ada into:

$ echo mathlib > alib.list
$ alibinit

3. Compile our math package:

$ ada cmaths.ada

4. Create a .adalinks file indicating that libm.a should be used when binding with mathlib:

$ echo -lm > mathlib/.adalinks

5. Create a main program to test our result:

with C_MATH, TEXT_IO;
procedure TESTMATH is
begin
TEXT_IO.PUT_LINE("sin(pi/2) = " &
LONG_FLOAT'EXTENDED_IMAGE(
C_MATH.SIN(3.1416/2.0)));
end TESTMATH;

6. Compile and bind our test program:

$ ada -mo testmath testmath.ada

7. Run the test program:

$ testmath
sin(pi/2) = 9.99999999993254E-01

Pragma Linker_Options

The user has the opportunity to pass information to the linker through the use of pragma Linker_Options. For more information on pragma Linker_Options, see <RM95 B.1(3)>. For example:

function sin(x : in long_float) return long_float is
   function c_sin(x : in long_float) return long_float;
   pragma import(c, c_sin, "sin");
   -- include shared library libm.a
   pragma linker_options("-lm");  
begin
   return c_sin(x);
end sin;

or

with prog;
procedure main is
   -- generate link map
   pragma linker_options("-bloadmap:link.map");
begin
   prog.doit;
end main;

Object Module Ordering

The order in which options and archive and object files are listed in the link (ld) command is as follows:

  1. all files preceded by -i;
  2. the object modules for Ada compilation units from the Ada program library;
  3. the object modules mentioned in pragmas Linker_Options, in reverse elaboration order. (See The effect of pragma Linker_Options. See B.1(37).)
  4. all files with extensions .o and .a that appear on the command line;
  5. the contents of the linker directives in the adalib.imports file;
  6. the contents of the .adalinks file;
  7. the C function library libc.a.

This implies that if you wish to replace symbols from the Ada library with those in another object file myobj.o, you must use "-i myobj.o".