Skip to content

Commit dc68872

Browse files
authored
[PHP] Upgrade GD to 2.3.3 (#2944)
## Motivation for the change, related issues Upgrades GD version to 2.3.3. The EWWW Image Optimizer relies on GD library features shipped with a more recent GD version than the one bundled with PHP. See nosilver4u/ewww-image-optimizer#377 ## Implementation details PHP comes with a bundled GD version 2.1.0. Upgrading to 2.3.3 involves: * Downloading and building 2.3.3 as a separate library (living in `packages/php-wasm/compile/libgd`) * Using it while compiling PHP 8.1+ via `--with-external-gd` * Falling back to the bundled libgd==2.1.0 for PHP <= 8.0. These older PHP releases don't seem to be compatible with newer GD and fail to build due to multiple missing symbols, e.g. `/root/php-src/ext/gd/gd.c:3536:8: error: use of undeclared identifier 'GD_FLIP_VERTICAL'`. ## Testing Instructions (or ideally a Blueprint) CI – we have tests covering `gd` across all PHP versions.
1 parent 96b45e0 commit dc68872

File tree

154 files changed

+513404
-551380
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

154 files changed

+513404
-551380
lines changed

CHANGELOG.md

Lines changed: 994 additions & 994 deletions
Large diffs are not rendered by default.

packages/docs/site/docs/developers/03-build-an-app/01-index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ Loading a `.zip` file is another alternative for previewing your project. See th
119119

120120
To use Playground as a PR previewer, you need:
121121

122-
- A CI pipeline that bundles your plugin or theme
123-
- Public access to the generated `.zip` file
122+
- A CI pipeline that bundles your plugin or theme
123+
- Public access to the generated `.zip` file
124124

125125
Those zip bundles aren't any different from regular WordPress Plugins, which means you can install them in Playground using the [JSON Blueprints](/blueprints) API. Once you expose an endpoint like https://your-site.com/pull-request-1234.zip, the following Blueprint will do the rest:
126126

@@ -187,9 +187,9 @@ blueprint={{
187187

188188
You can preview specific pull requests from WordPress Core and Gutenberg repositories using Query API parameters. Gutenberg branches also have an alternative to preview them with the parameter `gutenberg-branch`. This is useful for testing the latest trunk changes or specific feature branches without creating a PR.
189189

190-
- Preview a specific WordPress Core PR: `https://playground.wordpress.net/?core-pr=9500`
191-
- Preview a specific Gutenberg PR: `https://playground.wordpress.net/?gutenberg-pr=73010`
192-
- Preview the Gutenberg trunk branch: `https://playground.wordpress.net/?gutenberg-branch=trunk`
190+
- Preview a specific WordPress Core PR: `https://playground.wordpress.net/?core-pr=9500`
191+
- Preview a specific Gutenberg PR: `https://playground.wordpress.net/?gutenberg-pr=73010`
192+
- Preview the Gutenberg trunk branch: `https://playground.wordpress.net/?gutenberg-branch=trunk`
193193

194194
## Build a compatibility testing environment
195195

packages/docs/site/i18n/es/docusaurus-plugin-content-docs/current/developers/03-build-an-app/01-index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ Para usar Playground como un previsualizador de PR, necesitas:
197197
- Public access to the generated `.zip` file
198198
-->
199199

200-
- Un pipeline de CI que empaquete tu plugin o tema
201-
- Acceso público al archivo `.zip` generado
200+
- Un pipeline de CI que empaquete tu plugin o tema
201+
- Acceso público al archivo `.zip` generado
202202

203203
<!--
204204
Those zip bundles aren't any different from regular WordPress Plugins, which means you can install them in Playground using the [JSON Blueprints](/blueprints) API. Once you expose an endpoint like https://your-site.com/pull-request-1234.zip, the following Blueprint will do the rest:
@@ -287,9 +287,9 @@ Puedes previsualizar pull requests específicos de los repositorios de WordPress
287287
- Preview the Gutenberg trunk branch: `https://playground.wordpress.net/?gutenberg-branch=trunk`
288288
-->
289289

290-
- Previsualizar un PR específico de WordPress Core: `https://playground.wordpress.net/?core-pr=9500`
291-
- Previsualizar un PR específico de Gutenberg: `https://playground.wordpress.net/?gutenberg-pr=73010`
292-
- Previsualizar la rama trunk de Gutenberg: `https://playground.wordpress.net/?gutenberg-branch=trunk`
290+
- Previsualizar un PR específico de WordPress Core: `https://playground.wordpress.net/?core-pr=9500`
291+
- Previsualizar un PR específico de Gutenberg: `https://playground.wordpress.net/?gutenberg-pr=73010`
292+
- Previsualizar la rama trunk de Gutenberg: `https://playground.wordpress.net/?gutenberg-branch=trunk`
293293

294294
<!--
295295
## Build a compatibility testing environment

packages/docs/site/i18n/fr/docusaurus-plugin-content-docs/current/developers/03-build-an-app/01-index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ Pour utiliser Playground comme visualiseur de PR, vous avez besoin :
197197
- Public access to the generated `.zip` file
198198
-->
199199

200-
- D'un pipeline CI qui empaquette votre plugin ou thème
201-
- D'un accès public au fichier `.zip` généré
200+
- D'un pipeline CI qui empaquette votre plugin ou thème
201+
- D'un accès public au fichier `.zip` généré
202202

203203
<!--
204204
Those zip bundles aren't any different from regular WordPress Plugins, which means you can install them in Playground using the [JSON Blueprints](/blueprints) API. Once you expose an endpoint like https://your-site.com/pull-request-1234.zip, the following Blueprint will do the rest:
@@ -287,9 +287,9 @@ Vous pouvez prévisualiser des pull requests spécifiques des dépôts WordPress
287287
- Preview the Gutenberg trunk branch: `https://playground.wordpress.net/?gutenberg-branch=trunk`
288288
-->
289289

290-
- Prévisualiser un PR WordPress Core spécifique : `https://playground.wordpress.net/?core-pr=9500`
291-
- Prévisualiser un PR Gutenberg spécifique : `https://playground.wordpress.net/?gutenberg-pr=73010`
292-
- Prévisualiser la branche trunk de Gutenberg : `https://playground.wordpress.net/?gutenberg-branch=trunk`
290+
- Prévisualiser un PR WordPress Core spécifique : `https://playground.wordpress.net/?core-pr=9500`
291+
- Prévisualiser un PR Gutenberg spécifique : `https://playground.wordpress.net/?gutenberg-pr=73010`
292+
- Prévisualiser la branche trunk de Gutenberg : `https://playground.wordpress.net/?gutenberg-branch=trunk`
293293

294294
<!--
295295
## Build a compatibility testing environment

packages/docs/site/i18n/pt-BR/docusaurus-plugin-content-docs/current/developers/03-build-an-app/01-index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ Para usar o Playground como um visualizador de PR, você precisa:
159159
<!-- - A CI pipeline that bundles your plugin or theme -->
160160
<!-- - Public access to the generated `.zip` file -->
161161

162-
- Um pipeline de CI que empacote seu plugin ou tema
163-
- Acesso público ao arquivo `.zip` gerado
162+
- Um pipeline de CI que empacote seu plugin ou tema
163+
- Acesso público ao arquivo `.zip` gerado
164164

165165
<!-- Those zip bundles aren't any different from regular WordPress Plugins, which means you can install them in Playground using the [JSON Blueprints](/blueprints) API. Once you expose an endpoint like https://your-site.com/pull-request-1234.zip, the following Blueprint will do the rest: -->
166166

@@ -239,9 +239,9 @@ Você pode visualizar pull requests específicos dos repositórios WordPress Cor
239239
<!-- - Preview a specific Gutenberg PR: `https://playground.wordpress.net/?gutenberg-pr=73010` -->
240240
<!-- - Preview the Gutenberg trunk branch: `https://playground.wordpress.net/?gutenberg-branch=trunk` -->
241241

242-
- Visualizar um PR específico do WordPress Core: `https://playground.wordpress.net/?core-pr=9500`
243-
- Visualizar um PR específico do Gutenberg: `https://playground.wordpress.net/?gutenberg-pr=73010`
244-
- Visualizar o branch trunk do Gutenberg: `https://playground.wordpress.net/?gutenberg-branch=trunk`
242+
- Visualizar um PR específico do WordPress Core: `https://playground.wordpress.net/?core-pr=9500`
243+
- Visualizar um PR específico do Gutenberg: `https://playground.wordpress.net/?gutenberg-pr=73010`
244+
- Visualizar o branch trunk do Gutenberg: `https://playground.wordpress.net/?gutenberg-branch=trunk`
245245

246246
<!-- ## Build a compatibility testing environment -->
247247

packages/php-wasm/compile/Makefile

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,22 @@ libavif/jspi/dist/root/lib/lib/libavif.a: base-image
128128
docker cp $$(docker create playground-php-wasm:libavif):/root/lib/lib ./libavif/jspi/dist/root/lib
129129
docker cp $$(docker create playground-php-wasm:libavif):/root/lib/include ./libavif/jspi/dist/root/lib
130130

131+
libgd_asyncify: libgd/asyncify/dist/root/lib/lib/libgd.a
132+
libgd/asyncify/dist/root/lib/lib/libgd.a: base-image libz_asyncify libpng16_asyncify libjpeg_asyncify libwebp_asyncify libavif_asyncify
133+
mkdir -p ./libgd/asyncify/dist/root/lib
134+
docker build -f ./libgd/Dockerfile -t playground-php-wasm:libgd .
135+
docker cp $$(docker create playground-php-wasm:libgd):/root/install/lib ./libgd/asyncify/dist/root/lib
136+
docker cp $$(docker create playground-php-wasm:libgd):/root/install/include ./libgd/asyncify/dist/root/lib
137+
docker cp $$(docker create playground-php-wasm:libgd):/root/install/bin ./libgd/asyncify/dist/root/lib
138+
139+
libgd_jspi: libgd/jspi/dist/root/lib/lib/libgd.a
140+
libgd/jspi/dist/root/lib/lib/libgd.a: base-image libz_jspi libpng16_jspi libjpeg_jspi libwebp_jspi libavif_jspi
141+
mkdir -p ./libgd/jspi/dist/root/lib
142+
docker build -f ./libgd/Dockerfile -t playground-php-wasm:libgd . --build-arg JSPI=1
143+
docker cp $$(docker create playground-php-wasm:libgd):/root/install/lib ./libgd/jspi/dist/root/lib
144+
docker cp $$(docker create playground-php-wasm:libgd):/root/install/include ./libgd/jspi/dist/root/lib
145+
docker cp $$(docker create playground-php-wasm:libgd):/root/install/bin ./libgd/jspi/dist/root/lib
146+
131147
libxml2_asyncify: libxml2/asyncify/dist/root/lib/lib/libxml2.a
132148
libxml2/asyncify/dist/root/lib/lib/libxml2.a: base-image libz_asyncify
133149
mkdir -p ./libxml2/asyncify/dist/root/lib
@@ -317,8 +333,8 @@ libImageMagick/jspi/dist/root/lib/lib/libMagickCore-7.Q16HDRI.a: base-image libz
317333
docker cp $$(docker create playground-php-wasm:libImageMagick):/root/install/bin ./libImageMagick/jspi/dist/root/lib
318334

319335
all: all_jspi all_asyncify
320-
all_jspi: libz_jspi libzip_jspi libpng16_jspi libjpeg_jspi libwebp_jspi libaom_jspi libavif_jspi libxml2_jspi libopenssl_jspi libsqlite3_jspi libiconv_jspi bison2.7 oniguruma_jspi libcurl_jspi libintl_jspi libImageMagick_jspi
321-
all_asyncify: libz_asyncify libzip_asyncify libpng16_asyncify libjpeg_asyncify libwebp_asyncify libaom_asyncify libavif_asyncify libxml2_asyncify libopenssl_asyncify libsqlite3_asyncify libiconv_asyncify bison2.7 oniguruma_asyncify libcurl_asyncify libintl_asyncify libImageMagick_asyncify
336+
all_jspi: libz_jspi libzip_jspi libpng16_jspi libjpeg_jspi libwebp_jspi libaom_jspi libavif_jspi libgd_jspi libxml2_jspi libopenssl_jspi libsqlite3_jspi libiconv_jspi bison2.7 oniguruma_jspi libcurl_jspi libintl_jspi libImageMagick_jspi
337+
all_asyncify: libz_asyncify libzip_asyncify libpng16_asyncify libjpeg_asyncify libwebp_asyncify libaom_asyncify libavif_asyncify libgd_asyncify libxml2_asyncify libopenssl_asyncify libsqlite3_asyncify libiconv_asyncify bison2.7 oniguruma_asyncify libcurl_asyncify libintl_asyncify libImageMagick_asyncify
322338

323339
clean:
324340
rm -rf ./libz/jspi/dist
Binary file not shown.
-30.7 KB
Binary file not shown.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
FROM playground-php-wasm:base
2+
3+
ARG JSPI
4+
ARG GD_VERSION="2.3.3"
5+
6+
RUN mkdir -p /root/lib/include /root/lib/lib
7+
COPY ./libz/ /root/libz
8+
COPY ./libpng16/ /root/libpng16
9+
COPY ./libjpeg/ /root/libjpeg
10+
COPY ./libwebp/ /root/libwebp
11+
COPY ./libavif/ /root/libavif
12+
COPY ./libgd/libavifConfig.cmake /tmp/libavifConfig.cmake
13+
COPY ./libgd/libavifConfigVersion.cmake /tmp/libavifConfigVersion.cmake
14+
15+
RUN if [ "$JSPI" = "1" ]; then \
16+
cp -r /root/libz/jspi/dist/root/lib/* /root/lib; \
17+
cp -r /root/libpng16/jspi/dist/root/lib/* /root/lib; \
18+
cp -r /root/libjpeg/jspi/dist/root/lib/* /root/lib; \
19+
cp -r /root/libwebp/jspi/dist/root/lib/* /root/lib; \
20+
cp -r /root/libavif/jspi/dist/root/lib/* /root/lib; \
21+
else \
22+
cp -r /root/libz/asyncify/dist/root/lib/* /root/lib; \
23+
cp -r /root/libpng16/asyncify/dist/root/lib/* /root/lib; \
24+
cp -r /root/libjpeg/asyncify/dist/root/lib/* /root/lib; \
25+
cp -r /root/libwebp/asyncify/dist/root/lib/* /root/lib; \
26+
cp -r /root/libavif/asyncify/dist/root/lib/* /root/lib; \
27+
fi
28+
RUN mkdir -p /root/lib/lib/cmake/libavif && \
29+
cp /tmp/libavifConfig.cmake /root/lib/lib/cmake/libavif/libavifConfig.cmake && \
30+
cp /tmp/libavifConfigVersion.cmake /root/lib/lib/cmake/libavif/libavifConfigVersion.cmake
31+
32+
RUN wget https://github.com/libgd/libgd/releases/download/gd-$GD_VERSION/libgd-$GD_VERSION.tar.gz -O libgd.tar.gz
33+
RUN tar -xzf libgd.tar.gz
34+
WORKDIR /root/libgd-$GD_VERSION
35+
36+
# Patch gd_security.c to make overflow2 static (avoids duplicate symbol with PHP's gd_compat.o)
37+
RUN sed -i 's/^int overflow2/static int overflow2/' /root/libgd-$GD_VERSION/src/gd_security.c
38+
39+
# Patch gdkanji.c to make iconv stubs static (avoids duplicate symbol with emscripten libc)
40+
# Need to update both forward declarations and definitions
41+
RUN sed -i 's/^iconv_t iconv_open (const char/static iconv_t iconv_open (const char/' /root/libgd-$GD_VERSION/src/gdkanji.c && \
42+
sed -i 's/^size_t iconv (iconv_t/static size_t iconv (iconv_t/' /root/libgd-$GD_VERSION/src/gdkanji.c && \
43+
sed -i 's/^int iconv_close (iconv_t/static int iconv_close (iconv_t/' /root/libgd-$GD_VERSION/src/gdkanji.c && \
44+
sed -i 's/^iconv_open (/static iconv_open (/' /root/libgd-$GD_VERSION/src/gdkanji.c && \
45+
sed -i 's/^iconv (/static iconv (/' /root/libgd-$GD_VERSION/src/gdkanji.c && \
46+
sed -i 's/^iconv_close (/static iconv_close (/' /root/libgd-$GD_VERSION/src/gdkanji.c
47+
48+
# Add stub implementations for FreeType functions when FreeType is disabled
49+
# These are needed because PHP's GD extension expects them
50+
RUN echo '' >> /root/libgd-$GD_VERSION/src/gd.c && \
51+
echo '/* Stub implementations for when FreeType is disabled */' >> /root/libgd-$GD_VERSION/src/gd.c && \
52+
echo '#ifndef HAVE_LIBFREETYPE' >> /root/libgd-$GD_VERSION/src/gd.c && \
53+
echo '#include "gd.h"' >> /root/libgd-$GD_VERSION/src/gd.c && \
54+
echo 'BGD_DECLARE(void) gdFontCacheShutdown(void) {}' >> /root/libgd-$GD_VERSION/src/gd.c && \
55+
echo 'BGD_DECLARE(void) gdFreeFontCache(void) {}' >> /root/libgd-$GD_VERSION/src/gd.c && \
56+
echo '#endif' >> /root/libgd-$GD_VERSION/src/gd.c
57+
58+
RUN set -euxo pipefail; \
59+
source /root/emsdk/emsdk_env.sh; \
60+
export PKG_CONFIG_PATH=/root/lib/lib/pkgconfig:$PKG_CONFIG_PATH; \
61+
emcmake cmake -G"Unix Makefiles" \
62+
-DCMAKE_BUILD_TYPE=Release \
63+
-DCMAKE_INSTALL_PREFIX=/root/install \
64+
-DCMAKE_PREFIX_PATH=/root/lib \
65+
-DZLIB_LIBRARY=/root/lib/lib/libz.a \
66+
-DZLIB_INCLUDE_DIR=/root/lib/include \
67+
-DPNG_LIBRARY=/root/lib/lib/libpng16.a \
68+
-DPNG_PNG_INCLUDE_DIR=/root/lib/include \
69+
-DJPEG_LIBRARY=/root/lib/lib/libjpeg.a \
70+
-DJPEG_INCLUDE_DIR=/root/lib/include \
71+
-DWEBP_LIBRARY=/root/lib/lib/libwebp.a \
72+
-DWEBP_LIBRARIES="/root/lib/lib/libwebp.a;/root/lib/lib/libsharpyuv.a" \
73+
-DWEBP_INCLUDE_DIR=/root/lib/include \
74+
-DAVIF_LIBRARY=/root/lib/lib/libavif.a \
75+
-DAVIF_INCLUDE_DIR=/root/lib/include \
76+
-Dlibavif_DIR=/root/lib/lib/cmake/libavif \
77+
-DBUILD_STATIC_LIBS=ON \
78+
-DBUILD_SHARED_LIBS=OFF \
79+
-DBUILD_TEST=OFF \
80+
-DBUILD_PROGRAMS=OFF \
81+
-DENABLE_CPP=OFF \
82+
-DENABLE_GD_FORMATS=ON \
83+
-DENABLE_PNG=ON \
84+
-DENABLE_JPEG=ON \
85+
-DENABLE_WEBP=ON \
86+
-DENABLE_AVIF=ON \
87+
-DENABLE_LIQ=OFF \
88+
-DENABLE_TIFF=OFF \
89+
-DENABLE_ICONV=OFF \
90+
-DENABLE_XPM=OFF \
91+
-DENABLE_FREETYPE=OFF \
92+
-DENABLE_FONTCONFIG=OFF \
93+
-DENABLE_HEIF=OFF \
94+
-DENABLE_RAQM=OFF
95+
96+
# Build as side module, skipping all dependency libraries (they'll be linked with PHP later)
97+
RUN source /root/emsdk/emsdk_env.sh && \
98+
export JSPI_FLAGS=$(if [ "$JSPI" = "1" ]; then echo "-sSUPPORT_LONGJMP=wasm -fwasm-exceptions"; else echo ""; fi) && \
99+
EMCC_SKIP="-lc -lz -lpng -lpng16 -ljpeg -lwebp -lavif -liconv" \
100+
EMCC_FLAGS=" -D__x86_64__ -sSIDE_MODULE $JSPI_FLAGS" \
101+
emmake make gd_static -j"$(nproc)"
102+
103+
# Manually stage the static lib and headers (skip installing programs)
104+
RUN set -euxo pipefail && \
105+
mkdir -p /root/install/lib /root/install/include /root/install/lib/pkgconfig /root/install/bin && \
106+
LIBFILE=$(find /root/libgd-2.3.3 -maxdepth 4 -name "libgd*.a" | head -n1) && \
107+
if [ -z "$LIBFILE" ]; then echo "libgd static archive not found"; exit 1; fi && \
108+
cp "$LIBFILE" /root/install/lib/libgd.a && \
109+
(cp /root/libgd-2.3.3/src/gd_config.h /root/install/include/ || true) && \
110+
(cp /root/libgd-2.3.3/gd_config.h /root/install/include/ || true) && \
111+
cp /root/libgd-2.3.3/src/*.h /root/install/include/ && \
112+
(cp /root/libgd-2.3.3/gd.h /root/install/include/ || true) && \
113+
(cp /root/libgd-2.3.3/gd_errors.h /root/install/include/ || true)
114+
115+
RUN cat > /root/install/lib/pkgconfig/gdlib.pc <<'EOF'
116+
prefix=/root/lib
117+
exec_prefix=${prefix}
118+
libdir=${exec_prefix}/lib
119+
includedir=${prefix}/include
120+
121+
Name: gdlib
122+
Description: GD graphics library
123+
Version: 2.3.3
124+
Requires.private: libpng libjpeg libwebp libavif zlib
125+
Libs: -L${libdir} -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif
126+
Cflags: -I${includedir}
127+
EOF
128+
129+
RUN cat > /root/install/bin/gdlib-config <<'EOF'
130+
#!/bin/sh
131+
case "$1" in
132+
--version) echo 2.3.3 ;;
133+
--features) echo "PNG JPEG WEBP AVIF GIF XBM WBMP FREETYPE" ;;
134+
--libs) echo "-L/root/lib/lib -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif" ;;
135+
--cflags|--includes) echo "-I/root/lib/include" ;;
136+
--libdir) echo "/root/lib/lib" ;;
137+
--includedir) echo "/root/lib/include" ;;
138+
*) echo "--version --features --libs --cflags --includedir --libdir" ;;
139+
esac
140+
EOF
141+
142+
RUN chmod +x /root/install/bin/gdlib-config
143+
144+
RUN rm -rf /root/libgd-$GD_VERSION libgd.tar.gz
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
case "$1" in
3+
--version) echo 2.3.3 ;;
4+
--features) echo "PNG JPEG WEBP AVIF GIF XBM WBMP FREETYPE" ;;
5+
--libs) echo "-L/root/lib/lib -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif" ;;
6+
--cflags|--includes) echo "-I/root/lib/include" ;;
7+
--libdir) echo "/root/lib/lib" ;;
8+
--includedir) echo "/root/lib/include" ;;
9+
*) echo "--version --features --libs --cflags --includedir --libdir" ;;
10+
esac

0 commit comments

Comments
 (0)