FPC linker oddity

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

FPC linker oddity

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
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FPC linker oddity

Jonas Maebe-2
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.


Jonas
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FPC linker oddity

patspiper
On 21/06/15 23:08, Jonas Maebe wrote:

> 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
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FPC linker oddity

Jonas Maebe-2
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.


Jonas

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FPC linker oddity

patspiper
On 21/06/15 23:58, Jonas Maebe wrote:
> 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
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FPC linker oddity

Tomas Hajny-2
In reply to this post by Jonas Maebe-2
On Sun, June 21, 2015 22:58, Jonas Maebe wrote:

> 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


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal