TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

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"

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.a
  • lib/libmpdec.a and lib/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.a
  • libgmp.a, libgmpxx.a
  • libmpfr.a
  • libmpdec.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.

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.