1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// SPDX-License-Identifier: LGPL-3.0-linking-exception
{ This unit allows to find the implementation of a library from its
"linker name" whatever its version. }
unit linuxlib;
{$mode objfpc}{$H+}
{ Linker name
-----------
The linker name normally can only be used when compiling a program.
It ends up with .so and does not have any version number. There isn't
necessarily a file with this name though it may be provided in the
development package (ending with -dev).
- libwebp.so
- libportaudio.so
- libtiff.so
- libpython.so
Soname (qualified with a version number)
----------------------------------------
The soname can be supplied to the LoadLibray function to load at runtime,
without specifying any path. It is the same as the linker name, but with
a version number. The file exists most of the time and it is generally
a symbolic link to the implementation (or "real name").
- libwebp.so.6
- libportaudio.so.2
- libtiff.so.5
- libpython2.7.so
Implementation or real name (with minor number)
-----------------------------------------------
The real name contains the implementation. It has a minor number and
an optional release number. Most of the time, you don't need to know this
name to use the library.
- libwebp.so.6.0.2
- libportaudio.so.2.0.0
- libtiff.so.5.3.0
- libpython2.7.so.1.0
See: http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html }
interface
uses
BGRAClasses, SysUtils;
{* Retrieves the full path of a library on Linux.
Note that between different versions, there may be incompatibilities
(in the signature of the functions or the record types).
So make sure the functions you are calling are stable or
check the version of the library once its loaded using one of its functions. }
function FindLinuxLibrary(ALinkerName: string; AMinimumVersion: integer = 0): string;
implementation
uses process;
function FindBinPath(AFilename: string): string;
const
BinPaths: array[0..5] of string =
('/usr/local/sbin','/usr/local/bin','/usr/sbin','/usr/bin','/sbin','/bin');
var i: integer;
begin
for i := 0 to high(BinPaths) do
If FileExists(BinPaths[i] + '/' + AFilename) then
exit(BinPaths[i] + '/' + AFilename);
exit(AFilename);
end;
function FindLinuxLibrary(ALinkerName: string; AMinimumVersion: integer): string;
const
OpenBracket = ' (';
Arrow = ') => ';
var
dataText, s, fileName, flags, path, versionStr: string;
dataList, flagList: TStringList;
openBracketPos, arrowPos, posDot: SizeInt;
versionInt, errPos, i: integer;
maxVersionInt: integer;
begin
versionStr := copy(ExtractFileExt(ALinkerName), 2);
val(versionStr, versionInt, errPos);
if errPos = 0 then
begin
if AMinimumVersion = 0 then AMinimumVersion := versionInt;
ALinkerName := ChangeFileExt(ALinkerName,'');
end;
result := '';
maxVersionInt := AMinimumVersion-1;
RunCommand(FindBinPath('ldconfig'), ['-p'], dataText, []);
dataList := TStringList.Create;
dataList.Text := dataText;
flagList := TStringList.Create;
for i := 0 to dataList.Count-1 do
begin
s := dataList[i];
openBracketPos := pos(OpenBracket, s);
arrowPos := pos(Arrow,s);
if (openBracketPos <> 0) and (arrowPos <> 0) then
begin
fileName := trim(copy(s,1,openBracketPos-1));
if fileName.StartsWith(ALinkerName+'.') then
begin
versionStr := copy(fileName, length(ALinkerName)+2, length(fileName)-length(ALinkerName)-1);
posDot := pos('.', versionStr);
if posDot > 0 then versionStr := copy(versionStr, posDot-1);
val(versionStr, versionInt, errPos);
if errPos = 0 then
begin
flags := copy(s, openBracketPos+length(OpenBracket), arrowPos-openBracketPos-length(OpenBracket));
flagList.CommaText := flags;
if {$IFNDEF CPU64}not{$ENDIF} (flagList.IndexOf('x86-64') <> -1) then
begin
path := copy(s, arrowPos+length(Arrow), length(s)-arrowPos-length(Arrow)+1);
if versionInt > maxVersionInt then
begin
maxVersionInt := versionInt;
result := path;
end;
end;
end;
end;
end;
end;
flagList.Free;
dataList.Free;
end;
end.
|