diff --git a/config/source.json b/config/source.json index 5fbf8c4c..a14ac41a 100644 --- a/config/source.json +++ b/config/source.json @@ -1194,7 +1194,6 @@ "path": "php-src/ext/swoole", "type": "ghtar", "repo": "swoole/swoole-src", - "match": "v6\\.+", "prefer-stable": true, "license": { "type": "file", diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index 9685a1d8..b2cf9671 100644 --- a/src/SPC/ConsoleApplication.php +++ b/src/SPC/ConsoleApplication.php @@ -34,7 +34,7 @@ use Symfony\Component\Console\Application; */ final class ConsoleApplication extends Application { - public const string VERSION = '2.8.5'; + public const string VERSION = '2.8.6'; public function __construct() { diff --git a/src/SPC/builder/extension/mongodb.php b/src/SPC/builder/extension/mongodb.php index 08861e4e..64108d5c 100644 --- a/src/SPC/builder/extension/mongodb.php +++ b/src/SPC/builder/extension/mongodb.php @@ -5,11 +5,22 @@ declare(strict_types=1); namespace SPC\builder\extension; use SPC\builder\Extension; +use SPC\store\FileSystem; use SPC\util\CustomExt; #[CustomExt('mongodb')] class mongodb extends Extension { + public function patchBeforeBuildconf(): bool + { + FileSystem::replaceFileRegex( + SOURCE_PATH . '/php-src/ext/mongodb/config.m4', + '/^(\s+)(src\/libmongoc\/)/m', + '$1${ac_config_dir}/$2' + ); + return true; + } + public function getUnixConfigureArg(bool $shared = false): string { $arg = ' --enable-mongodb' . ($shared ? '=shared' : '') . ' '; diff --git a/src/SPC/builder/unix/library/libde265.php b/src/SPC/builder/unix/library/libde265.php index 184a4426..116f67aa 100644 --- a/src/SPC/builder/unix/library/libde265.php +++ b/src/SPC/builder/unix/library/libde265.php @@ -13,7 +13,8 @@ trait libde265 UnixCMakeExecutor::create($this) ->addConfigureArgs( '-DENABLE_SDL=OFF', - '-DENABLE_DECODER=OFF' + '-DENABLE_DECODER=OFF', + '-DHAVE_NEON=OFF', ) ->build(); $this->patchPkgconfPrefix(['libde265.pc']); diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index ccf61dd8..98d9f495 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -98,31 +98,50 @@ class Downloader { logger()->debug("finding {$name} source from github {$type} tarball"); $source['query'] ??= ''; - $data = json_decode(self::curlExec( - url: "https://api.github.com/repos/{$source['repo']}/{$type}{$source['query']}", - hooks: [[CurlHook::class, 'setupGithubToken']], - retries: self::getRetryAttempts() - ), true, 512, JSON_THROW_ON_ERROR); - $url = null; - foreach ($data as $rel) { - if (($rel['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) { - continue; + // Use /releases/latest when possible: it returns the semantically latest stable + // release regardless of publish order, avoiding issues with concurrent release branches. + if ($type === 'releases' && empty($source['query']) && !($source['match'] ?? null)) { + $data = json_decode(self::curlExec( + url: "https://api.github.com/repos/{$source['repo']}/releases/latest", + hooks: [[CurlHook::class, 'setupGithubToken']], + retries: self::getRetryAttempts() + ), true, 512, JSON_THROW_ON_ERROR); + if (!is_array($data) || empty($data['tarball_url'])) { + throw new DownloaderException("failed to find {$name} source"); } - if (($rel['draft'] ?? false) === true && (($source['prefer-stable'] ?? false) || !$rel['tarball_url'])) { - continue; + $url = $data['tarball_url']; + $version = $data['tag_name'] ?? $data['name'] ?? null; + } else { + $data = json_decode(self::curlExec( + url: "https://api.github.com/repos/{$source['repo']}/{$type}{$source['query']}", + hooks: [[CurlHook::class, 'setupGithubToken']], + retries: self::getRetryAttempts() + ), true, 512, JSON_THROW_ON_ERROR); + + $url = null; + $version = null; + foreach ($data as $rel) { + if (($rel['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) { + continue; + } + if (($rel['draft'] ?? false) === true && (($source['prefer-stable'] ?? false) || !$rel['tarball_url'])) { + continue; + } + if (!($source['match'] ?? null)) { + $url = $rel['tarball_url'] ?? null; + $version = $rel['tag_name'] ?? $rel['name'] ?? null; + break; + } + if (preg_match('|' . $source['match'] . '|', $rel['tarball_url'])) { + $url = $rel['tarball_url']; + $version = $rel['tag_name'] ?? $rel['name'] ?? null; + break; + } } - if (!($source['match'] ?? null)) { - $url = $rel['tarball_url'] ?? null; - break; + if (!$url) { + throw new DownloaderException("failed to find {$name} source"); } - if (preg_match('|' . $source['match'] . '|', $rel['tarball_url'])) { - $url = $rel['tarball_url']; - break; - } - } - if (!$url) { - throw new DownloaderException("failed to find {$name} source"); } $headers = self::curlExec( url: $url, @@ -134,7 +153,7 @@ class Downloader if ($matches) { $filename = $matches['filename']; } else { - $filename = "{$name}-" . ($type === 'releases' ? $data['tag_name'] : $data['name']) . '.tar.gz'; + $filename = "{$name}-" . ($version ?? 'latest') . '.tar.gz'; } return [$url, $filename]; diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index 7ce2d200..772ccbb5 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -95,6 +95,10 @@ class SourcePatcher // patch php-src/build/php.m4 PKG_CHECK_MODULES -> PKG_CHECK_MODULES_STATIC FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/build/php.m4', 'PKG_CHECK_MODULES(', 'PKG_CHECK_MODULES_STATIC('); + if ($builder->getPHPVersionID() >= 80300 && $builder->getPHPVersionID() < 80400) { + self::patchFile('spc_fix_avx512_cache_before_80400.patch', SOURCE_PATH . '/php-src'); + } + if ($builder->getOption('enable-micro-win32')) { self::patchMicroWin32(); } else { diff --git a/src/globals/defines.php b/src/globals/defines.php index 36ffba79..dae0c491 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -25,12 +25,16 @@ const DANGER_CMD = [ // spc internal extensions const SPC_INTERNAL_EXTENSIONS = [ 'core', + 'date', 'hash', 'json', + 'lexbor', 'pcre', + 'random', 'reflection', 'spl', 'standard', + 'uri', ]; // spc extension alias diff --git a/src/globals/patch/spc_fix_avx512_cache_before_80400.patch b/src/globals/patch/spc_fix_avx512_cache_before_80400.patch new file mode 100644 index 00000000..79393c01 --- /dev/null +++ b/src/globals/patch/spc_fix_avx512_cache_before_80400.patch @@ -0,0 +1,91 @@ +--- a/build/php.m4 ++++ b/build/php.m4 +@@ -2812,27 +2812,26 @@ + dnl PHP_CHECK_AVX512_SUPPORTS + dnl + AC_DEFUN([PHP_CHECK_AVX512_SUPPORTS], [ +- AC_MSG_CHECKING([for avx512 supports in compiler]) +- save_CFLAGS="$CFLAGS" +- CFLAGS="-mavx512f -mavx512cd -mavx512vl -mavx512dq -mavx512bw $CFLAGS" +- +- AC_LINK_IFELSE([AC_LANG_SOURCE([[ +- #include +- int main(void) { +- __m512i mask = _mm512_set1_epi32(0x1); +- char out[32]; +- _mm512_storeu_si512(out, _mm512_shuffle_epi8(mask, mask)); +- return 0; +- }]])], [ ++ AC_CACHE_CHECK([whether compiler supports AVX-512], [php_cv_have_avx512], [ ++ save_CFLAGS="$CFLAGS" ++ CFLAGS="-mavx512f -mavx512cd -mavx512vl -mavx512dq -mavx512bw $CFLAGS" ++ AC_LINK_IFELSE([AC_LANG_SOURCE([[ ++ #include ++ int main(void) { ++ __m512i mask = _mm512_set1_epi32(0x1); ++ char out[32]; ++ _mm512_storeu_si512(out, _mm512_shuffle_epi8(mask, mask)); ++ return 0; ++ }]])], ++ [php_cv_have_avx512=yes], ++ [php_cv_have_avx512=no]) ++ CFLAGS="$save_CFLAGS" ++ ]) ++ if test "$php_cv_have_avx512" = "yes"; then + have_avx512_supports=1 +- AC_MSG_RESULT([yes]) +- ], [ ++ else + have_avx512_supports=0 +- AC_MSG_RESULT([no]) +- ]) +- +- CFLAGS="$save_CFLAGS" +- ++ fi + AC_DEFINE_UNQUOTED([PHP_HAVE_AVX512_SUPPORTS], + [$have_avx512_supports], [Whether the compiler supports AVX512]) + ]) +@@ -2841,24 +2840,26 @@ + dnl PHP_CHECK_AVX512_VBMI_SUPPORTS + dnl + AC_DEFUN([PHP_CHECK_AVX512_VBMI_SUPPORTS], [ +- AC_MSG_CHECKING([for avx512 vbmi supports in compiler]) +- save_CFLAGS="$CFLAGS" +- CFLAGS="-mavx512f -mavx512cd -mavx512vl -mavx512dq -mavx512bw -mavx512vbmi $CFLAGS" +- AC_LINK_IFELSE([AC_LANG_SOURCE([[ +- #include +- int main(void) { +- __m512i mask = _mm512_set1_epi32(0x1); +- char out[32]; +- _mm512_storeu_si512(out, _mm512_permutexvar_epi8(mask, mask)); +- return 0; +- }]])], [ ++ AC_CACHE_CHECK([whether compiler supports AVX-512 VBMI], [php_cv_have_avx512vbmi], [ ++ save_CFLAGS="$CFLAGS" ++ CFLAGS="-mavx512f -mavx512cd -mavx512vl -mavx512dq -mavx512bw -mavx512vbmi $CFLAGS" ++ AC_LINK_IFELSE([AC_LANG_SOURCE([[ ++ #include ++ int main(void) { ++ __m512i mask = _mm512_set1_epi32(0x1); ++ char out[32]; ++ _mm512_storeu_si512(out, _mm512_permutexvar_epi8(mask, mask)); ++ return 0; ++ }]])], ++ [php_cv_have_avx512vbmi=yes], ++ [php_cv_have_avx512vbmi=no]) ++ CFLAGS="$save_CFLAGS" ++ ]) ++ if test "$php_cv_have_avx512vbmi" = "yes"; then + have_avx512_vbmi_supports=1 +- AC_MSG_RESULT([yes]) +- ], [ ++ else + have_avx512_vbmi_supports=0 +- AC_MSG_RESULT([no]) +- ]) +- CFLAGS="$save_CFLAGS" ++ fi + AC_DEFINE_UNQUOTED([PHP_HAVE_AVX512_VBMI_SUPPORTS], + [$have_avx512_vbmi_supports], [Whether the compiler supports AVX512 VBMI]) + ]) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 0e2b664f..6db808f6 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -14,7 +14,7 @@ declare(strict_types=1); // test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ // '8.1', - // '8.2', + '8.2', // '8.3', // '8.4', '8.5', @@ -26,9 +26,9 @@ $test_os = [ // 'macos-15-intel', // bin/spc for x86_64 'macos-15', // bin/spc for arm64 // 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 - 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 + // 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 // 'ubuntu-24.04', // bin/spc for x86_64 - 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 + // 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 // 'ubuntu-24.04-arm', // bin/spc for arm64 // 'windows-2022', // .\bin\spc.ps1 // 'windows-2025', @@ -50,13 +50,13 @@ $prefer_pre_built = 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' => 'openssl,brotli', + 'Linux', 'Darwin' => 'swoole,mongodb', 'Windows' => 'bcmath,brotli,bz2,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,iconv,intl,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pdo,pdo_mysql,pdo_pgsql,pgsql,session,simdjson,simplexml,sodium,sqlite3,tokenizer,xml,xmlreader,xmlwriter,zip,zlib', }; // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). $shared_extensions = match (PHP_OS_FAMILY) { - 'Linux' => 'zstd', + 'Linux' => '', 'Darwin' => '', 'Windows' => '', }; @@ -66,7 +66,7 @@ $with_suggested_libs = true; // If you want to test extra libs for extensions, add them below (comma separated, example `libwebp,libavif`). Unnecessary, when $with_suggested_libs is true. $with_libs = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'krb5', + 'Linux', 'Darwin' => '', 'Windows' => '', }; diff --git a/tests/mock/SPC_store.php b/tests/mock/SPC_store.php index 99f74fcc..9f9f6f29 100644 --- a/tests/mock/SPC_store.php +++ b/tests/mock/SPC_store.php @@ -12,6 +12,15 @@ use SPC\exception\SPCInternalException; function f_exec(string $command, mixed &$output, mixed &$result_code): bool { $result_code = 0; + if (str_contains($command, 'https://api.github.com/repos/AOMediaCodec/libavif/releases/latest')) { + $output = explode("\n", json_encode([ + 'tag_name' => 'v1.1.1', + 'tarball_url' => 'https://api.github.com/repos/AOMediaCodec/libavif/tarball/v1.1.1', + 'prerelease' => false, + 'draft' => false, + ])); + return true; + } if (str_contains($command, 'https://api.github.com/repos/AOMediaCodec/libavif/releases')) { $output = explode("\n", gzdecode(file_get_contents(__DIR__ . '/../assets/github_api_AOMediaCodec_libavif_releases.json.gz'))); return true;