From 5d1043334da415fae3f05576e95b040c60b08515 Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Wed, 26 Nov 2025 15:32:26 +0800 Subject: [PATCH 1/4] Add extension maxminddb support for macOS and Linux (#975) --- config/ext.json | 12 +++++++++ config/lib.json | 10 +++++++ config/source.json | 19 ++++++++++++++ src/SPC/ConsoleApplication.php | 2 +- src/SPC/builder/extension/maxminddb.php | 26 +++++++++++++++++++ .../builder/linux/library/libmaxminddb.php | 12 +++++++++ .../builder/macos/library/libmaxminddb.php | 12 +++++++++ src/SPC/builder/unix/library/libmaxminddb.php | 20 ++++++++++++++ src/globals/test-extensions.php | 16 ++++++------ 9 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 src/SPC/builder/extension/maxminddb.php create mode 100644 src/SPC/builder/linux/library/libmaxminddb.php create mode 100644 src/SPC/builder/macos/library/libmaxminddb.php create mode 100644 src/SPC/builder/unix/library/libmaxminddb.php diff --git a/config/ext.json b/config/ext.json index 303e0dde..e8f69339 100644 --- a/config/ext.json +++ b/config/ext.json @@ -358,6 +358,18 @@ "liblz4" ] }, + "maxminddb": { + "support": { + "BSD": "wip", + "Windows": "wip" + }, + "type": "external", + "source": "ext-maxminddb", + "arg-type": "with", + "lib-depends": [ + "libmaxminddb" + ] + }, "mbregex": { "type": "builtin", "arg-type": "custom", diff --git a/config/lib.json b/config/lib.json index 48a674c7..47f3c7b8 100644 --- a/config/lib.json +++ b/config/lib.json @@ -506,6 +506,16 @@ "liblz4.a" ] }, + "libmaxminddb": { + "source": "libmaxminddb", + "static-libs-unix": [ + "libmaxminddb.a" + ], + "headers": [ + "maxminddb.h", + "maxminddb_config.h" + ] + }, "libmemcached": { "source": "libmemcached", "cpp-library": true, diff --git a/config/source.json b/config/source.json index 76bf1835..06aa5c6f 100644 --- a/config/source.json +++ b/config/source.json @@ -184,6 +184,15 @@ ] } }, + "ext-maxminddb": { + "type": "url", + "url": "https://pecl.php.net/get/maxminddb", + "filename": "ext-maxminddb.tgz", + "license": { + "type": "file", + "path": "LICENSE" + } + }, "ext-memcache": { "type": "url", "url": "https://pecl.php.net/get/memcache", @@ -641,6 +650,16 @@ "path": "LICENSE" } }, + "libmaxminddb": { + "type": "ghrel", + "repo": "maxmind/libmaxminddb", + "match": "libmaxminddb-.+\\.tar\\.gz", + "prefer-stable": true, + "license": { + "type": "file", + "path": "LICENSE" + } + }, "libmemcached": { "type": "ghtagtar", "repo": "awesomized/libmemcached", diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index 9a957223..bbbed9b0 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.7.7'; + public const string VERSION = '2.7.8'; public function __construct() { diff --git a/src/SPC/builder/extension/maxminddb.php b/src/SPC/builder/extension/maxminddb.php new file mode 100644 index 00000000..7d7ee096 --- /dev/null +++ b/src/SPC/builder/extension/maxminddb.php @@ -0,0 +1,26 @@ +source_dir; + if (PHP_OS_FAMILY === 'Windows') { + f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && mklink /D maxminddb ' . $original . '\ext'); + } else { + f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && ln -s ' . $original . '/ext maxminddb'); + } + return true; + } + return false; + } +} diff --git a/src/SPC/builder/linux/library/libmaxminddb.php b/src/SPC/builder/linux/library/libmaxminddb.php new file mode 100644 index 00000000..06e309c4 --- /dev/null +++ b/src/SPC/builder/linux/library/libmaxminddb.php @@ -0,0 +1,12 @@ +addConfigureArgs( + '-DBUILD_TESTING=OFF', + '-DMAXMINDDB_BUILD_BINARIES=OFF', + ) + ->build(); + } +} diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index dddcc0f2..1d31d520 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,11 +13,11 @@ declare(strict_types=1); // test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ - // '8.1', - // '8.2', - // '8.3', + '8.1', + '8.2', + '8.3', '8.4', - // '8.5', + '8.5', // 'git', ]; @@ -35,7 +35,7 @@ $test_os = [ ]; // whether enable thread safe -$zts = true; +$zts = false; $no_strip = false; @@ -50,7 +50,7 @@ $prefer_pre_built = false; // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'curl', + 'Linux', 'Darwin' => 'maxminddb', 'Windows' => 'bcmath', }; @@ -62,7 +62,7 @@ $shared_extensions = match (PHP_OS_FAMILY) { }; // If you want to test lib-suggests for all extensions and libraries, set it to true. -$with_suggested_libs = true; +$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. $with_libs = match (PHP_OS_FAMILY) { @@ -74,7 +74,7 @@ $with_libs = match (PHP_OS_FAMILY) { // You can use `common`, `bulk`, `minimal` or `none`. // note: combination is only available for *nix platform. Windows must use `none` combination $base_combination = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'none', + 'Linux', 'Darwin' => 'minimal', 'Windows' => 'none', }; From 5b8c9e6f09a5f1467f77e553f445e76bd787f6e0 Mon Sep 17 00:00:00 2001 From: henderkes Date: Wed, 26 Nov 2025 09:37:21 +0100 Subject: [PATCH 2/4] we need to change source_path for shared build --- src/SPC/builder/extension/maxminddb.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/SPC/builder/extension/maxminddb.php b/src/SPC/builder/extension/maxminddb.php index 7d7ee096..a8422416 100644 --- a/src/SPC/builder/extension/maxminddb.php +++ b/src/SPC/builder/extension/maxminddb.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace SPC\builder\extension; use SPC\builder\Extension; +use SPC\store\FileSystem; use SPC\util\CustomExt; #[CustomExt('maxminddb')] @@ -12,15 +13,13 @@ class maxminddb extends Extension { public function patchBeforeBuildconf(): bool { - if (!is_link(SOURCE_PATH . '/php-src/ext/maxminddb')) { + if (!is_dir(SOURCE_PATH . '/php-src/ext/maxminddb')) { $original = $this->source_dir; - if (PHP_OS_FAMILY === 'Windows') { - f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && mklink /D maxminddb ' . $original . '\ext'); - } else { - f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && ln -s ' . $original . '/ext maxminddb'); - } + FileSystem::copyDir($original . '/ext', SOURCE_PATH . '/php-src/ext/maxminddb'); + $this->source_dir = SOURCE_PATH . '/php-src/ext/maxminddb'; return true; } + $this->source_dir = SOURCE_PATH . '/php-src/ext/maxminddb'; return false; } } From cb7eca90494c5679d42753386683d95a3bf64cad Mon Sep 17 00:00:00 2001 From: Jerry Ma Date: Wed, 26 Nov 2025 17:08:49 +0800 Subject: [PATCH 3/4] Bump version from 2.7.8 to 2.7.9 --- src/SPC/ConsoleApplication.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index bbbed9b0..1b1d3e19 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.7.8'; + public const string VERSION = '2.7.9'; public function __construct() { From e316971764eef0de65b650e1aac052f0c9651842 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sat, 29 Nov 2025 14:08:34 +0800 Subject: [PATCH 4/4] Fix cross-device warning in rename function --- src/SPC/store/FileSystem.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index 86daefc4..3b88a2bc 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -660,11 +660,19 @@ class FileSystem $source = self::convertPath($source); $dest = self::convertPath($dest); - // Try rename first (fast, atomic) - if (@rename($source, $dest)) { - return; + // Check if source and dest are on the same device to avoid cross-device rename errors + $source_stat = @stat($source); + $dest_parent = dirname($dest); + $dest_stat = @stat($dest_parent); + + // Only use rename if on same device + if ($source_stat !== false && $dest_stat !== false && $source_stat['dev'] === $dest_stat['dev']) { + if (@rename($source, $dest)) { + return; + } } + // Fall back to copy + delete for cross-device moves or if rename failed if (is_dir($source)) { self::copyDir($source, $dest); self::removeDir($source);