Skip to content

Commit 1ffcd1f

Browse files
authored
Add FFI::addLibraryPath utility (#264)
* Add `FFI::addLibraryPath` utility In favor of the `VIPSHOME` env. Resolves: #232. * Incorporate review comment
1 parent efbf4c4 commit 1ffcd1f

File tree

2 files changed

+57
-25
lines changed

2 files changed

+57
-25
lines changed

Diff for: README.md

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ To your `php.ini`.
7373
require __DIR__ . '/vendor/autoload.php';
7474
use Jcupitt\Vips;
7575

76+
// handy for Windows
77+
Vips\FFI::addLibraryPath("C:/vips-dev-8.16/bin");
78+
7679
// check libvips version
7780
echo 'libvips version: ' . Vips\Config::version() . PHP_EOL;
7881

Diff for: src/FFI.php

+54-25
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)