Build from source
Rapira compiles from source on Linux and macOS. Building it yourself covers the cases the prebuilt binaries on the Installation page don't, and the only requirement beyond the usual Rust and C toolchain is a PHP that Rapira can embed.
When to build from source
- There is no prebuilt binary for your platform — an unusual CPU architecture, or a musl-based distro such as Alpine.
- Your distribution is older than the packages support. The releases are built against glibc 2.34 — Debian 12, Ubuntu 22.04 and RHEL 9 are the oldest they install on (see Installation).
- You need a different set of PHP extensions. The release builds bundle a PHP compiled from the flag list in
ci/php-configure-flags.txt, which is deliberately small: session, mbstring, OPcache, OpenSSL, curl, the XML family, PDO with SQLite. If your application needspdo_mysql,intlorgd, build Rapira against a PHP that has them. - You are working on Rapira itself, or want something that hasn't been released yet.
The toolchain
Three things beyond the usual build essentials:
- Rust, stable channel.
rust-toolchain.tomlin the repository pins it, so rustup selects the right toolchain on its own. - A C compiler and
pkg-config. Part of the build is C: small shims compiled against the PHP headers. - libclang, because the bindings to the Zend API are generated at build time by bindgen. The package is
libclang-devon Debian/Ubuntu,clang-develon Fedora,clangon Arch.
PHP with the embed SAPI
Rapira links the interpreter into its own process rather than reaching it over a socket, so PHP has to exist as a shared library: version 8.4 or 8.5, NTS (non-thread-safe), configured with --enable-embed=shared, which is what produces libphp.so (libphp.dylib on macOS).
ZTS builds are rejected
A thread-safe (ZTS) PHP fails the build with an explicit error — Rapira is NTS-only, since it runs one interpreter per worker process. If the PHP on your PATH is a ZTS build, install an NTS one and point PHP_CONFIG at it (see below).
Several distributions package the embed SAPI already:
sudo apt install php8.4-dev libphp8.4-embed # Debian/Ubuntu (deb.sury.org / ppa:ondrej)
sudo dnf install php-devel php-embedded # Fedora/RHEL
sudo pacman -S php php-embed # Arch
sudo apk add php84-dev php84-embed # AlpinemacOS has no packaged embed SAPI
Homebrew's php formula is built without it, so there is nothing to link against. On macOS, build PHP from source.
Building PHP yourself
Build PHP yourself when your distribution has no embed package, when you're on macOS, or when the packaged build lacks extensions your application needs.
ci/php-configure-flags.txt in the repository is the reference configure line — the same list the release builds use. Feed it to configure in an unpacked PHP source tree and add whatever extensions your application needs:
./configure --prefix="$HOME/.local/php-nts" $(tr '\n' ' ' < /path/to/rapira/ci/php-configure-flags.txt)
make -j"$(getconf _NPROCESSORS_ONLN)"
make installOn macOS, install the dependencies first (brew install pkg-config openssl@3 curl oniguruma libxml2 sqlite), put their lib/pkgconfig directories on PKG_CONFIG_PATH, and append --with-iconv="$(xcrun --show-sdk-path)/usr" after the flags file — a bare --with-iconv can't find libiconv there, and with autoconf the last form wins.
The plain libphp.so name
The build links -lphp, and the only directories it searches are lib and lib64 under the PHP prefix, so a file named exactly libphp.so (or libphp.dylib) has to be in one of them. Debian and Ubuntu ship only the versioned libphp8.4.so, and Alpine's copy has the plain name but sits in lib/phpXX, which is not searched — either way, linking fails until you put a plain-named symlink in the prefix's lib or lib64:
sudo ln -sf /usr/lib/libphp8.4.so /usr/lib/libphp.so # Debian/Ubuntu
sudo ln -sf /usr/lib/php84/libphp.so /usr/lib/libphp.so # AlpineWithout root, put the symlink in a directory of your own and point both the linker and the loader at it:
mkdir -p ~/.local/phplib
ln -sf /usr/lib/libphp8.4.so ~/.local/phplib/libphp.so
export RUSTFLAGS="-L native=$HOME/.local/phplib"
export LD_LIBRARY_PATH="$HOME/.local/phplib:/usr/lib"Building Rapira
With PHP in place, the build itself is an ordinary cargo build:
git clone https://github.com/rapira-rs/rapira.git
cd rapira
cargo build --releaseThe binary lands in target/release/rapira.
PHP is discovered through php-config. If the one on PATH is not the build you want Rapira to embed, name it explicitly:
PHP_CONFIG=$HOME/.local/php-nts/bin/php-config cargo build --releasemake test runs the test suites and resolves the library paths for you: it finds the embed library under the php-config prefix (lib, lib64, lib/phpXX, plain or versioned name) and normalizes it into the plain name the linker wants. Run it to confirm the setup before relying on your own build.
Running the binary you built
At runtime Rapira loads libphp.so (libphp.dylib on macOS) dynamically. If it lives in a standard location there is nothing to do; otherwise point the loader at it:
LD_LIBRARY_PATH="$HOME/.local/php-nts/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" ./target/release/rapira serve worker.php # Linux
DYLD_LIBRARY_PATH="$HOME/.local/php-nts/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}" ./target/release/rapira serve worker.php # macOSThe result is the same server the packages install: Quickstart walks through a first script, CLI lists what serve accepts, and Configuration covers rapira.toml.
Working on Rapira itself
make test runs both suites — the in-process one and the end-to-end suite that spawns the real binary — make stubs regenerates the arginfo header from crates/php_sys/rapira.stub.php, and CI runs the build, cargo fmt, clippy and coverage on every pull request.