However, there are times that you want to link to C libraries, or to external object files that are generated using a C compiler (or even another pascal compiler). The Free Pascal compiler can generate calls to a C function, and can generate functions that can be called from C (exported functions). More on these calling conventions can be found in section Calling.
In general, there are 2 things you must do to use a function that resides in an external library or object file:
The first step in using external code blocks is declaring the function you want to use. Free Pascal supports Delphi syntax, i.e. you must use the external directive. The external directive replaces, in effect, the code block of the function.
The external directive doesn't specify a calling convention; it just tells the compiler that the code for a procedure or function resides in an external code block.
There exist four variants of the external directive :
Procedure ProcName (Args : TPRocArgs); external;The external directive tells the compiler that the function resides in an external block of code. You can use this together with the {$L } or {$LinkLib } directives to link to a function or procedure in a library or external object file. Object files are looked for in the object search path (set by -Fo) and libraries are searched for in the linker path (set by -Fl).
Procedure ProcName (Args : TPRocArgs); external 'Name';This tells the compiler that the procedure resides in a library with name 'Name'. This method is equivalent to the following:
Procedure ProcName (Args : TPRocArgs);external; {$LinkLib 'Name'}
Procedure ProcName (Args : TPRocArgs); external 'Name' name 'OtherProcName';This has the same meaning as the previous declaration, only the compiler will use the name 'OtherProcName' when linking to the library. This can be used to give different names to procedures and functions in an external library.
This method is equivalent to the following code:
Procedure OtherProcName (Args : TProcArgs); external; {$LinkLib 'Name'} Procedure ProcName (Args : TPRocArgs); begin OtherProcName (Args); end;
Procedure ProcName (Args : TPRocArgs); external 'Name' Index SomeIndex;This tells the compiler that the procedure ProcName resides in a dynamic link library, with index SomeIndex.
Remark: Note that this is ONLY available under WINDOWS and OS/2.
In earlier versions of the Free Pascal compiler, the following construct was also possible :
Procedure ProcName (Args : TPRocArgs); [ C ];This method is equivalent to the following statement:
Procedure ProcName (Args : TPRocArgs); cdecl; external;However, the [ C ] directive is no longer supported as of version 0.99.5 of Free Pascal, therefore you should use the external directive, with the cdecl directive, if needed.
Some libaries or code blocks have variables which they export. You can access these variables much in the same way as external functions. To access an external variable, you declare it as follows:
Var MyVar : MyType; external name 'varname';The effect of this declaration is twofold:
A second possibility is the declaration:
Var varname : MyType; cvar; external;The effect of this declaration is twofold as in the previous case:
In order to be able to compile such statements, the compiler switch -Sv must be used.
As an example, let's look at the following C file (in extvar.c):
/* Declare a variable, allocate storage */ int extvar = 12;And the following program (in extdemo.pp):
Program ExtDemo; {$L extvar.o} Var { Case sensitive declaration !! } extvar : longint; cvar;external; I : longint; external name 'extvar'; begin { Extvar can be used case insensitive !! } Writeln ('Variable ''extvar'' has value : ',ExtVar); Writeln ('Variable ''I'' has value : ',i); end.Compiling the C file, and the pascal program:
gcc -c -o extvar.o extvar.c ppc386 -Sv extdemoWill produce a program extdemo which will print
Variable 'extvar' has value : 12 Variable 'I' has value : 12on your screen.
Having declared the external function or variable that resides in an object file, you can use it as if it was 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 LINUX systems, this filename is case sensitive. Under DOS, case isn't important. Note that file.o must be in the current directory if you don't specify a path. The linker will not search for file.o if it isn't found.
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 that calculates the nth Fibonacci number :
.text .align 4 .globl Fibonacci .type Fibonacci,@function Fibonacci: pushl %ebp movl %esp,%ebp movl 8(%ebp),%edx xorl %ecx,%ecx xorl %eax,%eax movl $1,%ebx incl %edx loop: decl %edx je endloop movl %ecx,%eax addl %ebx,%eax movl %ebx,%ecx movl %eax,%ebx jmp loop endloop: movl %ebp,%esp popl %ebp retThen 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} begin For I:=1 to 40 do writeln ('Fib(',i,') : ',Fibonacci (i)); end.With just two commands, this can be made into a program :
as -o fib.o fib.s ppc386 fibo.ppThis example supposes that you have your assembler routine in fib.s, and your Pascal program in fibo.pp.
To link your program to a library, the procedure depends on how you declared the external procedure.
In case you used the follwing 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 NT it will link to Name.dll, on LINUX 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 explicity link to the library. This can be done in 2 ways:
{$LinkLib 'gpm'}This will link to the gpm library. On LINUX systems, you needn't specify the extension or 'lib' prefix of the library. The compiler takes care of that. On DOS or WINDOWS systems, you need to specify the full name.
ppc386 -k'-lgpm' myprog.ppIs 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; begin Writeln (strlen('Programming is easy !')); end.This program can be compiled with :
ppc386 prlen.ppSupposing, 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} Const 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'; begin printf(F,[P,123]); end.The output of this program looks like this:
This example uses printf to print numbers (123) and strings.
Free Pascal supports making shared or static libraries in a straightforward and easy manner. If you want to make libraries for other Free Pascal programmers, you just need to provide a command line switch. If you want C programmers to be able to use your code as well, you will need to adapt your code a little. This process is described first.
When exporting functions from a library, there are 2 things you must take in account:
The naming conventions can be controlled by 3 modifiers:
If you want to make your procedures and functions available to C programmers, you can do this very easily. All you need to do is declare the functions and procedures that you want to make available as export, as follows:
Procedure ExportedProcedure; export;
Remark: You can only declare a function as exported in the Implementation section of a unit. This function may not appear in the interface part of a unit. This is logical, since a Pascal routine cannot call an exported function, anyway.
However, the generated object file will not contain the name of the function as you declared it. The Free Pascal compiler ''mangles'' the name you give your function. It makes the name all-uppercase, and adds the types of all parameters to it. There are cases when you want to provide a mangled name without changing the calling convention. In such cases, you can use the Alias modifier.
The Alias modifier allows you to specify another name (a nickname) for your function or procedure.
The prototype for an aliased function or procedure is as follows :
Procedure AliasedProc; [ Alias : 'AliasName'];The procedure AliasedProc will also be known as AliasName. Take care, the name you specify is case sensitive (as C is).
Remark: If you use in your unit functions that are in other units, or system functions, then the C program will need to link in the object files from the units too.
Var MyVar : MyTpe; cvar;This will tell the compiler that the assembler name of the variable (the one which is used by C programs) should be exactly as specified in the declaration, i.e., case sensitive.
It is not allowed to declare multiple variables as cvar in one statement, i.e. the following code will produce an error:
var Z1,Z2 : longint;cvar;
Once you have your (adapted) code, with exported and other functions, you can compile your unit, and tell the compiler to make it into a library. The compiler will simply compile your unit, and perform the necessary steps to transform it into a static or shared (dynamical) library.
You can do this as follows, for a dynamical library:
ppc386 -CD myunitOn LINUX this will leave you with a file libmyunit.so. On WINDOWS and OS/2, this will leave you with myunit.dll.
If you want a static library, you can do
ppc386 -CS myunitThis will leave you with libmyunit.a and a file myunit.ppu. The myunit.ppu is the unit file needed by the Free Pascal compiler.
The resulting files are then libraries. To make static libraries, you need the ranlib or ar program on your system. It is standard on any LINUX system, and is provided with the GCC compiler under DOS. For the dos distribution, a copy of ar is included in the file gnuutils.zip.
BEWARE: This command doesn't include anything but the current unit in the library. Other units are left out, so if you use code from other units, you must deploy them together with your library.
ppumove -e ppl -o name unit1 unit2 unit3This will move 3 units in 1 library (called libname.so on linux, name.dll on WINDOWS) and it will create 3 files unit1.ppl, unit2.ppl and unit3.ppl, which are unit files, but which tell the compiler to look in library name when linking your executable.
The ppumove program has options to create statical or dynamical libraries. It is provided with the compiler.
When you compile a program or unit, the compiler will by default always look for .ppl files. If it doesn't find one, it will look for a .ppu file.
To be able to differentiate between units that have been compiled as static or dynamic libraries, there are 2 switches:
These two switches can be used in conjunction with the configuration file ppc386.cfg. The existence of one of these symbols can be used to decide which unit search path to set. For example:
# Set unit paths #IFDEF FPC_LINK_STATIC -Up/usr/lib/fpc/linuxunits/staticunits #ENDIF #IFDEF FPC_LINK_DYNAMIC -Up/usr/lib/fpc/linuxunits/sharedunits #ENDIFWith such a configuration file, the compiler will look for it's units in different directories, depending on whether -XD or -XS is used.
You can compile your units using smart linking. When you use smartlinking, the compiler creates a series of code blocks that are as small as possible, i.e. a code block will contain only the code for one procedure or function.
When you compile a program that uses a smart-linked unit, the compiler will only link in the code that you actually need, and will leave out all other code. This will result in a smaller binary, which is loaded in memory faster, thus speeding up execution.
To enable smartlinking, one can give the smartlink option on the command line : -Cx, or one can put the {$SMARTLINK ON} directive in the unit file:
Unit Testunit {SMARTLINK ON} Interface ...Smartlinking will slow down the compilation process, especially for large units.
When a unit foo.pp is smartlinked, the name of the codefile is changed to libfoo.a.
Technically speaking, the compiler makes small assembler files for each procedure and function in the unit, as well as for all global defined variables (whether they're in the interface section or not). It then assembles all these small files, and uses ar to collect the resulting object files in one archive.
Smartlinking and the creation of shared (or dynamic) libraries are mutually exclusive, that is, if you turn on smartlinking, then the creation of shared libraries is turned of. The creation of static libraries is still possible. The reason for this is that it has little sense in making a smarlinked dynamical library. The whole shared library is loaded into memory anyway by the dynamic linker (or WINDOWS NT), so there would be no gain in size by making it smartlinked.