vips-sys
Low-level Rust FFI bindings for libvips. Designed to be stable, minimal, and a foundation for higher-level wrappers.
- Docs: https://docs.rs/vips-sys/
- Requirement: Current stable Rust (edition 2024);
libvips >= 8.2(bindings generated from 8.18.7) - Goals: fast builds, reliable linking, cross-platform reuse
Highlights
| Default | Feature bindgen |
|
|---|---|---|
| Bindings | Pregenerated src/bindings/prebuilt.rs |
Live bindgen via clang |
| Needs libclang? | No | Yes |
Typical cargo build |
Seconds | Slower (first time) |
| Use when | Normal development / CI | Updating API surface / new libvips |
Normal builds do not run bindgen. You only need a libvips library to link against.
0.3.0 compatibility
helpers::shutdown is now unsafe: callers must prove every libvips user has
finished and no later calls can occur. Normal applications should keep libvips
initialized for the process lifetime. Failed initialization can be retried.
Feature v8_18 requests a libvips 8.18+ link probe. The default declarations
also contain newer symbols, but a declaration does not add that symbol to an
older system library. Only call APIs present in the library you link.
The vendored source is pinned to the latest release, 8.18.7. Its public headers are unchanged from 8.18.6. See the upstream audit.
Installation
macOS
# Apple Silicon:
Debian / Ubuntu
Windows (MSVC)
set VCPKG_ROOT=C:\path\to\vcpkg
vcpkg install libvips:x64-windows
set VCPKGRS_TRIPLET=x64-windows
set VCPKGRS_DYNAMIC=1
set PATH=%VCPKG_ROOT%\installed\x64-windows\bin;%PATH%
cargo test --features helpers
The official port name is libvips. The Unix pkg-config name remains vips;
link library names are read from the installed port manifest and its dependencies.
Dynamic triplets require VCPKGRS_DYNAMIC=1 and their DLLs on PATH.
For static libvips with Rust's default dynamic CRT:
vcpkg install libvips:x64-windows-static-md
set VCPKGRS_TRIPLET=x64-windows-static-md
cargo test --features helpers,static
For a static CRT, use x64-windows-static together with
RUSTFLAGS=-Ctarget-feature=+crt-static. Replace x64 with arm64 or x86 to
match the Rust target. VCPKGRS_TRIPLET takes precedence over
VCPKG_DEFAULT_TRIPLET; absent both, static requests select the target
architecture and CRT, while other requests use vcpkg-rs defaults (static-md
unless dynamic linking or a static CRT is selected).
The MSVC backend follows Cargo's target environment, including cross-compilation. This selects headers and link metadata; a cross linker and target-built libraries are still required for producing a working executable.
Cargo
[]
= { = "0.3.0", = ["helpers"] }
Features
| Feature | Default | Description |
|---|---|---|
| (none) | ✓ | Pregenerated bindings + link probe |
helpers |
init / is_initialized / unsafe shutdown / cached version queries |
|
static |
Prefer static linking (LIBVIPS_STATIC=1 overrides) |
|
dynamic |
Prefer dynamic linking | |
bindgen |
Regenerate bindings with clang against local headers | |
stub |
Link stub/vips_stub.c when no system libvips is found (tests only) |
Tests without a system libvips
If pkg-config/vcpkg/LIBVIPS_LIB_DIR cannot find a real library, stub builds a
tiny C stand-in (vips_init / vips_version / …) so unit tests can link. When a
real library is present it is always preferred — never ship production binaries
built with stub.
Static linking
= { = "0.3.0", = ["static"] }
LIBVIPS_STATIC=1
Resolution order:
pkg-config --static/ vcpkg static triplet if a static libvips is installed- Meson + ninja build of
vendor/libvipsintoOUT_DIR(if tools are onPATH) - Clear error otherwise
The static preference selects the libvips archive; system codec dependencies
may remain dynamic. The vendor builder requires Meson 0.60+, Ninja and native
GLib/codec development files. MESON_PATH / NINJA_PATH select the tools, and
CXXSTDLIB overrides the platform C++ runtime when using a custom toolchain.
It builds the archive and development artifacts only. Ninja handles source
changes incrementally; compiler/environment changes reset Meson configuration.
Cross targets require prebuilt target libraries rather than this native builder.
Vendored libvips (submodule)
vendor/libvips tracks libvips at v8.18.7
(see rust-sys-crate):
# or:
Link / header resolution:
LIBVIPS_LIB_DIR/LIBVIPS_INCLUDE_DIR(optionalLIBVIPS_STATIC=1)- System library via
pkg-config(Unix) orvcpkg(MSVC) - Static vendor build when
staticis requested - Vendored headers for include paths (still need a library to link)
Refreshing pregenerated bindings
# Requires: libclang, glib headers, and vips headers (system or vendor submodule)
# build.rs prints the OUT_DIR path — copy it over:
Use headers configured with deprecated APIs enabled when refreshing the complete prebuilt surface. The refresh script checks the version, refuses accidental API removal and keeps optional codec build details out of the reusable defaults.
wrapper.h is the single bindgen entry point and is kept in the repo.
generate.sh was removed in favor of the bindgen feature.
Build-time exports:
LIBVIPS_VERSION— detected version string (from pkg-config when available)cfg(vips_8_16)/cfg(vips_8_17)/cfg(vips_8_18)— when version is new enough
Example (helpers)
use helpers;
Environment variables
| Variable | Purpose |
|---|---|
PKG_CONFIG_PATH |
Find vips.pc |
LIBVIPS_LIB_DIR / LIBVIPS_INCLUDE_DIR |
Explicit library / headers |
LIBVIPS_STATIC |
1 prefer static; 0/false/off disable |
LIBVIPS_NO_VENDOR |
Ignore vendor/libvips |
LIBVIPS_NO_BINDGEN |
With bindgen, copy pregenerated bindings without parsing headers |
LIBVIPS_VERSION |
Override version string for cfg |
VCPKG_ROOT |
Windows vcpkg installation root |
VCPKGRS_TRIPLET / VCPKG_DEFAULT_TRIPLET |
Explicit triplet (Rust helper override wins) |
VCPKGRS_DYNAMIC |
Required opt-in for dynamic vcpkg libraries |
BINDGEN_EXTRA_CLANG_ARGS |
Extra clang flags (bindgen feature) |
LIBCLANG_PATH |
libclang location (bindgen feature) |
MESON_PATH / NINJA_PATH |
Native vendor build tools |
CXXSTDLIB |
Override the static provider's C++ runtime |
Troubleshooting
- link error, library not found — install libvips (
libvips-dev/vcpkg install libvips) - bindgen feature fails — install
libclang, glib headers, and vips headers - static on macOS — prefer dynamic (Homebrew); use vendor + meson for true static
- Windows headers — set
VCPKG_ROOTso include paths resolve
License
This crate’s Rust source code (including build.rs and src/) is licensed under
MIT.
libvips itself is LGPL-2.1
(and depends on other LGPL/GPL-compatible components such as GLib). That license is
not MIT and does not relicense this crate.
What that means for you
| Artifact | License |
|---|---|
vips-sys sources / pregenerated FFI declarations |
MIT |
Linked libvips library (system, vcpkg, or built from vendor/) |
LGPL-2.1 |
| Your final binary that links libvips | Must comply with LGPL-2.1 for libvips |
Practical notes:
- Dynamic linking (default): keep libvips replaceable/relinkable and ship the LGPL notice + a way to obtain libvips sources, as required by LGPL-2.1.
- Static linking (
staticfeature or vendored meson build): LGPL obligations are stricter (e.g. allow relinking against a modified libvips). Evaluate before shipping. - The
vendor/libvipsgit submodule is LGPL-2.1 source. It is excluded from the crates.io package (exclude = ["vendor/"]); if you redistribute that tree yourself, do so under LGPL-2.1. - Pregenerated bindings are FFI declarations of the public C API, not a copy of libvips implementation code.
This is engineering guidance, not legal advice. For commercial compliance, consult counsel.
Changelog
See CHANGELOG.md.