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.
355 lines
11 KiB
355 lines
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:
|
|
|
|
```text
|
|
/home/swoole/workspace/aot/
|
|
├── compiler/
|
|
└── phpx/
|
|
```
|
|
|
|
It is recommended to set the PHPX root directory first:
|
|
|
|
```shell
|
|
export PHPX_HOME=/home/swoole/workspace/aot/phpx
|
|
```
|
|
|
|
The installation prefix is fixed to:
|
|
|
|
```text
|
|
$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:
|
|
|
|
```text
|
|
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`:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
wasm32-wasip2-clang++ --print-target-triple
|
|
```
|
|
|
|
It must output:
|
|
|
|
```text
|
|
wasm32-unknown-wasip2
|
|
```
|
|
|
|
The installation prefix must already contain PHP/WASI headers and `libphp.a` matching the current PHPX:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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.
|
|
|
|
```shell
|
|
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`:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```text
|
|
.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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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:
|
|
|
|
```shell
|
|
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`.
|
|
|