diff --git a/config/ext.json b/config/ext.json index a3ec80410..9e0c3f3ee 100644 --- a/config/ext.json +++ b/config/ext.json @@ -21,11 +21,9 @@ "type": "builtin" }, "bz2": { - "support": { - "Windows": "wip" - }, "type": "builtin", - "arg-type": "with-prefix", + "arg-type-unix": "with-prefix", + "arg-type-windows": "with", "lib-depends": [ "bzip2" ] @@ -473,7 +471,6 @@ }, "pdo_sqlsrv": { "support": { - "Windows": "wip", "BSD": "wip" }, "type": "external", @@ -519,7 +516,6 @@ }, "rar": { "support": { - "Windows": "wip", "BSD": "wip", "Darwin": "partial" }, @@ -636,12 +632,11 @@ }, "sqlsrv": { "support": { - "Windows": "wip", "BSD": "wip" }, "type": "external", "source": "sqlsrv", - "lib-depends": [ + "lib-depends-unix": [ "unixodbc" ], "ext-depends-linux": [ @@ -925,12 +920,12 @@ }, "yaml": { "support": { - "Windows": "wip", "BSD": "wip" }, "type": "external", "source": "yaml", - "arg-type": "with-prefix", + "arg-type-unix": "with-prefix", + "arg-type-windows": "with", "lib-depends": [ "libyaml" ] @@ -943,8 +938,18 @@ "type": "builtin", "arg-type": "with-prefix", "arg-type-windows": "enable", - "lib-depends": [ + "lib-depends-unix": [ "libzip" + ], + "ext-depends-windows": [ + "zlib", + "bz2" + ], + "lib-depends-windows": [ + "libzip", + "zlib", + "bzip2", + "xz" ] }, "zlib": { diff --git a/config/lib.json b/config/lib.json index d57ba0dfa..faaef8656 100644 --- a/config/lib.json +++ b/config/lib.json @@ -21,10 +21,8 @@ "libbz2.a" ], "static-libs-windows": [ - [ - "libbz2.lib", - "libbz2_a.lib" - ] + "libbz2.lib", + "libbz2_a.lib" ], "headers": [ "bzlib.h" @@ -448,23 +446,30 @@ "libzip.a" ], "static-libs-windows": [ - [ - "zip.lib", - "libzip_a.lib" - ] + "zip.lib", + "libzip_a.lib" ], "headers": [ "zip.h", "zipconf.h" ], - "lib-depends": [ + "lib-depends-unix": [ "zlib" ], - "lib-suggests": [ + "lib-suggests-unix": [ "bzip2", "xz", "zstd", "openssl" + ], + "lib-depends-windows": [ + "zlib", + "bzip2", + "xz" + ], + "lib-suggests-windows": [ + "zstd", + "openssl" ] }, "ncurses": { @@ -625,10 +630,8 @@ "liblzma.a" ], "static-libs-windows": [ - [ - "liblzma.lib", - "liblzma_a.lib" - ] + "liblzma.lib", + "liblzma_a.lib" ], "headers-unix": [ "lzma" @@ -637,7 +640,7 @@ "lzma", "lzma.h" ], - "lib-depends": [ + "lib-depends-unix": [ "libiconv" ] }, diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index 4b50e6f27..1131ef129 100644 --- a/src/SPC/ConsoleApplication.php +++ b/src/SPC/ConsoleApplication.php @@ -25,7 +25,7 @@ */ final class ConsoleApplication extends Application { - public const VERSION = '2.2.4'; + public const VERSION = '2.3.0'; public function __construct() { diff --git a/src/SPC/builder/extension/sqlsrv.php b/src/SPC/builder/extension/sqlsrv.php new file mode 100644 index 000000000..edf5d919b --- /dev/null +++ b/src/SPC/builder/extension/sqlsrv.php @@ -0,0 +1,36 @@ +builder->getExt('pdo_sqlsrv') === null) { + // support sqlsrv without pdo_sqlsrv + FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/sqlsrv/config.w32', 'PHP_PDO_SQLSRV', '"no"'); + $this->pdo_sqlsrv_patched = true; + return true; + } + return false; + } + + public function patchBeforeConfigure(): bool + { + if ($this->pdo_sqlsrv_patched) { + // revert pdo_sqlsrv patch + FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/sqlsrv/config.w32', '"no" == "no"', 'PHP_PDO_SQLSRV == "no"'); + return true; + } + return false; + } +} diff --git a/src/SPC/builder/windows/library/bzip2.php b/src/SPC/builder/windows/library/bzip2.php new file mode 100644 index 000000000..81a74b0a9 --- /dev/null +++ b/src/SPC/builder/windows/library/bzip2.php @@ -0,0 +1,21 @@ +builder->makeSimpleWrapper('nmake /nologo /f Makefile.msc CFLAGS="-DWIN32 -MT -Ox -D_FILE_OFFSET_BITS=64 -nologo"'); + cmd()->cd($this->source_dir) + ->execWithWrapper($nmake, 'clean') + ->execWithWrapper($nmake, 'lib'); + copy($this->source_dir . '\libbz2.lib', BUILD_LIB_PATH . '\libbz2.lib'); + copy($this->source_dir . '\libbz2.lib', BUILD_LIB_PATH . '\libbz2_a.lib'); + copy($this->source_dir . '\bzlib.h', BUILD_INCLUDE_PATH . '\bzlib.h'); + } +} diff --git a/src/SPC/builder/windows/library/libyaml.php b/src/SPC/builder/windows/library/libyaml.php new file mode 100644 index 000000000..5d4026c58 --- /dev/null +++ b/src/SPC/builder/windows/library/libyaml.php @@ -0,0 +1,44 @@ +source_dir . '\build'); + + // check missing files: cmake\config.h.in and .\YamlConfig.cmake.in + if (!file_exists($this->source_dir . '\cmake\config.h.in')) { + FileSystem::createDir($this->source_dir . '\cmake'); + copy(ROOT_DIR . '\src\globals\extra\libyaml_config.h.in', $this->source_dir . '\cmake\config.h.in'); + } + if (!file_exists($this->source_dir . '\YamlConfig.cmake.in')) { + copy(ROOT_DIR . '\src\globals\extra\libyaml_YamlConfig.cmake.in', $this->source_dir . '\YamlConfig.cmake.in'); + } + + // 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 ' . + '-DBUILD_TESTING=OFF ' . + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' + ) + ->execWithWrapper( + $this->builder->makeSimpleWrapper('cmake'), + "--build build --config Release --target install -j{$this->builder->concurrency}" + ); + } +} diff --git a/src/SPC/builder/windows/library/libzip.php b/src/SPC/builder/windows/library/libzip.php new file mode 100644 index 000000000..9a8206af2 --- /dev/null +++ b/src/SPC/builder/windows/library/libzip.php @@ -0,0 +1,46 @@ +source_dir . '\build'); + + $openssl = $this->builder->getLib('openssl') ? 'ON' : 'OFF'; + $zstd = $this->builder->getLib('zstd') ? 'ON' : 'OFF'; + + // 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 ' . + '-DENABLE_BZIP2=ON ' . + '-DENABLE_LZMA=ON ' . + "-DENABLE_ZSTD={$zstd} " . + "-DENABLE_OPENSSL={$openssl} " . + '-DBUILD_TOOLS=OFF ' . + '-DBUILD_DOC=OFF ' . + '-DBUILD_EXAMPLES=OFF ' . + '-DBUILD_REGRESS=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 . '\zip.lib', BUILD_LIB_PATH . '\libzip_a.lib'); + } +} diff --git a/src/SPC/builder/windows/library/xz.php b/src/SPC/builder/windows/library/xz.php new file mode 100644 index 000000000..cf5b7234c --- /dev/null +++ b/src/SPC/builder/windows/library/xz.php @@ -0,0 +1,39 @@ +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}" + ); + + // copy liblzma.lib to liblzma_a.lib + copy(BUILD_LIB_PATH . '/liblzma.lib', BUILD_LIB_PATH . '/liblzma_a.lib'); + // patch lzma.h + FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '/lzma.h', 'defined(LZMA_API_STATIC)', 'defined(_WIN32)'); + } +} diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index 6295a8897..6d192bce6 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -521,7 +521,7 @@ private static function replaceFile(string $filename, int $replace_type = REPLAC private static function emitSourceExtractHook(string $name): void { foreach ((self::$_extract_hook[$name] ?? []) as $hook) { - if ($hook() === true) { + if ($hook($name) === true) { logger()->info('Patched source [' . $name . '] after extracted'); } } diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index 962386193..dc114fe2b 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -9,6 +9,7 @@ use SPC\builder\unix\UnixBuilderBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; class SourcePatcher { @@ -20,12 +21,18 @@ public static function init(): void FileSystem::addSourceExtractHook('swoole', [SourcePatcher::class, 'patchSwoole']); FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchPhpLibxml212']); FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchGDWin32']); + FileSystem::addSourceExtractHook('sqlsrv', [SourcePatcher::class, 'patchSQLSRVWin32']); + FileSystem::addSourceExtractHook('pdo_sqlsrv', [SourcePatcher::class, 'patchSQLSRVWin32']); + FileSystem::addSourceExtractHook('yaml', [SourcePatcher::class, 'patchYamlWin32']); } /** * Source patcher runner before buildconf * - * @param BuilderBase $builder Builder + * @param BuilderBase $builder Builder + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException */ public static function patchBeforeBuildconf(BuilderBase $builder): void { @@ -77,7 +84,7 @@ public static function patchBeforeConfigure(BuilderBase $builder): void * @throws RuntimeException * @throws FileSystemException */ - public static function patchMicro(?array $list = null, bool $reverse = false): bool + public static function patchMicro(): bool { if (!file_exists(SOURCE_PATH . '/php-src/sapi/micro/php_micro.c')) { return false; @@ -112,7 +119,7 @@ public static function patchMicro(?array $list = null, bool $reverse = false): b if (PHP_OS_FAMILY === 'Darwin') { $default[] = 'macos_iconv'; } - $patch_list = $list ?? $default; + $patch_list = $default; $patches = []; $serial = ['80', '81', '82', '83', '84']; foreach ($patch_list as $patchName) { @@ -135,7 +142,7 @@ public static function patchMicro(?array $list = null, bool $reverse = false): b f_passthru( 'cd ' . SOURCE_PATH . '/php-src && ' . - (PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . $patchesStr . ' | patch -p1 ' . ($reverse ? '-R' : '') + (PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . $patchesStr . ' | patch -p1 ' ); return true; @@ -183,6 +190,9 @@ public static function patchOpenssl11Darwin(): bool return false; } + /** + * @throws FileSystemException + */ public static function patchSwoole(): bool { // swoole hook needs pdo/pdo.h @@ -281,6 +291,9 @@ public static function unpatchHardcodedINI(): bool return $result; } + /** + * @throws FileSystemException + */ public static function patchMicroPhar(int $version_id): void { FileSystem::backupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c'); @@ -306,11 +319,35 @@ public static function patchMicroPhar(int $version_id): void } } + /** + * @throws RuntimeException + */ public static function unpatchMicroPhar(): void { FileSystem::restoreBackupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c'); } + /** + * Fix the compilation issue of sqlsrv and pdo_sqlsrv on Windows (/sdl check is too strict and will cause Zend compilation to fail) + * + * @throws FileSystemException + */ + public static function patchSQLSRVWin32(string $source_name): bool + { + $source_name = preg_replace('/[^a-z_]/', '', $source_name); + if (file_exists(SOURCE_PATH . '/php-src/ext/' . $source_name . '/config.w32')) { + FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/' . $source_name . '/config.w32', '/sdl', ''); + return true; + } + return false; + } + + public static function patchYamlWin32(): bool + { + FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/yaml/config.w32', "lib.substr(lib.length - 6, 6) == '_a.lib'", "lib.substr(lib.length - 6, 6) == '_a.lib' || 'yes' == 'yes'"); + return true; + } + /** * Patch cli SAPI Makefile for Windows. * @@ -325,7 +362,7 @@ public static function patchWindowsCLITarget(): void $line_num = 0; $found = false; foreach ($lines as $v) { - if (strpos($v, '$(BUILD_DIR)\php.exe:') !== false) { + if (str_contains($v, '$(BUILD_DIR)\php.exe:')) { $found = $line_num; break; } @@ -339,6 +376,9 @@ public static function patchWindowsCLITarget(): void FileSystem::writeFile(SOURCE_PATH . '/php-src/Makefile', implode("\r\n", $lines)); } + /** + * @throws RuntimeException + */ public static function patchPhpLibxml212(): bool { $file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h'); @@ -360,6 +400,9 @@ public static function patchPhpLibxml212(): bool return false; } + /** + * @throws FileSystemException + */ public static function patchGDWin32(): bool { $file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h'); @@ -393,6 +436,9 @@ public static function patchSPCVersionToPHP(string $version = 'unknown'): void } } + /** + * @throws FileSystemException + */ public static function patchMicroWin32(): void { // patch micro win32 diff --git a/src/globals/defines.php b/src/globals/defines.php index b18687566..bcd59a16a 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -43,6 +43,7 @@ 'core', 'hash', 'json', + 'pcre', 'reflection', 'spl', 'standard', diff --git a/src/globals/extra/libyaml_YamlConfig.cmake.in b/src/globals/extra/libyaml_YamlConfig.cmake.in new file mode 100644 index 000000000..839f3abab --- /dev/null +++ b/src/globals/extra/libyaml_YamlConfig.cmake.in @@ -0,0 +1,10 @@ +@PACKAGE_INIT@ + +set_and_check(yaml_TARGETS "@PACKAGE_CONFIG_DIR_CONFIG@/yamlTargets.cmake") + +if(NOT yaml_TARGETS_IMPORTED) + set(yaml_TARGETS_IMPORTED 1) + include(${yaml_TARGETS}) +endif() + +set(yaml_LIBRARIES yaml) \ No newline at end of file diff --git a/src/globals/extra/libyaml_config.h.in b/src/globals/extra/libyaml_config.h.in new file mode 100644 index 000000000..c92894bb2 --- /dev/null +++ b/src/globals/extra/libyaml_config.h.in @@ -0,0 +1,4 @@ +#define YAML_VERSION_MAJOR @YAML_VERSION_MAJOR@ +#define YAML_VERSION_MINOR @YAML_VERSION_MINOR@ +#define YAML_VERSION_PATCH @YAML_VERSION_PATCH@ +#define YAML_VERSION_STRING "@YAML_VERSION_STRING@" \ No newline at end of file diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index d49365bac..ff3993c07 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -20,13 +20,13 @@ // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { 'Linux', 'Darwin' => 'sockets', - 'Windows' => 'mbstring,pdo_sqlite,mbregex,gd', + 'Windows' => 'mbstring,pdo_sqlite,mbregex,bz2,sqlsrv,pdo_sqlsrv,yaml,zip,rar,apcu', }; // 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' => '', - 'Windows' => 'libjpeg,libwebp,libavif,freetype', + 'Windows' => '', }; // Please change your test base combination. We recommend testing with `common`.