mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-17 05:45:35 +08:00
Compare commits
43 Commits
2.7.3
...
e02be69e40
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e02be69e40 | ||
|
|
35a90f2769 | ||
|
|
fa87149631 | ||
|
|
8dfe722e14 | ||
|
|
dcbfe1e0ab | ||
|
|
e11946fd10 | ||
|
|
44399cd185 | ||
|
|
927d7f55ba | ||
|
|
e323d7b155 | ||
|
|
d0b253c346 | ||
|
|
81430e6853 | ||
|
|
83696e92b7 | ||
|
|
b0538c09bf | ||
|
|
40f89d1dca | ||
|
|
fa2e041cc9 | ||
|
|
3c614663a3 | ||
|
|
b5c7185374 | ||
|
|
d0a9a3a594 | ||
|
|
2e6329bb86 | ||
|
|
d3ba04fc5b | ||
|
|
7a78ea0185 | ||
|
|
36b04f9eba | ||
|
|
79ab6490fd | ||
|
|
191d345250 | ||
|
|
311ee40ae4 | ||
|
|
808d224b08 | ||
|
|
4247883664 | ||
|
|
3198cc40c1 | ||
|
|
8680e83af3 | ||
|
|
0156f33a20 | ||
|
|
df8b2dbf16 | ||
|
|
30e174ac95 | ||
|
|
b9f8f02d98 | ||
|
|
0b0ae270da | ||
|
|
893ce31b17 | ||
|
|
e35d6c2651 | ||
|
|
8dd0512335 | ||
|
|
5c1194ea92 | ||
|
|
953ed83df5 | ||
|
|
c330d02e78 | ||
|
|
af6a23011c | ||
|
|
882ae07deb | ||
|
|
4bc30b0b6f |
@@ -414,9 +414,17 @@
|
|||||||
"libmemcached",
|
"libmemcached",
|
||||||
"fastlz"
|
"fastlz"
|
||||||
],
|
],
|
||||||
|
"lib-suggests": [
|
||||||
|
"zstd"
|
||||||
|
],
|
||||||
"ext-depends": [
|
"ext-depends": [
|
||||||
"session",
|
"session",
|
||||||
"zlib"
|
"zlib"
|
||||||
|
],
|
||||||
|
"ext-suggests": [
|
||||||
|
"igbinary",
|
||||||
|
"msgpack",
|
||||||
|
"session"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mongodb": {
|
"mongodb": {
|
||||||
|
|||||||
@@ -9,17 +9,19 @@
|
|||||||
"lib-base",
|
"lib-base",
|
||||||
"micro"
|
"micro"
|
||||||
],
|
],
|
||||||
|
"lib-depends-macos": [
|
||||||
|
"lib-base",
|
||||||
|
"micro",
|
||||||
|
"libxml2"
|
||||||
|
],
|
||||||
"lib-suggests-linux": [
|
"lib-suggests-linux": [
|
||||||
"libacl",
|
"libacl",
|
||||||
"brotli",
|
"brotli",
|
||||||
"watcher"
|
"watcher"
|
||||||
],
|
],
|
||||||
"lib-suggests-unix": [
|
"lib-suggests-macos": [
|
||||||
"brotli",
|
"brotli",
|
||||||
"watcher"
|
"watcher"
|
||||||
],
|
|
||||||
"lib-depends-macos": [
|
|
||||||
"libxml2"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"micro": {
|
"micro": {
|
||||||
@@ -200,6 +202,7 @@
|
|||||||
"openssl",
|
"openssl",
|
||||||
"libcares"
|
"libcares"
|
||||||
],
|
],
|
||||||
|
"cpp-library": true,
|
||||||
"provide-pre-built": true,
|
"provide-pre-built": true,
|
||||||
"frameworks": [
|
"frameworks": [
|
||||||
"CoreFoundation"
|
"CoreFoundation"
|
||||||
@@ -228,6 +231,7 @@
|
|||||||
},
|
},
|
||||||
"imagemagick": {
|
"imagemagick": {
|
||||||
"source": "imagemagick",
|
"source": "imagemagick",
|
||||||
|
"cpp-library": true,
|
||||||
"pkg-configs": [
|
"pkg-configs": [
|
||||||
"Magick++-7.Q16HDRI",
|
"Magick++-7.Q16HDRI",
|
||||||
"MagickCore-7.Q16HDRI",
|
"MagickCore-7.Q16HDRI",
|
||||||
@@ -450,6 +454,7 @@
|
|||||||
},
|
},
|
||||||
"libmemcached": {
|
"libmemcached": {
|
||||||
"source": "libmemcached",
|
"source": "libmemcached",
|
||||||
|
"cpp-library": true,
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
"libmemcached.a",
|
"libmemcached.a",
|
||||||
"libmemcachedprotocol.a",
|
"libmemcachedprotocol.a",
|
||||||
@@ -594,7 +599,6 @@
|
|||||||
],
|
],
|
||||||
"lib-suggests-unix": [
|
"lib-suggests-unix": [
|
||||||
"xz",
|
"xz",
|
||||||
"icu",
|
|
||||||
"zlib"
|
"zlib"
|
||||||
],
|
],
|
||||||
"lib-depends-windows": [
|
"lib-depends-windows": [
|
||||||
@@ -865,6 +869,7 @@
|
|||||||
},
|
},
|
||||||
"watcher": {
|
"watcher": {
|
||||||
"source": "watcher",
|
"source": "watcher",
|
||||||
|
"cpp-library": true,
|
||||||
"static-libs-unix": [
|
"static-libs-unix": [
|
||||||
"libwatcher-c.a"
|
"libwatcher-c.a"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -324,7 +324,7 @@
|
|||||||
},
|
},
|
||||||
"grpc": {
|
"grpc": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"rev": "v1.68.x",
|
"rev": "v1.75.x",
|
||||||
"url": "https://github.com/grpc/grpc.git",
|
"url": "https://github.com/grpc/grpc.git",
|
||||||
"provide-pre-built": true,
|
"provide-pre-built": true,
|
||||||
"license": {
|
"license": {
|
||||||
|
|||||||
@@ -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.3';
|
public const string VERSION = '2.7.4';
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use SPC\exception\WrongUsageException;
|
|||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\LockFile;
|
use SPC\store\LockFile;
|
||||||
|
use SPC\store\pkg\GoXcaddy;
|
||||||
use SPC\store\SourceManager;
|
use SPC\store\SourceManager;
|
||||||
use SPC\store\SourcePatcher;
|
use SPC\store\SourcePatcher;
|
||||||
use SPC\util\AttributeMapper;
|
use SPC\util\AttributeMapper;
|
||||||
@@ -507,8 +508,7 @@ abstract class BuilderBase
|
|||||||
throw new WrongUsageException('FrankenPHP SAPI is only available on Linux and macOS!');
|
throw new WrongUsageException('FrankenPHP SAPI is only available on Linux and macOS!');
|
||||||
}
|
}
|
||||||
// frankenphp needs package go-xcaddy installed
|
// frankenphp needs package go-xcaddy installed
|
||||||
$pkg_dir = PKG_ROOT_PATH . '/go-xcaddy-' . arch2gnu(php_uname('m')) . '-' . osfamily2shortname();
|
if (!GoXcaddy::isInstalled()) {
|
||||||
if (!file_exists("{$pkg_dir}/bin/go") || !file_exists("{$pkg_dir}/bin/xcaddy")) {
|
|
||||||
global $argv;
|
global $argv;
|
||||||
throw new WrongUsageException("FrankenPHP SAPI requires the go-xcaddy package, please install it first: {$argv[0]} install-pkg go-xcaddy");
|
throw new WrongUsageException("FrankenPHP SAPI requires the go-xcaddy package, please install it first: {$argv[0]} install-pkg go-xcaddy");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ use SPC\exception\ValidationException;
|
|||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\toolchain\ToolchainManager;
|
|
||||||
use SPC\toolchain\ZigToolchain;
|
|
||||||
use SPC\util\SPCConfigUtil;
|
use SPC\util\SPCConfigUtil;
|
||||||
use SPC\util\SPCTarget;
|
use SPC\util\SPCTarget;
|
||||||
|
|
||||||
@@ -223,12 +221,24 @@ class Extension
|
|||||||
public function patchBeforeSharedMake(): bool
|
public function patchBeforeSharedMake(): bool
|
||||||
{
|
{
|
||||||
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs()));
|
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()], array_map(fn ($l) => $l->getName(), $this->builder->getLibs()));
|
||||||
[$staticLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
|
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
|
||||||
FileSystem::replaceFileRegex(
|
$lstdcpp = str_contains($sharedLibs, '-l:libstdc++.a') ? '-l:libstdc++.a' : null;
|
||||||
$this->source_dir . '/Makefile',
|
$lstdcpp ??= str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : '';
|
||||||
'/^(.*_SHARED_LIBADD\s*=.*)$/m',
|
|
||||||
'$1 ' . trim($staticLibs)
|
$makefileContent = file_get_contents($this->source_dir . '/Makefile');
|
||||||
);
|
if (preg_match('/^(.*_SHARED_LIBADD\s*=\s*)(.*)$/m', $makefileContent, $matches)) {
|
||||||
|
$prefix = $matches[1];
|
||||||
|
$currentLibs = trim($matches[2]);
|
||||||
|
$newLibs = trim("{$currentLibs} {$staticLibs} {$lstdcpp}");
|
||||||
|
$deduplicatedLibs = deduplicate_flags($newLibs);
|
||||||
|
|
||||||
|
FileSystem::replaceFileRegex(
|
||||||
|
$this->source_dir . '/Makefile',
|
||||||
|
'/^(.*_SHARED_LIBADD\s*=.*)$/m',
|
||||||
|
$prefix . $deduplicatedLibs
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if ($objs = getenv('SPC_EXTRA_RUNTIME_OBJECTS')) {
|
if ($objs = getenv('SPC_EXTRA_RUNTIME_OBJECTS')) {
|
||||||
FileSystem::replaceFileRegex(
|
FileSystem::replaceFileRegex(
|
||||||
$this->source_dir . '/Makefile',
|
$this->source_dir . '/Makefile',
|
||||||
@@ -402,26 +412,7 @@ class Extension
|
|||||||
*/
|
*/
|
||||||
public function buildUnixShared(): void
|
public function buildUnixShared(): void
|
||||||
{
|
{
|
||||||
$config = (new SPCConfigUtil($this->builder))->config(
|
$env = $this->getSharedExtensionEnv();
|
||||||
[$this->getName()],
|
|
||||||
array_map(fn ($l) => $l->getName(), $this->getLibraryDependencies(recursive: true)),
|
|
||||||
$this->builder->getOption('with-suggested-exts'),
|
|
||||||
$this->builder->getOption('with-suggested-libs'),
|
|
||||||
);
|
|
||||||
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
|
|
||||||
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
|
|
||||||
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
|
|
||||||
$env = [
|
|
||||||
'CFLAGS' => $config['cflags'],
|
|
||||||
'CXXFLAGS' => $config['cflags'],
|
|
||||||
'LDFLAGS' => $config['ldflags'],
|
|
||||||
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
|
|
||||||
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
|
|
||||||
];
|
|
||||||
if (ToolchainManager::getToolchainClass() === ZigToolchain::class && SPCTarget::getTargetOS() === 'Linux') {
|
|
||||||
$env['SPC_COMPILER_EXTRA'] = '-lstdc++';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->patchBeforeSharedPhpize()) {
|
if ($this->patchBeforeSharedPhpize()) {
|
||||||
logger()->info("Extension [{$this->getName()}] patched before shared phpize");
|
logger()->info("Extension [{$this->getName()}] patched before shared phpize");
|
||||||
}
|
}
|
||||||
@@ -493,6 +484,30 @@ class Extension
|
|||||||
return $this->build_static;
|
return $this->build_static;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the environment variables a shared extension needs to be built.
|
||||||
|
* CFLAGS, CXXFLAGS, LDFLAGS and so on.
|
||||||
|
*/
|
||||||
|
protected function getSharedExtensionEnv(): array
|
||||||
|
{
|
||||||
|
$config = (new SPCConfigUtil($this->builder))->config(
|
||||||
|
[$this->getName()],
|
||||||
|
array_map(fn ($l) => $l->getName(), $this->getLibraryDependencies(recursive: true)),
|
||||||
|
$this->builder->getOption('with-suggested-exts'),
|
||||||
|
$this->builder->getOption('with-suggested-libs'),
|
||||||
|
);
|
||||||
|
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
|
||||||
|
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
|
||||||
|
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
|
||||||
|
return [
|
||||||
|
'CFLAGS' => $config['cflags'],
|
||||||
|
'CXXFLAGS' => $config['cflags'],
|
||||||
|
'LDFLAGS' => $config['ldflags'],
|
||||||
|
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
|
||||||
|
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected function addLibraryDependency(string $name, bool $optional = false): void
|
protected function addLibraryDependency(string $name, bool $optional = false): void
|
||||||
{
|
{
|
||||||
$depLib = $this->builder->getLib($name);
|
$depLib = $this->builder->getLib($name);
|
||||||
@@ -565,12 +580,12 @@ class Extension
|
|||||||
$added = 0;
|
$added = 0;
|
||||||
foreach ($ret as $depName => $dep) {
|
foreach ($ret as $depName => $dep) {
|
||||||
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
|
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
|
||||||
if (!in_array($depdepName, array_keys($deps), true)) {
|
if (!array_key_exists($depdepName, $deps)) {
|
||||||
$deps[$depdepName] = $depdep;
|
$deps[$depdepName] = $depdep;
|
||||||
++$added;
|
++$added;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!in_array($depName, array_keys($deps), true)) {
|
if (!array_key_exists($depName, $deps)) {
|
||||||
$deps[$depName] = $dep;
|
$deps[$depName] = $dep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class dba extends Extension
|
|||||||
{
|
{
|
||||||
public function getUnixConfigureArg(bool $shared = false): string
|
public function getUnixConfigureArg(bool $shared = false): string
|
||||||
{
|
{
|
||||||
$qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH) : '';
|
$qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . BUILD_ROOT_PATH) : '';
|
||||||
return '--enable-dba' . ($shared ? '=shared' : '') . $qdbm;
|
return '--enable-dba' . ($shared ? '=shared' : '') . $qdbm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,4 +56,11 @@ class grpc extends Extension
|
|||||||
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes');
|
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getSharedExtensionEnv(): array
|
||||||
|
{
|
||||||
|
$env = parent::getSharedExtensionEnv();
|
||||||
|
$env['CPPFLAGS'] = $env['CXXFLAGS'] . ' -Wno-attributes';
|
||||||
|
return $env;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ class memcached extends Extension
|
|||||||
'--with-libmemcached-dir=' . BUILD_ROOT_PATH . ' ' .
|
'--with-libmemcached-dir=' . BUILD_ROOT_PATH . ' ' .
|
||||||
'--disable-memcached-sasl ' .
|
'--disable-memcached-sasl ' .
|
||||||
'--enable-memcached-json ' .
|
'--enable-memcached-json ' .
|
||||||
|
($this->builder->getLib('zstd') ? '--with-zstd ' : '') .
|
||||||
|
($this->builder->getExt('igbinary') ? '--enable-memcached-igbinary ' : '') .
|
||||||
|
($this->builder->getExt('session') ? '--enable-memcached-session ' : '') .
|
||||||
|
($this->builder->getExt('msgpack') ? '--enable-memcached-msgpack ' : '') .
|
||||||
'--with-system-fastlz';
|
'--with-system-fastlz';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,9 +103,8 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
$this->seekPhpSrcLogFileOnException(fn () => shell()->cd(SOURCE_PATH . '/php-src')->exec(
|
||||||
->exec(
|
$php_configure_env . ' ' .
|
||||||
$php_configure_env . ' ' .
|
|
||||||
getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' .
|
getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' .
|
||||||
($enableCli ? '--enable-cli ' : '--disable-cli ') .
|
($enableCli ? '--enable-cli ' : '--disable-cli ') .
|
||||||
($enableFpm ? '--enable-fpm ' . ($this->getLib('libacl') !== null ? '--with-fpm-acl ' : '') : '--disable-fpm ') .
|
($enableFpm ? '--enable-fpm ' . ($this->getLib('libacl') !== null ? '--with-fpm-acl ' : '') : '--disable-fpm ') .
|
||||||
@@ -118,7 +117,7 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
$zts .
|
$zts .
|
||||||
$maxExecutionTimers .
|
$maxExecutionTimers .
|
||||||
$this->makeStaticExtensionArgs() . ' '
|
$this->makeStaticExtensionArgs() . ' '
|
||||||
);
|
));
|
||||||
|
|
||||||
$this->emitPatchPoint('before-php-make');
|
$this->emitPatchPoint('before-php-make');
|
||||||
SourcePatcher::patchBeforeMake($this);
|
SourcePatcher::patchBeforeMake($this);
|
||||||
@@ -148,16 +147,15 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
}
|
}
|
||||||
$this->buildEmbed();
|
$this->buildEmbed();
|
||||||
}
|
}
|
||||||
// build dynamic extensions if needed, must happen before building FrankenPHP to make sure we export all necessary, undefined symbols
|
if ($enableFrankenphp) {
|
||||||
|
logger()->info('building frankenphp');
|
||||||
|
$this->buildFrankenphp();
|
||||||
|
}
|
||||||
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
|
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
|
||||||
if (!empty($shared_extensions)) {
|
if (!empty($shared_extensions)) {
|
||||||
logger()->info('Building shared extensions ...');
|
logger()->info('Building shared extensions ...');
|
||||||
$this->buildSharedExts();
|
$this->buildSharedExts();
|
||||||
}
|
}
|
||||||
if ($enableFrankenphp) {
|
|
||||||
logger()->info('building frankenphp');
|
|
||||||
$this->buildFrankenphp();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPHP(int $build_target = BUILD_TARGET_NONE)
|
public function testPHP(int $build_target = BUILD_TARGET_NONE)
|
||||||
@@ -327,7 +325,7 @@ class LinuxBuilder extends UnixBuilderBase
|
|||||||
$target = "{$libDir}/{$realLibName}";
|
$target = "{$libDir}/{$realLibName}";
|
||||||
if (file_exists($target)) {
|
if (file_exists($target)) {
|
||||||
[, $output] = shell()->execWithResult('readelf -d ' . escapeshellarg($target));
|
[, $output] = shell()->execWithResult('readelf -d ' . escapeshellarg($target));
|
||||||
$output = join("\n", $output);
|
$output = implode("\n", $output);
|
||||||
if (preg_match('/SONAME.*\[(.+)]/', $output, $sonameMatch)) {
|
if (preg_match('/SONAME.*\[(.+)]/', $output, $sonameMatch)) {
|
||||||
$currentSoname = $sonameMatch[1];
|
$currentSoname = $sonameMatch[1];
|
||||||
if ($currentSoname !== basename($target)) {
|
if ($currentSoname !== basename($target)) {
|
||||||
|
|||||||
@@ -118,9 +118,8 @@ class MacOSBuilder extends UnixBuilderBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
$embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static';
|
$embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static';
|
||||||
shell()->cd(SOURCE_PATH . '/php-src')
|
$this->seekPhpSrcLogFileOnException(fn () => shell()->cd(SOURCE_PATH . '/php-src')->exec(
|
||||||
->exec(
|
getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' .
|
||||||
getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' .
|
|
||||||
($enableCli ? '--enable-cli ' : '--disable-cli ') .
|
($enableCli ? '--enable-cli ' : '--disable-cli ') .
|
||||||
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
|
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
|
||||||
($enableEmbed ? "--enable-embed={$embed_type} " : '--disable-embed ') .
|
($enableEmbed ? "--enable-embed={$embed_type} " : '--disable-embed ') .
|
||||||
@@ -132,7 +131,7 @@ class MacOSBuilder extends UnixBuilderBase
|
|||||||
$zts .
|
$zts .
|
||||||
$this->makeStaticExtensionArgs() . ' ' .
|
$this->makeStaticExtensionArgs() . ' ' .
|
||||||
$envs_build_php
|
$envs_build_php
|
||||||
);
|
));
|
||||||
|
|
||||||
$this->emitPatchPoint('before-php-make');
|
$this->emitPatchPoint('before-php-make');
|
||||||
SourcePatcher::patchBeforeMake($this);
|
SourcePatcher::patchBeforeMake($this);
|
||||||
@@ -162,15 +161,15 @@ class MacOSBuilder extends UnixBuilderBase
|
|||||||
}
|
}
|
||||||
$this->buildEmbed();
|
$this->buildEmbed();
|
||||||
}
|
}
|
||||||
|
if ($enableFrankenphp) {
|
||||||
|
logger()->info('building frankenphp');
|
||||||
|
$this->buildFrankenphp();
|
||||||
|
}
|
||||||
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
|
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
|
||||||
if (!empty($shared_extensions)) {
|
if (!empty($shared_extensions)) {
|
||||||
logger()->info('Building shared extensions ...');
|
logger()->info('Building shared extensions ...');
|
||||||
$this->buildSharedExts();
|
$this->buildSharedExts();
|
||||||
}
|
}
|
||||||
if ($enableFrankenphp) {
|
|
||||||
logger()->info('building frankenphp');
|
|
||||||
$this->buildFrankenphp();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPHP(int $build_target = BUILD_TARGET_NONE)
|
public function testPHP(int $build_target = BUILD_TARGET_NONE)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace SPC\builder\unix;
|
|||||||
|
|
||||||
use SPC\builder\BuilderBase;
|
use SPC\builder\BuilderBase;
|
||||||
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
|
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
|
||||||
|
use SPC\exception\SPCException;
|
||||||
use SPC\exception\SPCInternalException;
|
use SPC\exception\SPCInternalException;
|
||||||
use SPC\exception\ValidationException;
|
use SPC\exception\ValidationException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
@@ -266,7 +267,7 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
|
|
||||||
protected function buildFrankenphp(): void
|
protected function buildFrankenphp(): void
|
||||||
{
|
{
|
||||||
GlobalEnvManager::addPathIfNotExists(GoXcaddy::getEnvironment()['PATH']);
|
GlobalEnvManager::addPathIfNotExists(GoXcaddy::getPath());
|
||||||
$nobrotli = $this->getLib('brotli') === null ? ',nobrotli' : '';
|
$nobrotli = $this->getLib('brotli') === null ? ',nobrotli' : '';
|
||||||
$nowatcher = $this->getLib('watcher') === null ? ',nowatcher' : '';
|
$nowatcher = $this->getLib('watcher') === null ? ',nowatcher' : '';
|
||||||
$xcaddyModules = getenv('SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES');
|
$xcaddyModules = getenv('SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES');
|
||||||
@@ -290,11 +291,11 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$debugFlags = $this->getOption('no-strip') ? '-w -s ' : '';
|
$debugFlags = $this->getOption('no-strip') ? '-w -s ' : '';
|
||||||
$extLdFlags = "-extldflags '-pie{$dynamic_exports}'";
|
$extLdFlags = "-extldflags '-pie{$dynamic_exports} {$this->arch_ld_flags}'";
|
||||||
$muslTags = '';
|
$muslTags = '';
|
||||||
$staticFlags = '';
|
$staticFlags = '';
|
||||||
if (SPCTarget::isStatic()) {
|
if (SPCTarget::isStatic()) {
|
||||||
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000{$dynamic_exports}'";
|
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000{$dynamic_exports} {$this->arch_ld_flags}'";
|
||||||
$muslTags = 'static_build,';
|
$muslTags = 'static_build,';
|
||||||
$staticFlags = '-static-pie';
|
$staticFlags = '-static-pie';
|
||||||
}
|
}
|
||||||
@@ -302,7 +303,6 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
$config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list);
|
$config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list);
|
||||||
$cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS');
|
$cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS');
|
||||||
$libs = $config['libs'];
|
$libs = $config['libs'];
|
||||||
$libs .= PHP_OS_FAMILY === 'Linux' ? ' -lrt' : '';
|
|
||||||
// Go's gcc driver doesn't automatically link against -lgcov or -lrt. Ugly, but necessary fix.
|
// Go's gcc driver doesn't automatically link against -lgcov or -lrt. Ugly, but necessary fix.
|
||||||
if ((str_contains((string) getenv('SPC_DEFAULT_C_FLAGS'), '-fprofile') ||
|
if ((str_contains((string) getenv('SPC_DEFAULT_C_FLAGS'), '-fprofile') ||
|
||||||
str_contains((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), '-fprofile')) &&
|
str_contains((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), '-fprofile')) &&
|
||||||
@@ -310,22 +310,17 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
$cflags .= ' -Wno-error=missing-profile';
|
$cflags .= ' -Wno-error=missing-profile';
|
||||||
$libs .= ' -lgcov';
|
$libs .= ' -lgcov';
|
||||||
}
|
}
|
||||||
$env = [
|
$env = [...[
|
||||||
'CGO_ENABLED' => '1',
|
'CGO_ENABLED' => '1',
|
||||||
'CGO_CFLAGS' => clean_spaces($cflags),
|
'CGO_CFLAGS' => clean_spaces($cflags),
|
||||||
'CGO_LDFLAGS' => "{$this->arch_ld_flags} {$staticFlags} {$config['ldflags']} {$libs}",
|
'CGO_LDFLAGS' => "{$this->arch_ld_flags} {$staticFlags} {$config['ldflags']} {$libs}",
|
||||||
'XCADDY_GO_BUILD_FLAGS' => '-buildmode=pie ' .
|
'XCADDY_GO_BUILD_FLAGS' => '-buildmode=pie ' .
|
||||||
'-ldflags \"-linkmode=external ' . $extLdFlags . ' ' . $debugFlags .
|
'-ldflags \"-linkmode=external ' . $extLdFlags . ' ' . $debugFlags .
|
||||||
'-X \'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ' .
|
'-X \'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ' .
|
||||||
"{$frankenPhpVersion} PHP {$libphpVersion} Caddy'\\\" " .
|
"v{$frankenPhpVersion} PHP {$libphpVersion} Caddy'\\\" " .
|
||||||
"-tags={$muslTags}nobadger,nomysql,nopgx{$nobrotli}{$nowatcher}",
|
"-tags={$muslTags}nobadger,nomysql,nopgx{$nobrotli}{$nowatcher}",
|
||||||
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
|
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
|
||||||
];
|
], ...GoXcaddy::getEnvironment()];
|
||||||
foreach (GoXcaddy::getEnvironment() as $key => $value) {
|
|
||||||
if ($key !== 'PATH') {
|
|
||||||
$env[$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shell()->cd(BUILD_BIN_PATH)
|
shell()->cd(BUILD_BIN_PATH)
|
||||||
->setEnv($env)
|
->setEnv($env)
|
||||||
->exec("xcaddy build --output frankenphp {$xcaddyModules}");
|
->exec("xcaddy build --output frankenphp {$xcaddyModules}");
|
||||||
@@ -338,4 +333,20 @@ abstract class UnixBuilderBase extends BuilderBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek php-src/config.log when building PHP, add it to exception.
|
||||||
|
*/
|
||||||
|
protected function seekPhpSrcLogFileOnException(callable $callback): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$callback();
|
||||||
|
} catch (SPCException $e) {
|
||||||
|
if (file_exists(SOURCE_PATH . '/php-src/config.log')) {
|
||||||
|
$e->addExtraLogFile('php-src config.log', 'php-src.config.log');
|
||||||
|
copy(SOURCE_PATH . '/php-src/config.log', SPC_LOGS_DIR . '/php-src.config.log');
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ trait imagemagick
|
|||||||
{
|
{
|
||||||
protected function build(): void
|
protected function build(): void
|
||||||
{
|
{
|
||||||
|
$original_ldflags = $this->builder->arch_ld_flags;
|
||||||
|
if (str_contains($this->builder->arch_ld_flags, '-Wl,--as-needed')) {
|
||||||
|
$this->builder->arch_ld_flags = str_replace('-Wl,--as-needed', '', $original_ldflags);
|
||||||
|
}
|
||||||
|
|
||||||
$ac = UnixAutoconfExecutor::create($this)
|
$ac = UnixAutoconfExecutor::create($this)
|
||||||
->optionalLib('libzip', ...ac_with_args('zip'))
|
->optionalLib('libzip', ...ac_with_args('zip'))
|
||||||
->optionalLib('libjpeg', ...ac_with_args('jpeg'))
|
->optionalLib('libjpeg', ...ac_with_args('jpeg'))
|
||||||
@@ -32,7 +37,7 @@ trait imagemagick
|
|||||||
);
|
);
|
||||||
|
|
||||||
// special: linux-static target needs `-static`
|
// special: linux-static target needs `-static`
|
||||||
$ldflags = SPCTarget::isStatic() ? ('-static -ldl') : '-ldl';
|
$ldflags = SPCTarget::isStatic() ? '-static -ldl' : '-ldl';
|
||||||
|
|
||||||
// special: macOS needs -iconv
|
// special: macOS needs -iconv
|
||||||
$libs = SPCTarget::getTargetOS() === 'Darwin' ? '-liconv' : '';
|
$libs = SPCTarget::getTargetOS() === 'Darwin' ? '-liconv' : '';
|
||||||
@@ -45,6 +50,8 @@ trait imagemagick
|
|||||||
|
|
||||||
$ac->configure()->make();
|
$ac->configure()->make();
|
||||||
|
|
||||||
|
$this->builder->arch_ld_flags = $original_ldflags;
|
||||||
|
|
||||||
$filelist = [
|
$filelist = [
|
||||||
'ImageMagick.pc',
|
'ImageMagick.pc',
|
||||||
'ImageMagick-7.Q16HDRI.pc',
|
'ImageMagick-7.Q16HDRI.pc',
|
||||||
|
|||||||
@@ -20,17 +20,17 @@ trait libxml2
|
|||||||
"-DZLIB_INCLUDE_DIR={$this->getIncludeDir()}",
|
"-DZLIB_INCLUDE_DIR={$this->getIncludeDir()}",
|
||||||
'-DLIBXML2_WITH_ZLIB=OFF',
|
'-DLIBXML2_WITH_ZLIB=OFF',
|
||||||
)
|
)
|
||||||
->optionalLib('icu', ...cmake_boolean_args('LIBXML2_WITH_ICU'))
|
|
||||||
->optionalLib('xz', ...cmake_boolean_args('LIBXML2_WITH_LZMA'))
|
->optionalLib('xz', ...cmake_boolean_args('LIBXML2_WITH_LZMA'))
|
||||||
->addConfigureArgs(
|
->addConfigureArgs(
|
||||||
'-DLIBXML2_WITH_ICONV=ON',
|
'-DLIBXML2_WITH_ICONV=ON',
|
||||||
|
'-DLIBXML2_WITH_ICU=OFF', // optional, but discouraged: https://gitlab.gnome.org/GNOME/libxml2/-/blob/master/README.md
|
||||||
'-DLIBXML2_WITH_PYTHON=OFF',
|
'-DLIBXML2_WITH_PYTHON=OFF',
|
||||||
'-DLIBXML2_WITH_PROGRAMS=OFF',
|
'-DLIBXML2_WITH_PROGRAMS=OFF',
|
||||||
'-DLIBXML2_WITH_TESTS=OFF',
|
'-DLIBXML2_WITH_TESTS=OFF',
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($this instanceof LinuxLibraryBase) {
|
if ($this instanceof LinuxLibraryBase) {
|
||||||
$cmake->addConfigureArgs('-DIconv_IS_BUILD_IN=OFF');
|
$cmake->addConfigureArgs('-DIconv_IS_BUILT_IN=OFF');
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmake->build();
|
$cmake->build();
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ declare(strict_types=1);
|
|||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
use SPC\exception\ValidationException;
|
use SPC\exception\ValidationException;
|
||||||
|
use SPC\store\pkg\GoXcaddy;
|
||||||
|
use SPC\store\pkg\Zig;
|
||||||
use SPC\toolchain\ToolchainManager;
|
use SPC\toolchain\ToolchainManager;
|
||||||
use SPC\toolchain\ZigToolchain;
|
use SPC\toolchain\ZigToolchain;
|
||||||
use SPC\util\ConfigValidator;
|
use SPC\util\ConfigValidator;
|
||||||
@@ -63,7 +65,7 @@ class CraftCommand extends BuildCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// install go and xcaddy for frankenphp
|
// install go and xcaddy for frankenphp
|
||||||
if (in_array('frankenphp', $craft['sapi'])) {
|
if (in_array('frankenphp', $craft['sapi']) && !GoXcaddy::isInstalled()) {
|
||||||
$retcode = $this->runCommand('install-pkg', 'go-xcaddy');
|
$retcode = $this->runCommand('install-pkg', 'go-xcaddy');
|
||||||
if ($retcode !== 0) {
|
if ($retcode !== 0) {
|
||||||
$this->output->writeln('<error>craft go-xcaddy failed</error>');
|
$this->output->writeln('<error>craft go-xcaddy failed</error>');
|
||||||
@@ -71,7 +73,7 @@ class CraftCommand extends BuildCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// install zig if requested
|
// install zig if requested
|
||||||
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
|
if (ToolchainManager::getToolchainClass() === ZigToolchain::class && !Zig::isInstalled()) {
|
||||||
$retcode = $this->runCommand('install-pkg', 'zig');
|
$retcode = $this->runCommand('install-pkg', 'zig');
|
||||||
if ($retcode !== 0) {
|
if ($retcode !== 0) {
|
||||||
$this->output->writeln('<error>craft zig failed</error>');
|
$this->output->writeln('<error>craft zig failed</error>');
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// retry
|
// retry
|
||||||
$retry = intval($this->getOption('retry'));
|
$retry = (int) $this->getOption('retry');
|
||||||
f_putenv('SPC_DOWNLOAD_RETRIES=' . $retry);
|
f_putenv('SPC_DOWNLOAD_RETRIES=' . $retry);
|
||||||
|
|
||||||
// Use shallow-clone can reduce git resource download
|
// Use shallow-clone can reduce git resource download
|
||||||
@@ -265,7 +265,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
f_passthru((PHP_OS_FAMILY === 'Windows' ? 'rmdir /s /q ' : 'rm -rf ') . DOWNLOAD_PATH);
|
f_passthru((PHP_OS_FAMILY === 'Windows' ? 'rmdir /s /q ' : 'rm -rf ') . DOWNLOAD_PATH);
|
||||||
}
|
}
|
||||||
// unzip command check
|
// unzip command check
|
||||||
if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) {
|
if (PHP_OS_FAMILY !== 'Windows' && !self::findCommand('unzip')) {
|
||||||
$this->output->writeln('Missing unzip command, you need to install it first !');
|
$this->output->writeln('Missing unzip command, you need to install it first !');
|
||||||
$this->output->writeln('You can use "bin/spc doctor" command to check and install required tools');
|
$this->output->writeln('You can use "bin/spc doctor" command to check and install required tools');
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class LinuxToolCheckList
|
|||||||
public const TOOLS_DEBIAN = [
|
public const TOOLS_DEBIAN = [
|
||||||
'make', 'bison', 're2c', 'flex',
|
'make', 'bison', 're2c', 'flex',
|
||||||
'git', 'autoconf', 'automake', 'autopoint',
|
'git', 'autoconf', 'automake', 'autopoint',
|
||||||
'tar', 'unzip', 'gzip',
|
'tar', 'unzip', 'gzip', 'gcc', 'g++',
|
||||||
'bzip2', 'cmake', 'patch',
|
'bzip2', 'cmake', 'patch',
|
||||||
'xz', 'libtoolize', 'which',
|
'xz', 'libtoolize', 'which',
|
||||||
'patchelf',
|
'patchelf',
|
||||||
@@ -37,7 +37,7 @@ class LinuxToolCheckList
|
|||||||
public const TOOLS_RHEL = [
|
public const TOOLS_RHEL = [
|
||||||
'perl', 'make', 'bison', 're2c', 'flex',
|
'perl', 'make', 'bison', 're2c', 'flex',
|
||||||
'git', 'autoconf', 'automake',
|
'git', 'autoconf', 'automake',
|
||||||
'tar', 'unzip', 'gzip', 'gcc',
|
'tar', 'unzip', 'gzip', 'gcc', 'g++',
|
||||||
'bzip2', 'cmake', 'patch', 'which',
|
'bzip2', 'cmake', 'patch', 'which',
|
||||||
'xz', 'libtool', 'gettext-devel',
|
'xz', 'libtool', 'gettext-devel',
|
||||||
'patchelf',
|
'patchelf',
|
||||||
@@ -53,7 +53,8 @@ class LinuxToolCheckList
|
|||||||
'base-devel' => 'automake',
|
'base-devel' => 'automake',
|
||||||
'gettext-devel' => 'gettextize',
|
'gettext-devel' => 'gettextize',
|
||||||
'gettext-dev' => 'gettextize',
|
'gettext-dev' => 'gettextize',
|
||||||
'perl-IPC-Cmd' => '/usr/share/doc/perl-IPC-Cmd',
|
'perl-IPC-Cmd' => '/usr/share/perl5/vendor_perl/IPC/Cmd.pm',
|
||||||
|
'perl-Time-Piece' => '/usr/lib64/perl5/Time/Piece.pm',
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @noinspection PhpUnused */
|
/** @noinspection PhpUnused */
|
||||||
@@ -65,7 +66,7 @@ class LinuxToolCheckList
|
|||||||
$required = match ($distro['dist']) {
|
$required = match ($distro['dist']) {
|
||||||
'alpine' => self::TOOLS_ALPINE,
|
'alpine' => self::TOOLS_ALPINE,
|
||||||
'redhat' => self::TOOLS_RHEL,
|
'redhat' => self::TOOLS_RHEL,
|
||||||
'centos' => array_merge(self::TOOLS_RHEL, ['perl-IPC-Cmd']),
|
'centos' => array_merge(self::TOOLS_RHEL, ['perl-IPC-Cmd', 'perl-Time-Piece']),
|
||||||
'arch' => self::TOOLS_ARCH,
|
'arch' => self::TOOLS_ARCH,
|
||||||
default => self::TOOLS_DEBIAN,
|
default => self::TOOLS_DEBIAN,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -65,19 +65,19 @@ class Downloader
|
|||||||
url: "https://api.github.com/repos/{$source['repo']}/{$type}",
|
url: "https://api.github.com/repos/{$source['repo']}/{$type}",
|
||||||
hooks: [[CurlHook::class, 'setupGithubToken']],
|
hooks: [[CurlHook::class, 'setupGithubToken']],
|
||||||
retries: self::getRetryAttempts()
|
retries: self::getRetryAttempts()
|
||||||
), true);
|
), true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
$url = null;
|
$url = null;
|
||||||
for ($i = 0; $i < count($data); ++$i) {
|
foreach ($data as $rel) {
|
||||||
if (($data[$i]['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) {
|
if (($rel['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!($source['match'] ?? null)) {
|
if (!($source['match'] ?? null)) {
|
||||||
$url = $data[$i]['tarball_url'] ?? null;
|
$url = $rel['tarball_url'] ?? null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (preg_match('|' . $source['match'] . '|', $data[$i]['tarball_url'])) {
|
if (preg_match('|' . $source['match'] . '|', $rel['tarball_url'])) {
|
||||||
$url = $data[$i]['tarball_url'];
|
$url = $rel['tarball_url'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,7 +232,8 @@ class Downloader
|
|||||||
$quiet = !defined('DEBUG_MODE') ? '-q --quiet' : '';
|
$quiet = !defined('DEBUG_MODE') ? '-q --quiet' : '';
|
||||||
$git = SPC_GIT_EXEC;
|
$git = SPC_GIT_EXEC;
|
||||||
$shallow = defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '';
|
$shallow = defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '';
|
||||||
$recursive = ($submodules === null) ? '--recursive' : '';
|
$recursive = ($submodules === null && defined('GIT_SHALLOW_CLONE')) ? '--recursive --shallow-submodules' : null;
|
||||||
|
$recursive ??= $submodules === null ? '--recursive' : '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
self::registerCancelEvent(function () use ($download_path) {
|
self::registerCancelEvent(function () use ($download_path) {
|
||||||
@@ -243,8 +244,9 @@ class Downloader
|
|||||||
});
|
});
|
||||||
f_passthru("{$git} clone {$quiet} --config core.autocrlf=false --branch \"{$branch}\" {$shallow} {$recursive} \"{$url}\" \"{$download_path}\"");
|
f_passthru("{$git} clone {$quiet} --config core.autocrlf=false --branch \"{$branch}\" {$shallow} {$recursive} \"{$url}\" \"{$download_path}\"");
|
||||||
if ($submodules !== null) {
|
if ($submodules !== null) {
|
||||||
|
$depth_flag = defined('GIT_SHALLOW_CLONE') ? '--depth 1' : '';
|
||||||
foreach ($submodules as $submodule) {
|
foreach ($submodules as $submodule) {
|
||||||
f_passthru("cd \"{$download_path}\" && {$git} submodule update --init " . escapeshellarg($submodule));
|
f_passthru("cd \"{$download_path}\" && {$git} submodule update --init {$depth_flag} " . escapeshellarg($submodule));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SPCException $e) {
|
} catch (SPCException $e) {
|
||||||
@@ -399,7 +401,7 @@ class Downloader
|
|||||||
* Download source
|
* Download source
|
||||||
*
|
*
|
||||||
* @param string $name source name
|
* @param string $name source name
|
||||||
* @param null|array{
|
* @param null|array{
|
||||||
* type: string,
|
* type: string,
|
||||||
* repo: ?string,
|
* repo: ?string,
|
||||||
* url: ?string,
|
* url: ?string,
|
||||||
@@ -414,7 +416,7 @@ class Downloader
|
|||||||
* path: ?string,
|
* path: ?string,
|
||||||
* text: ?string
|
* text: ?string
|
||||||
* }
|
* }
|
||||||
* } $source source meta info: [type, path, rev, url, filename, regex, license]
|
* } $source source meta info: [type, path, rev, url, filename, regex, license]
|
||||||
* @param bool $force Whether to force download (default: false)
|
* @param bool $force Whether to force download (default: false)
|
||||||
* @param int $download_as Lock source type (default: SPC_LOCK_SOURCE)
|
* @param int $download_as Lock source type (default: SPC_LOCK_SOURCE)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ class FileSystem
|
|||||||
public static function convertWinPathToMinGW(string $path): string
|
public static function convertWinPathToMinGW(string $path): string
|
||||||
{
|
{
|
||||||
if (preg_match('/^[A-Za-z]:/', $path)) {
|
if (preg_match('/^[A-Za-z]:/', $path)) {
|
||||||
$path = '/' . strtolower(substr($path, 0, 1)) . '/' . str_replace('\\', '/', substr($path, 2));
|
$path = '/' . strtolower($path[0]) . '/' . str_replace('\\', '/', substr($path, 2));
|
||||||
}
|
}
|
||||||
return $path;
|
return $path;
|
||||||
}
|
}
|
||||||
@@ -314,8 +314,13 @@ class FileSystem
|
|||||||
$sub_file = self::convertPath($dir . '/' . $v);
|
$sub_file = self::convertPath($dir . '/' . $v);
|
||||||
if (is_dir($sub_file) && $recursive) {
|
if (is_dir($sub_file) && $recursive) {
|
||||||
# 如果是 目录 且 递推 , 则递推添加下级文件
|
# 如果是 目录 且 递推 , 则递推添加下级文件
|
||||||
$list = array_merge($list, self::scanDirFiles($sub_file, $recursive, $relative));
|
$sub_list = self::scanDirFiles($sub_file, $recursive, $relative);
|
||||||
} elseif (is_file($sub_file) || is_dir($sub_file) && !$recursive && $include_dir) {
|
if (is_array($sub_list)) {
|
||||||
|
foreach ($sub_list as $item) {
|
||||||
|
$list[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (is_file($sub_file) || (is_dir($sub_file) && !$recursive && $include_dir)) {
|
||||||
# 如果是 文件 或 (是 目录 且 不递推 且 包含目录)
|
# 如果是 文件 或 (是 目录 且 不递推 且 包含目录)
|
||||||
if (is_string($relative) && mb_strpos($sub_file, $relative) === 0) {
|
if (is_string($relative) && mb_strpos($sub_file, $relative) === 0) {
|
||||||
$list[] = ltrim(mb_substr($sub_file, mb_strlen($relative)), '/\\');
|
$list[] = ltrim(mb_substr($sub_file, mb_strlen($relative)), '/\\');
|
||||||
@@ -440,7 +445,7 @@ class FileSystem
|
|||||||
public static function writeFile(string $path, mixed $content, ...$args): bool|int|string
|
public static function writeFile(string $path, mixed $content, ...$args): bool|int|string
|
||||||
{
|
{
|
||||||
$dir = pathinfo(self::convertPath($path), PATHINFO_DIRNAME);
|
$dir = pathinfo(self::convertPath($path), PATHINFO_DIRNAME);
|
||||||
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
|
if (!is_dir($dir) && !mkdir($dir, 0755, true) && !is_dir($dir)) {
|
||||||
throw new FileSystemException('Write file failed, cannot create parent directory: ' . $dir);
|
throw new FileSystemException('Write file failed, cannot create parent directory: ' . $dir);
|
||||||
}
|
}
|
||||||
return file_put_contents($path, $content, ...$args);
|
return file_put_contents($path, $content, ...$args);
|
||||||
|
|||||||
@@ -30,10 +30,14 @@ abstract class CustomPackage
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the environment variables this package needs to be usable.
|
* Get the environment variables this package needs to be usable.
|
||||||
* PATH needs to be appended, rather than replaced.
|
|
||||||
*/
|
*/
|
||||||
abstract public static function getEnvironment(): array;
|
abstract public static function getEnvironment(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the PATH required to use this package.
|
||||||
|
*/
|
||||||
|
abstract public static function getPath(): ?string;
|
||||||
|
|
||||||
abstract public static function isInstalled(): bool;
|
abstract public static function isInstalled(): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,18 +13,7 @@ class GoXcaddy extends CustomPackage
|
|||||||
{
|
{
|
||||||
public static function isInstalled(): bool
|
public static function isInstalled(): bool
|
||||||
{
|
{
|
||||||
$arch = arch2gnu(php_uname('m'));
|
$folder = PKG_ROOT_PATH . '/go-xcaddy';
|
||||||
$os = match (PHP_OS_FAMILY) {
|
|
||||||
'Windows' => 'win',
|
|
||||||
'Darwin' => 'macos',
|
|
||||||
'BSD' => 'freebsd',
|
|
||||||
default => 'linux',
|
|
||||||
};
|
|
||||||
|
|
||||||
$packageName = "go-xcaddy-{$arch}-{$os}";
|
|
||||||
$pkgroot = PKG_ROOT_PATH;
|
|
||||||
$folder = "{$pkgroot}/{$packageName}";
|
|
||||||
|
|
||||||
return is_dir($folder) && is_file("{$folder}/bin/go") && is_file("{$folder}/bin/xcaddy");
|
return is_dir($folder) && is_file("{$folder}/bin/go") && is_file("{$folder}/bin/xcaddy");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +48,7 @@ class GoXcaddy extends CustomPackage
|
|||||||
'macos' => 'darwin',
|
'macos' => 'darwin',
|
||||||
default => throw new \InvalidArgumentException('Unsupported OS: ' . $name),
|
default => throw new \InvalidArgumentException('Unsupported OS: ' . $name),
|
||||||
};
|
};
|
||||||
$go_version = '1.24.4';
|
$go_version = '1.25.0';
|
||||||
$config = [
|
$config = [
|
||||||
'type' => 'url',
|
'type' => 'url',
|
||||||
'url' => "https://go.dev/dl/go{$go_version}.{$os}-{$arch}.tar.gz",
|
'url' => "https://go.dev/dl/go{$go_version}.{$os}-{$arch}.tar.gz",
|
||||||
@@ -70,15 +59,15 @@ class GoXcaddy extends CustomPackage
|
|||||||
public function extract(string $name): void
|
public function extract(string $name): void
|
||||||
{
|
{
|
||||||
$pkgroot = PKG_ROOT_PATH;
|
$pkgroot = PKG_ROOT_PATH;
|
||||||
$go_exec = "{$pkgroot}/{$name}/bin/go";
|
$go_exec = "{$pkgroot}/go-xcaddy/bin/go";
|
||||||
$xcaddy_exec = "{$pkgroot}/{$name}/bin/xcaddy";
|
$xcaddy_exec = "{$pkgroot}/go-xcaddy/bin/xcaddy";
|
||||||
if (file_exists($go_exec) && file_exists($xcaddy_exec)) {
|
if (file_exists($go_exec) && file_exists($xcaddy_exec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$lock = json_decode(FileSystem::readFile(LockFile::LOCK_FILE), true);
|
$lock = json_decode(FileSystem::readFile(LockFile::LOCK_FILE), true);
|
||||||
$source_type = $lock[$name]['source_type'];
|
$source_type = $lock[$name]['source_type'];
|
||||||
$filename = DOWNLOAD_PATH . '/' . ($lock[$name]['filename'] ?? $lock[$name]['dirname']);
|
$filename = DOWNLOAD_PATH . '/' . ($lock[$name]['filename'] ?? $lock[$name]['dirname']);
|
||||||
$extract = $lock[$name]['move_path'] ?? "{$pkgroot}/{$name}";
|
$extract = $lock[$name]['move_path'] ?? "{$pkgroot}/go-xcaddy";
|
||||||
|
|
||||||
FileSystem::extractPackage($name, $source_type, $filename, $extract);
|
FileSystem::extractPackage($name, $source_type, $filename, $extract);
|
||||||
|
|
||||||
@@ -91,9 +80,9 @@ class GoXcaddy extends CustomPackage
|
|||||||
// install xcaddy without using musl tools, xcaddy build requires dynamic linking
|
// install xcaddy without using musl tools, xcaddy build requires dynamic linking
|
||||||
shell()
|
shell()
|
||||||
->appendEnv([
|
->appendEnv([
|
||||||
'PATH' => "{$pkgroot}/{$name}/bin:" . $sanitizedPath,
|
'PATH' => "{$pkgroot}/go-xcaddy/bin:" . $sanitizedPath,
|
||||||
'GOROOT' => "{$pkgroot}/{$name}",
|
'GOROOT' => "{$pkgroot}/go-xcaddy",
|
||||||
'GOBIN' => "{$pkgroot}/{$name}/bin",
|
'GOBIN' => "{$pkgroot}/go-xcaddy/bin",
|
||||||
'GOPATH' => "{$pkgroot}/go",
|
'GOPATH' => "{$pkgroot}/go",
|
||||||
])
|
])
|
||||||
->exec('CC=cc go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest');
|
->exec('CC=cc go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest');
|
||||||
@@ -101,22 +90,17 @@ class GoXcaddy extends CustomPackage
|
|||||||
|
|
||||||
public static function getEnvironment(): array
|
public static function getEnvironment(): array
|
||||||
{
|
{
|
||||||
$arch = arch2gnu(php_uname('m'));
|
$packageName = 'go-xcaddy';
|
||||||
$os = match (PHP_OS_FAMILY) {
|
|
||||||
'Windows' => 'win',
|
|
||||||
'Darwin' => 'macos',
|
|
||||||
'BSD' => 'freebsd',
|
|
||||||
default => 'linux',
|
|
||||||
};
|
|
||||||
|
|
||||||
$packageName = "go-xcaddy-{$arch}-{$os}";
|
|
||||||
$pkgroot = PKG_ROOT_PATH;
|
$pkgroot = PKG_ROOT_PATH;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'PATH' => "{$pkgroot}/{$packageName}/bin",
|
|
||||||
'GOROOT' => "{$pkgroot}/{$packageName}",
|
'GOROOT' => "{$pkgroot}/{$packageName}",
|
||||||
'GOBIN' => "{$pkgroot}/{$packageName}/bin",
|
'GOBIN' => "{$pkgroot}/{$packageName}/bin",
|
||||||
'GOPATH' => "{$pkgroot}/go",
|
'GOPATH' => "{$pkgroot}/go",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getPath(): ?string
|
||||||
|
{
|
||||||
|
return PKG_ROOT_PATH . '/go-xcaddy/bin';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class Zig extends CustomPackage
|
|||||||
public function extract(string $name): void
|
public function extract(string $name): void
|
||||||
{
|
{
|
||||||
$pkgroot = PKG_ROOT_PATH;
|
$pkgroot = PKG_ROOT_PATH;
|
||||||
$zig_bin_dir = "{$pkgroot}/{$name}";
|
$zig_bin_dir = "{$pkgroot}/zig";
|
||||||
|
|
||||||
$files = ['zig', 'zig-cc', 'zig-c++', 'zig-ar', 'zig-ld.lld', 'zig-ranlib', 'zig-objcopy'];
|
$files = ['zig', 'zig-cc', 'zig-c++', 'zig-ar', 'zig-ld.lld', 'zig-ranlib', 'zig-objcopy'];
|
||||||
$all_exist = true;
|
$all_exist = true;
|
||||||
@@ -120,7 +120,7 @@ class Zig extends CustomPackage
|
|||||||
$lock = json_decode(FileSystem::readFile(LockFile::LOCK_FILE), true);
|
$lock = json_decode(FileSystem::readFile(LockFile::LOCK_FILE), true);
|
||||||
$source_type = $lock[$name]['source_type'];
|
$source_type = $lock[$name]['source_type'];
|
||||||
$filename = DOWNLOAD_PATH . '/' . ($lock[$name]['filename'] ?? $lock[$name]['dirname']);
|
$filename = DOWNLOAD_PATH . '/' . ($lock[$name]['filename'] ?? $lock[$name]['dirname']);
|
||||||
$extract = "{$pkgroot}/{$name}";
|
$extract = "{$pkgroot}/zig";
|
||||||
|
|
||||||
FileSystem::extractPackage($name, $source_type, $filename, $extract);
|
FileSystem::extractPackage($name, $source_type, $filename, $extract);
|
||||||
|
|
||||||
@@ -129,34 +129,12 @@ class Zig extends CustomPackage
|
|||||||
|
|
||||||
public static function getEnvironment(): array
|
public static function getEnvironment(): array
|
||||||
{
|
{
|
||||||
$arch = arch2gnu(php_uname('m'));
|
return [];
|
||||||
$os = match (PHP_OS_FAMILY) {
|
|
||||||
'Windows' => 'win',
|
|
||||||
'Darwin' => 'macos',
|
|
||||||
'BSD' => 'freebsd',
|
|
||||||
default => 'linux',
|
|
||||||
};
|
|
||||||
|
|
||||||
$packageName = "zig-{$arch}-{$os}";
|
|
||||||
$path = PKG_ROOT_PATH . "/{$packageName}";
|
|
||||||
|
|
||||||
return [
|
|
||||||
'PATH' => $path,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getPath(): string
|
public static function getPath(): ?string
|
||||||
{
|
{
|
||||||
$arch = arch2gnu(php_uname('m'));
|
return PKG_ROOT_PATH . '/zig';
|
||||||
$os = match (PHP_OS_FAMILY) {
|
|
||||||
'Windows' => 'win',
|
|
||||||
'Darwin' => 'macos',
|
|
||||||
'BSD' => 'freebsd',
|
|
||||||
default => 'linux',
|
|
||||||
};
|
|
||||||
|
|
||||||
$packageName = "zig-{$arch}-{$os}";
|
|
||||||
return PKG_ROOT_PATH . "/{$packageName}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createZigCcScript(string $bin_dir): void
|
private function createZigCcScript(string $bin_dir): void
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
||||||
BUILDROOT_ABS="$(realpath "$SCRIPT_DIR/../../buildroot/include" 2>/dev/null || true)"
|
BUILDROOT_ABS="$(realpath "$SCRIPT_DIR/../../../buildroot/include" 2>/dev/null || true)"
|
||||||
PARSED_ARGS=()
|
PARSED_ARGS=()
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
@@ -19,9 +19,15 @@ while [[ $# -gt 0 ]]; do
|
|||||||
ARG_ABS="$(realpath "$ARG" 2>/dev/null || true)"
|
ARG_ABS="$(realpath "$ARG" 2>/dev/null || true)"
|
||||||
[[ "$ARG_ABS" == "$BUILDROOT_ABS" ]] && PARSED_ARGS+=("-I$ARG") || PARSED_ARGS+=("-isystem$ARG")
|
[[ "$ARG_ABS" == "$BUILDROOT_ABS" ]] && PARSED_ARGS+=("-I$ARG") || PARSED_ARGS+=("-isystem$ARG")
|
||||||
;;
|
;;
|
||||||
-march=*|-mcpu=*) # replace -march=x86-64 with -march=x86_64
|
-march=*|-mcpu=*)
|
||||||
OPT_NAME="${1%%=*}"
|
OPT_NAME="${1%%=*}"
|
||||||
OPT_VALUE="${1#*=}"
|
OPT_VALUE="${1#*=}"
|
||||||
|
# Skip armv8- flags entirely as Zig doesn't support them
|
||||||
|
if [[ "$OPT_VALUE" == armv8-* ]]; then
|
||||||
|
shift
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# replace -march=x86-64 with -march=x86_64
|
||||||
OPT_VALUE="${OPT_VALUE//-/_}"
|
OPT_VALUE="${OPT_VALUE//-/_}"
|
||||||
PARSED_ARGS+=("${OPT_NAME}=${OPT_VALUE}")
|
PARSED_ARGS+=("${OPT_NAME}=${OPT_VALUE}")
|
||||||
shift
|
shift
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ class ZigToolchain implements ToolchainInterface
|
|||||||
|
|
||||||
public function afterInit(): void
|
public function afterInit(): void
|
||||||
{
|
{
|
||||||
if (!is_dir(Zig::getEnvironment()['PATH'])) {
|
if (!Zig::isInstalled()) {
|
||||||
throw new EnvironmentException('You are building with zig, but zig is not installed, please install zig first. (You can use `doctor` command to install it)');
|
throw new EnvironmentException('You are building with zig, but zig is not installed, please install zig first. (You can use `doctor` command to install it)');
|
||||||
}
|
}
|
||||||
GlobalEnvManager::addPathIfNotExists(Zig::getEnvironment()['PATH']);
|
GlobalEnvManager::addPathIfNotExists(Zig::getPath());
|
||||||
f_passthru('ulimit -n 2048'); // zig opens extra file descriptors, so when a lot of extensions are built statically, 1024 is not enough
|
f_passthru('ulimit -n 2048'); // zig opens extra file descriptors, so when a lot of extensions are built statically, 1024 is not enough
|
||||||
$cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: '';
|
$cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: '';
|
||||||
$cxxflags = getenv('SPC_DEFAULT_CXX_FLAGS') ?: '';
|
$cxxflags = getenv('SPC_DEFAULT_CXX_FLAGS') ?: '';
|
||||||
|
|||||||
@@ -4,20 +4,40 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
assert(function_exists('gettext'));
|
assert(function_exists('gettext'));
|
||||||
assert(function_exists('bindtextdomain'));
|
assert(function_exists('bindtextdomain'));
|
||||||
|
assert(function_exists('bind_textdomain_codeset'));
|
||||||
assert(function_exists('textdomain'));
|
assert(function_exists('textdomain'));
|
||||||
|
|
||||||
if (!is_dir('locale/en_US/LC_MESSAGES/')) {
|
foreach (['en_US', 'en_GB'] as $lc) {
|
||||||
mkdir('locale/en_US/LC_MESSAGES/', 0755, true);
|
$dir = "locale/{$lc}/LC_MESSAGES";
|
||||||
|
if (!is_dir($dir)) {
|
||||||
|
mkdir($dir, 0755, true);
|
||||||
|
}
|
||||||
|
$mo = '3hIElQAAAAACAAAAHAAAACwAAAAFAAAAPAAAAAAAAABQAAAABgAAAFEAAAAXAQAAWAAAAAcAAABwAQAAAQAAAAAAAAAAAAAAAgAAAAAAAAAA56S65L6LAFByb2plY3QtSWQtVmVyc2lvbjogUEFDS0FHRSBWRVJTSU9OClJlcG9ydC1Nc2dpZC1CdWdzLVRvOiAKUE8tUmV2aXNpb24tRGF0ZTogWUVBUi1NTy1EQSBITzpNSytaT05FCkxhc3QtVHJhbnNsYXRvcjogRlVMTCBOQU1FIDxFTUFJTEBBRERSRVNTPgpMYW5ndWFnZS1UZWFtOiBMQU5HVUFHRSA8TExAbGkub3JnPgpMYW5ndWFnZTogCk1JTUUtVmVyc2lvbjogMS4wCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD1VVEYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA4Yml0CgBFeGFtcGxlAA==';
|
||||||
|
$path = "{$dir}/test.mo";
|
||||||
|
if (!file_exists($path)) {
|
||||||
|
file_put_contents($path, base64_decode($mo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!file_exists('locale/en_US/LC_MESSAGES/test.mo')) {
|
|
||||||
$mo = '3hIElQAAAAACAAAAHAAAACwAAAAFAAAAPAAAAAAAAABQAAAABgAAAFEAAAAXAQAAWAAAAAcAAABwAQAAAQAAAAAAAAAAAAAAAgAAAAAAAAAA56S65L6LAFByb2plY3QtSWQtVmVyc2lvbjogUEFDS0FHRSBWRVJTSU9OClJlcG9ydC1Nc2dpZC1CdWdzLVRvOiAKUE8tUmV2aXNpb24tRGF0ZTogWUVBUi1NTy1EQSBITzpNSStaT05FCkxhc3QtVHJhbnNsYXRvcjogRlVMTCBOQU1FIDxFTUFJTEBBRERSRVNTPgpMYW5ndWFnZS1UZWFtOiBMQU5HVUFHRSA8TExAbGkub3JnPgpMYW5ndWFnZTogCk1JTUUtVmVyc2lvbjogMS4wCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD1VVEYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA4Yml0CgBFeGFtcGxlAA==';
|
// Probe for an available English locale
|
||||||
file_put_contents('locale/en_US/LC_MESSAGES/test.mo', base64_decode($mo));
|
$candidates = [
|
||||||
}
|
'en_US.UTF-8', 'en_US.utf8', 'en_US.utf-8', 'en_US',
|
||||||
putenv('LANG=en_US');
|
'en_GB.UTF-8', 'en_GB.utf8', 'en_GB.utf-8', 'en_GB',
|
||||||
assert(setlocale(LC_ALL, 'en_US.utf-8') === 'en_US.utf-8');
|
'English_United States.65001', 'English_United States.1252',
|
||||||
|
'English_United Kingdom.65001', 'English_United Kingdom.1252',
|
||||||
|
];
|
||||||
|
|
||||||
|
$locale = setlocale(LC_ALL, $candidates);
|
||||||
|
assert($locale !== false);
|
||||||
|
|
||||||
|
putenv('LC_ALL=' . $locale);
|
||||||
|
putenv('LANG=' . $locale);
|
||||||
|
putenv('LANGUAGE=' . (stripos($locale, 'US') !== false ? 'en_US:en_GB' : 'en_GB:en_US'));
|
||||||
|
|
||||||
$domain = 'test';
|
$domain = 'test';
|
||||||
bindtextdomain($domain, 'locale/');
|
bindtextdomain($domain, 'locale/');
|
||||||
|
bind_textdomain_codeset($domain, 'UTF-8');
|
||||||
textdomain($domain);
|
textdomain($domain);
|
||||||
|
|
||||||
assert(gettext(json_decode('"\u793a\u4f8b"', true)) === 'Example');
|
$src = json_decode('"\u793a\u4f8b"', true);
|
||||||
|
assert(gettext($src) === 'Example');
|
||||||
|
|||||||
@@ -245,6 +245,16 @@ function clean_spaces(string $string): string
|
|||||||
return trim(preg_replace('/\s+/', ' ', $string));
|
return trim(preg_replace('/\s+/', ' ', $string));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deduplicate_flags(string $flags): string
|
||||||
|
{
|
||||||
|
$tokens = preg_split('/\s+/', trim($flags));
|
||||||
|
|
||||||
|
// Reverse, unique, reverse back - keeps last occurrence of duplicates
|
||||||
|
$deduplicated = array_reverse(array_unique(array_reverse($tokens)));
|
||||||
|
|
||||||
|
return implode(' ', $deduplicated);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a callback function to handle keyboard interrupts (Ctrl+C).
|
* Register a callback function to handle keyboard interrupts (Ctrl+C).
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ $test_os = [
|
|||||||
'macos-13', // bin/spc for x86_64
|
'macos-13', // bin/spc for x86_64
|
||||||
// 'macos-14', // bin/spc for arm64
|
// 'macos-14', // bin/spc for arm64
|
||||||
'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
|
||||||
@@ -56,7 +56,7 @@ $extensions = match (PHP_OS_FAMILY) {
|
|||||||
|
|
||||||
// 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' => 'zip',
|
'Linux' => 'grpc,imagick',
|
||||||
'Darwin' => '',
|
'Darwin' => '',
|
||||||
'Windows' => '',
|
'Windows' => '',
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user