Recent

Author Topic: Dynamic Library on Linux  (Read 2683 times)

Kevan S. Hashemi

  • New Member
  • *
  • Posts: 23
Dynamic Library on Linux
« on: May 11, 2020, 06:25:20 pm »
Dear FPC Community,

I have the following library program:

Code: Pascal  [Select][+][-]
  1. library d;
  2. function answer:integer; cdecl;
  3. begin
  4.         writeln('Hello from d library, answer routine.');
  5.         answer:=42;
  6. end;
  7.  
  8. exports answer;
  9. end.

And the following main program that loads the "d" library when it starts up:

Code: Pascal  [Select][+][-]
  1. program m;
  2. {$linklib d}
  3. function answer:integer; cdecl; external;
  4. begin
  5.         writeln('Answer: ',answer);
  6. end.

On MacOSX I compile and run like this (leaving out compiler messages):

Code: Bash  [Select][+][-]
  1. $ fpc d
  2. $ fpc m
  3. $ ./m
  4. Hello from d library, answer routine.
  5. Answer: 42

On Linux 64-bit Scientific Linux 6.4, a Fedora variant used by CERN, with "Free Pascal Compiler version 3.0.4 [2017/10/03] for x86_64" downloaded from FPC site yesterday I get the following (again, I have removed normal compiler output to leave only warnings):

Code: Bash  [Select][+][-]
  1. $ fpc d
  2. /usr/local/bin/ld: warning: link.res contains output sections; did you forget -T?
  3. $ fpc m
  4. /usr/local/bin/ld: warning: link.res contains output sections; did you forget -T?
  5. $  file libd.so
  6. libd.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
  7. $ ./m
  8. ./m: error while loading shared libraries: libd.so: cannot open shared object file: No such file or directory

The "cdecl" is required on both MacOSX and Linux, or else "m" won't compile. The "stdcall" directive, or the absence of any directive, results in a compiler error: fps cannot understand the "answer" function.

What am I doing wrong on Linux?

Best, Kevan

Fred vS

  • Hero Member
  • *****
  • Posts: 1787
    • StrumPract is the musicians best friend
Re: Dynamic Library on Linux
« Reply #1 on: May 11, 2020, 07:00:19 pm »
Hello.

With the directive
Code: Pascal  [Select][+][-]
  1. {$linklib d}
the linker will look for the library in the linker library search path.

Did you copy libd.so in one of that library search path? (usually one of this:)
Code: Pascal  [Select][+][-]
  1. /lib
or
Code: Pascal  [Select][+][-]
  1.  /usr/lib
or
Code: Pascal  [Select][+][-]
  1. /usr/local/lib


If you want use a custom directory, then you should use LoadLibrary() to dynamically load your library.

[EDIT] You may also set the linker library search path with the -Fl command line option.
« Last Edit: May 11, 2020, 07:15:16 pm by Fred vS »
I use Lazarus 2.0.6 32/64 and FPC 3.2.0 32/64 on Debian 10.2 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64 and Mac OS X Snow Leopard 32.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt, Carbon.

https://github.com/fredvs

jiaxing2

  • Full Member
  • ***
  • Posts: 164
Re: Dynamic Library on Linux
« Reply #2 on: May 11, 2020, 08:12:55 pm »
Dear FPC Community,

I have the following library program:

Code: Pascal  [Select][+][-]
  1. library d;
  2. function answer:integer; cdecl;
  3. begin
  4.         writeln('Hello from d library, answer routine.');
  5.         answer:=42;
  6. end;
  7.  
  8. exports answer;
  9. end.

And the following main program that loads the "d" library when it starts up:

Code: Pascal  [Select][+][-]
  1. program m;
  2. {$linklib d}
  3. function answer:integer; cdecl; external;
  4. begin
  5.         writeln('Answer: ',answer);
  6. end.

On MacOSX I compile and run like this (leaving out compiler messages):

Code: Bash  [Select][+][-]
  1. $ fpc d
  2. $ fpc m
  3. $ ./m
  4. Hello from d library, answer routine.
  5. Answer: 42

On Linux 64-bit Scientific Linux 6.4, a Fedora variant used by CERN, with "Free Pascal Compiler version 3.0.4 [2017/10/03] for x86_64" downloaded from FPC site yesterday I get the following (again, I have removed normal compiler output to leave only warnings):

Code: Bash  [Select][+][-]
  1. $ fpc d
  2. /usr/local/bin/ld: warning: link.res contains output sections; did you forget -T?
  3. $ fpc m
  4. /usr/local/bin/ld: warning: link.res contains output sections; did you forget -T?
  5. $  file libd.so
  6. libd.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
  7. $ ./m
  8. ./m: error while loading shared libraries: libd.so: cannot open shared object file: No such file or directory

The "cdecl" is required on both MacOSX and Linux, or else "m" won't compile. The "stdcall" directive, or the absence of any directive, results in a compiler error: fps cannot understand the "answer" function.

What am I doing wrong on Linux?

Best, Kevan

Everything is normal. FPC done it job fine. The problem is Linux can't find libd.so when running m because Linux doesn't search the current directory by default.

So, run ldconfig "absolute path to the directory contains libd.so" as root and you could run m as normal.

More information: https://unix.stackexchange.com/questions/67781/use-shared-libraries-in-usr-local-lib

Kevan S. Hashemi

  • New Member
  • *
  • Posts: 23
Re: Dynamic Library on Linux
« Reply #3 on: May 11, 2020, 09:10:50 pm »
Dear Fred,

Thanks for your help.

I copied libd.so into /lib, /usr/lib, and then /usr/local/lib, but program "m" still says it can't find the file. Please note: I compile "m" without errors. The shared library libd.so is in the same directory as m.pas and the compiler finds the library just fine. If I delete libd.so and try to compile, I get an error saying the compiler cannot find the library. After compiling libd.so and the executable "m", I use ldd to look for dependancies:

Code: Bash  [Select][+][-]
  1. [hashemi@vmboxslc64 Build]$ ldd libd.so
  2.         /lib64/ld-linux-x86-64.so.2 (0x00000038b7a00000)
  3.         linux-vdso.so.1 =>  (0x00007ffe8cf7e000)
  4. [hashemi@vmboxslc64 Build]$ ldd m
  5.         linux-vdso.so.1 =>  (0x00007ffe2374c000)
  6.         libd.so => not found
  7. $ file libd.so
  8. libd.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped

So it's not just FPC that can't find the file. But the file is definitely present. Does my example code work for you, if you compile with FPC on your Debian system?

Best, Kevan

MarkMLl

  • Hero Member
  • *****
  • Posts: 1094
Re: Dynamic Library on Linux
« Reply #4 on: May 11, 2020, 09:32:16 pm »
I'm by no means an expert at this, and whenever I've used .so files I've explicitly used LoadLibrary().

I find myself wondering whether ldconfig is relevant here, and I think it might be worth considering what's in its manpage:

(on some 64-bit architectures such as x86-64, /lib and /usr/lib are the trusted directories for 32-bit libraries, while /lib64 and /usr/lib64 are used for 64-bit libraries).

Having said that, my last couple of attempts to use LoadLibrary() on x86_64 (Debian "stable" v10) haven't worked out well, however they were rather tricky setups with calls in both directions... there /might/ be a compiler- or OS version-specific problem in there, but I worked around it rather than investigating in depth. However your  ldd m  output suggests that that's probably a red herring.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8597
  • FPC developer.
Re: Dynamic Library on Linux
« Reply #5 on: May 11, 2020, 09:37:59 pm »
Compile with -st to stop at linking, and inspect the ppas.sh file that calls the linker.

This way you can call the linker independent from FPC.

It's the linker and the dynamic linker that search libraries.

Fred vS

  • Hero Member
  • *****
  • Posts: 1787
    • StrumPract is the musicians best friend
Re: Dynamic Library on Linux
« Reply #6 on: May 11, 2020, 09:57:19 pm »
Quote
Does my example code work for you, if you compile with FPC on your Debian system?

Yes, following my previous post, on Debian 10, 6' bit:

Code: Pascal  [Select][+][-]
  1. fred@fiens ~> fpc d
  2. Free Pascal Compiler version 3.0.4+dfsg-22 [2019/01/24] for x86_64
  3. Copyright (c) 1993-2017 by Florian Klaempfl and others
  4. Target OS: Linux for x86-64
  5. Compiling d.pas
  6. Linking libd.so
  7. 9 lines compiled, 0.2 sec

Code: Pascal  [Select][+][-]
  1. fred@fiens ~> fpc m
  2. Free Pascal Compiler version 3.0.4+dfsg-22 [2019/01/24] for x86_64
  3. Copyright (c) 1993-2017 by Florian Klaempfl and others
  4. Target OS: Linux for x86-64
  5. Compiling m.pas
  6. Linking m
  7. 6 lines compiled, 0.1 sec
  8.  

Code: Pascal  [Select][+][-]
  1. fred@fiens ~> ./m
  2. ./m: error while loading shared libraries: libd.so: cannot open shared object file: No such file or directory
  3.  

Code: Pascal  [Select][+][-]
  1. fred@fiens ~> sudo cp libd.so /usr/lib

Code: Pascal  [Select][+][-]
  1. fred@fiens ~> ./m
  2. Hello from d library, answer routine.
  3. Answer: 42
I use Lazarus 2.0.6 32/64 and FPC 3.2.0 32/64 on Debian 10.2 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64 and Mac OS X Snow Leopard 32.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt, Carbon.

https://github.com/fredvs

Kevan S. Hashemi

  • New Member
  • *
  • Posts: 23
Re: Dynamic Library on Linux
« Reply #7 on: May 11, 2020, 10:25:15 pm »
Fred: Thanks for showing that moving the library into the standard search path will get the program working.

Marcov: I love that -st option, which produces a script to perform linking. I tried -sh as well.

MarkMLI: You are absolutely correct about /lib64. When I move my libd.so into /lib64, my program runs. And "ldd" finds it there too.

jiaxing2: It would have taken me a long time to figure out that "ldd" does not search the local directory.

The four of you have saved me a lot of trouble. Thank you. Here is a working solution that uses the LD_LIBRARY_PATH environment variable, and allows us to leave the shared object where it is, and we don't have to reconfigure the system as root.

Code: Bash  [Select][+][-]
  1. $ LD_LIBRARY_PATH=.
  2. $ export LD_LIBRARY_PATH
  3. $ ./m
  4. Hello from d library, answer routine.
  5. Answer: 42
  6. $ ldd m
  7.         linux-vdso.so.1 =>  (0x00007fff9fbfe000)
  8.         libd.so => ./libd.so (0x00007fcc17a85000)
  9.         /lib64/ld-linux-x86-64.so.2 (0x00000038b7a00000)

Note that LD_LIBRARY_PATH adds to the library search path. It does not over-write the library search path.
 
Best, Kevan

Fred vS

  • Hero Member
  • *****
  • Posts: 1787
    • StrumPract is the musicians best friend
Re: Dynamic Library on Linux
« Reply #8 on: May 11, 2020, 10:38:29 pm »
Hello Kevan.

Thanks for the thanks!

I would recommend you to take a look at Loadlibrary - (dynamically loading a dynamic library):

https://wiki.lazarus.freepascal.org/Lazarus/FPC_Libraries

Code: Pascal  [Select][+][-]
  1. LoadLibrary('/the/direcrory/of/libd.so');

I agree, there is a few more code needed but much less problem after.

Fre;D
« Last Edit: May 11, 2020, 10:51:21 pm by Fred vS »
I use Lazarus 2.0.6 32/64 and FPC 3.2.0 32/64 on Debian 10.2 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64 and Mac OS X Snow Leopard 32.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt, Carbon.

https://github.com/fredvs

MarkMLl

  • Hero Member
  • *****
  • Posts: 1094
Re: Dynamic Library on Linux
« Reply #9 on: May 11, 2020, 10:50:40 pm »
MarkMLI: You are absolutely correct about /lib64. When I move my libd.so into /lib64, my program runs. And "ldd" finds it there too.

jiaxing2: It would have taken me a long time to figure out that "ldd" does not search the local directory.

You really were very close to fixing it yourself. If you hadn't mentioned ldd- which I always forget about- I wouldn't have had a quick way of reminding myself the name of the ldconfig program, and if you'd used  ldd -v  you'd probably have seen "x86_64" repeated often enough to twig :-)

Quote
Note that LD_LIBRARY_PATH adds to the library search path. It does not over-write the library search path.

Actually, that takes me /way/ back: the first Linux distro I used (Yggdrassil, 25+ years ago) recommended LD_LIBRARY_PATH to add an automatic text decompressor when files were being viewed from the live CD, and more recently I've used it to add a shim layer to V4L. It's not generally appreciated how much mischief it can cause...

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.

Fred vS

  • Hero Member
  • *****
  • Posts: 1787
    • StrumPract is the musicians best friend
Re: Dynamic Library on Linux
« Reply #10 on: May 12, 2020, 03:21:07 am »
Hello Kevan.

Here your code for m program using loadlibrary(), supposing that libd.so is in the same directory as the program:

Code: Pascal  [Select][+][-]
  1. program m;
  2.    uses dynlibs, SysUtils;
  3.  
  4.     type
  5.       TMyMethod=function :integer; cdecl;
  6.    
  7.      var
  8.        MyLib: TLibHandle = dynlibs.NilHandle;
  9.        MyMethod: TMyMethod;
  10.      
  11.     begin
  12.        MyLib := LoadLibrary(ExtractFilePath(ParamStr(0)) + '/libd.so');
  13.        if MyLib = 0 then Exit;
  14.        MyMethod := TMyMethod(GetProcedureAddress(MyLib, 'answer'));
  15.        if MyMethod <> nil then writeln('Answer: ',MyMethod);
  16.        FreeLibrary(MyLib);
  17.        MyLib:= DynLibs.NilHandle;
  18.     end.

Note that if you use only the filename without the full path:

Code: Pascal  [Select][+][-]
  1. MyLib := LoadLibrary('libd.so');

LoadLibrary will do like external does: looking in the linker library search path.

Then it will work if libd.so is in /usr/lib or /usr/lib64 for example.
« Last Edit: May 12, 2020, 06:40:42 am by Fred vS »
I use Lazarus 2.0.6 32/64 and FPC 3.2.0 32/64 on Debian 10.2 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64 and Mac OS X Snow Leopard 32.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt, Carbon.

https://github.com/fredvs

jiaxing2

  • Full Member
  • ***
  • Posts: 164
Re: Dynamic Library on Linux
« Reply #11 on: May 12, 2020, 07:46:09 am »
Note that if you use only the filename without the full path:

Code: Pascal  [Select][+][-]
  1. MyLib := LoadLibrary('libd.so');

LoadLibrary will do like external does: looking in the linker library search path.

Then it will work if libd.so is in /usr/lib or /usr/lib64 for example.

On my system /usr/lib64 is not included by default and needs to be added to /etc/ld.so.conf. The IUP library installs to this directory.

MarkMLl

  • Hero Member
  • *****
  • Posts: 1094
Re: Dynamic Library on Linux
« Reply #12 on: May 12, 2020, 10:07:00 am »
General point: note that LoadLibrary() etc. has a GetLoadErrorStr() function which returns the last saved message from the OS.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.

trev

  • Hero Member
  • *****
  • Posts: 825
  • Former Delphi 1-7 and 10.2 User
Re: Dynamic Library on Linux
« Reply #13 on: May 12, 2020, 02:30:33 pm »
You can also use:

Code: Pascal  [Select][+][-]
  1. uses
  2.   SysUtils;
  3. ...
  4.    // check whether loading was successful
  5.    if LibHandle <> 0 then
  6. ...
  7.    else
  8.      // error message on load failure
  9.      WriteLn('GetLastOSError = ', SysErrorMessage(GetLastOSError));
  10.  

Many ways to skin an error ;)
o Lazarus v2.1.0 r63598, FPC v3.3.1 r45778, macOS 10.14.6 (with sup update), Xcode 11.3.1
o Lazarus v2.1.0 r61574, FPC v3.3.1 r42318, FreeBSD 12.1 amd64 (Parallels VM)
o FPC 3.0.4, FreeBSD 12-STABLE r361007 amd64
o Lazarus v2.1.0 r61574, FPC v3.0.4, Ubuntu 18.04 (Parallels VM)

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8597
  • FPC developer.
Re: Dynamic Library on Linux
« Reply #14 on: May 12, 2020, 02:41:01 pm »
On my system /usr/lib64 is not included by default and needs to be added to /etc/ld.so.conf. The IUP library installs to this directory.

Note that officially after changing ld.so.conf you must run ldconfig. Linux never has been too critical on that, but some BSDs did.

 

TinyPortal © 2005-2018