Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0136d51
Added -fPIC to libintl
mho22 Jun 5, 2025
f6f6a97
Set php-wasm as a main module and enable dynamic linking
mho22 Jun 5, 2025
990f945
Implement XDebug as zend extension, compile and build
mho22 Jun 9, 2025
aa63703
Remove artifacts
mho22 Jun 9, 2025
8e87691
Correct merge conflicts
mho22 Jun 9, 2025
6f82103
Build xdebug with nx command and PHP_VERSION arg
mho22 Jun 10, 2025
fcfebd3
Add a withXdebug option in loadNodeRuntime
mho22 Jun 10, 2025
6c14976
Create separate file for supported php versions
mho22 Jun 10, 2025
f0e2d7c
Add proper ini entries and mount current working directory in with-xd…
mho22 Jun 11, 2025
77ddbda
Compile all php-wasm and xdebug extensions
mho22 Jun 11, 2025
460c878
Prevent Xdebug to be loaded in Asyncify
mho22 Jun 16, 2025
29520ea
Add tests
mho22 Jun 16, 2025
549f04f
Remove socket connection error and recompile php
mho22 Jun 17, 2025
c6411e4
Correct conflicts
mho22 Jun 17, 2025
491d0bb
Correct lint errors and add tests to CI
mho22 Jun 17, 2025
b3cc02c
Added temporary new job test-unit-jspi
mho22 Jun 17, 2025
fefc94c
Add last test on DBGP communication
mho22 Jun 17, 2025
ffcf2c4
Correct conflicts
mho22 Jun 17, 2025
c382bef
Correct errors and clean unused code
mho22 Jun 17, 2025
e19f292
Correct Errors and make improvements
mho22 Jun 18, 2025
bd0729c
Merge branch 'trunk' into add-xdebug-support-to-php-wasm-node-jspi
mho22 Jun 18, 2025
522a7ea
Add previous emscriptenOptions in new ones
mho22 Jun 18, 2025
ffe001f
Correct errors and implement modifications
mho22 Jun 19, 2025
2fe9bbe
Apply new filepath for built and unbuilt version
mho22 Jun 19, 2025
143c23c
Unbundle sqlite3 in PHP 7.3 and 7.2
mho22 Jun 19, 2025
a1eee4f
Document multiple processes like sqlite <7.4 and esbuild path replace…
mho22 Jun 23, 2025
63733cf
Implement an 'import-url' Vite plugin and an ESBuild plugin to handle…
mho22 Jun 24, 2025
f3fb08a
wrap zend_list_free Zend function to avoid function signature mismatc…
mho22 Jun 26, 2025
eccb56f
minor modifications
mho22 Jun 26, 2025
037a25b
Add comment and test for function signature mismatch
mho22 Jun 30, 2025
8e7b5c9
correct merge conflicts from trunk
mho22 Jul 1, 2025
dc7afb4
Merge branch 'trunk' into add-xdebug-support-to-php-wasm-node-jspi
mho22 Jul 1, 2025
1e66704
remove only from the unknown function signature mismatch test
mho22 Jul 1, 2025
654df4a
Recompile Asyncify PHP versions with aditional asyncify imports
mho22 Jul 1, 2025
02b80ed
Merge branch 'trunk' into add-xdebug-support-to-php-wasm-node-jspi
mho22 Jul 1, 2025
454e740
Try to solve failing checks
mho22 Jul 1, 2025
eec8621
add env variable in ci
mho22 Jul 1, 2025
afcfae0
experiment use of max_old_space_size with runner
mho22 Jul 1, 2025
82b6e58
add aftereach in tests which disposes PHP wasm runtime
mho22 Jul 1, 2025
3ffdd92
improve aftereach which disposes PHP wasm runtime
mho22 Jul 1, 2025
aa53bc3
improve aftereach which disposes PHP wasm runtime
mho22 Jul 1, 2025
e5e453b
add php-networking in ci jobs list
mho22 Jul 1, 2025
f4c2388
Tweak some timeouts to make the checks pass
mho22 Jul 1, 2025
7418095
Tweak some timeouts to make the checks pass
mho22 Jul 1, 2025
3763dbc
Tweak some timeouts to make the checks pass
mho22 Jul 1, 2025
57d15a6
Merge branch 'trunk' into add-xdebug-support-to-php-wasm-node-jspi
mho22 Jul 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,24 @@ jobs:
MYSQL_DATABASE: test_db
MYSQL_USER: user
MYSQL_PASSWORD: password
test-unit-jspi:
runs-on: ubuntu-latest
needs: [lint-and-typecheck]
strategy:
fail-fast: false
matrix:
include:
- name: test-unit-jspi (1/1)
target: test-php-dynamic-loading
name: ${{ matrix.name }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/prepare-playground
with:
node-version: 23
- run: node --expose-gc node_modules/nx/bin/nx affected --target=${{ matrix.target }}
# Most of these tests pass locally but the process is crashing
# on the CI runner.
#
Expand Down
1 change: 0 additions & 1 deletion packages/php-wasm/compile/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,6 @@ libintl/asyncify/dist/root/lib/lib/libintl.a: base-image
docker cp $$(docker create playground-php-wasm:libintl):/root/lib/include ./libintl/asyncify/dist/root/lib
docker cp $$(docker create playground-php-wasm:libintl):/root/lib/data/. ./libintl/


libintl_jspi: libintl/jspi/dist/root/lib/lib/libintl.a
libintl/jspi/dist/root/lib/lib/libintl.a: base-image
mkdir -p ./libintl/jspi/dist/root/lib
Expand Down
23 changes: 10 additions & 13 deletions packages/php-wasm/compile/base-image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ RUN chmod a+x /root/replace.sh
COPY ./replace-across-lines.sh /root/replace-across-lines.sh
RUN chmod a+x /root/replace-across-lines.sh

COPY ./emcc-for-php-wasm.sh /root/emcc-for-php-wasm.sh
COPY ./print-wasm-imports-and-exports.c /root/print-wasm-imports-and-exports.c

# Patch emcc to allow skipping flags and passing additional flags using environment variables.
#
# We're compiling libraries statically using emscripten's -sSIDE_MODULE. It differs from the usual unix
Expand All @@ -85,17 +88,11 @@ RUN chmod a+x /root/replace-across-lines.sh
# │ skip those flags when │ │ add these flags when │
# │ calling emcc │ │ calling emcc │
# └────────────────────────┘ └────────────────────────┘
RUN cp /root/emsdk/upstream/emscripten/emcc /root/emsdk/upstream/emscripten/emcc2 && \
cp /root/emsdk/upstream/emscripten/emcc.py /root/emsdk/upstream/emscripten/emcc2.py && \
echo $'#!/bin/bash\n\
for arg do shift\n\
[[ " ${EMCC_SKIP[*]} " =~ " ${arg} " ]] && continue \n\
set -- "$@" "$arg" \n\
done\n\
# Passing extra flags breaks the version check \n\
if [[ "$@" == "-v" ]]; then\n\
export EMCC_FLAGS=""\n\
fi\n\
/root/emsdk/upstream/emscripten/emcc2 "$@" $EMCC_FLAGS \n' > /root/emsdk/upstream/emscripten/emcc && \
RUN <<EOF
set -euo pipefail
cp /root/emsdk/upstream/emscripten/emcc /root/emsdk/upstream/emscripten/emcc2
cp /root/emsdk/upstream/emscripten/emcc.py /root/emsdk/upstream/emscripten/emcc2.py
cp /root/emcc-for-php-wasm.sh /root/emsdk/upstream/emscripten/emcc
chmod a+x /root/emsdk/upstream/emscripten/emcc

cc /root/print-wasm-imports-and-exports.c -o /root/print-wasm-imports-and-exports
EOF
43 changes: 43 additions & 0 deletions packages/php-wasm/compile/base-image/emcc-for-php-wasm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash

set -euo pipefail

# Passing extra flags breaks the version check
if [[ "$@" == "-v" ]]; then
export EMCC_FLAGS=""
fi

# Convert args to an array for filtering
args=("${@}")

# Remove flags that we do not want to pass to emcc
if [[ -n "${EMCC_SKIP:-}" ]]; then
for ((i=0; i < ${#args[@]}; i++)); do
if [[ " ${EMCC_SKIP[*]} " =~ " ${args[$i]} " ]]; then
unset 'args[i]'
fi
done
fi

# Remove duplicate library references to avoid linking errors.
# Begin at end because we generally want dependencies to come last,
# and if two things depend on a lib, we want the lib to come after both.
declare -A seen_libs
for ((i=${#args[@]} - 1; i >= 0; i--)); do
# Skip empty args because array may be sparse
[[ -z "${args[$i]:-}" ]] && continue

arg=${args[i]}
if (
[[ "$arg" =~ ^-l([a-z]|[A-Z]|[0-9]|[\-_])+$ ]] ||
[[ "$arg" =~ (^|/)lib([a-z]|[A-Z]|[0-9]|[\-_])+\.a$ ]]
); then
if [[ -v seen_libs["$arg"] ]]; then
unset 'args[i]'
else
seen_libs["$arg"]=1
fi
fi
done

/root/emsdk/upstream/emscripten/emcc2 "${args[@]}" ${EMCC_FLAGS:-}
220 changes: 220 additions & 0 deletions packages/php-wasm/compile/base-image/print-wasm-imports-and-exports.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define WASM_MAGIC 0x6D736100
#define WASM_VERSION 0x1

// Section IDs
#define IMPORT_SECTION 2
#define EXPORT_SECTION 7

typedef struct {
uint32_t magic;
uint32_t version;
} wasm_header_t;

typedef struct {
uint8_t id;
uint32_t size;
} section_header_t;

// Read LEB128 encoded unsigned integer
uint32_t read_leb128(FILE *fp) {
uint32_t result = 0;
uint32_t shift = 0;
uint8_t byte;

do {
byte = fgetc(fp);
result |= ((byte & 0x7f) << shift);
shift += 7;
} while (byte & 0x80);

return result;
}

// Read string from wasm binary
char* read_string(FILE *fp) {
uint32_t len = read_leb128(fp);
char *str = malloc(len + 1);
fread(str, 1, len, fp);
str[len] = '\0';
return str;
}

void parse_imports(FILE *fp) {
uint32_t count = read_leb128(fp);
printf("[\n");

for (uint32_t i = 0; i < count; i++) {
char *module = read_string(fp);
char *name = read_string(fp);
uint8_t kind = fgetc(fp);

printf(" {\n");
printf(" \"module\": \"%s\",\n", module);
printf(" \"name\": \"%s\",\n", name);
printf(" \"kind\": \"0x%02x\",\n", kind);

// Parse import type based on kind
switch(kind) {
case 0x00: // Function
printf(" \"type\": \"function\",\n");
printf(" \"typeIndex\": %d\n", read_leb128(fp));
break;
case 0x01: { // Table
printf(" \"type\": \"table\",\n");
// Skip table type but include in JSON
uint8_t elemType = fgetc(fp);
uint8_t flags = fgetc(fp);
uint32_t initial = read_leb128(fp);
printf(" \"elementType\": \"0x%02x\",\n", elemType);
printf(" \"initial\": %d", initial);
if (flags & 0x01) {
uint32_t max = read_leb128(fp);
printf(",\n \"maximum\": %d\n", max);
} else {
printf("\n");
}
break;
}
case 0x02: { // Memory
printf(" \"type\": \"memory\",\n");
uint8_t flags = fgetc(fp);
uint32_t initial = read_leb128(fp);
printf(" \"initial\": %d", initial);
if (flags & 0x01) {
uint32_t max = read_leb128(fp);
printf(",\n \"maximum\": %d\n", max);
} else {
printf("\n");
}
break;
}
case 0x03: { // Global
printf(" \"type\": \"global\",\n");
uint8_t valueType = fgetc(fp);
uint8_t mutability = fgetc(fp);
printf(" \"valueType\": \"0x%02x\",\n", valueType);
printf(" \"mutable\": %s\n", mutability ? "true" : "false");
break;
}
}

free(module);
free(name);

if (i < count - 1) {
printf(" },\n");
} else {
printf(" }\n");
}
}

printf(" ]");
}

void parse_exports(FILE *fp) {
printf("[\n");

// Read number of exports
uint32_t count = read_leb128(fp);

for (uint32_t i = 0; i < count; i++) {
// Read export name
uint32_t name_len = read_leb128(fp);
char* name = malloc(name_len + 1);
fread(name, 1, name_len, fp);
name[name_len] = '\0';

// Read export kind and index
uint8_t kind = fgetc(fp);
uint32_t index = read_leb128(fp);

printf(" {\n");
printf(" \"name\": \"%s\",\n", name);
printf(" \"kind\": %d,\n", kind);
printf(" \"index\": %d\n", index);

if (i < count - 1) {
printf(" },\n");
} else {
printf(" }\n");
}

free(name);
}

printf(" ]");
}

int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <wasm file>\n", argv[0]);
return 1;
}

FILE *fp = fopen(argv[1], "rb");
if (!fp) {
perror("Failed to open file");
return 1;
}

// Read and verify header
wasm_header_t header;
fread(&header, sizeof(header), 1, fp);

if (header.magic != WASM_MAGIC || header.version != WASM_VERSION) {
fprintf(stderr, "Invalid WASM file\n");
fclose(fp);
return 1;
}

printf("{\n");

// Find imports and exports sections
int found_imports = 0;
int found_exports = 0;

while (!feof(fp) && (!found_imports || !found_exports)) {
section_header_t section;
section.id = fgetc(fp);
if (feof(fp)) break;

section.size = read_leb128(fp);

if (section.id == IMPORT_SECTION) {
printf(" \"imports\": ");
parse_imports(fp);
found_imports = 1;
if (!found_exports) {
printf(",");
}
printf("\n");
} else if (section.id == EXPORT_SECTION) {
printf(" \"exports\": ");
parse_exports(fp);
found_exports = 1;
if (!found_imports) {
printf(",");
}
printf("\n");
} else {
// Skip other sections
fseek(fp, section.size, SEEK_CUR);
}
}

if (!found_imports) {
printf(" \"imports\": []\n");
}
if (!found_exports) {
printf(" \"exports\": []\n");
}

printf("}\n");

fclose(fp);
return 0;
}
6 changes: 4 additions & 2 deletions packages/php-wasm/compile/libintl/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ RUN set -euxo pipefail && \
cd /root/icu/source && \
mkdir -p /root/lib && \
source /root/emsdk/emsdk_env.sh && \
export CFLAGS="-fPIC" && \
export CXXFLAGS="-fPIC" && \
emconfigure ./configure \
--build=i386-pc-linux-gnu \
--target=wasm32-unknown-emscripten \
Expand All @@ -41,8 +43,8 @@ RUN set -euxo pipefail && \
--disable-shared \
--enable-static && \
export JSPI_FLAGS=$(if [ "$JSPI" = "1" ]; then echo "-sSUPPORT_LONGJMP=wasm -fwasm-exceptions"; else echo ""; fi) && \
EMCC_FLAGS=" -D__x86_64__ -sSIDE_MODULE $JSPI_FLAGS " emmake make -j"$(nproc)" && \
EMCC_FLAGS=" -D__x86_64__ -sSIDE_MODULE $JSPI_FLAGS " emmake make install -i;
EMCC_FLAGS=" -D__x86_64__ -fPIC -sSIDE_MODULE $JSPI_FLAGS " emmake make -j"$(nproc)" && \
EMCC_FLAGS=" -D__x86_64__ -fPIC -sSIDE_MODULE $JSPI_FLAGS " emmake make install;


RUN set -euxo pipefail && \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ SOBJ=so
A=a
LIBPREFIX=lib
LIB_EXT_ORDER=.74.2
COMPILE=/root/emsdk/upstream/emscripten/emcc -ffunction-sections -fdata-sections -D_REENTRANT -DU_HAVE_ELF_H=1 -DU_HAVE_STRTOD_L=1 -DU_HAVE_XLOCALE_H=1 -DU_HAVE_STRING_VIEW=1 -DU_ATTRIBUTE_DEPRECATED= -O2 -std=c11 -Wall -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -c
COMPILE=/root/emsdk/upstream/emscripten/emcc -ffunction-sections -fdata-sections -D_REENTRANT -DU_HAVE_ELF_H=1 -DU_HAVE_STRTOD_L=1 -DU_HAVE_XLOCALE_H=1 -DU_HAVE_STRING_VIEW=1 -DU_ATTRIBUTE_DEPRECATED= -fPIC -std=c11 -Wall -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -c
LIBFLAGS=-I/root/lib/include -DPIC -fPIC
GENLIB=/root/emsdk/upstream/emscripten/emcc -O2 -std=c11 -Wall -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -Wl,--gc-sections -shared -Wl,-Bsymbolic
GENLIB=/root/emsdk/upstream/emscripten/emcc -fPIC -std=c11 -Wall -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings -Wl,--gc-sections -shared -Wl,-Bsymbolic
LDICUDTFLAGS=-nodefaultlibs -nostdlib
LD_SONAME=-Wl,-soname -Wl,
RPATH_FLAGS=
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading