Skip to content

Commit 2a03c32

Browse files
authored
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
1 parent 0b8a050 commit 2a03c32

File tree

12 files changed

+2050
-1634
lines changed

12 files changed

+2050
-1634
lines changed

config/ext.json

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

config/lib.json

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

src/SPC/builder/windows/SystemUtil.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public static function makeCmakeToolchainFile(?string $cflags = null, ?string $l
9090
$buildroot = str_replace('\\', '\\\\', BUILD_ROOT_PATH);
9191
$toolchain = <<<CMAKE
9292
set(CMAKE_SYSTEM_NAME Windows)
93+
SET(CMAKE_SYSTEM_PROCESSOR x64)
9394
SET(CMAKE_C_FLAGS "{$cflags}")
9495
SET(CMAKE_C_FLAGS_DEBUG "{$cflags}")
9596
SET(CMAKE_CXX_FLAGS "{$cflags}")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SPC\builder\windows\library;
6+
7+
use SPC\store\FileSystem;
8+
9+
class freetype extends WindowsLibraryBase
10+
{
11+
public const NAME = 'freetype';
12+
13+
protected function build(): void
14+
{
15+
// reset cmake
16+
FileSystem::resetDir($this->source_dir . '\build');
17+
18+
// start build
19+
cmd()->cd($this->source_dir)
20+
->execWithWrapper(
21+
$this->builder->makeSimpleWrapper('cmake'),
22+
'-B build ' .
23+
'-A x64 ' .
24+
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
25+
'-DCMAKE_BUILD_TYPE=Release ' .
26+
'-DBUILD_SHARED_LIBS=OFF ' .
27+
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
28+
)
29+
->execWithWrapper(
30+
$this->builder->makeSimpleWrapper('cmake'),
31+
"--build build --config Release --target install -j{$this->builder->concurrency}"
32+
);
33+
// freetype.lib to libfreetype_a.lib
34+
copy(BUILD_LIB_PATH . '\freetype.lib', BUILD_LIB_PATH . '\libfreetype_a.lib');
35+
}
36+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SPC\builder\windows\library;
6+
7+
use SPC\store\FileSystem;
8+
9+
class libavif extends WindowsLibraryBase
10+
{
11+
public const NAME = 'libavif';
12+
13+
protected function build(): void
14+
{
15+
// reset cmake
16+
FileSystem::resetDir($this->source_dir . '\build');
17+
18+
// start build
19+
cmd()->cd($this->source_dir)
20+
->execWithWrapper(
21+
$this->builder->makeSimpleWrapper('cmake'),
22+
'-B build ' .
23+
'-A x64 ' .
24+
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
25+
'-DCMAKE_BUILD_TYPE=Release ' .
26+
'-DBUILD_SHARED_LIBS=OFF ' .
27+
'-DAVIF_BUILD_APPS=OFF ' .
28+
'-DAVIF_BUILD_TESTS=OFF ' .
29+
'-DAVID_ENABLE_GTEST=OFF ' .
30+
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
31+
)
32+
->execWithWrapper(
33+
$this->builder->makeSimpleWrapper('cmake'),
34+
"--build build --config Release --target install -j{$this->builder->concurrency}"
35+
);
36+
}
37+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SPC\builder\windows\library;
6+
7+
use SPC\store\FileSystem;
8+
9+
class libjpeg extends WindowsLibraryBase
10+
{
11+
public const NAME = 'libjpeg';
12+
13+
protected function build(): void
14+
{
15+
$zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
16+
// reset cmake
17+
FileSystem::resetDir($this->source_dir . '\build');
18+
19+
// start build
20+
cmd()->cd($this->source_dir)
21+
->execWithWrapper(
22+
$this->builder->makeSimpleWrapper('cmake'),
23+
'-B build ' .
24+
'-A x64 ' .
25+
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
26+
'-DCMAKE_BUILD_TYPE=Release ' .
27+
'-DENABLE_SHARED=OFF ' .
28+
'-DENABLE_STATIC=ON ' .
29+
'-DBUILD_TESTING=OFF ' .
30+
'-DWITH_JAVA=OFF ' .
31+
'-DWITH_CRT_DLL=OFF ' .
32+
"-DENABLE_ZLIB_COMPRESSION={$zlib} " .
33+
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
34+
)
35+
->execWithWrapper(
36+
$this->builder->makeSimpleWrapper('cmake'),
37+
"--build build --config Release --target install -j{$this->builder->concurrency}"
38+
);
39+
copy(BUILD_LIB_PATH . '\jpeg-static.lib', BUILD_LIB_PATH . '\libjpeg_a.lib');
40+
}
41+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SPC\builder\windows\library;
6+
7+
use SPC\store\FileSystem;
8+
9+
class libpng extends WindowsLibraryBase
10+
{
11+
public const NAME = 'libpng';
12+
13+
protected function build(): void
14+
{
15+
// reset cmake
16+
FileSystem::resetDir($this->source_dir . '\build');
17+
18+
// start build
19+
cmd()->cd($this->source_dir)
20+
->execWithWrapper(
21+
$this->builder->makeSimpleWrapper('cmake'),
22+
'-B build ' .
23+
'-A x64 ' .
24+
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
25+
'-DCMAKE_BUILD_TYPE=Release ' .
26+
'-DSKIP_INSTALL_PROGRAM=ON ' .
27+
'-DSKIP_INSTALL_FILES=ON ' .
28+
'-DBUILD_SHARED_LIBS=OFF ' .
29+
'-DPNG_STATIC=ON ' .
30+
'-DPNG_SHARED=OFF ' .
31+
'-DPNG_TESTS=OFF ' .
32+
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
33+
)
34+
->execWithWrapper(
35+
$this->builder->makeSimpleWrapper('cmake'),
36+
"--build build --config Release --target install -j{$this->builder->concurrency}"
37+
);
38+
copy(BUILD_LIB_PATH . '\libpng16_static.lib', BUILD_LIB_PATH . '\libpng_a.lib');
39+
}
40+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SPC\builder\windows\library;
6+
7+
use SPC\store\FileSystem;
8+
9+
class libwebp extends WindowsLibraryBase
10+
{
11+
public const NAME = 'libwebp';
12+
13+
protected function build(): void
14+
{
15+
// reset cmake
16+
FileSystem::resetDir($this->source_dir . '\build');
17+
18+
// start build
19+
cmd()->cd($this->source_dir)
20+
->execWithWrapper(
21+
$this->builder->makeSimpleWrapper('cmake'),
22+
'-B build ' .
23+
'-A x64 ' .
24+
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
25+
'-DCMAKE_BUILD_TYPE=Release ' .
26+
'-DBUILD_SHARED_LIBS=OFF ' .
27+
'-DWEBP_LINK_STATIC=ON ' .
28+
'-DWEBP_BUILD_ANIM_UTILS=OFF ' .
29+
'-DWEBP_BUILD_CWEBP=OFF ' .
30+
'-DWEBP_BUILD_DWEBP=OFF ' .
31+
'-DWEBP_BUILD_GIF2WEBP=OFF ' .
32+
'-DWEBP_BUILD_IMG2WEBP=OFF ' .
33+
'-DWEBP_BUILD_VWEBP=OFF ' .
34+
'-DWEBP_BUILD_WEBPINFO=OFF ' .
35+
'-DWEBP_BUILD_LIBWEBPMUX=OFF ' .
36+
'-DWEBP_BUILD_WEBPMUX=OFF ' .
37+
'-DWEBP_BUILD_EXTRAS=OFF ' .
38+
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
39+
)
40+
->execWithWrapper(
41+
$this->builder->makeSimpleWrapper('cmake'),
42+
"--build build --config Release --target install -j{$this->builder->concurrency}"
43+
);
44+
}
45+
}

src/SPC/store/SourcePatcher.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public static function init(): void
1919
FileSystem::addSourceExtractHook('openssl', [SourcePatcher::class, 'patchOpenssl11Darwin']);
2020
FileSystem::addSourceExtractHook('swoole', [SourcePatcher::class, 'patchSwoole']);
2121
FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchPhpLibxml212']);
22+
FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchGDWin32']);
2223
}
2324

2425
/**
@@ -359,6 +360,23 @@ public static function patchPhpLibxml212(): bool
359360
return false;
360361
}
361362

363+
public static function patchGDWin32(): bool
364+
{
365+
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
366+
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
367+
$ver_id = intval($match[1]);
368+
if ($ver_id < 80200) {
369+
// see: https://github.com/php/php-src/commit/243966177e39eb71822935042c3f13fa6c5b9eed
370+
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/gd/libgd/gdft.c', '#ifndef MSWIN32', '#ifndef _WIN32');
371+
}
372+
// custom config.w32, because official config.w32 is hard-coded many things
373+
$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');
374+
file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32.bak', file_get_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32'));
375+
return file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32', $origin) !== false;
376+
}
377+
return false;
378+
}
379+
362380
/**
363381
* Add additional `static-php-cli.version` ini value for PHP source.
364382
*

src/globals/extra/gd_config_80.w32

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// vim:ft=javascript
2+
3+
ARG_WITH("gd", "Bundled GD support", "yes");
4+
5+
if (PHP_GD != "no") {
6+
// check for gd.h (required)
7+
if (!CHECK_HEADER_ADD_INCLUDE("gd.h", "CFLAGS_GD", PHP_GD + ";ext\\gd\\libgd")) {
8+
ERROR("gd not enabled; libraries and headers not found");
9+
}
10+
11+
// zlib ext support (required)
12+
if (!CHECK_LIB("zlib_a.lib;zlib.lib", "gd", PHP_GD)) {
13+
ERROR("gd not enabled; zlib not enabled");
14+
}
15+
16+
// libjpeg lib support
17+
if (CHECK_LIB("libjpeg_a.lib;libjpeg.lib", "gd", PHP_GD) &&
18+
CHECK_HEADER_ADD_INCLUDE("jpeglib.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include")) {
19+
AC_DEFINE("HAVE_LIBJPEG", 1, "JPEG support");
20+
AC_DEFINE("HAVE_GD_JPG", 1, "JPEG support");
21+
}
22+
23+
// libpng16 lib support
24+
if (CHECK_LIB("libpng_a.lib;libpng.lib", "gd", PHP_GD) &&
25+
CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng16")) {
26+
AC_DEFINE("HAVE_LIBPNG", 1, "PNG support");
27+
AC_DEFINE("HAVE_GD_PNG", 1, "PNG support");
28+
}
29+
30+
// freetype lib support
31+
if (CHECK_LIB("libfreetype_a.lib;libfreetype.lib", "gd", PHP_GD) &&
32+
CHECK_HEADER_ADD_INCLUDE("ft2build.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\freetype2;" + PHP_PHP_BUILD + "\\include\\freetype")) {
33+
AC_DEFINE("HAVE_LIBFREETYPE", 1, "FreeType support");
34+
AC_DEFINE("HAVE_GD_FREETYPE", 1, "FreeType support");
35+
}
36+
37+
// xpm lib support
38+
if (CHECK_LIB("libXpm_a.lib", "gd", PHP_GD) &&
39+
CHECK_HEADER_ADD_INCLUDE("xpm.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\X11")) {
40+
AC_DEFINE("HAVE_LIBXPM", 1, "XPM support");
41+
AC_DEFINE("HAVE_GD_XPM", 1, "XPM support");
42+
}
43+
44+
// iconv lib support
45+
if ((CHECK_LIB("libiconv_a.lib;libiconv.lib", "gd", PHP_GD) || CHECK_LIB("iconv_a.lib;iconv.lib", "gd", PHP_GD)) &&
46+
CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_GD", PHP_GD)) {
47+
AC_DEFINE("HAVE_LIBICONV", 1, "Iconv support");
48+
}
49+
50+
// libwebp lib support
51+
if ((CHECK_LIB("libwebp_a.lib", "gd", PHP_GD) || CHECK_LIB("libwebp.lib", "gd", PHP_GD)) &&
52+
CHECK_LIB("libsharpyuv.lib", "gd", PHP_GD) &&
53+
CHECK_HEADER_ADD_INCLUDE("decode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp") &&
54+
CHECK_HEADER_ADD_INCLUDE("encode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp")) {
55+
AC_DEFINE("HAVE_LIBWEBP", 1, "WebP support");
56+
AC_DEFINE("HAVE_GD_WEBP", 1, "WebP support");
57+
}
58+
59+
// libavif lib is not supported on php <= 8.0
60+
61+
CHECK_LIB("User32.lib", "gd", PHP_GD);
62+
CHECK_LIB("Gdi32.lib", "gd", PHP_GD);
63+
64+
EXTENSION("gd", "gd.c", null, "-Iext/gd/libgd");
65+
ADD_SOURCES("ext/gd/libgd", "gd.c \
66+
gdcache.c gdfontg.c gdfontl.c gdfontmb.c gdfonts.c gdfontt.c \
67+
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 \
68+
gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \
69+
gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c gd_xbm.c gd_security.c gd_transform.c \
70+
gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c \
71+
gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c", "gd");
72+
73+
AC_DEFINE('HAVE_LIBGD', 1, 'GD support');
74+
AC_DEFINE('HAVE_GD_BUNDLED', 1, "Bundled GD");
75+
AC_DEFINE('HAVE_GD_BMP', 1, "BMP support");
76+
AC_DEFINE('HAVE_GD_TGA', 1, "TGA support");
77+
ADD_FLAG("CFLAGS_GD", " \
78+
/D PHP_GD_EXPORTS=1 \
79+
/D HAVE_GD_GET_INTERPOLATION \
80+
");
81+
if (ICC_TOOLSET) {
82+
ADD_FLAG("LDFLAGS_GD", "/nodefaultlib:libcmt");
83+
}
84+
85+
PHP_INSTALL_HEADERS("", "ext/gd ext/gd/libgd");
86+
}

0 commit comments

Comments
 (0)