Packages
vix
0.40.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.1
0.33.0
0.32.0
0.31.1
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.1
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.1
0.10.0
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.2.1
0.2.0
retired
0.1.0
NIF based bindings for libvips
Current section
Files
Jump to
Current section
Files
DEVELOPMENT.md
# Vix Development Guide
Repo-specific notes for native builds, precompiled libvips, CI, and releases.
## Compilation Modes
Vix supports three `VIX_COMPILATION_MODE` values:
- `PRECOMPILED_NIF_AND_LIBVIPS` is the default. It downloads a precompiled Vix
NIF from the Vix GitHub release when one is available. Do not use this as the
only check for native C changes, because it can reuse the released NIF instead
of compiling local C sources.
- `PRECOMPILED_LIBVIPS` compiles the local NIF and links it against the
sharp-libvips tarball. Use this for changes to native code, precompiled
libvips, link flags, or packaged runtime files.
- `PLATFORM_PROVIDED_LIBVIPS` uses `pkg-config vips` and links against the host
libvips. Set `VIX_LIBVIPS_PREFIX` to test a specific local libvips install.
Useful commands:
```bash
rm -rf _build/*/lib/vix cache/ priv/*
ELIXIR_MAKE_CACHE_DIR="$(pwd)/cache" \
VIX_COMPILATION_MODE=PRECOMPILED_LIBVIPS \
mix test
VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS mix test
VIX_LIBVIPS_PREFIX=/path/to/libvips/prefix \
VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS \
mix test
make debug
make V=1 all
```
Generated paths such as `_build/`, `deps/`, `priv/`, `cache/`, `.libvips/`,
`toolchains/`, and `checksum.exs` should not be committed.
## Precompiled libvips
Vix downloads precompiled libvips from
[`akash-akya/sharp-libvips`](https://github.com/akash-akya/sharp-libvips).
Current configuration:
- sharp-libvips release tag: `v8.18.3-rc1`
- upstream libvips version: `8.18.3`
- Vix config: `@release_tag` in `build_scripts/precompiler.exs`
- asset pattern: `sharp-libvips-<platform>.tar.gz`
Current target mapping:
| Vix target | sharp-libvips asset |
| --- | --- |
| `x86_64-linux-gnu` | `sharp-libvips-linux-x64.tar.gz` |
| `x86_64-linux-musl` | `sharp-libvips-linuxmusl-x64.tar.gz` |
| `aarch64-linux-gnu` | `sharp-libvips-linux-arm64v8.tar.gz` |
| `aarch64-linux-musl` | `sharp-libvips-linuxmusl-arm64v8.tar.gz` |
| `arm-linux-gnueabihf` | `sharp-libvips-linux-armv6.tar.gz` |
| `armv7l-linux-gnueabihf` | `sharp-libvips-linux-armv6.tar.gz` |
| `x86_64-apple-darwin` | `sharp-libvips-darwin-x64.tar.gz` |
| `aarch64-apple-darwin` | `sharp-libvips-darwin-arm64v8.tar.gz` |
For precompiled POSIX builds, Vix links directly to `libvips-cpp`:
```text
precompiled_libvips/lib/libvips-cpp.so.*
precompiled_libvips/lib/libvips-cpp.*.dylib
```
This is expected. The sharp-libvips package exports the libvips C ABI from
`libvips-cpp`, so the precompiled POSIX package does not need a separate
`libvips.so` or `libvips.dylib`.
The files copied into precompiled Vix NIF archives are controlled by
`make_precompiler_priv_paths` in `mix.exs`.
## Local libvips Builds
Use `scripts/build_libvips.sh` when testing Vix against an upstream libvips ref
without publishing a sharp-libvips release. The script builds a normal C
libvips install for `PLATFORM_PROVIDED_LIBVIPS`.
```bash
./scripts/build_libvips.sh --ref vX.Y.Z
VIX_LIBVIPS_PREFIX="$(pwd)/.libvips/vX.Y.Z" \
VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS \
mix test
```
If `--ref` is omitted, the script resolves the latest upstream libvips release.
Use `--overwrite` to replace an existing local prefix.
## Toolchains
`precompile.yaml` uses musl cross-compilers for musl NIF targets. The scripts
mirror the required musl.cc archives on Vix GitHub releases:
```bash
./scripts/download_toolchains.sh
./scripts/mirror_toolchains.sh
```
The current mirrored version is `11.2.1`; update `TOOLCHAIN_VERSION` in both
scripts if the mirror changes.
## CI
`.github/workflows/ci.yaml` runs on pushes and pull requests to `master` and
`dev`. It covers:
- Linux `PLATFORM_PROVIDED_LIBVIPS` against the latest upstream libvips release.
- Linux `PRECOMPILED_LIBVIPS`.
- Linux default precompiled NIF mode with `mix elixir_make.checksum --only-local`.
- ARM precompiled smoke test through Docker/QEMU.
- macOS default precompiled and `PRECOMPILED_LIBVIPS` through Nix.
- compile with warnings as errors, unused dependency checks, formatter, Credo,
and Dialyzer.
`.github/workflows/precompile.yaml` runs for `v*` tags and uploads
`cache/*.tar.gz` NIF artifacts to the matching GitHub release.
## Release Process
### Standard Vix Release
1. Bump `@version` in `mix.exs`, commit, and push `master`.
```bash
git add mix.exs
git commit -m "Bump version to X.Y.Z"
git push origin master
```
2. Create and push the release tag.
```bash
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin vX.Y.Z
```
3. Wait for `.github/workflows/precompile.yaml` to upload all NIF tarballs to
the GitHub release.
4. Generate checksums.
```bash
unset VIX_COMPILATION_MODE
rm -rf cache/ priv/* _build/*/lib/vix
ELIXIR_MAKE_CACHE_DIR="$(pwd)/cache" \
MIX_ENV=prod \
mix elixir_make.checksum --all
cat checksum.exs
```
`checksum.exs` is generated, ignored by Git, and should not be committed.
The checksum task rewrites it, so deleting an old copy first is optional.
Keep it in the working tree for `mix hex.publish`.
5. Test the release artifacts, then publish.
```bash
unset VIX_COMPILATION_MODE
rm -rf cache/ priv/* _build/*/lib/vix
ELIXIR_MAKE_CACHE_DIR="$(pwd)/cache" mix test
mix hex.publish
```
Before accepting the publish prompt, confirm the file list includes
`checksum.exs` and `DEVELOPMENT.md`.
6. Optional cleanup:
```bash
rm -rf cache/ priv/* checksum.exs _build/*/lib/vix doc/ vix-*.tar
```
This is only housekeeping. `checksum.exs` can remain locally after publish.
### Failed Tag Build
If the tag workflow fails before Hex publish, fix `master`, push the fix, move
the tag, and force-push the tag:
```bash
git push origin master
git tag -fa vX.Y.Z -m "Release vX.Y.Z"
git push --force origin vX.Y.Z
```
The release workflow uses `overwrite_files: true`, so rerunning the same tag can
replace partial GitHub release artifacts. After a Hex package is public, do not
move the tag; publish a new patch or release-candidate version instead.
### Libvips Update
Use this when Vix should consume a new sharp-libvips release.
1. Rebase the sharp-libvips fork.
```bash
cd ~/repos/clang/sharp-libvips-2
git fetch upstream
git checkout main
git rebase upstream/main
```
Preserve only the fork behavior Vix needs: direct GitHub release asset
upload, `.integrity` files, fork-local notices, and any deliberate freshness
gate change. Do not reintroduce old C-only packaging changes; Vix expects
precompiled POSIX packages to provide `libvips-cpp`.
2. Push and tag the sharp-libvips release candidate.
```bash
git push --force-with-lease origin main
git tag -a v<libvips-version>-rc<N> -m "libvips <libvips-version> rc<N>"
git push origin v<libvips-version>-rc<N>
```
3. Verify the release assets.
```bash
curl -fsSL \
https://api.github.com/repos/akash-akya/sharp-libvips/releases/tags/v8.18.3-rc1 \
| jq -r '.assets[].name' \
| sort
```
Vix needs the mapped tarballs above and their `.integrity` files.
4. Update Vix.
- Change `@release_tag` in `build_scripts/precompiler.exs`.
- If the package layout changed, update `c_src/Makefile`,
`make_precompiler_priv_paths` in `mix.exs`, and the target mapping in
`build_scripts/precompiler.exs`.
5. Test locally.
```bash
rm -rf _build/*/lib/vix cache/ priv/*
ELIXIR_MAKE_CACHE_DIR="$(pwd)/cache" \
VIX_COMPILATION_MODE=PRECOMPILED_LIBVIPS \
mix test
VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS mix test
```
6. Follow the standard Vix release process.
## Troubleshooting
### Precompiled libvips Download Fails
Check the configured tag and asset URL:
```bash
grep '@release_tag' build_scripts/precompiler.exs
curl -I \
https://github.com/akash-akya/sharp-libvips/releases/download/v8.18.3-rc1/sharp-libvips-linux-x64.tar.gz
```
If Erlang reports a crypto or SSL error before downloading, fix the local
Erlang/OpenSSL installation. For example, an OTP build linked to
`libcrypto.so.1.1` will fail where that shared library is missing.
### NIF Link Fails
```bash
make deep_clean
make debug
make V=1 all
find priv/precompiled_libvips/lib -maxdepth 1 -name 'libvips-cpp*' -print
pkg-config --modversion vips
pkg-config --cflags --libs vips
```
### Checksum Verification Fails
Regenerate checksums against the intended GitHub release artifacts:
```bash
rm -rf cache/ priv/* _build/*/lib/vix
ELIXIR_MAKE_CACHE_DIR="$(pwd)/cache" \
MIX_ENV=prod \
mix elixir_make.checksum --all
```