@@ -79,6 +79,15 @@ class FFI
79
79
*/
80
80
private static bool $ ffi_inited = false ;
81
81
82
+ /**
83
+ * A list of paths where libvips might reside.
84
+ *
85
+ * @internal
86
+ */
87
+ private static array $ libraryPaths = [
88
+ "" // system library
89
+ ];
90
+
82
91
/**
83
92
* Look up these once.
84
93
*
@@ -169,6 +178,39 @@ public static function atLeast(int $x, int $y, int $z = 0): bool
169
178
self ::$ library_micro >= $ z );
170
179
}
171
180
181
+ /**
182
+ * Adds a directory to the search path for shared libraries.
183
+ *
184
+ * This method has no effect if FFI handles are already initialized,
185
+ * if the specified path is non-existent, or if the path is already
186
+ * included.
187
+ *
188
+ * @param string $path The path of the library.
189
+ * @return bool `true` if the path was added; otherwise, `false`.
190
+ */
191
+ public static function addLibraryPath (string $ path ): bool
192
+ {
193
+ // Already initialized.
194
+ if (self ::$ ffi_inited ) {
195
+ return false ;
196
+ }
197
+
198
+ $ path = realpath ($ path );
199
+ if ($ path === false ) {
200
+ return false ;
201
+ }
202
+
203
+ $ path .= DIRECTORY_SEPARATOR ;
204
+
205
+ if (in_array ($ path , self ::$ libraryPaths )) {
206
+ return false ;
207
+ }
208
+
209
+ self ::$ libraryPaths [] = $ path ;
210
+
211
+ return true ;
212
+ }
213
+
172
214
/**
173
215
* Shut down libvips. Call this just before process exit.
174
216
*
@@ -208,12 +250,11 @@ private static function libraryName(string $name, int $abi): string
208
250
}
209
251
210
252
private static function libraryLoad (
211
- array $ libraryPaths ,
212
253
string $ libraryName ,
213
254
string $ interface
214
255
): ?\FFI {
215
256
Utils::debugLog ("trying to open " , ["libraryName " => $ libraryName ]);
216
- foreach ($ libraryPaths as $ path ) {
257
+ foreach (self :: $ libraryPaths as $ path ) {
217
258
Utils::debugLog ("trying path " , ["path " => $ path ]);
218
259
try {
219
260
$ library = \FFI ::cdef ($ interface , $ path . $ libraryName );
@@ -252,37 +293,25 @@ private static function init(): void
252
293
253
294
$ is_64bits = PHP_INT_SIZE === 8 ;
254
295
255
- $ libraryPaths = [
256
- "" // system library
257
- ];
258
-
259
- $ vipshome = getenv ("VIPSHOME " );
260
- if ($ vipshome ) {
261
- // lib<qual>/ predicates lib/
262
- $ libraryPaths [] = $ vipshome . ($ is_64bits ? "/lib64/ " : "/lib32/ " );
263
- // lib/ is always searched
264
- $ libraryPaths [] = $ vipshome . "/lib/ " ;
265
- }
266
-
267
296
if (PHP_OS_FAMILY === "OSX " || PHP_OS_FAMILY === "Darwin " ) {
268
297
// Homebrew on Apple Silicon
269
- $ libraryPaths [] = "/opt/homebrew/lib/ " ;
298
+ self :: addLibraryPath ( "/opt/homebrew/lib " ) ;
270
299
// See https://github.com/Homebrew/brew/issues/13481#issuecomment-1207203483
271
- $ libraryPaths [] = "/usr/local/lib/ " ;
300
+ self :: addLibraryPath ( "/usr/local/lib " ) ;
272
301
}
273
302
274
- $ vips = self ::libraryLoad ($ libraryPaths , $ vips_libname , <<<'CPP'
303
+ $ vips = self ::libraryLoad ($ vips_libname , <<<'CPP'
275
304
int vips_init (const char *argv0);
276
305
const char *vips_error_buffer (void);
277
306
int vips_version(int flag);
278
307
CPP);
279
308
280
309
if ($ vips === null ) {
281
310
// drop the "" (system path) member
282
- array_shift ($ libraryPaths );
311
+ array_shift (self :: $ libraryPaths );
283
312
$ msg = "Unable to open library ' $ vips_libname' " ;
284
- if (!empty ($ libraryPaths )) {
285
- $ msg .= " in any of [' " . implode ("', ' " , $ libraryPaths ) . "'] " ;
313
+ if (!empty (self :: $ libraryPaths )) {
314
+ $ msg .= " in any of [' " . implode ("', ' " , self :: $ libraryPaths ) . "'] " ;
286
315
}
287
316
$ msg .= ". Make sure that you've installed libvips and that ' $ vips_libname' " ;
288
317
$ msg .= " is on your system's library search path. " ;
@@ -777,13 +806,13 @@ private static function init(): void
777
806
* one that libvips itself is using, and they will share runtime types.
778
807
*/
779
808
self ::$ glib =
780
- self ::libraryLoad ($ libraryPaths , $ vips_libname , $ glib_decls ) ??
781
- self ::libraryLoad ($ libraryPaths , $ glib_libname , $ glib_decls );
809
+ self ::libraryLoad ($ vips_libname , $ glib_decls ) ??
810
+ self ::libraryLoad ($ glib_libname , $ glib_decls );
782
811
self ::$ gobject =
783
- self ::libraryLoad ($ libraryPaths , $ vips_libname , $ gobject_decls ) ??
784
- self ::libraryLoad ($ libraryPaths , $ gobject_libname , $ gobject_decls );
812
+ self ::libraryLoad ($ vips_libname , $ gobject_decls ) ??
813
+ self ::libraryLoad ($ gobject_libname , $ gobject_decls );
785
814
786
- self ::$ vips = self ::libraryLoad ($ libraryPaths , $ vips_libname , $ vips_decls );
815
+ self ::$ vips = self ::libraryLoad ($ vips_libname , $ vips_decls );
787
816
788
817
# Useful for debugging
789
818
# self::$vips->vips_leak_set(1);
0 commit comments