Add full gd support on Windows (#484)

* Add full gd support (libjpeg, libpng, libwebp, libavif, freetype), and related patches

* cs fix

* Fix PHP 8.0 gd build
This commit is contained in:
Jerry Ma 2024-06-26 20:35:11 +08:00 committed by GitHub
parent 0b8a0504a2
commit 2a03c32bc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 2050 additions and 1634 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -90,6 +90,7 @@ class SystemUtil
$buildroot = str_replace('\\', '\\\\', BUILD_ROOT_PATH);
$toolchain = <<<CMAKE
set(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_PROCESSOR x64)
SET(CMAKE_C_FLAGS "{$cflags}")
SET(CMAKE_C_FLAGS_DEBUG "{$cflags}")
SET(CMAKE_CXX_FLAGS "{$cflags}")

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class freetype extends WindowsLibraryBase
{
public const NAME = 'freetype';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
// freetype.lib to libfreetype_a.lib
copy(BUILD_LIB_PATH . '\freetype.lib', BUILD_LIB_PATH . '\libfreetype_a.lib');
}
}

View File

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libavif extends WindowsLibraryBase
{
public const NAME = 'libavif';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DAVIF_BUILD_APPS=OFF ' .
'-DAVIF_BUILD_TESTS=OFF ' .
'-DAVID_ENABLE_GTEST=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
}
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libjpeg extends WindowsLibraryBase
{
public const NAME = 'libjpeg';
protected function build(): void
{
$zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DENABLE_SHARED=OFF ' .
'-DENABLE_STATIC=ON ' .
'-DBUILD_TESTING=OFF ' .
'-DWITH_JAVA=OFF ' .
'-DWITH_CRT_DLL=OFF ' .
"-DENABLE_ZLIB_COMPRESSION={$zlib} " .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
copy(BUILD_LIB_PATH . '\jpeg-static.lib', BUILD_LIB_PATH . '\libjpeg_a.lib');
}
}

View File

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libpng extends WindowsLibraryBase
{
public const NAME = 'libpng';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DSKIP_INSTALL_PROGRAM=ON ' .
'-DSKIP_INSTALL_FILES=ON ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DPNG_STATIC=ON ' .
'-DPNG_SHARED=OFF ' .
'-DPNG_TESTS=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
copy(BUILD_LIB_PATH . '\libpng16_static.lib', BUILD_LIB_PATH . '\libpng_a.lib');
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libwebp extends WindowsLibraryBase
{
public const NAME = 'libwebp';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DWEBP_LINK_STATIC=ON ' .
'-DWEBP_BUILD_ANIM_UTILS=OFF ' .
'-DWEBP_BUILD_CWEBP=OFF ' .
'-DWEBP_BUILD_DWEBP=OFF ' .
'-DWEBP_BUILD_GIF2WEBP=OFF ' .
'-DWEBP_BUILD_IMG2WEBP=OFF ' .
'-DWEBP_BUILD_VWEBP=OFF ' .
'-DWEBP_BUILD_WEBPINFO=OFF ' .
'-DWEBP_BUILD_LIBWEBPMUX=OFF ' .
'-DWEBP_BUILD_WEBPMUX=OFF ' .
'-DWEBP_BUILD_EXTRAS=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
}
}

View File

@ -19,6 +19,7 @@ class SourcePatcher
FileSystem::addSourceExtractHook('openssl', [SourcePatcher::class, 'patchOpenssl11Darwin']);
FileSystem::addSourceExtractHook('swoole', [SourcePatcher::class, 'patchSwoole']);
FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchPhpLibxml212']);
FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchGDWin32']);
}
/**
@ -359,6 +360,23 @@ class SourcePatcher
return false;
}
public static function patchGDWin32(): bool
{
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
$ver_id = intval($match[1]);
if ($ver_id < 80200) {
// see: https://github.com/php/php-src/commit/243966177e39eb71822935042c3f13fa6c5b9eed
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/gd/libgd/gdft.c', '#ifndef MSWIN32', '#ifndef _WIN32');
}
// custom config.w32, because official config.w32 is hard-coded many things
$origin = $ver_id >= 80100 ? file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_81.w32') : file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_80.w32');
file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32.bak', file_get_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32'));
return file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32', $origin) !== false;
}
return false;
}
/**
* Add additional `static-php-cli.version` ini value for PHP source.
*

View File

@ -0,0 +1,86 @@
// vim:ft=javascript
ARG_WITH("gd", "Bundled GD support", "yes");
if (PHP_GD != "no") {
// check for gd.h (required)
if (!CHECK_HEADER_ADD_INCLUDE("gd.h", "CFLAGS_GD", PHP_GD + ";ext\\gd\\libgd")) {
ERROR("gd not enabled; libraries and headers not found");
}
// zlib ext support (required)
if (!CHECK_LIB("zlib_a.lib;zlib.lib", "gd", PHP_GD)) {
ERROR("gd not enabled; zlib not enabled");
}
// libjpeg lib support
if (CHECK_LIB("libjpeg_a.lib;libjpeg.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("jpeglib.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include")) {
AC_DEFINE("HAVE_LIBJPEG", 1, "JPEG support");
AC_DEFINE("HAVE_GD_JPG", 1, "JPEG support");
}
// libpng16 lib support
if (CHECK_LIB("libpng_a.lib;libpng.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng16")) {
AC_DEFINE("HAVE_LIBPNG", 1, "PNG support");
AC_DEFINE("HAVE_GD_PNG", 1, "PNG support");
}
// freetype lib support
if (CHECK_LIB("libfreetype_a.lib;libfreetype.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("ft2build.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\freetype2;" + PHP_PHP_BUILD + "\\include\\freetype")) {
AC_DEFINE("HAVE_LIBFREETYPE", 1, "FreeType support");
AC_DEFINE("HAVE_GD_FREETYPE", 1, "FreeType support");
}
// xpm lib support
if (CHECK_LIB("libXpm_a.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("xpm.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\X11")) {
AC_DEFINE("HAVE_LIBXPM", 1, "XPM support");
AC_DEFINE("HAVE_GD_XPM", 1, "XPM support");
}
// iconv lib support
if ((CHECK_LIB("libiconv_a.lib;libiconv.lib", "gd", PHP_GD) || CHECK_LIB("iconv_a.lib;iconv.lib", "gd", PHP_GD)) &&
CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_GD", PHP_GD)) {
AC_DEFINE("HAVE_LIBICONV", 1, "Iconv support");
}
// libwebp lib support
if ((CHECK_LIB("libwebp_a.lib", "gd", PHP_GD) || CHECK_LIB("libwebp.lib", "gd", PHP_GD)) &&
CHECK_LIB("libsharpyuv.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("decode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp") &&
CHECK_HEADER_ADD_INCLUDE("encode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp")) {
AC_DEFINE("HAVE_LIBWEBP", 1, "WebP support");
AC_DEFINE("HAVE_GD_WEBP", 1, "WebP support");
}
// libavif lib is not supported on php <= 8.0
CHECK_LIB("User32.lib", "gd", PHP_GD);
CHECK_LIB("Gdi32.lib", "gd", PHP_GD);
EXTENSION("gd", "gd.c", null, "-Iext/gd/libgd");
ADD_SOURCES("ext/gd/libgd", "gd.c \
gdcache.c gdfontg.c gdfontl.c gdfontmb.c gdfonts.c gdfontt.c \
gdft.c gd_gd2.c gd_gd.c gd_gif_in.c gd_gif_out.c gdhelpers.c gd_io.c gd_io_dp.c \
gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \
gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c gd_xbm.c gd_security.c gd_transform.c \
gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c \
gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c", "gd");
AC_DEFINE('HAVE_LIBGD', 1, 'GD support');
AC_DEFINE('HAVE_GD_BUNDLED', 1, "Bundled GD");
AC_DEFINE('HAVE_GD_BMP', 1, "BMP support");
AC_DEFINE('HAVE_GD_TGA', 1, "TGA support");
ADD_FLAG("CFLAGS_GD", " \
/D PHP_GD_EXPORTS=1 \
/D HAVE_GD_GET_INTERPOLATION \
");
if (ICC_TOOLSET) {
ADD_FLAG("LDFLAGS_GD", "/nodefaultlib:libcmt");
}
PHP_INSTALL_HEADERS("", "ext/gd ext/gd/libgd");
}

View File

@ -0,0 +1,94 @@
// vim:ft=javascript
ARG_WITH("gd", "Bundled GD support", "yes");
if (PHP_GD != "no") {
// check for gd.h (required)
if (!CHECK_HEADER_ADD_INCLUDE("gd.h", "CFLAGS_GD", PHP_GD + ";ext\\gd\\libgd")) {
ERROR("gd not enabled; libraries and headers not found");
}
// zlib ext support (required)
if (!CHECK_LIB("zlib_a.lib;zlib.lib", "gd", PHP_GD)) {
ERROR("gd not enabled; zlib not enabled");
}
// libjpeg lib support
if (CHECK_LIB("libjpeg_a.lib;libjpeg.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("jpeglib.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include")) {
AC_DEFINE("HAVE_LIBJPEG", 1, "JPEG support");
AC_DEFINE("HAVE_GD_JPG", 1, "JPEG support");
}
// libpng16 lib support
if (CHECK_LIB("libpng_a.lib;libpng.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng16")) {
AC_DEFINE("HAVE_LIBPNG", 1, "PNG support");
AC_DEFINE("HAVE_GD_PNG", 1, "PNG support");
}
// freetype lib support
if (CHECK_LIB("libfreetype_a.lib;libfreetype.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("ft2build.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\freetype2;" + PHP_PHP_BUILD + "\\include\\freetype")) {
AC_DEFINE("HAVE_LIBFREETYPE", 1, "FreeType support");
AC_DEFINE("HAVE_GD_FREETYPE", 1, "FreeType support");
}
// xpm lib support
if (CHECK_LIB("libXpm_a.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("xpm.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\X11")) {
AC_DEFINE("HAVE_LIBXPM", 1, "XPM support");
AC_DEFINE("HAVE_GD_XPM", 1, "XPM support");
}
// iconv lib support
if ((CHECK_LIB("libiconv_a.lib;libiconv.lib", "gd", PHP_GD) || CHECK_LIB("iconv_a.lib;iconv.lib", "gd", PHP_GD)) &&
CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_GD", PHP_GD)) {
AC_DEFINE("HAVE_LIBICONV", 1, "Iconv support");
}
// libwebp lib support
if ((CHECK_LIB("libwebp_a.lib", "gd", PHP_GD) || CHECK_LIB("libwebp.lib", "gd", PHP_GD)) &&
CHECK_LIB("libsharpyuv.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("decode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp") &&
CHECK_HEADER_ADD_INCLUDE("encode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp")) {
AC_DEFINE("HAVE_LIBWEBP", 1, "WebP support");
AC_DEFINE("HAVE_GD_WEBP", 1, "WebP support");
}
// libavif lib support
if (CHECK_LIB("avif_a.lib", "gd", PHP_GD) &&
CHECK_LIB("aom_a.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) {
ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBAVIF /D HAVE_GD_AVIF");
} else if (CHECK_LIB("avif.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) {
ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBAVIF /D HAVE_GD_AVIF");
}
CHECK_LIB("User32.lib", "gd", PHP_GD);
CHECK_LIB("Gdi32.lib", "gd", PHP_GD);
EXTENSION("gd", "gd.c", null, "-Iext/gd/libgd");
ADD_SOURCES("ext/gd/libgd", "gd.c \
gdcache.c gdfontg.c gdfontl.c gdfontmb.c gdfonts.c gdfontt.c \
gdft.c gd_gd2.c gd_gd.c gd_gif_in.c gd_gif_out.c gdhelpers.c gd_io.c gd_io_dp.c \
gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \
gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c gd_xbm.c gd_security.c gd_transform.c \
gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c gd_avif.c \
gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c", "gd");
AC_DEFINE('HAVE_LIBGD', 1, 'GD support');
AC_DEFINE('HAVE_GD_BUNDLED', 1, "Bundled GD");
AC_DEFINE('HAVE_GD_BMP', 1, "BMP support");
AC_DEFINE('HAVE_GD_TGA', 1, "TGA support");
ADD_FLAG("CFLAGS_GD", " \
/D PHP_GD_EXPORTS=1 \
/D HAVE_GD_GET_INTERPOLATION \
");
if (ICC_TOOLSET) {
ADD_FLAG("LDFLAGS_GD", "/nodefaultlib:libcmt");
}
PHP_INSTALL_HEADERS("", "ext/gd ext/gd/libgd");
}

View File

@ -19,14 +19,14 @@ $upx = true;
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'imagick,gmp',
'Windows' => 'mbstring,pdo_sqlite,mbregex',
'Linux', 'Darwin' => 'sockets',
'Windows' => 'mbstring,pdo_sqlite,mbregex,gd',
};
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
$with_libs = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'libtiff',
'Windows' => '',
'Linux', 'Darwin' => '',
'Windows' => 'libjpeg,libwebp,libavif,freetype',
};
// Please change your test base combination. We recommend testing with `common`.