Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mimalloc support for macOS and Linux #663

Merged
merged 10 commits into from
Mar 23, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions config/lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,12 @@
"openssl"
]
},
"mimalloc": {
"source": "mimalloc",
"static-libs-unix": [
"mimalloc.o"
]
},
"ncurses": {
"source": "ncurses",
"static-libs-unix": [
Expand Down
10 changes: 10 additions & 0 deletions config/source.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
9 changes: 7 additions & 2 deletions docs/en/guide/extension-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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.
11 changes: 9 additions & 2 deletions src/SPC/builder/linux/LinuxBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,13 @@ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
$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
Expand Down Expand Up @@ -310,7 +311,13 @@ protected function buildEmbed(): void
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 . '"');
$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
Expand Down
12 changes: 12 additions & 0 deletions src/SPC/builder/linux/library/mimalloc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace SPC\builder\linux\library;

class mimalloc extends LinuxLibraryBase
{
use \SPC\builder\unix\library\mimalloc;

public const NAME = 'mimalloc';
}
8 changes: 8 additions & 0 deletions src/SPC/builder/macos/MacOSBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,12 @@ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;

// prepare build php envs
$mimallocLibs = $this->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')) {
Expand Down Expand Up @@ -298,6 +300,12 @@ protected function buildEmbed(): void
->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');

$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
Expand Down
12 changes: 12 additions & 0 deletions src/SPC/builder/macos/library/mimalloc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace SPC\builder\macos\library;

class mimalloc extends MacOSLibraryBase
{
use \SPC\builder\unix\library\mimalloc;

public const NAME = 'mimalloc';
}
38 changes: 38 additions & 0 deletions src/SPC/builder/unix/library/mimalloc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace SPC\builder\unix\library;

use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;

trait mimalloc
{
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
$args = '';
if (getenv('SPC_LIBC') === 'musl') {
$args .= '-DMI_LIBC_MUSL=ON ';
}
$args .= '-DMI_BUILD_SHARED=OFF ';
$args .= '-DMI_INSTALL_TOPLEVEL=ON ';
FileSystem::resetDir($this->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');
}
}
19 changes: 12 additions & 7 deletions src/SPC/store/Downloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,19 @@ public static function getLatestGithubTarball(string $name, array $source, strin
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");
Expand Down
4 changes: 4 additions & 0 deletions src/SPC/util/SPCConfigUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public function config(array $extensions = [], array $libraries = [], bool $incl
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,
Expand Down
8 changes: 4 additions & 4 deletions src/globals/test-extensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
// test os (macos-13, macos-14, ubuntu-latest, windows-latest are available)
$test_os = [
// 'macos-13',
// 'macos-14',
// 'ubuntu-latest',
'windows-latest',
'macos-14',
'ubuntu-latest',
// 'windows-latest',
];

// whether enable thread safe
Expand All @@ -46,7 +46,7 @@

// 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',
};

Expand Down