Skip to content

Commit d0a66ab

Browse files
authored
Merge pull request #663 from crazywhalecc/feat/mimalloc
Add mimalloc support for macOS and Linux
2 parents e850df5 + 744e066 commit d0a66ab

File tree

12 files changed

+133
-22
lines changed

12 files changed

+133
-22
lines changed

config/lib.json

+6
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,12 @@
589589
"openssl"
590590
]
591591
},
592+
"mimalloc": {
593+
"source": "mimalloc",
594+
"static-libs-unix": [
595+
"mimalloc.o"
596+
]
597+
},
592598
"ncurses": {
593599
"source": "ncurses",
594600
"static-libs-unix": [

config/source.json

+10
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,16 @@
636636
"path": "LICENSE"
637637
}
638638
},
639+
"mimalloc": {
640+
"type": "ghtagtar",
641+
"repo": "microsoft/mimalloc",
642+
"match": "v2.+",
643+
"provide-pre-built": false,
644+
"license": {
645+
"type": "file",
646+
"path": "LICENSE"
647+
}
648+
},
639649
"mongodb": {
640650
"type": "ghrel",
641651
"repo": "mongodb/mongo-php-driver",

docs/en/guide/extension-notes.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ and this extension cannot be compiled into php by static linking, so it cannot b
7676

7777
## xdebug
7878

79-
1. Xdebug is a Zend extension. The functions of Xdebug depend on PHP's Zend engine and underlying code.
80-
If you want to statically compile it into PHP, you may need a huge amount of patch code, which is not feasible.
79+
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`.
8180
2. The macOS platform can compile an xdebug extension under PHP compiled on the same platform,
8281
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.
8382
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.
149148

150149
1. The [SPX extension](https://github.com/NoiseByNorthwest/php-spx) only supports NTS mode.
151150
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).
151+
152+
## mimalloc
153+
154+
1. This is not technically an extension, but a library.
155+
2. Building with `--with-libs="mimalloc"` on Linux or macOS will override the default allocator.
156+
3. This is experimental for now, but is recommended in threaded environments.

docs/zh/guide/extension-notes.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ bin/spc build gd --with-libs=freetype,libjpeg,libavif,libwebp --build-cli
7070

7171
## xdebug
7272

73-
1. Xdebug 是一个 Zend 扩展,Xdebug 的功能依赖于 PHP 的 Zend 引擎和底层代码,如果要将其静态编译到 PHP 中,可能需要巨量的 patch 代码,这是不可行的
73+
1. Xdebug 只能作为共享扩展构建。在 Linux 上,您需要使用带有 `SPC_LIBC=glibc` 的 static-php-cli,然后使用选项 `--with-php-config=/path/to/buildroot/bin/php-config` 从源代码编译 php-xdebug
7474
2. macOS 平台可以通过在相同平台编译的 PHP 下编译一个 xdebug 扩展,并提取其中的 `xdebug.so` 文件,再在 static-php-cli 中使用 `--no-strip` 参数保留调试符号表,同时加入 `ffi` 扩展。
7575
编译的 `./php` 二进制可以通过指定 INI 配置并运行,例如`./php -d 'zend_extension=xdebug.so' your-code.php`
7676

@@ -136,3 +136,9 @@ parallel 扩展只支持 PHP 8.0 及以上版本,并只支持 ZTS 构建(`--
136136

137137
1. [SPX 扩展](https://github.com/NoiseByNorthwest/php-spx) 只支持非线程模式。
138138
2. SPX 目前不支持 Windows,且官方仓库也不支持静态编译,static-php-cli 使用了 [修改版本](https://github.com/static-php/php-spx)
139+
140+
## mimalloc
141+
142+
1. 从技术上讲,这不是扩展,而是一个库。
143+
2. 在 Linux 或 macOS 上使用 `--with-libs="mimalloc"` 进行构建将覆盖默认分配器。
144+
3. 目前,这还处于实验阶段,但建议在线程环境中使用。

src/SPC/builder/linux/LinuxBuilder.php

+9-2
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,13 @@ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
150150
$enable_micro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
151151
$enable_embed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
152152

153+
$mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : '';
153154
// prepare build php envs
154155
$envs_build_php = SystemUtil::makeEnvVarString([
155156
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
156157
'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'),
157158
'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'),
158-
'LIBS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'),
159+
'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'),
159160
]);
160161

161162
// process micro upx patch if micro sapi enabled
@@ -310,9 +311,15 @@ protected function buildEmbed(): void
310311
shell()->cd(SOURCE_PATH . '/php-src')
311312
->exec('sed -i "s|//lib|/lib|g" Makefile')
312313
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
313-
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/php-config', 'prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"');
314314
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
315315
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
316+
$php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
317+
str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
318+
// move mimalloc to the beginning of libs
319+
$php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
320+
// move lstdc++ to the end of libs
321+
$php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str);
322+
FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
316323
}
317324

318325
private function getMakeExtraVars(): array
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SPC\builder\linux\library;
6+
7+
class mimalloc extends LinuxLibraryBase
8+
{
9+
use \SPC\builder\unix\library\mimalloc;
10+
11+
public const NAME = 'mimalloc';
12+
}

src/SPC/builder/macos/MacOSBuilder.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,12 @@ public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
148148
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
149149

150150
// prepare build php envs
151+
$mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : '';
151152
$envs_build_php = SystemUtil::makeEnvVarString([
152153
'CFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS'),
153154
'CPPFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS'),
154155
'LDFLAGS' => getenv('SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS'),
156+
'LIBS' => $mimallocLibs . getenv('SPC_CMD_VAR_PHP_CONFIGURE_LIBS'),
155157
]);
156158

157159
if ($this->getLib('postgresql')) {
@@ -298,9 +300,13 @@ protected function buildEmbed(): void
298300
->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a')
299301
->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o')
300302
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o');
301-
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/php-config', 'prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"');
302303
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
303304
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
305+
$php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
306+
str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
307+
// move mimalloc to the beginning of libs
308+
$php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
309+
FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
304310
}
305311

306312
private function getMakeExtraVars(): array
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SPC\builder\macos\library;
6+
7+
class mimalloc extends MacOSLibraryBase
8+
{
9+
use \SPC\builder\unix\library\mimalloc;
10+
11+
public const NAME = 'mimalloc';
12+
}
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SPC\builder\unix\library;
6+
7+
use SPC\exception\FileSystemException;
8+
use SPC\exception\RuntimeException;
9+
use SPC\store\FileSystem;
10+
11+
trait mimalloc
12+
{
13+
/**
14+
* @throws RuntimeException
15+
* @throws FileSystemException
16+
*/
17+
protected function build(): void
18+
{
19+
$args = '';
20+
if (getenv('SPC_LIBC') === 'musl') {
21+
$args .= '-DMI_LIBC_MUSL=ON ';
22+
}
23+
$args .= '-DMI_BUILD_SHARED=OFF ';
24+
$args .= '-DMI_INSTALL_TOPLEVEL=ON ';
25+
FileSystem::resetDir($this->source_dir . '/build');
26+
shell()->cd($this->source_dir . '/build')
27+
->execWithEnv(
28+
'cmake ' .
29+
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
30+
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
31+
'-DCMAKE_BUILD_TYPE=Release ' .
32+
$args .
33+
'..'
34+
)
35+
->execWithEnv("make -j{$this->builder->concurrency}")
36+
->execWithEnv('make install');
37+
}
38+
}

src/SPC/store/Downloader.php

+12-7
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,19 @@ public static function getLatestGithubTarball(string $name, array $source, strin
6969
retry: self::getRetryTime()
7070
), true);
7171

72-
if (($source['prefer-stable'] ?? false) === false) {
73-
$url = $data[0]['tarball_url'];
74-
} else {
75-
$id = 0;
76-
while ($data[$id]['prerelease'] === true) {
77-
++$id;
72+
$url = null;
73+
for ($i = 0; $i < count($data); ++$i) {
74+
if (($data[$i]['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) {
75+
continue;
76+
}
77+
if (!($source['match'] ?? null)) {
78+
$url = $data[$i]['tarball_url'] ?? null;
79+
break;
80+
}
81+
if (preg_match('|' . $source['match'] . '|', $data[$i]['tarball_url'])) {
82+
$url = $data[$i]['tarball_url'];
83+
break;
7884
}
79-
$url = $data[$id]['tarball_url'] ?? null;
8085
}
8186
if (!$url) {
8287
throw new DownloaderException("failed to find {$name} source");

src/SPC/util/SPCConfigUtil.php

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ public function config(array $extensions = [], array $libraries = [], bool $incl
4242
if ($this->builder->hasCpp()) {
4343
$libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++';
4444
}
45+
// mimalloc must come first
46+
if (str_contains($libs, BUILD_LIB_PATH . '/mimalloc.o')) {
47+
$libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs);
48+
}
4549
return [
4650
'cflags' => $cflags,
4751
'ldflags' => $ldflags,

src/globals/test-extensions.php

+9-9
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77
/**
88
* This is GitHub Actions automatic test extension args generator.
9-
* You can edit $extensions, $with_libs and $base_combination.
9+
* You can edit $test_php_version, $test_os, $zts, $no_strip, $upx, $prefer_pre_built, $extensions, $with_libs and $base_combination.
1010
*/
1111

1212
// --------------------------------- edit area ---------------------------------
1313

14-
// test php version
14+
// test php version (8.1 ~ 8.4 available, multiple for matrix)
1515
$test_php_version = [
1616
'8.1',
1717
'8.2',
@@ -21,10 +21,10 @@
2121

2222
// test os (macos-13, macos-14, ubuntu-latest, windows-latest are available)
2323
$test_os = [
24-
// 'macos-13',
25-
// 'macos-14',
26-
// 'ubuntu-latest',
27-
'windows-latest',
24+
'macos-13',
25+
'macos-14',
26+
'ubuntu-latest',
27+
// 'windows-latest',
2828
];
2929

3030
// whether enable thread safe
@@ -40,21 +40,21 @@
4040

4141
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
4242
$extensions = match (PHP_OS_FAMILY) {
43-
'Linux', 'Darwin' => 'gd',
43+
'Linux', 'Darwin' => '',
4444
'Windows' => 'bz2,ctype,curl,dom,filter,gd,iconv,mbstring,opcache,openssl,pdo,pdo_sqlite,phar,session,simplexml,sqlite3,tokenizer,xml,xmlwriter,yaml,zip,zlib',
4545
};
4646

4747
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
4848
$with_libs = match (PHP_OS_FAMILY) {
49-
'Linux', 'Darwin' => 'freetype',
49+
'Linux', 'Darwin' => 'mimalloc',
5050
'Windows' => 'libjpeg,libavif,freetype,libwebp',
5151
};
5252

5353
// Please change your test base combination. We recommend testing with `common`.
5454
// You can use `common`, `bulk`, `minimal` or `none`.
5555
// note: combination is only available for *nix platform. Windows must use `none` combination
5656
$base_combination = match (PHP_OS_FAMILY) {
57-
'Linux', 'Darwin' => 'minimal',
57+
'Linux', 'Darwin' => 'bulk',
5858
'Windows' => 'none',
5959
};
6060

0 commit comments

Comments
 (0)