Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2015-06

FPC linker oddity

6 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

patspiper

The following simple program which uses the $LINKLIB compiler directive builds fine under Linux:

program Project1;
{$Linklib c}
Const P : PChar = 'This is fun !';
Function strlen (P: PChar): Longint; cdecl; external;
begin
   WriteLn ('Length of (',p,') : ',strlen(p))
end.
However, cross-compiling to Windows a similar program fails:
program Project1;
{$Linklib kernel32}
   Function GetTickCount: DWORD; external;
begin
   WriteLn ('GetTickCount ', GetTickCount);
end.
project1.lpr(10,1) Error: Undefined symbol:
P$PROJECT1_$$_GETTICKCOUNT$$LONGWORD
Changing the GetTickCount declaration to any of the following works:
   Function GetTickCount: DWORD; external name
'_$dll$kernel32$GetTickCount';
   Function GetTickCount: DWORD; external 'kernel32';

Why is the behaviour different between Linux and Windows?

Stephano

Reply by email

Jonas Maebe
to patspiper
patspiper wrote 15 lines
program Project1; {$Linklib kernel32} Function GetTickCount: DWORD; external; begin WriteLn ('GetTickCount ', GetTickCount); end. project1.lpr(10,1) Error: Undefined symbol: P$PROJECT1_$$_GETTICKCOUNT$$LONGWORD Changing the GetTickCount declaration to any of the following works: Function GetTickCount: DWORD; external name '_$dll$kernel32$GetTickCount'; Function GetTickCount: DWORD; external 'kernel32'; Why is the behaviour different between Linux and Windows?

ELF (used by Linux) and PECOFF (used by Windows) use completely different ways of shared linking.

Jonas

Reply by email

patspiper
to Jonas Maebe
Jonas Maebe wrote 18 lines
On 21/06/15 21:43, patspiper wrote: > program Project1; > {$Linklib kernel32} > Function GetTickCount: DWORD; external; > begin > WriteLn ('GetTickCount ', GetTickCount); > end. > project1.lpr(10,1) Error: Undefined symbol: > P$PROJECT1_$$_GETTICKCOUNT$$LONGWORD > > Changing the GetTickCount declaration to any of the following works: > Function GetTickCount: DWORD; external name > '_$dll$kernel32$GetTickCount'; > Function GetTickCount: DWORD; external 'kernel32'; > > Why is the behaviour different between Linux and Windows? ELF (used by Linux) and PECOFF (used by Windows) use completely different ways of shared linking.

So what should be done to remedy the Windows case when $LINKLIB is used, that is unless $LINKLIB is not to be used with Windows?

Note that in the 2 'solutions' I gave, $LINKLIB is not needed and can be removed altogether.

Stephano

Reply by email

Jonas Maebe
to patspiper
patspiper wrote 12 lines
On 21/06/15 23:08, Jonas Maebe wrote: > On 21/06/15 21:43, patspiper wrote: >> Changing the GetTickCount declaration to any of the following works: >> Function GetTickCount: DWORD; external name >> '_$dll$kernel32$GetTickCount'; >> Function GetTickCount: DWORD; external 'kernel32'; >> >> Why is the behaviour different between Linux and Windows? > ELF (used by Linux) and PECOFF (used by Windows) use completely > different ways of shared linking. So what should be done to remedy the Windows case when $LINKLIB is used, that is unless $LINKLIB is not to be used with Windows?

{$linklib xxx} can be useful on Windows if you have a DLL that has an initialisation routine that you want to be run, but you're not calling any code from it.

Note that in the 2 'solutions' I gave, $LINKLIB is not needed and can be removed altogether.

That's correct. And the second way is the normal way to import routines from a DLL under Windows (which also works under *nix; only Darwin is different for legacy reasons: there you need the {$linklib xxx} to ensure that the library is linked).

Using both {$linklib xxx} and "external 'xxx'" is best, since it will always work on all platforms.

Jonas

Reply by email

patspiper
to Jonas Maebe
Jonas Maebe wrote 7 lines
On 21/06/15 22:20, patspiper wrote: > > So what should be done to remedy the Windows case when $LINKLIB is used, > that is unless $LINKLIB is not to be used with Windows? {$linklib xxx} can be useful on Windows if you have a DLL that has an initialisation routine that you want to be run, but you're not calling any code from it.
Then maybe the programmer's manual (section 7.1.1 Declaring external
functions or procedures) needs to be corrected as it mentions that
Procedure ProcName (Args : TPRocArgs); external ’Name’;
is equivalent to:
{$LinkLib ’Name’}
Procedure ProcName (Args : TPRocArgs);external;

But in fact $Linklib doesn't work on Windows whereas external 'name' does.

Stephano

Reply by email

Tomas Hajny
to Jonas Maebe: {$linklib xxx} can be useful on Windows if you have a DLL that has an initialisation…
Jonas Maebe wrote 28 lines
On 21/06/15 22:20, patspiper wrote: > On 21/06/15 23:08, Jonas Maebe wrote: >> On 21/06/15 21:43, patspiper wrote: >>> Changing the GetTickCount declaration to any of the following works: >>> Function GetTickCount: DWORD; external name >>> '_$dll$kernel32$GetTickCount'; >>> Function GetTickCount: DWORD; external 'kernel32'; >>> >>> Why is the behaviour different between Linux and Windows? >> ELF (used by Linux) and PECOFF (used by Windows) use completely >> different ways of shared linking. > So what should be done to remedy the Windows case when $LINKLIB is used, > that is unless $LINKLIB is not to be used with Windows? {$linklib xxx} can be useful on Windows if you have a DLL that has an initialisation routine that you want to be run, but you're not calling any code from it. > Note that in the 2 'solutions' I gave, $LINKLIB is not needed and can be > removed altogether. That's correct. And the second way is the normal way to import routines from a DLL under Windows (which also works under *nix; only Darwin is different for legacy reasons: there you need the {$linklib xxx} to ensure that the library is linked). Using both {$linklib xxx} and "external 'xxx'" is best, since it will always work on all platforms.

I'm not sure if it is really the best. At least FPC 2.6.4 expects that the LINKLIB ... refers to an (existing) import library and issues 'Error: Import library not found for kernel32', whereas the import library is generated on the fly based on the import declarations of the individual external symbols if LINKLIB is not used.

Tomas

Reply by email