At a minimum, you need the following:
| Tool | Version | What it's for |
|---|---|---|
| PHP CLI | 8.2+ recommended | The ffi extension must be loaded and ffi.enable must allow CLI FFI. |
| Composer | 2.x | Installs PHPUnit, PHPStan, php-cs-fixer, and cebe/php-openapi. |
| Git | 2.x | Needed for Git install sources. |
| Make | any POSIX make | Used by the included Makefile. |
| libclang | required to install packages | Reads C headers to generate the FFI cdef. On macOS it ships with the Xcode Command Line Tools (xcode-select --install); on Linux install your distro's clang/llvm dev package (e.g. apt install libclang-dev). pnl loads it at runtime — set LIBCLANG_PATH if it lives in a non-standard location. |
| C compiler | optional | A cc/gcc/clang sharpens library-path discovery on multiarch systems. It is also required at install time only if you opt into compile_options.static_inline (compiling static inline functions into a callable shim — see Configuration); otherwise it is not needed. |
| C libraries | per package | The libusb/libnfc/SDL examples need the matching libraries and headers (the -dev/-devel package, which also ships the .pc file pnl reads). |
pnl reads libraries' .pc files directly, so the external pkg-config/pkgconf binary is not required. pnl -i reports toolchain readiness (libclang, cc).
Rust is only needed when you build the pnl/pnlx binaries from source or work on this repository. Installing and using packages does not compile per-package Rust code.
The environment currently validated locally:
rustc 1.92.0
cargo 1.92.0
PHP 8.5.2 CLI NTS
Composer 2.8.8
git 2.52.0
libclang (Xcode Command Line Tools)
macOS/aarch64 with Homebrew libusb, libnfc, SDL2
Whether PHP can use FFI is checked at runtime. If PHP cannot use FFI, the SDK raises an FFI-related exception before loading any native library.
In a PHP project, the simplest path is the composer package, which ships the SDK and installs vendor/bin/pnl / vendor/bin/pnlx. The native binary is built or downloaded on first use (see PHP Usage):
composer require m3m0r7/pnlIf you do not want to build from source, download a prebuilt archive from the GitHub Releases page. Each tagged release (v0.1.0, ...) attaches archives built by GitHub Actions for Linux, macOS, and Windows:
pnl-<version>-x86_64-unknown-linux-gnu.tar.gz
pnl-<version>-x86_64-apple-darwin.tar.gz
pnl-<version>-aarch64-apple-darwin.tar.gz
pnl-<version>-x86_64-pc-windows-msvc.zip
Pick the archive for your platform, unpack it, and put pnl / pnlx somewhere on your PATH:
tar xzf pnl-<version>-aarch64-apple-darwin.tar.gz
sudo install -m 0755 pnl pnlx /usr/local/bin/A binary installed this way is not managed by pnl self-upgrade (which only updates the versioned symlink layout below). To update, download the new release and reinstall the same way; pnl will tell you when a newer version is available.
Build the release binaries from source:
# Build both pnl and pnlx in release mode.
make buildThis produces target/release/pnl and target/release/pnlx. Install them:
# Install under $XDG_DATA_HOME/pnl and link pnl/pnlx from /usr/local/bin.
sudo make install PREFIX=/usr/localsudo is needed because the symlinks land in $PREFIX/bin (e.g. /usr/local/bin). The binaries themselves go into a versioned layout under $PNL_HOME, and the PREFIX bin directory receives symlinks only:
~/.local/share/pnl/versions/<version>/bin/pnl
~/.local/share/pnl/versions/<version>/bin/pnlx
~/.local/share/pnl/current -> versions/<version>
/usr/local/bin/pnl -> ~/.local/share/pnl/current/bin/pnl
/usr/local/bin/pnlx -> ~/.local/share/pnl/current/bin/pnlx
The install root follows the XDG Base Directory spec: $XDG_DATA_HOME/pnl, defaulting to ~/.local/share/pnl. Change it with make install PNL_HOME=/path/to/pnl-home. pnl self-upgrade later updates the same layout by switching the current link to a newly built version (see Commands).
During development you can also call target/debug/pnl and target/debug/pnlx directly after cargo build.