11 KiB
Rebuilding the PHPX WASM Static Library
This document is aimed at TypePHP/PHPX developers and explains how to recompile and install the
PHPX static library for wasm32-wasip2. Ordinary TypePHP users do not need to perform these steps; release packages should provide the complete
WASI SDK directly.
Directory Convention
This document assumes the source layout is as follows:
/home/swoole/workspace/aot/
├── compiler/
└── phpx/
It is recommended to set the PHPX root directory first:
export PHPX_HOME=/home/swoole/workspace/aot/phpx
The installation prefix is fixed to:
$PHPX_HOME/wasm/wasm32-wasip2
This directory is both the input of the existing PHP/WASI SDK and the installation location of the PHPX build results:
wasm/wasm32-wasip2/
├── include/php/ PHP/WASI headers
├── include/phpx/ PHPX/TypePHP runtime headers
├── lib/libphp.a
├── lib/libphpx.a
├── lib/libgmp.a
├── lib/libgmpxx.a
├── lib/libmpfr.a
├── lib/libmpdec.a
├── lib/libmpdec++.a
└── .typephp-wasi-sdk-abi
Do not copy host-platform libphpx.so, phpx.dll, or .a files here.
WASM static libraries contain the target ABI and cannot be used across WASI, Linux, macOS, or Windows.
Toolchain Preparation
PHPX WASM currently supports only WASI 0.2 Preview 2. Add the WASI SDK to PATH:
export PATH=/opt/wasi-sdk-33.0/bin:$PATH
PATH only lets the shell and build tools find the WASI SDK programs; it does not make CMake automatically select the
WASI target. When configuring the build directory for the first time, you must still pass
-DCMAKE_TOOLCHAIN_FILE=.../wasi-sdk-p2.cmake. If you omit it, CMake will choose the host platform's
/usr/bin/cc and /usr/bin/c++, and PHPX's target check will immediately reject that configuration.
Confirm the necessary tools:
command -v wasm32-wasip2-clang
command -v wasm32-wasip2-clang++
command -v llvm-ar
command -v llvm-ranlib
command -v llvm-nm
command -v cmake
command -v ninja
Confirm the compile target:
wasm32-wasip2-clang++ --print-target-triple
It must output:
wasm32-unknown-wasip2
The installation prefix must already contain PHP/WASI headers and libphp.a matching the current PHPX:
test -f "$PHPX_HOME/wasm/wasm32-wasip2/include/php/main/php.h"
test -f "$PHPX_HOME/wasm/wasm32-wasip2/lib/libphp.a"
Daily Development: Rebuild PHPX Directly with CMake
When a PHPX .cc or header file changes, incrementally rebuild directly using phpx/wasm/CMakeLists.txt.
This is the recommended flow for daily development; it does not re-download or recompile PHP, GMP, or MPFR, nor does it regenerate
libphp.a.
First, locate the CMake toolchain from the current WASI compiler to avoid depending on a hardcoded SDK version path:
WASI_RESOURCE_DIR="$(wasm32-wasip2-clang++ --print-resource-dir)"
WASI_SDK_ROOT="$(cd "$WASI_RESOURCE_DIR/../../.." && pwd)"
WASI_CMAKE_TOOLCHAIN="$WASI_SDK_ROOT/share/cmake/wasi-sdk-p2.cmake"
test -f "$WASI_CMAKE_TOOLCHAIN"
Using Ninja (Recommended)
First configure a persistent build directory:
cmake \
-S "$PHPX_HOME/wasm" \
-B "$PHPX_HOME/build/wasm32-wasip2" \
-G Ninja \
-DCMAKE_TOOLCHAIN_FILE="$WASI_CMAKE_TOOLCHAIN" \
-DCMAKE_BUILD_TYPE=Release \
-DPHPX_WASI_SDK_DIR="$PHPX_HOME/wasm/wasm32-wasip2" \
-DCMAKE_INSTALL_PREFIX="$PHPX_HOME/wasm/wasm32-wasip2"
The toolchain takes effect when CMake executes project(), so it can only be set during the first configuration of a build directory.
If the directory was configured without a toolchain before and has already cached the host compiler, do not append arguments onto the existing cache;
use a new build directory instead, for example:
cmake \
-S "$PHPX_HOME/wasm" \
-B "$PHPX_HOME/build/wasm32-wasip2-wasi" \
-G Ninja \
-DCMAKE_TOOLCHAIN_FILE="$WASI_CMAKE_TOOLCHAIN" \
-DCMAKE_BUILD_TYPE=Release \
-DPHPX_WASI_SDK_DIR="$PHPX_HOME/wasm/wasm32-wasip2" \
-DCMAKE_INSTALL_PREFIX="$PHPX_HOME/wasm/wasm32-wasip2"
Subsequent build/install commands should also use this new directory.
Compile and install:
cmake --build "$PHPX_HOME/build/wasm32-wasip2" --parallel 16
cmake --install "$PHPX_HOME/build/wasm32-wasip2"
When the PHPX source changes again later, you only need to run:
cmake --build "$PHPX_HOME/build/wasm32-wasip2" --parallel 16
cmake --install "$PHPX_HOME/build/wasm32-wasip2"
CMake/Ninja only recompiles the changed source files and then updates libphpx.a in the installation directory.
Using Make
make can be used, but the Unix Makefiles generator must be selected during the first configuration, using a different build
directory; you cannot switch generators in a directory already configured by Ninja:
cmake \
-S "$PHPX_HOME/wasm" \
-B "$PHPX_HOME/build/wasm32-wasip2-make" \
-G "Unix Makefiles" \
-DCMAKE_TOOLCHAIN_FILE="$WASI_CMAKE_TOOLCHAIN" \
-DCMAKE_BUILD_TYPE=Release \
-DPHPX_WASI_SDK_DIR="$PHPX_HOME/wasm/wasm32-wasip2" \
-DCMAKE_INSTALL_PREFIX="$PHPX_HOME/wasm/wasm32-wasip2"
make -C "$PHPX_HOME/build/wasm32-wasip2-make" -j16
make -C "$PHPX_HOME/build/wasm32-wasip2-make" install
After later modifying PHPX code, just repeat the two make commands. You can also use the generator-independent form:
cmake --build "$PHPX_HOME/build/wasm32-wasip2-make" --parallel 16
cmake --install "$PHPX_HOME/build/wasm32-wasip2-make"
The artifacts of Ninja and Make are the same; Ninja is generally faster in dependency scanning and incremental builds, so internal development defaults to Ninja.
This flow updates:
lib/libphpx.alib/libmpdec.aandlib/libmpdec++.a(recompiled only when the related source changes)- PHPX public headers under
include/phpx/ .typephp-wasi-runtime-abi
It does not update libphp.a, GMP, or MPFR, nor does it rewrite the full SDK's
.typephp-wasi-sdk-abi. Therefore, this flow should be run on an already fully installed SDK.
Force Recompiling PHPX
When you suspect that old objects or the CMake cache are no longer trustworthy, prefer using a new, explicit build directory:
cmake \
-S "$PHPX_HOME/wasm" \
-B "$PHPX_HOME/build/wasm32-wasip2-clean" \
-G Ninja \
-DCMAKE_TOOLCHAIN_FILE="$WASI_CMAKE_TOOLCHAIN" \
-DCMAKE_BUILD_TYPE=Release \
-DPHPX_WASI_SDK_DIR="$PHPX_HOME/wasm/wasm32-wasip2" \
-DCMAKE_INSTALL_PREFIX="$PHPX_HOME/wasm/wasm32-wasip2"
cmake --build "$PHPX_HOME/build/wasm32-wasip2-clean" --parallel 16
cmake --install "$PHPX_HOME/build/wasm32-wasip2-clean"
This does not delete libphp.a and the dependency libraries in the installation directory, nor does it mix in old CMake configuration.
First Build or Rebuilding PHPX Numeric Dependencies
Use PHPX's unified build entry in the following cases:
- Setting up the PHPX WASI installation directory for the first time;
- GMP or MPFR version, patch, or compile parameter changes;
- Changes to PHPX vendored mpdecimal or its WASI configuration;
- The need to check and install all PHPX WASI headers and static libraries at once.
cd "$PHPX_HOME"
./wasm/build.sh \
--prefix "$PHPX_HOME/wasm/wasm32-wasip2" \
--build-dir "$PHPX_HOME/build/wasm32-wasip2-sdk" \
--jobs 16
Explicitly use $PHPX_HOME/build/ to avoid the default /tmp build directory being lost after a reboot. The downloaded GMP and
MPFR source and build cache are retained and can be reused in subsequent builds.
This entry builds or installs:
libphpx.alibgmp.a,libgmpxx.alibmpfr.alibmpdec.a,libmpdec++.a- The corresponding headers and the PHPX runtime ABI marker
It requires PHP/WASI headers to already exist in the installation prefix; it does not build libphp.a.
PHP ABI Changes: Rebuilding the Full SDK
If the PHP source, extension set, PHP configuration, Zend ABI, or PHP installed headers change, you must rebuild the full SDK from the
TypePHP compiler repository, and you cannot replace only libphpx.a:
cd /home/swoole/workspace/aot/compiler
./wasm/build-sdk.sh \
--prefix "$PHPX_HOME/wasm/wasm32-wasip2" \
--php-source "$PWD/projects/php-8.5.9" \
--phpx-source "$PHPX_HOME" \
--build-dir "$PWD/build/wasm-sdk" \
--jobs 16
The full build installs the PHP and PHPX parts in sequence, and writes the following after all artifacts are verified:
.typephp-wasi-sdk-abi
Do not forge this marker by hand. The existence of the marker only means the build flow declares ABI compatibility; it cannot fix actually mixed old headers or static libraries.
Artifact Verification
After installation completes, check the key files:
WASI_PREFIX="$PHPX_HOME/wasm/wasm32-wasip2"
test -s "$WASI_PREFIX/lib/libphpx.a"
test -s "$WASI_PREFIX/lib/libphp.a"
test -f "$WASI_PREFIX/include/phpx/phpx.h"
test -f "$WASI_PREFIX/include/phpx/phpx_helper.h"
test -f "$WASI_PREFIX/include/phpx/typephp_helper.h"
llvm-ar t "$WASI_PREFIX/lib/libphpx.a" | head
cat "$WASI_PREFIX/.typephp-wasi-runtime-abi"
cat "$WASI_PREFIX/.typephp-wasi-sdk-abi"
The current markers should be:
typephp-wasip2-phpx-abi-v1
typephp-wasip2-sdk-abi-v4
The marker versions will be upgraded as the ABI design evolves; if the expected values in the code have changed, follow the current build scripts rather than writing old values back just to pass detection.
TypePHP Regression Verification
First verify the Wasmtime component:
cd /home/swoole/workspace/aot/compiler
PHPX_HOME="$PHPX_HOME" \
./run-tests.php --wasm --compiler ./bin/tpc.php tests/wasm/
Then verify that Wasmtime and Chrome output are consistent, and cover parallel build/output directory isolation:
PHPX_HOME="$PHPX_HOME" \
./run-tests.php -j 4 --target wasm-all --compiler ./bin/tpc.php tests/wasm/
Browser tests also require jco, Node.js, and Chrome to be in PATH. wasm-all runs each case in
Wasmtime and Chrome separately, and compares the output of both sides.
Finally build the browser example:
cd examples/wasm-hello
PHPX_HOME="$PHPX_HOME" ../../bin/tpc.php project.yml
npm run build
Common Errors
PersistentCacheSlot or PHPX helpers are undefined
The generated code uses a new PHPX header/API, but include/phpx/ or
lib/libphpx.a in the installation prefix is still an old version. Run the "Daily development: rebuild PHPX only" flow, and make sure the configuration and installation
use the same PHPX_WASI_SDK_DIR/CMAKE_INSTALL_PREFIX.
TypePHP WASI SDK is missing or ABI-incompatible
Check whether PHPX_HOME points to the actual PHPX root directory, and whether the full SDK marker, PHP/PHPX headers,
and static libraries come from the same compatible build. Run the full SDK rebuild when the PHP ABI has changed.
CMake detects the host compiler
You must pass the WASI SDK's wasi-sdk-p2.cmake. Do not use the host
CMakeLists.txt in the PHPX root directory to build WASM directly. Adding the WASI SDK to PATH is not equivalent to loading the CMake
toolchain. If CMakeCache.txt has already recorded /usr/bin/cc or /usr/bin/c++, use a
new build directory to reconfigure.
TypePHP still links the old implementation after modifying PHPX
Confirm that PHPX_HOME takes priority over the Composer directory, and check the actual artifact time:
stat "$PHPX_HOME/wasm/wasm32-wasip2/lib/libphpx.a"
TypePHP should read both headers and static libraries from the same $PHPX_HOME/wasm/wasm32-wasip2.