/usr/src/castle-game-engine-4.1.1/base/castledynlib.pas is in castle-game-engine-src 4.1.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | {
Copyright 2003-2013 Michalis Kamburelis.
This file is part of "Castle Game Engine".
"Castle Game Engine" is free software; see the file COPYING.txt,
included in this distribution, for details about the copyright.
"Castle Game Engine" is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
----------------------------------------------------------------------------
}
{ Dynamic libraries loading (TDynLib). }
unit CastleDynLib;
interface
uses
{$ifdef MSWINDOWS} Windows, {$endif}
{$ifdef UNIX} Unix, Dl, {$endif}
SysUtils
{$ifdef FPC} , DynLibs {$endif};
type
TDynLibHandle = {$ifdef FPC} TLibHandle {$else} HModule {$endif};
{$ifndef FPC}
const
{ Invalid TDynLibHandle value (meaning : LoadLibrary failed) }
InvalidDynLibHandle: TDynLibHandle = 0;
{$else}
{ Workaround for FPC bug [http://bugs.freepascal.org/view.php?id=6489] }
{$define InvalidDynLibHandle := DynLibs.NilHandle}
{$endif}
type
{ }
EDynLibError =class(Exception);
TDynLibSymbolErrorBehaviour = (seRaise, seReturnNil, seWarnAndReturnNil);
(*Load functions from dynamic libraries.
I wrote my own class to handle dynamic libraries because:
@unorderedList(
@item(I wanted to have @link(Load) and @link(Symbol) functions that
@italic(by default do error checking) (and raise necessary exceptions).)
@item(I wanted to have a field SymbolErrorBehaviour --- this lets me to
specify, @italic(once for all subsequent Symbol calls),
what error checking I want.
Default is to check errors and raise exceptions.
There is also a very usefull value reWarnAndContinue:
it allows you to run program @italic(once) and see all symbols that
are missing from dynamic library.)
@item(Also, the interface of this is OS-independent and works for
both FPC and Delphi, so you can avoid ugly $ifdefs in your code.)
)
Typical usage:
@longCode(#
var
ALLibrary: TDynLib = nil;
initialization
ALLibrary := TDynLib.Load('libopenal.so');
{ ... some calls to ALLibrary.Symbol() ... }
finalization
FreeAndNil(ALLibrary);
end.
#)
It is important that ALLibrary is initialized to nil (actually, writing
" = nil" is not necessary for a global variable) and that in finalization
you use Free(AndNil). This allows you to exit gracefully if library does not
exist on the system and @link(Load) will raise an exception: ALLibrary will
stay then as nil and FreeAndNil(ALLibrary) will be a valid NOP.
Using FreeAndNil(ALLibrary) instead of ALLibrary.Free is just a good
practice.
*)
TDynLib = class
private
{ In this class, we always have a valid FHandle. }
FHandle: TDynLibHandle;
FName: string;
FSymbolErrorBehaviour: TDynLibSymbolErrorBehaviour;
public
{ Standard constructor, requires a valid TDynLibHandle already.
Usually you will prefer to use @link(Load) method instead of
directly calling this constructor.
@raises(ECheckFailed if you supply invalid handle.) }
constructor Create(const AName: string; AHandle: TDynLibHandle);
destructor Destroy; override;
{ Name of the library to link to. In practice, file name of the *.so
or *.dylib or *.dll file.
A precise strategy where this library is searched
is specific to a platform, see the semantics of SysUtils.LoadLibrary
(DynLibs for FPC) call on given OS. }
property Name: string read FName;
{ Link to a dynamic library specified by Name. Returns created
TDynLib instance.
If the library is not found and CheckResult is @false, @nil will
be returned. If CheckResult is @true then EDynLibError will be raised
in case library is not found. So if CheckResult is @true, @nil is
never returned.
Note that the default situation prevents from unintentionally ignoring
an error and @italic(that's good).
@raises(EDynLibError If library not found and CheckResult is @true.) }
class function Load(const AName: string; CheckResult: boolean = true): TDynLib;
{ What happens when @link(Symbol) fails. }
property SymbolErrorBehaviour: TDynLibSymbolErrorBehaviour
read FSymbolErrorBehaviour write FSymbolErrorBehaviour
default seRaise;
{ Return address of given symbol (function name etc.) from loaded dynamic
library. If the symbol doesn't exist, then SymbolErrorBehaviour
says what happens:
@unorderedList(
@item(seRaise (default), then EDynLibError will be raised.)
@item(seReturnNil, then return @nil (and continue, ignoring error).)
@item(seWarnAndReturnNil, then write warning (using WarningWrite)
and return @nil (and continue, ignoring error).
This is useful for debugging : you can easily open the library and after
one run of the program you can see what symbols (that you requested)
were missing from the library. This is useful when you have a library
but you are not sure whether it is compatible and contains all the
symbols that you want.)
)
@raises(EDynLibError If SymbolName doesn't exist and
SymbolErrorBehaviour is seRaise.)
}
function Symbol(SymbolName: PChar): Pointer;
end;
implementation
uses CastleUtils;
constructor TDynLib.Create(const AName: string; AHandle: TDynLibHandle);
begin
inherited Create;
FName := AName;
FHandle := AHandle;
Check(AHandle <> InvalidDynLibHandle,
'TDynLib can not be created with invalid DynLibHandle');
SymbolErrorBehaviour := seRaise;
end;
destructor TDynLib.Destroy;
begin
{ Should we check here for errors after FreeLibrary ?
Well, this is finalization code so this is one place where strict error
checking (and raising exceptions on them) may be not so good idea.
For now I will not do it. }
{$ifdef FPC} UnloadLibrary {$else} FreeLibrary {$endif} (FHandle);
inherited;
end;
class function TDynLib.Load(const AName: string; CheckResult: boolean): TDynLib;
function LoadLibraryGlobally(AName: PChar): TDynLibHandle;
{ TODO: under UNIX (Linux, more specifically, since I don't use this code
with any other UNIX yet) I must load with RTLD_GLOBAL, else GLU crashes
(it seems GLU requires that someone else loads GL symbols for it ?
I really don't know. TO BE FIXED.) }
begin
result:=
{$ifdef UNIX} TDynLibHandle( dlopen(AName, RTLD_LAZY or RTLD_GLOBAL) );
{$else} LoadLibrary(AName);
{$endif}
end;
var Handle: TDynLibHandle;
begin
Handle := LoadLibraryGlobally(PChar(AName));
if Handle = InvalidDynLibHandle then
begin
if CheckResult then
raise EDynLibError.Create('Can''t load library "' +AName+ '"'
{$ifdef UNIX} + ': ' + dlerror {$endif}) else
result := nil;
end else
result := Self.Create(AName, Handle);
end;
function TDynLib.Symbol(SymbolName: PChar): Pointer;
function ErrStr: string;
begin result := 'Symbol "'+SymbolName+'" not found in library "'+Name+'"' end;
begin
result:= {$ifdef FPC} GetProcedureAddress {$else} GetProcAddress {$endif}
(FHandle, SymbolName);
if result = nil then
case SymbolErrorBehaviour of
seRaise: raise EDynLibError.Create(ErrStr);
seReturnNil: ;
seWarnAndReturnNil: WarningWrite(ErrStr);
else raise EInternalError.Create('SymbolErrorBehaviour=?');
end;
end;
end.
|