@@ -79,6 +79,15 @@ class FFI
7979     */ 
8080    private  static  bool  $ ffi_inited  = false ;
8181
82+     /** 
83+      * A list of paths where libvips might reside. 
84+      * 
85+      * @internal 
86+      */ 
87+     private  static  array  $ libraryPaths  = [
88+         ""  // system library 
89+     ];
90+ 
8291    /** 
8392     * Look up these once. 
8493     * 
@@ -169,6 +178,39 @@ public static function atLeast(int $x, int $y, int $z = 0): bool
169178                self ::$ library_micro  >= $ z );
170179    }
171180
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+ 
172214    /** 
173215     * Shut down libvips. Call this just before process exit. 
174216     * 
@@ -208,12 +250,11 @@ private static function libraryName(string $name, int $abi): string
208250    }
209251
210252    private  static  function  libraryLoad (
211-         array  $ libraryPaths ,
212253        string  $ libraryName ,
213254        string  $ interface
214255    ): ?\FFI   {
215256        Utils::debugLog ("trying to open " , ["libraryName "  => $ libraryName ]);
216-         foreach  ($ libraryPaths  as  $ path ) {
257+         foreach  (self :: $ libraryPaths  as  $ path ) {
217258            Utils::debugLog ("trying path " , ["path "  => $ path ]);
218259            try  {
219260                $ library  = \FFI ::cdef ($ interface , $ path  . $ libraryName );
@@ -252,37 +293,25 @@ private static function init(): void
252293
253294        $ is_64bits  = PHP_INT_SIZE  === 8 ;
254295
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- 
267296        if  (PHP_OS_FAMILY  === "OSX "  || PHP_OS_FAMILY  === "Darwin " ) {
268297            // Homebrew on Apple Silicon 
269-             $ libraryPaths [] =  "/opt/homebrew/lib/  "  ;
298+             self :: addLibraryPath ( "/opt/homebrew/lib "  ) ;
270299            // See https://github.com/Homebrew/brew/issues/13481#issuecomment-1207203483 
271-             $ libraryPaths [] =  "/usr/local/lib/  "  ;
300+             self :: addLibraryPath ( "/usr/local/lib "  ) ;
272301        }
273302
274-         $ vips  = self ::libraryLoad ($ libraryPaths ,  $ vips_libname , <<<'CPP'
303+         $ vips  = self ::libraryLoad ($ vips_libname , <<<'CPP'
275304            int vips_init (const char *argv0); 
276305            const char *vips_error_buffer (void); 
277306            int vips_version(int flag); 
278307        CPP);
279308
280309        if  ($ vips  === null ) {
281310            // drop the "" (system path) member 
282-             array_shift ($ libraryPaths );
311+             array_shift (self :: $ libraryPaths );
283312            $ 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 ) . "'] " ;
286315            }
287316            $ msg  .= ". Make sure that you've installed libvips and that ' $ vips_libname' " ;
288317            $ msg  .= " is on your system's library search path. " ;
@@ -777,13 +806,13 @@ private static function init(): void
777806         * one that libvips itself is using, and they will share runtime types. 
778807         */ 
779808        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 );
782811        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 );
785814
786-         self ::$ vips  = self ::libraryLoad ($ libraryPaths ,  $ vips_libname , $ vips_decls );
815+         self ::$ vips  = self ::libraryLoad ($ vips_libname , $ vips_decls );
787816
788817        # Useful for debugging 
789818        # self::$vips->vips_leak_set(1); 
0 commit comments