Compare commits

...

17 Commits

Author SHA1 Message Date
henderkes
5ef4623051 grpc will fail for php 8.5, it's not updated yet 2025-12-27 23:05:35 +01:00
henderkes
e952f1c76a we don't even need to build grpc library for grpc extension... 2025-12-27 22:36:24 +01:00
henderkes
09b89a30f9 WIP: use system libraries for grpc without building our own grpc lib 2025-12-27 22:20:02 +01:00
henderkes
9a681a9fa6 add mariadb mysqlnd plugins 2025-12-27 21:22:10 +01:00
crazywhalecc
f7ca621efe Test 2025-12-26 15:03:54 +08:00
henderkes
6b5200002e fix downloader selecting drafts 2025-12-20 23:29:25 +01:00
henderkes
53f7cdefe0 fix swoole compilation with php 8.5.1 2025-12-18 20:12:01 +01:00
henderkes
e1a14bbb9f fix implicit include 2025-12-18 17:39:05 +01:00
henderkes
9e051c8c80 fix: check for link first before checking for is_dir 2025-12-18 17:32:02 +01:00
henderkes
e677be74d7 remove 2025-12-18 17:32:02 +01:00
henderkes
037d224fd7 why does phpstan think this is necessary? 2025-12-18 17:32:02 +01:00
henderkes
ce44e00bd4 @crazywhalecc how to use patch points to delete source dirs? 2025-12-18 17:32:01 +01:00
henderkes
0247458853 we were installing to wrong dir if source name != lib name 2025-12-18 17:32:01 +01:00
henderkes
656a58c3fa remove source dir after successful build in CI environment 2025-12-18 17:32:01 +01:00
Jerry Ma
9fdfef5057 macOS don't need to disable avx2 explicitly (#1007) 2025-12-18 21:21:47 +08:00
Marc
18c5ccfe9d the libwebp 1.6.0 bug affects centos 7 too (#1004) 2025-12-16 09:33:20 +01:00
henderkes
d064e1353c the libwebp 1.6.0 bug affects centos 7 too 2025-12-15 18:50:20 +01:00
16 changed files with 388 additions and 238 deletions

428
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -236,7 +236,9 @@
"arg-type-unix": "enable-path", "arg-type-unix": "enable-path",
"cpp-extension": true, "cpp-extension": true,
"lib-depends": [ "lib-depends": [
"grpc" "zlib",
"openssl",
"libcares"
] ]
}, },
"iconv": { "iconv": {
@@ -487,6 +489,36 @@
"zlib" "zlib"
] ]
}, },
"mysqlnd_ed25519": {
"type": "external",
"source": "mysqlnd_ed25519",
"arg-type": "enable",
"target": [
"shared"
],
"ext-depends": [
"mysqlnd"
],
"lib-depends": [
"libsodium",
"openssl"
]
},
"mysqlnd_parsec": {
"type": "external",
"source": "mysqlnd_parsec",
"arg-type": "enable",
"target": [
"shared"
],
"ext-depends": [
"mysqlnd"
],
"lib-depends": [
"libsodium",
"openssl"
]
},
"oci8": { "oci8": {
"type": "wip", "type": "wip",
"support": { "support": {

View File

@@ -871,6 +871,24 @@
"path": "LICENSE" "path": "LICENSE"
} }
}, },
"mysqlnd_ed25519": {
"type": "pie",
"repo": "mariadb/mysqlnd_ed25519",
"path": "php-src/ext/mysqlnd_ed25519",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"mysqlnd_parsec": {
"type": "pie",
"repo": "mariadb/mysqlnd_parsec",
"path": "php-src/ext/mysqlnd_parsec",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ncurses": { "ncurses": {
"type": "filelist", "type": "filelist",
"url": "https://ftp.gnu.org/pub/gnu/ncurses/", "url": "https://ftp.gnu.org/pub/gnu/ncurses/",

View File

@@ -34,7 +34,7 @@ use Symfony\Component\Console\Application;
*/ */
final class ConsoleApplication extends Application final class ConsoleApplication extends Application
{ {
public const string VERSION = '2.7.10'; public const string VERSION = '2.7.11';
public function __construct() public function __construct()
{ {

View File

@@ -385,6 +385,9 @@ class Extension
logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)'); logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)');
return; return;
} }
if ((string) Config::getExt($this->getName(), 'type') === 'addon') {
return;
}
logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)'); logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)');
foreach ($this->dependencies as $dependency) { foreach ($this->dependencies as $dependency) {
if (!$dependency instanceof Extension) { if (!$dependency instanceof Extension) {

View File

@@ -184,18 +184,18 @@ abstract class LibraryBase
// extract first if not exists // extract first if not exists
if (!is_dir($this->source_dir)) { if (!is_dir($this->source_dir)) {
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-extract'); $this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-extract');
SourceManager::initSource(libs: [static::NAME], source_only: true); SourceManager::initSource(libs: [static::NAME], source_only: true);
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-extract'); $this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-extract');
} }
if (!$this->patched && $this->patchBeforeBuild()) { if (!$this->patched && $this->patchBeforeBuild()) {
file_put_contents($this->source_dir . '/.spc.patched', 'PATCHED!!!'); file_put_contents($this->source_dir . '/.spc.patched', 'PATCHED!!!');
} }
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build'); $this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-build');
$this->build(); $this->build();
$this->installLicense(); $this->installLicense();
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build'); $this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-build');
return LIB_STATUS_OK; return LIB_STATUS_OK;
} }
@@ -346,19 +346,19 @@ abstract class LibraryBase
*/ */
protected function installLicense(): void protected function installLicense(): void
{ {
FileSystem::createDir(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName());
$source = Config::getLib($this->getName(), 'source'); $source = Config::getLib($this->getName(), 'source');
FileSystem::createDir(BUILD_ROOT_PATH . "/source-licenses/{$source}");
$license_files = Config::getSource($source)['license'] ?? []; $license_files = Config::getSource($source)['license'] ?? [];
if (is_assoc_array($license_files)) { if (is_assoc_array($license_files)) {
$license_files = [$license_files]; $license_files = [$license_files];
} }
foreach ($license_files as $index => $license) { foreach ($license_files as $index => $license) {
if ($license['type'] === 'text') { if ($license['type'] === 'text') {
FileSystem::writeFile(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt", $license['text']); FileSystem::writeFile(BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt", $license['text']);
continue; continue;
} }
if ($license['type'] === 'file') { if ($license['type'] === 'file') {
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt"); copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt");
} }
} }
} }
@@ -375,8 +375,17 @@ abstract class LibraryBase
return false; return false;
} }
} }
$pkg_config_path = getenv('PKG_CONFIG_PATH') ?: '';
$search_paths = array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path));
foreach (Config::getLib(static::NAME, 'pkg-configs', []) as $name) { foreach (Config::getLib(static::NAME, 'pkg-configs', []) as $name) {
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$name}.pc")) { $found = false;
foreach ($search_paths as $path) {
if (file_exists($path . "/{$name}.pc")) {
$found = true;
break;
}
}
if (!$found) {
return false; return false;
} }
} }

View File

@@ -43,4 +43,9 @@ EOF
); );
return true; return true;
} }
protected function getExtraEnv(): array
{
return ['CFLAGS' => '-std=c17'];
}
} }

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mysqlnd_ed25519')]
class mysqlnd_ed25519 extends Extension
{
public function getConfigureArg(bool $shared = false): string
{
return '--with-mysqlnd_ed25519' . ($shared ? '=shared' : '');
}
public function getUnixConfigureArg(bool $shared = false): string
{
return $this->getConfigureArg();
}
}

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mysqlnd_parsec')]
class mysqlnd_parsec extends Extension
{
public function getConfigureArg(bool $shared = false): string
{
return '--enable-mysqlnd_parsec' . ($shared ? '=shared' : '');
}
public function getUnixConfigureArg(bool $shared = false): string
{
return $this->getConfigureArg();
}
}

View File

@@ -17,6 +17,7 @@ class swoole extends Extension
public function patchBeforeMake(): bool public function patchBeforeMake(): bool
{ {
$patched = parent::patchBeforeMake(); $patched = parent::patchBeforeMake();
FileSystem::replaceFileStr($this->source_dir . '/ext-src/php_swoole_private.h', 'PHP_VERSION_ID > 80500', 'PHP_VERSION_ID >= 80600');
if ($this->builder instanceof MacOSBuilder) { if ($this->builder instanceof MacOSBuilder) {
// Fix swoole with event extension <util.h> conflict bug // Fix swoole with event extension <util.h> conflict bug
$util_path = shell()->execWithResult('xcrun --show-sdk-path', false)[1][0] . '/usr/include/util.h'; $util_path = shell()->execWithResult('xcrun --show-sdk-path', false)[1][0] . '/usr/include/util.h';

View File

@@ -34,7 +34,7 @@ trait UnixLibraryTrait
$files = array_map(fn ($x) => "{$x}.pc", $conf_pc); $files = array_map(fn ($x) => "{$x}.pc", $conf_pc);
} }
foreach ($files as $name) { foreach ($files as $name) {
$realpath = realpath(BUILD_ROOT_PATH . '/lib/pkgconfig/' . $name); $realpath = realpath(BUILD_LIB_PATH . '/pkgconfig/' . $name);
if ($realpath === false) { if ($realpath === false) {
throw new PatchException('pkg-config prefix patcher', 'Cannot find library [' . static::NAME . '] pkgconfig file [' . $name . '] in ' . BUILD_LIB_PATH . '/pkgconfig/ !'); throw new PatchException('pkg-config prefix patcher', 'Cannot find library [' . static::NAME . '] pkgconfig file [' . $name . '] in ' . BUILD_LIB_PATH . '/pkgconfig/ !');
} }

View File

@@ -5,12 +5,17 @@ declare(strict_types=1);
namespace SPC\builder\unix\library; namespace SPC\builder\unix\library;
use SPC\util\executor\UnixCMakeExecutor; use SPC\util\executor\UnixCMakeExecutor;
use SPC\util\SPCTarget;
trait libwebp trait libwebp
{ {
protected function build(): void protected function build(): void
{ {
$code = '#include <immintrin.h>
int main() { return _mm256_cvtsi256_si32(_mm256_setzero_si256()); }';
$cc = getenv('CC') ?: 'gcc';
[$ret] = shell()->execWithResult("printf '%s' '{$code}' | {$cc} -x c -mavx2 -o /dev/null - 2>&1");
$disableAvx2 = $ret !== 0 && GNU_ARCH === 'x86_64' && PHP_OS_FAMILY === 'Linux';
UnixCMakeExecutor::create($this) UnixCMakeExecutor::create($this)
->addConfigureArgs( ->addConfigureArgs(
'-DWEBP_BUILD_EXTRAS=OFF', '-DWEBP_BUILD_EXTRAS=OFF',
@@ -23,7 +28,7 @@ trait libwebp
'-DWEBP_BUILD_WEBPINFO=OFF', '-DWEBP_BUILD_WEBPINFO=OFF',
'-DWEBP_BUILD_WEBPMUX=OFF', '-DWEBP_BUILD_WEBPMUX=OFF',
'-DWEBP_BUILD_FUZZTEST=OFF', '-DWEBP_BUILD_FUZZTEST=OFF',
SPCTarget::getLibcVersion() === '2.31' && GNU_ARCH === 'x86_64' ? '-DWEBP_ENABLE_SIMD=OFF' : '' // fix an edge bug for debian 11 with gcc 10 $disableAvx2 ? '-DWEBP_ENABLE_SIMD=OFF' : ''
) )
->build(); ->build();
// patch pkgconfig // patch pkgconfig

View File

@@ -108,6 +108,9 @@ class Downloader
if (($rel['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) { if (($rel['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) {
continue; continue;
} }
if (($rel['draft'] ?? false) === true && (($source['prefer-stable'] ?? false) || !$rel['tarball_url'])) {
continue;
}
if (!($source['match'] ?? null)) { if (!($source['match'] ?? null)) {
$url = $rel['tarball_url'] ?? null; $url = $rel['tarball_url'] ?? null;
break; break;

View File

@@ -408,13 +408,13 @@ class FileSystem
continue; continue;
} }
$sub_file = self::convertPath($dir . '/' . $v); $sub_file = self::convertPath($dir . '/' . $v);
if (is_dir($sub_file)) { if (is_link($sub_file) || is_file($sub_file)) {
# 如果是 目录 且 递推 , 则递推添加下级文件 if (!unlink($sub_file)) {
if (!self::removeDir($sub_file)) {
return false; return false;
} }
} elseif (is_link($sub_file) || is_file($sub_file)) { } elseif (is_dir($sub_file)) {
if (!unlink($sub_file)) { # 如果是 目录 且 递推 , 则递推添加下级文件
if (!self::removeDir($sub_file)) {
return false; return false;
} }
} }

View File

@@ -226,9 +226,17 @@ class SPCConfigUtil
// parse pkg-configs // parse pkg-configs
foreach ($libraries as $library) { foreach ($libraries as $library) {
$pc = Config::getLib($library, 'pkg-configs', []); $pc = Config::getLib($library, 'pkg-configs', []);
$pkg_config_path = getenv('PKG_CONFIG_PATH') ?: '';
$search_paths = array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path));
foreach ($pc as $file) { foreach ($pc as $file) {
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$file}.pc")) { $found = false;
throw new WrongUsageException("pkg-config file '{$file}.pc' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "/pkgconfig'. Please build it first."); foreach ($search_paths as $path) {
if (file_exists($path . "/{$file}.pc")) {
$found = true;
}
}
if (!$found) {
throw new WrongUsageException("pkg-config file '{$file}.pc' for lib [{$library}] does not exist. Please build it first.");
} }
} }
$pc_cflags = implode(' ', $pc); $pc_cflags = implode(' ', $pc);
@@ -257,9 +265,17 @@ class SPCConfigUtil
foreach ($libraries as $library) { foreach ($libraries as $library) {
// add pkg-configs libs // add pkg-configs libs
$pkg_configs = Config::getLib($library, 'pkg-configs', []); $pkg_configs = Config::getLib($library, 'pkg-configs', []);
foreach ($pkg_configs as $pkg_config) { $pkg_config_path = getenv('PKG_CONFIG_PATH') ?: '';
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$pkg_config}.pc")) { $search_paths = array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path));
throw new WrongUsageException("pkg-config file '{$pkg_config}.pc' for lib [{$library}] does not exist in '" . BUILD_LIB_PATH . "/pkgconfig'. Please build it first."); foreach ($pkg_configs as $file) {
$found = false;
foreach ($search_paths as $path) {
if (file_exists($path . "/{$file}.pc")) {
$found = true;
}
}
if (!$found) {
throw new WrongUsageException("pkg-config file '{$file}.pc' for lib [{$library}] does not exist. Please build it first.");
} }
} }
$pkg_configs = implode(' ', $pkg_configs); $pkg_configs = implode(' ', $pkg_configs);

View File

@@ -14,8 +14,8 @@ declare(strict_types=1);
// test php version (8.1 ~ 8.4 available, multiple for matrix) // test php version (8.1 ~ 8.4 available, multiple for matrix)
$test_php_version = [ $test_php_version = [
// '8.1', // '8.1',
// '8.2', '8.2',
// '8.3', '8.3',
'8.4', '8.4',
'8.5', '8.5',
// 'git', // 'git',
@@ -25,11 +25,11 @@ $test_php_version = [
$test_os = [ $test_os = [
'macos-15-intel', // bin/spc for x86_64 'macos-15-intel', // bin/spc for x86_64
'macos-15', // bin/spc for arm64 'macos-15', // bin/spc for arm64
// 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 '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-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 // 'ubuntu-24.04-arm', // bin/spc for arm64
// 'windows-2022', // .\bin\spc.ps1 // 'windows-2022', // .\bin\spc.ps1
// 'windows-2025', // 'windows-2025',
]; ];
@@ -50,13 +50,13 @@ $prefer_pre_built = false;
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) { $extensions = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'bcmath,xsl,xml', 'Linux', 'Darwin' => 'mysqli',
'Windows' => 'bcmath', 'Windows' => 'bcmath',
}; };
// If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`).
$shared_extensions = match (PHP_OS_FAMILY) { $shared_extensions = match (PHP_OS_FAMILY) {
'Linux' => '', 'Linux' => 'grpc,mysqlnd_parsec,mysqlnd_ed25519',
'Darwin' => '', 'Darwin' => '',
'Windows' => '', 'Windows' => '',
}; };
@@ -66,7 +66,7 @@ $with_suggested_libs = false;
// If you want to test extra libs for extensions, add them below (comma separated, example `libwebp,libavif`). Unnecessary, when $with_suggested_libs is 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) { $with_libs = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => '', 'Linux', 'Darwin' => 'libwebp',
'Windows' => '', 'Windows' => '',
}; };