From 20542542c54b33ed2d8547cf35b2f79812249af0 Mon Sep 17 00:00:00 2001 From: sage <149851+lopcode@users.noreply.github.com> Date: Sun, 15 Mar 2026 16:21:52 +0100 Subject: [PATCH] Add explicit library search name to allow installation of runtime-only libvips42 on Debian-based systems --- README.md | 10 ++--- .../app/photofox/vipsffm/VipsLibLookup.java | 40 ++++++++++++------- docker_tests/debian-12/Dockerfile | 2 +- docker_tests/ubuntu-2404-jemalloc/Dockerfile | 2 +- docker_tests/ubuntu-2404/Dockerfile | 2 +- docs/index.html | 16 ++++---- 6 files changed, 42 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 68e5910..6896d86 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ repositories { } dependencies { - implementation("app.photofox.vips-ffm:vips-ffm-core:1.9.5") + implementation("app.photofox.vips-ffm:vips-ffm-core:1.9.6") } ``` @@ -171,14 +171,14 @@ You can find them in the [`docker_tests`](docker_tests) folder. This library requires the `libvips`, `glib`, and `gobject` native libraries to be present in your library path: * On macOS: `DYLD_LIBRARY_PATH` (installed with `brew install vips`) -* On Linux: `LD_LIBRARY_PATH` (installed with `apt install libvips-dev` on Debian / Ubuntu) +* On Linux: `LD_LIBRARY_PATH` (installed with `apt install libvips42` on Debian / Ubuntu) * On Windows: `PATH` The naming conventions of these libraries are not consistent across operating systems, so vips-ffm attempts to load each in the following order: -* `vips`, `vips.{abiNumber}`, `libvips-{abiNumber}` -* `glib-2.0`, `glib-2.0.{abiNumber}`, `libglib-2.0-{abiNumber}` -* `gobject-2.0`, `gobject-2.0.{abiNumber}`, `libgobject-2.0-{abiNumber}` +* `vips`, `vips.{abiNumber}`, `libvips.so.{abiNumber}`, `libvips-{abiNumber}` +* `glib-2.0`, `glib-2.0.{abiNumber}`, `libglib-2.0.so.{abiNumber}`, `libglib-2.0-{abiNumber}` +* `gobject-2.0`, `gobject-2.0.{abiNumber}`, `libgobject-2.0.so.{abiNumber}`, `libgobject-2.0-{abiNumber}` Override properties are provided to set your own "ABI number", but note that vips-ffm might not support that version yet (which could manifest as crashes/segfaults): diff --git a/core/src/main/java/app/photofox/vipsffm/VipsLibLookup.java b/core/src/main/java/app/photofox/vipsffm/VipsLibLookup.java index 5661444..b07ff20 100644 --- a/core/src/main/java/app/photofox/vipsffm/VipsLibLookup.java +++ b/core/src/main/java/app/photofox/vipsffm/VipsLibLookup.java @@ -33,9 +33,10 @@ private static SymbolLookup findVipsLoader(Arena arena) { var abiNumber = Optional.ofNullable(System.getProperty("vipsffm.abinumber.vips.override")) .orElse("42"); var names = List.of( - "vips", // default unix-like - "vips." + abiNumber, // some linux systems don't symlink and need abi number - "libvips-" + abiNumber // windows needs everything + new SymbolLookupSpec("vips", true), // default unix-like + new SymbolLookupSpec("vips." + abiNumber, true), // some linux systems don't symlink and need abi number + new SymbolLookupSpec("libvips.so." + abiNumber, false), // some linux runtime libs use the lib.so.abiNumber format + new SymbolLookupSpec("libvips-" + abiNumber, true) // windows needs everything ); return findFirstSymbolLookup(arena, names); } @@ -48,9 +49,10 @@ private static SymbolLookup findGlibLoader(Arena arena) { var abiNumber = Optional.ofNullable(System.getProperty("vipsffm.abinumber.glib.override")) .orElse("0"); var names = List.of( - "glib-2.0", // default unix-like - "glib-2.0." + abiNumber, // some linux systems don't symlink and need abi number - "libglib-2.0-" + abiNumber // windows needs everything + new SymbolLookupSpec("glib-2.0", true), // default unix-like + new SymbolLookupSpec("glib-2.0." + abiNumber, true), // some linux systems don't symlink and need abi number + new SymbolLookupSpec("libglib-2.0.so." + abiNumber, false), // some linux runtime libs use the lib.so.abiNumber format + new SymbolLookupSpec("libglib-2.0-" + abiNumber, true) // windows needs everything ); return findFirstSymbolLookup(arena, names); } @@ -63,19 +65,25 @@ private static SymbolLookup findGObjectLoader(Arena arena) { var abiNumber = Optional.ofNullable(System.getProperty("vipsffm.abinumber.gobject.override")) .orElse("0"); var names = List.of( - "gobject-2.0", // default unix-like - "gobject-2.0." + abiNumber, // some linux systems don't symlink and need abi number - "libgobject-2.0-" + abiNumber // windows needs everything + new SymbolLookupSpec("gobject-2.0", true), // default unix-like + new SymbolLookupSpec("gobject-2.0." + abiNumber, true), // some linux systems don't symlink and need abi number + new SymbolLookupSpec("libgobject-2.0.so." + abiNumber, false), // some linux runtime libs use the lib.so.abiNumber format + new SymbolLookupSpec("libgobject-2.0-" + abiNumber, true) // windows needs everything ); return findFirstSymbolLookup(arena, names); } + private record SymbolLookupSpec( + String name, + boolean mapToSystemName + ) {} + private static SymbolLookup findFirstSymbolLookup( Arena arena, - List names + List specs ) { - for (var name : names) { - var attempt = attemptLibraryLookup(name, arena); + for (var spec : specs) { + var attempt = attemptLibraryLookup(spec.name, arena, spec.mapToSystemName); if (attempt.isPresent()) { return attempt.get(); } @@ -83,10 +91,14 @@ private static SymbolLookup findFirstSymbolLookup( return null; } - static Optional attemptLibraryLookup(String name, Arena arena) { + static Optional attemptLibraryLookup(String name, Arena arena, boolean useSystemNaming) { + var libraryName = name; + if (useSystemNaming) { + libraryName = System.mapLibraryName(libraryName); + } try { return Optional.of( - SymbolLookup.libraryLookup(System.mapLibraryName(name), arena) + SymbolLookup.libraryLookup(libraryName, arena) ); } catch (IllegalArgumentException _) { return Optional.empty(); diff --git a/docker_tests/debian-12/Dockerfile b/docker_tests/debian-12/Dockerfile index 3160911..5a81393 100644 --- a/docker_tests/debian-12/Dockerfile +++ b/docker_tests/debian-12/Dockerfile @@ -6,7 +6,7 @@ ENV PATH="${JAVA_HOME}/bin:${PATH}" COPY sample /opt/sample COPY run_samples.sh /opt/run_samples.sh -RUN apt update && apt install --no-install-recommends --yes libvips-dev libvips-tools libjemalloc2 +RUN apt update && apt install --no-install-recommends --yes libvips42 libvips-tools libjemalloc2 RUN vips --version WORKDIR /opt diff --git a/docker_tests/ubuntu-2404-jemalloc/Dockerfile b/docker_tests/ubuntu-2404-jemalloc/Dockerfile index 402b893..feb2748 100644 --- a/docker_tests/ubuntu-2404-jemalloc/Dockerfile +++ b/docker_tests/ubuntu-2404-jemalloc/Dockerfile @@ -6,7 +6,7 @@ ENV PATH="${JAVA_HOME}/bin:${PATH}" COPY sample /opt/sample COPY run_samples.sh /opt/run_samples.sh -RUN apt update && apt install --no-install-recommends --yes libvips-dev libvips-tools libjemalloc2 +RUN apt update && apt install --no-install-recommends --yes libvips42 libvips-tools libjemalloc2 RUN ln -sT "$(readlink -e /usr/lib/*/libjemalloc.so.2)" /usr/local/lib/libjemalloc.so RUN vips --version diff --git a/docker_tests/ubuntu-2404/Dockerfile b/docker_tests/ubuntu-2404/Dockerfile index 754f92d..7eb26e5 100644 --- a/docker_tests/ubuntu-2404/Dockerfile +++ b/docker_tests/ubuntu-2404/Dockerfile @@ -6,7 +6,7 @@ ENV PATH="${JAVA_HOME}/bin:${PATH}" COPY sample /opt/sample COPY run_samples.sh /opt/run_samples.sh -RUN apt update && apt install --no-install-recommends --yes libvips-dev libvips-tools libjemalloc2 +RUN apt update && apt install --no-install-recommends --yes libvips42 libvips-tools libjemalloc2 RUN vips --version WORKDIR /opt diff --git a/docs/index.html b/docs/index.html index 406e58c..51b9e3e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -58,11 +58,11 @@

core API

Supports a vast range of image formats, including HEIC, JXL, WebP, PNG, JPEG, and more. Pronounced "vips (like zips) eff-eff-emm". The project is relatively new, but aims to be production ready. Tested on macOS 14, Windows 11, and Linux (Ubuntu 24.04, Debian 12.1, with and without jemalloc). Should work on any architecture you can use libvips and -Java on (arm64/amd64/etc).

-

Uses the "Foreign Function & Memory API" (JEP 454), and the "Class-File API" (JEP 457) released in JDK 22. -Built in such a way that it's usually the fastest image processing library available for Java.

+Java on (arm64/amd64/etc). Built in such a way that it's usually the fastest image processing library available for Java, +by using the "Foreign Function & Memory API" (JEP 454) and code generation.

Used the library? I'd love to hear from more users - let me know in Discussions. Please also give the repo a star 🌟️!

+

Made in the EU πŸ‡ͺπŸ‡ΊπŸ‡ΈπŸ‡ͺ

Usage

vips-ffm is available on Maven Central. To get set up with Gradle:

repositories {
@@ -70,7 +70,7 @@ 

Usage

} dependencies { - implementation("app.photofox.vips-ffm:vips-ffm-core:1.9.5") + implementation("app.photofox.vips-ffm:vips-ffm-core:1.9.6") }

Figure out what you're trying to do by looking at the libvips documentation @@ -204,15 +204,15 @@

Native library loading

This library requires the libvips, glib, and gobject native libraries to be present in your library path:

  • On macOS: DYLD_LIBRARY_PATH (installed with brew install vips)
  • -
  • On Linux: LD_LIBRARY_PATH (installed with apt install libvips-dev on Debian / Ubuntu)
  • +
  • On Linux: LD_LIBRARY_PATH (installed with apt install libvips42 on Debian / Ubuntu)
  • On Windows: PATH

The naming conventions of these libraries are not consistent across operating systems, so vips-ffm attempts to load each in the following order:

    -
  • vips, vips.{abiNumber}, libvips-{abiNumber}
  • -
  • glib-2.0, glib-2.0.{abiNumber}, libglib-2.0-{abiNumber}
  • -
  • gobject-2.0, gobject-2.0.{abiNumber}, libgobject-2.0-{abiNumber}
  • +
  • vips, vips.{abiNumber}, libvips.so.{abiNumber}, libvips-{abiNumber}
  • +
  • glib-2.0, glib-2.0.{abiNumber}, libglib-2.0.so.{abiNumber}, libglib-2.0-{abiNumber}
  • +
  • gobject-2.0, gobject-2.0.{abiNumber}, libgobject-2.0.so.{abiNumber}, libgobject-2.0-{abiNumber}

Override properties are provided to set your own "ABI number", but note that vips-ffm might not support that version yet (which could manifest as crashes/segfaults):