7.1.4 Declaring the external object code

Linking to an object file

Having declared the external function or variable that resides in an object file, you can use it as if it were defined in your own program or unit. To produce an executable, you must still link the object file in. This can be done with the {$L file.o} directive.

This will cause the linker to link in the object file file.o. On most systems, this filename is case sensitive. The object file is first searched in the current directory, and then the directories specified by the -Fo command line.

You cannot specify libraries in this way, it is for object files only.

Here we present an example. Consider that you have some assembly routine which uses the C calling convention that calculates the nth Fibonacci number:

        .align 4  
.globl Fibonacci  
        .type Fibonacci,@function  
        pushl %ebp  
        movl %esp,%ebp  
        movl 8(%ebp),%edx  
        xorl %ecx,%ecx  
        xorl %eax,%eax  
        movl $1,%ebx  
        incl %edx  
        decl %edx  
        je endloop  
        movl %ecx,%eax  
        addl %ebx,%eax  
        movl %ebx,%ecx  
        movl %eax,%ebx  
        jmp loop  
        movl %ebp,%esp  
        popl %ebp  

Then you can call this function with the following Pascal Program:

Program FibonacciDemo;  
var i : longint;  
Function Fibonacci (L : longint):longint;cdecl;external;  
{$L fib.o}  
  For I:=1 to 40 do  
    writeln ('Fib(',i,') : ',Fibonacci (i));  

With just two commands, this can be made into a program:

as -o fib.o fib.s  
ppc386 fibo.pp

This example supposes that you have your assembler routine in fib.s, and your Pascal program in fibo.pp.

Linking to a library

To link your program to a library, the procedure depends on how you declared the external procedure.

In case you used the following syntax to declare your procedure:

Procedure ProcName (Args : TPRocArgs); external 'Name';

You don’t need to take additional steps to link your file in, the compiler will do all that is needed for you. On Windows it will link to name.dll, on linux and most unix’es your program will be linked to library libname, which can be a static or dynamic library.

In case you used

Procedure ProcName (Args : TPRocArgs); external;

You still need to explicitly link to the library. This can be done in 2 ways:

  1. You can tell the compiler in the source file what library to link to using the {$LinkLib ’Name’} directive:
    {$LinkLib 'gpm'}

    This will link to the gpm library. On unix systems (such as linux), you must not specify the extension or ’lib’ prefix of the library. The compiler takes care of that. On other systems (such as Windows), you need to specify the full name.

  2. You can also tell the compiler on the command line to link in a library: The -k option can be used for that. For example
    ppc386 -k'-lgpm' myprog.pp

    Is equivalent to the above method, and tells the linker to link to the gpm library.

As an example, consider the following program:

program printlength;  
{$linklib c} { Case sensitive }  
{ Declaration for the standard C function strlen }  
Function strlen (P : pchar) : longint; cdecl;external;  
  Writeln (strlen('Programming is easy !'));  

This program can be compiled with:

ppc386  prlen.pp

Supposing, of course, that the program source resides in prlen.pp.

To use functions in C that have a variable number of arguments, you must compile your unit or program in objfpc mode or Delphi mode, and use the Array of const argument, as in the following example:

program testaocc;  
{$mode objfpc}  
  P : Pchar  
    = 'example';  
  F : Pchar  
    = 'This %s uses printf to print numbers (%d) and strings.'#10;  
procedure printf(fm: pchar;args: array of const);cdecl;external 'c';  

The output of this program looks like this:

This example uses printf to print numbers (123) and strings.

As an alternative, the program can be constructed as follows:

program testaocc;  
  P : Pchar  
    = 'example';  
  F : Pchar  
    = 'This %s uses printf to print numbers (%d) and strings.'#10;  
procedure printf(fm: pchar);cdecl;varargs;external 'c';  

The varargs modifier signals the compiler that the function allows a variable number of arguments (the ellipsis notation in C).