diff --git a/config/lib.json b/config/lib.json index 8e728ccd..eb009f21 100644 --- a/config/lib.json +++ b/config/lib.json @@ -589,6 +589,12 @@ "openssl" ] }, + "mimalloc": { + "source": "mimalloc", + "static-libs-unix": [ + "mimalloc.o" + ] + }, "ncurses": { "source": "ncurses", "static-libs-unix": [ diff --git a/config/source.json b/config/source.json index e5cc9212..006c9d6b 100644 --- a/config/source.json +++ b/config/source.json @@ -636,6 +636,16 @@ "path": "LICENSE" } }, + "mimalloc": { + "type": "ghtagtar", + "repo": "microsoft/mimalloc", + "match": "v2.+", + "provide-pre-built": false, + "license": { + "type": "file", + "path": "LICENSE" + } + }, "mongodb": { "type": "ghrel", "repo": "mongodb/mongo-php-driver", diff --git a/docs/en/guide/extension-notes.md b/docs/en/guide/extension-notes.md index 914281f2..1d9209c9 100644 --- a/docs/en/guide/extension-notes.md +++ b/docs/en/guide/extension-notes.md @@ -76,8 +76,7 @@ and this extension cannot be compiled into php by static linking, so it cannot b ## xdebug -1. Xdebug is a Zend extension. The functions of Xdebug depend on PHP's Zend engine and underlying code. -If you want to statically compile it into PHP, you may need a huge amount of patch code, which is not feasible. +1. Xdebug is only buildable as a shared extension. On Linux, you need to use static-php-cli with SPC_LIBC=glibc and then compile php-xdebug from source with the option `--with-php-config=/path/to/buildroot/bin/php-config`. 2. The macOS platform can compile an xdebug extension under PHP compiled on the same platform, extract the `xdebug.so` file, and then use the `--no-strip` parameter in static-php-cli to retain the debug symbol table and add the `ffi` extension. The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`. @@ -149,3 +148,9 @@ Parallel is only supported on PHP 8.0 ZTS and above. 1. The [SPX extension](https://github.com/NoiseByNorthwest/php-spx) only supports NTS mode. 2. SPX does not support Windows, and the official repository does not support static compilation. static-php-cli uses a [modified version](https://github.com/static-php/php-spx). + +## mimalloc + +1. This is not technically an extension, but a library. +2. Building with `--with-libs="mimalloc"` on Linux or macOS will override the default allocator. +3. This is experimental for now, but is recommended in threaded environments. \ No newline at end of file diff --git a/docs/zh/guide/extension-notes.md b/docs/zh/guide/extension-notes.md index cdd66ef2..c13deeea 100644 --- a/docs/zh/guide/extension-notes.md +++ b/docs/zh/guide/extension-notes.md @@ -70,7 +70,7 @@ bin/spc build gd --with-libs=freetype,libjpeg,libavif,libwebp --build-cli ## xdebug -1. Xdebug 是一个 Zend 扩展,Xdebug 的功能依赖于 PHP 的 Zend 引擎和底层代码,如果要将其静态编译到 PHP 中,可能需要巨量的 patch 代码,这是不可行的。 +1. Xdebug 只能作为共享扩展构建。在 Linux 上,您需要使用带有 `SPC_LIBC=glibc` 的 static-php-cli,然后使用选项 `--with-php-config=/path/to/buildroot/bin/php-config` 从源代码编译 php-xdebug。 2. macOS 平台可以通过在相同平台编译的 PHP 下编译一个 xdebug 扩展,并提取其中的 `xdebug.so` 文件,再在 static-php-cli 中使用 `--no-strip` 参数保留调试符号表,同时加入 `ffi` 扩展。 编译的 `./php` 二进制可以通过指定 INI 配置并运行,例如`./php -d 'zend_extension=xdebug.so' your-code.php`。 @@ -136,3 +136,9 @@ parallel 扩展只支持 PHP 8.0 及以上版本,并只支持 ZTS 构建(`-- 1. [SPX 扩展](https://github.com/NoiseByNorthwest/php-spx) 只支持非线程模式。 2. SPX 目前不支持 Windows,且官方仓库也不支持静态编译,static-php-cli 使用了 [修改版本](https://github.com/static-php/php-spx)。 + +## mimalloc + +1. 从技术上讲,这不是扩展,而是一个库。 +2. 在 Linux 或 macOS 上使用 `--with-libs="mimalloc"` 进行构建将覆盖默认分配器。 +3. 目前,这还处于实验阶段,但建议在线程环境中使用。 \ No newline at end of file diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index d2f98692..cd48728f 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -150,12 +150,13 @@ class LinuxBuilder extends UnixBuilderBase $enable_micro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO; $enable_embed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED; + $mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : ''; // prepare build php envs $envs_build_php = SystemUtil::makeEnvVarString([ 'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'), 'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'), 'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'), - 'LIBS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'), + 'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'), ]); // process micro upx patch if micro sapi enabled @@ -310,9 +311,15 @@ class LinuxBuilder extends UnixBuilderBase shell()->cd(SOURCE_PATH . '/php-src') ->exec('sed -i "s|//lib|/lib|g" Makefile') ->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install"); - FileSystem::replaceFileStr(BUILD_BIN_PATH . '/php-config', 'prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"'); FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'"); FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#'); + $php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config'); + str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str); + // move mimalloc to the beginning of libs + $php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str); + // move lstdc++ to the end of libs + $php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str); + FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str); } private function getMakeExtraVars(): array diff --git a/src/SPC/builder/linux/library/mimalloc.php b/src/SPC/builder/linux/library/mimalloc.php new file mode 100644 index 00000000..7ea6d833 --- /dev/null +++ b/src/SPC/builder/linux/library/mimalloc.php @@ -0,0 +1,12 @@ +getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : ''; $envs_build_php = SystemUtil::makeEnvVarString([ 'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'), 'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'), 'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'), + 'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'), ]); if ($this->getLib('postgresql')) { @@ -298,9 +300,13 @@ class MacOSBuilder extends UnixBuilderBase ->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a') ->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o') ->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o'); - FileSystem::replaceFileStr(BUILD_BIN_PATH . '/php-config', 'prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"'); FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'"); FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#'); + $php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config'); + str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str); + // move mimalloc to the beginning of libs + $php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str); + FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str); } private function getMakeExtraVars(): array diff --git a/src/SPC/builder/macos/library/mimalloc.php b/src/SPC/builder/macos/library/mimalloc.php new file mode 100644 index 00000000..c86c8ed6 --- /dev/null +++ b/src/SPC/builder/macos/library/mimalloc.php @@ -0,0 +1,12 @@ +source_dir . '/build'); + shell()->cd($this->source_dir . '/build') + ->execWithEnv( + 'cmake ' . + '-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' . + "-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " . + '-DCMAKE_BUILD_TYPE=Release ' . + $args . + '..' + ) + ->execWithEnv("make -j{$this->builder->concurrency}") + ->execWithEnv('make install'); + } +} diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index 16edeeae..fbaeb7a7 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -69,14 +69,19 @@ class Downloader retry: self::getRetryTime() ), true); - if (($source['prefer-stable'] ?? false) === false) { - $url = $data[0]['tarball_url']; - } else { - $id = 0; - while ($data[$id]['prerelease'] === true) { - ++$id; + $url = null; + for ($i = 0; $i < count($data); ++$i) { + if (($data[$i]['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) { + continue; + } + if (!($source['match'] ?? null)) { + $url = $data[$i]['tarball_url'] ?? null; + break; + } + if (preg_match('|' . $source['match'] . '|', $data[$i]['tarball_url'])) { + $url = $data[$i]['tarball_url']; + break; } - $url = $data[$id]['tarball_url'] ?? null; } if (!$url) { throw new DownloaderException("failed to find {$name} source"); diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index 2961ef90..f4a121eb 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -42,6 +42,10 @@ class SPCConfigUtil if ($this->builder->hasCpp()) { $libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++'; } + // mimalloc must come first + if (str_contains($libs, BUILD_LIB_PATH . '/mimalloc.o')) { + $libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs); + } return [ 'cflags' => $cflags, 'ldflags' => $ldflags, diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 1f67b2eb..85f47e1e 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -6,12 +6,12 @@ declare(strict_types=1); /** * This is GitHub Actions automatic test extension args generator. - * You can edit $extensions, $with_libs and $base_combination. + * You can edit $test_php_version, $test_os, $zts, $no_strip, $upx, $prefer_pre_built, $extensions, $with_libs and $base_combination. */ // --------------------------------- edit area --------------------------------- -// test php version +// test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ '8.1', '8.2', @@ -21,10 +21,10 @@ $test_php_version = [ // test os (macos-13, macos-14, ubuntu-latest, windows-latest are available) $test_os = [ - // 'macos-13', - // 'macos-14', - // 'ubuntu-latest', - 'windows-latest', + 'macos-13', + 'macos-14', + 'ubuntu-latest', + // 'windows-latest', ]; // whether enable thread safe @@ -40,13 +40,13 @@ $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' => 'gd', + 'Linux', 'Darwin' => '', 'Windows' => 'bz2,ctype,curl,dom,filter,gd,iconv,mbstring,opcache,openssl,pdo,pdo_sqlite,phar,session,simplexml,sqlite3,tokenizer,xml,xmlwriter,yaml,zip,zlib', }; // 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' => 'freetype', + 'Linux', 'Darwin' => 'mimalloc', 'Windows' => 'libjpeg,libavif,freetype,libwebp', }; @@ -54,7 +54,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' => 'minimal', + 'Linux', 'Darwin' => 'bulk', 'Windows' => 'none', };