mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-23 00:35:38 +08:00
Compare commits
33 Commits
fe4803cfaf
...
feat/pgo-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
347a3c3c11 | ||
|
|
ed0863db6f | ||
|
|
6ba9cd27d6 | ||
|
|
81213f5c6e | ||
|
|
0299ed52b3 | ||
|
|
b437b2fad7 | ||
|
|
15e2b7bc8a | ||
|
|
9bceaace8e | ||
|
|
1778032633 | ||
|
|
404b2dca24 | ||
|
|
6060a6c8fa | ||
|
|
a65441bbeb | ||
|
|
6b6a099a47 | ||
|
|
8f557aae8a | ||
|
|
3b8abda8c9 | ||
|
|
5747a5661e | ||
|
|
d52ba59edc | ||
|
|
2d5abd31c1 | ||
|
|
69d0f9b8cc | ||
|
|
d846db2ef2 | ||
|
|
f06891155c | ||
|
|
15deecd34f | ||
|
|
7ae5d742c2 | ||
|
|
95be291a84 | ||
|
|
d89add106a | ||
|
|
a36129c6cd | ||
|
|
3f3edd62a1 | ||
|
|
82b77af317 | ||
|
|
df26b93e58 | ||
|
|
d1b4c05381 | ||
|
|
e1658bc0e6 | ||
|
|
5053620b61 | ||
|
|
9366cbacd9 |
@@ -2,8 +2,8 @@ ext-amqp:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: amqp
|
||||
type: pie
|
||||
repo: php-amqp/php-amqp
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-apcu:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: APCu
|
||||
type: pie
|
||||
repo: apcu/apcu
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-ast:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: ast
|
||||
type: pie
|
||||
repo: nikic/php-ast
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: BSD-3-Clause
|
||||
|
||||
@@ -2,12 +2,13 @@ ext-brotli:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: git
|
||||
type: ghtagtar
|
||||
repo: kjdev/php-ext-brotli
|
||||
extract: php-src/ext/brotli
|
||||
rev: master
|
||||
url: 'https://github.com/kjdev/php-ext-brotli'
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: MIT
|
||||
depends:
|
||||
- brotli
|
||||
php-extension:
|
||||
arg-type: '--enable-brotli@shared_suffix@ --with-libbrotli'
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-dio:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: dio
|
||||
type: pie
|
||||
repo: pecl/dio
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-ev:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: ev
|
||||
type: pie
|
||||
repo: osmanov/pecl-ev
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-excimer:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: excimer
|
||||
type: ghtagtar
|
||||
repo: wikimedia/mediawiki-php-excimer
|
||||
extract: php-src/ext/excimer
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-gearman:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: gearman
|
||||
type: ghtar
|
||||
repo: php/pecl-networking-gearman
|
||||
extract: php-src/ext/gearman
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -10,3 +10,5 @@ ext-gmssl:
|
||||
license: PHP-3.01
|
||||
depends:
|
||||
- gmssl
|
||||
php-extension:
|
||||
arg-type: with-path
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-grpc:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: grpc
|
||||
type: pie
|
||||
repo: grpc/grpc-php-ext
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: Apache-2.0
|
||||
|
||||
@@ -2,8 +2,10 @@ ext-igbinary:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: igbinary
|
||||
type: ghtagtar
|
||||
repo: igbinary/igbinary
|
||||
match: tags/\d+(\.\d+)+$
|
||||
extract: php-src/ext/igbinary
|
||||
metadata:
|
||||
license-files: [COPYING]
|
||||
license: BSD-3-Clause
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-imap:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: imap
|
||||
type: ghtagtar
|
||||
repo: php/pecl-mail-imap
|
||||
extract: php-src/ext/imap
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-inotify:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: inotify
|
||||
type: pie
|
||||
repo: arnaud-lb/inotify
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-memcache:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: memcache
|
||||
type: ghtar
|
||||
repo: websupport-sk/pecl-memcache
|
||||
extract: php-src/ext/memcache
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.0
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-memcached:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: memcached
|
||||
type: pie
|
||||
repo: php-memcached/php-memcached
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-msgpack:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: msgpack
|
||||
type: pie
|
||||
repo: msgpack/msgpack-php
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: BSD-3-Clause
|
||||
|
||||
@@ -4,7 +4,7 @@ ext-mysqlnd_ed25519:
|
||||
source:
|
||||
type: pie
|
||||
repo: mariadb/mysqlnd_ed25519
|
||||
extract: php-src/ext/mysqlnd_ed25519
|
||||
extract: mysqlnd_ed25519
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: BSD-3-Clause
|
||||
|
||||
@@ -4,7 +4,7 @@ ext-mysqlnd_parsec:
|
||||
source:
|
||||
type: pie
|
||||
repo: mariadb/mysqlnd_parsec
|
||||
extract: php-src/ext/mysqlnd_parsec
|
||||
extract: mysqlnd_parsec
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: BSD-3-Clause
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-opentelemetry:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: opentelemetry
|
||||
type: pie
|
||||
repo: open-telemetry/ext-opentelemetry
|
||||
build-root: ext
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: Apache-2.0
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-parallel:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: parallel
|
||||
type: pie
|
||||
repo: pecl/parallel
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-pcov:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: pcov
|
||||
type: pie
|
||||
repo: pecl/pcov
|
||||
extract: pcov
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-redis:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: redis
|
||||
type: pie
|
||||
repo: phpredis/phpredis
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -4,7 +4,6 @@ ext-spx:
|
||||
source:
|
||||
type: pie
|
||||
repo: noisebynorthwest/php-spx
|
||||
extract: php-src/ext/spx
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: GPL-3.0-or-later
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-ssh2:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: ssh2
|
||||
type: ghtar
|
||||
repo: php/pecl-networking-ssh2
|
||||
extract: php-src/ext/ssh2
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-trader:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: trader
|
||||
type: ghtagtar
|
||||
repo: php/pecl-math-trader
|
||||
extract: php-src/ext/trader
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: BSD-2-Clause
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-uuid:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: uuid
|
||||
type: pie
|
||||
repo: pecl/uuid
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: LGPL-2.1-only
|
||||
|
||||
@@ -2,9 +2,9 @@ ext-uv:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: uv
|
||||
prefer-stable: false
|
||||
type: ghtagtar
|
||||
repo: amphp/ext-uv
|
||||
extract: php-src/ext/uv
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -4,6 +4,7 @@ ext-xdebug:
|
||||
source:
|
||||
type: pie
|
||||
repo: xdebug/xdebug
|
||||
extract: xdebug
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: Xdebug-1.03
|
||||
|
||||
@@ -2,8 +2,8 @@ ext-xhprof:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: xhprof
|
||||
type: ghtar
|
||||
repo: longxinH/xhprof
|
||||
extract: php-src/ext/xhprof-src
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
|
||||
@@ -2,8 +2,9 @@ ext-yac:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: yac
|
||||
type: ghtagtar
|
||||
repo: laruence/yac
|
||||
extract: php-src/ext/yac
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,9 +2,8 @@ ext-zip:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: pecl
|
||||
name: zip
|
||||
extract: ext-zip
|
||||
type: pie
|
||||
repo: pecl/zip
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: PHP-3.01
|
||||
|
||||
@@ -2,9 +2,8 @@ ext-zstd:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: git
|
||||
url: 'https://github.com/kjdev/php-ext-zstd'
|
||||
rev: master
|
||||
type: ghtar
|
||||
repo: kjdev/php-ext-zstd
|
||||
extract: php-src/ext/zstd
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
|
||||
@@ -2,8 +2,9 @@ gmssl:
|
||||
type: library
|
||||
artifact:
|
||||
source:
|
||||
type: ghtar
|
||||
repo: guanzhi/GmSSL
|
||||
type: git
|
||||
url: 'https://github.com/guanzhi/GmSSL.git'
|
||||
rev: master
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
license: Apache-2.0
|
||||
|
||||
@@ -4,10 +4,10 @@ krb5:
|
||||
source:
|
||||
type: url
|
||||
url: 'https://web.mit.edu/kerberos/dist/krb5/1.22/krb5-1.22.2.tar.gz'
|
||||
build-root: src
|
||||
metadata:
|
||||
license-files: [NOTICE]
|
||||
license: BSD-3-Clause
|
||||
source-root: src
|
||||
depends:
|
||||
- openssl
|
||||
suggests:
|
||||
|
||||
@@ -17,4 +17,11 @@ class gmssl
|
||||
FileSystem::replaceFileStr($target_path . '/src/hex.c', 'unsigned char *OPENSSL_hexstr2buf(const char *str, size_t *len)', 'unsigned char *GMSSL_hexstr2buf(const char *str, size_t *len)');
|
||||
FileSystem::replaceFileStr($target_path . '/src/hex.c', 'OPENSSL_hexchar2int', 'GMSSL_hexchar2int');
|
||||
}
|
||||
|
||||
#[AfterSourceExtract('ext-gmssl')]
|
||||
#[PatchDescription('Rename pbkdf2_hmac_sm3_genkey() to sm3_pbkdf2() (renamed upstream in GmSSL 3.2+; identical signature)')]
|
||||
public function patchExt(string $target_path): void
|
||||
{
|
||||
FileSystem::replaceFileStr($target_path . '/gmssl.c', 'pbkdf2_hmac_sm3_genkey(', 'sm3_pbkdf2(');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ use StaticPHP\Runtime\SystemTarget;
|
||||
* Builds the compiler-rt bits zig ships without — libclang_rt.profile.a (PGO instrumentation)
|
||||
* and clang_rt.crtbegin.o/crtend.o (__dso_handle for shared libs). Target-arch specific:
|
||||
* libs land in PKG_ROOT_PATH/zig/lib/{triple}.
|
||||
* Also builds libclang_rt.cpu_model.a (__cpu_model / __cpu_indicator_init, the libgcc-compatible
|
||||
* globals that __builtin_cpu_supports()/__builtin_cpu_init() reference) for arches that have it.
|
||||
*/
|
||||
class llvm_compiler_rt
|
||||
{
|
||||
@@ -90,13 +92,18 @@ class llvm_compiler_rt
|
||||
if (!file_exists($crtBegin) || !file_exists($crtEnd)) {
|
||||
$this->buildCrtObjects($sourceDir, $crtBegin, $crtEnd, $triple);
|
||||
}
|
||||
$cpuModelLib = "{$libDir}/libclang_rt.cpu_model.a";
|
||||
if (self::cpuModelArch($triple) !== null && !file_exists($cpuModelLib)) {
|
||||
$this->buildCpuModelBuiltins($sourceDir, $cpuModelLib, $triple);
|
||||
}
|
||||
}
|
||||
|
||||
public function isBuilt(string $libDir): bool
|
||||
{
|
||||
return file_exists("{$libDir}/libclang_rt.profile.a")
|
||||
&& file_exists("{$libDir}/clang_rt.crtbegin.o")
|
||||
&& file_exists("{$libDir}/clang_rt.crtend.o");
|
||||
&& file_exists("{$libDir}/clang_rt.crtend.o")
|
||||
&& (self::cpuModelArch(basename($libDir)) === null || file_exists("{$libDir}/libclang_rt.cpu_model.a"));
|
||||
}
|
||||
|
||||
private function detectZigLlvmVersion(): ?string
|
||||
@@ -144,4 +151,43 @@ class llvm_compiler_rt
|
||||
shell()->exec("zig cc {$cflags} -o " . escapeshellarg($dst) . ' ' . escapeshellarg($src));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build libclang_rt.cpu_model.a, provides
|
||||
* the globals that __builtin_cpu_supports() reference.
|
||||
*/
|
||||
private function buildCpuModelBuiltins(string $srcRoot, string $libPath, string $triple): void
|
||||
{
|
||||
$builtins = "{$srcRoot}/lib/builtins";
|
||||
$family = self::cpuModelArch($triple);
|
||||
$cpuModelDir = "{$builtins}/cpu_model";
|
||||
if (is_dir($cpuModelDir)) {
|
||||
$src = "{$cpuModelDir}/{$family}.c";
|
||||
$includes = '-I' . escapeshellarg($builtins) . ' -I' . escapeshellarg($cpuModelDir);
|
||||
} else {
|
||||
$src = "{$builtins}/cpu_model.c";
|
||||
$includes = '-I' . escapeshellarg($builtins);
|
||||
}
|
||||
if (!is_file($src)) {
|
||||
throw new BuildFailureException("llvm-compiler-rt: cpu_model source not found for {$triple} under {$builtins}");
|
||||
}
|
||||
|
||||
$objDir = "{$srcRoot}/obj-cpu-model-{$triple}";
|
||||
f_mkdir($objDir, recursive: true);
|
||||
$obj = "{$objDir}/cpu_model.o";
|
||||
$cflags = "-target {$triple} -c -O2 -fPIC {$includes}";
|
||||
shell()->exec('zig cc ' . $cflags . ' -o ' . escapeshellarg($obj) . ' ' . escapeshellarg($src));
|
||||
shell()->exec('zig ar rcs ' . escapeshellarg($libPath) . ' ' . escapeshellarg($obj));
|
||||
}
|
||||
|
||||
private static function cpuModelArch(string $triple): ?string
|
||||
{
|
||||
$arch = explode('-', $triple)[0];
|
||||
return match (true) {
|
||||
in_array($arch, ['x86_64', 'amd64', 'i386', 'i686', 'x86'], true) => 'x86',
|
||||
in_array($arch, ['aarch64', 'arm64'], true) => 'aarch64',
|
||||
str_starts_with($arch, 'riscv') => 'riscv',
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,37 @@ class event extends PhpExtensionPackage
|
||||
|
||||
#[BeforeStage('php', [php::class, 'makeForUnix'], 'ext-event')]
|
||||
#[PatchDescription('Prevent event extension compile error on macOS')]
|
||||
#[PatchDescription('Patch libevent http_connection.c to use a const peer address')]
|
||||
public function patchBeforeMake(PackageInstaller $installer): void
|
||||
{
|
||||
$php_src = $installer->getTargetPackage('php')->getSourceDir();
|
||||
// Prevent event extension compile error on macOS
|
||||
if (SystemTarget::getTargetOS() === 'Darwin') {
|
||||
$php_src = $installer->getTargetPackage('php')->getSourceDir();
|
||||
FileSystem::replaceFileRegex("{$php_src}/main/php_config.h", '/^#define HAVE_OPENPTY 1$/m', '');
|
||||
}
|
||||
$this->patchLibeventConstPeer("{$php_src}/ext/event");
|
||||
}
|
||||
|
||||
#[BeforeStage('ext-event', [PhpExtensionPackage::class, 'makeForUnix'])]
|
||||
#[PatchDescription('Patch libevent http_connection.c to use a const peer address')]
|
||||
public function patchBeforeSharedMake(PhpExtensionPackage $pkg): void
|
||||
{
|
||||
$this->patchLibeventConstPeer($pkg->getSourceDir());
|
||||
}
|
||||
|
||||
private function patchLibeventConstPeer(string $event_source_dir): bool
|
||||
{
|
||||
$file = "{$event_source_dir}/php8/classes/http_connection.c";
|
||||
if (!is_file($file)) {
|
||||
return false;
|
||||
}
|
||||
// libevent >= 2.2 changed evhttp_connection_get_peer()'s
|
||||
// address arg to `const char **`
|
||||
$header = $this->getBuilder()->getBuildRootPath() . '/include/event2/http.h';
|
||||
$isConst = is_file($header)
|
||||
&& preg_match('/evhttp_connection_get_peer\s*\([^;]*\bconst\s+char\s*\*\*\s*address/s', file_get_contents($header)) === 1;
|
||||
return (bool) ($isConst
|
||||
? FileSystem::replaceFileRegex($file, '/^\tchar \*address;$/m', "\tconst char *address;")
|
||||
: FileSystem::replaceFileRegex($file, '/^\tconst char \*address;$/m', "\tchar *address;"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class password_argon2 extends PhpExtensionPackage
|
||||
#[CustomPhpConfigureArg('Darwin')]
|
||||
public function getConfigureArg(PackageInstaller $installer, PackageBuilder $builder): string
|
||||
{
|
||||
if ($installer->getPhpExtensionPackage('openssl')?->isBuildStatic() || $this->isBuildShared()) {
|
||||
if ($installer->getPhpExtensionPackage('openssl')?->isBuildStatic()) {
|
||||
if (php::getPHPVersionID() >= 80500 || (php::getPHPVersionID() >= 80400 && !$builder->getOption('enable-zts'))) {
|
||||
return '--without-password-argon2'; // use --with-openssl-argon2 in openssl extension instead
|
||||
}
|
||||
|
||||
@@ -62,6 +62,23 @@ class swoole extends PhpExtensionPackage
|
||||
}
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [php::class, 'makeForUnix'], 'ext-swoole')]
|
||||
#[PatchDescription('Initialise SWOOLE_G(cli) to false in the module globals ctor (upstream bug: it is left uninitialised, so under a threaded SAPI like frankenphp its garbage value passes the CLI-only guard in RINIT and segfaults on the first request)')]
|
||||
public function patchBeforeMake3(): void
|
||||
{
|
||||
// php_swoole_init_globals() sets every other global explicitly but never assigns
|
||||
// `cli`, relying on zero-initialisation. That holds for CLI/embed but not for
|
||||
// frankenphp's per-thread ZTS globals, where `cli` reads garbage-nonzero. Since
|
||||
// sapi_module.name is always "frankenphp" there, the `cli = true` conditional never
|
||||
// fires — so the fix is simply to default `cli` to false at the source of the gate.
|
||||
// Reported upstream; drop this patch once swoole ships the initialiser.
|
||||
FileSystem::replaceFileStr(
|
||||
$this->getSourceDir() . '/ext-src/php_swoole.cc',
|
||||
" swoole_globals->leak_detection = false;\n\n if (strcmp(\"cli\", sapi_module.name) == 0",
|
||||
" swoole_globals->leak_detection = false;\n swoole_globals->cli = false;\n\n if (strcmp(\"cli\", sapi_module.name) == 0",
|
||||
);
|
||||
}
|
||||
|
||||
#[CustomPhpConfigureArg('Darwin')]
|
||||
#[CustomPhpConfigureArg('Linux')]
|
||||
public function getUnixConfigureArg(bool $shared, PackageBuilder $builder, PackageInstaller $installer): string
|
||||
|
||||
@@ -8,6 +8,7 @@ use StaticPHP\Attribute\Package\BuildFor;
|
||||
use StaticPHP\Attribute\Package\Library;
|
||||
use StaticPHP\Package\LibraryPackage;
|
||||
use StaticPHP\Runtime\Executor\UnixAutoconfExecutor;
|
||||
use StaticPHP\Runtime\SystemTarget;
|
||||
|
||||
#[Library('libffi')]
|
||||
class libffi extends LibraryPackage
|
||||
@@ -28,7 +29,7 @@ class libffi extends LibraryPackage
|
||||
#[BuildFor('Darwin')]
|
||||
public function buildDarwin(): void
|
||||
{
|
||||
$arch = getenv('SPC_ARCH');
|
||||
$arch = SystemTarget::getTargetArch();
|
||||
UnixAutoconfExecutor::create($this)
|
||||
->configure(
|
||||
"--host={$arch}-apple-darwin",
|
||||
|
||||
@@ -9,6 +9,7 @@ use StaticPHP\Attribute\Package\Library;
|
||||
use StaticPHP\Package\LibraryPackage;
|
||||
use StaticPHP\Runtime\Executor\UnixAutoconfExecutor;
|
||||
use StaticPHP\Runtime\Executor\WindowsCMakeExecutor;
|
||||
use StaticPHP\Runtime\SystemTarget;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
|
||||
#[Library('libpng')]
|
||||
@@ -24,7 +25,7 @@ class libpng
|
||||
];
|
||||
|
||||
// Enable architecture-specific optimizations
|
||||
match (getenv('SPC_ARCH')) {
|
||||
match (SystemTarget::getTargetArch()) {
|
||||
'x86_64' => $args[] = '--enable-intel-sse',
|
||||
'aarch64' => $args[] = '--enable-arm-neon',
|
||||
default => null,
|
||||
|
||||
@@ -65,6 +65,7 @@ class ncurses
|
||||
'--without-tests',
|
||||
'--without-dlsym',
|
||||
'--without-debug',
|
||||
'--disable-stripping',
|
||||
'--enable-symlinks',
|
||||
"--with-terminfo-dirs={$terminfo_dirs}",
|
||||
"--bindir={$package->getBinDir()}",
|
||||
|
||||
@@ -76,7 +76,7 @@ class openssl
|
||||
public function buildForDarwin(LibraryPackage $pkg): void
|
||||
{
|
||||
$zlib_libs = $pkg->getInstaller()->getLibraryPackage('zlib')->getStaticLibFiles();
|
||||
$arch = getenv('SPC_ARCH');
|
||||
$arch = SystemTarget::getTargetArch();
|
||||
|
||||
shell()->cd($pkg->getSourceDir())->initializeEnv($pkg)
|
||||
->exec(
|
||||
@@ -95,12 +95,7 @@ class openssl
|
||||
#[BuildFor('Linux')]
|
||||
public function build(LibraryPackage $lib): void
|
||||
{
|
||||
$arch = getenv('SPC_ARCH');
|
||||
|
||||
$env = "CC='" . getenv('CC') . ' -idirafter ' . BUILD_INCLUDE_PATH .
|
||||
' -idirafter /usr/include/ ' .
|
||||
' -idirafter /usr/include/' . getenv('SPC_ARCH') . '-linux-gnu/ ' .
|
||||
"' ";
|
||||
$arch = SystemTarget::getTargetArch();
|
||||
|
||||
$ex_lib = trim($lib->getInstaller()->getLibraryPackage('zlib')->getStaticLibFiles()) . ' -ldl -pthread';
|
||||
$zlib_extra =
|
||||
@@ -119,7 +114,7 @@ class openssl
|
||||
|
||||
shell()->cd($lib->getSourceDir())->initializeEnv($lib)
|
||||
->exec(
|
||||
"{$env} ./Configure no-shared zlib " .
|
||||
'./Configure no-shared zlib ' .
|
||||
"--prefix={$lib->getBuildRootPath()} " .
|
||||
"--libdir={$lib->getLibDir()} " .
|
||||
"--openssldir={$openssl_dir} " .
|
||||
|
||||
@@ -143,6 +143,7 @@ class php extends TargetPackage
|
||||
$package->addBuildOption('disable-opcache-jit', null, null, 'Disable opcache jit');
|
||||
$package->addBuildOption('with-config-file-path', null, InputOption::VALUE_REQUIRED, 'Set the path in which to look for php.ini', PHP_OS_FAMILY === 'Windows' ? null : '/usr/local/etc/php');
|
||||
$package->addBuildOption('with-config-file-scan-dir', null, InputOption::VALUE_REQUIRED, 'Set the directory to scan for .ini files after reading php.ini', PHP_OS_FAMILY === 'Windows' ? null : '/usr/local/etc/php/conf.d');
|
||||
$package->addBuildOption('with-sysconfdir', null, InputOption::VALUE_REQUIRED, 'Set the sysconfdir (e.g. /etc/php-zts) used by configure (not available on Windows)');
|
||||
$package->addBuildOption('with-hardcoded-ini', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Patch PHP source code, inject hardcoded INI');
|
||||
$package->addBuildOption('enable-zts', null, null, 'Enable thread safe support');
|
||||
$package->addBuildOption('no-smoke-test', null, InputOption::VALUE_OPTIONAL, 'Disable smoke test for specific SAPIs, or all if no value provided', false);
|
||||
@@ -336,7 +337,7 @@ class php extends TargetPackage
|
||||
logger()->info("Adding hardcoded INI [{$source_name} = {$ini_value}]");
|
||||
}
|
||||
if (!empty($custom_ini)) {
|
||||
ApplicationContext::invoke([SourcePatcher::class, 'patchHardcodedINI'], [$package->getSourceDir(), $custom_ini]);
|
||||
ApplicationContext::invoke([SourcePatcher::class, 'patchHardcodedINI'], ['php_source_dir' => $package->getSourceDir(), 'ini' => $custom_ini]);
|
||||
}
|
||||
|
||||
// Patch StaticPHP version
|
||||
@@ -368,7 +369,6 @@ class php extends TargetPackage
|
||||
return;
|
||||
}
|
||||
if (SystemTarget::isUnix()) {
|
||||
$package->runStage([$this, 'unixBuildSharedExt']);
|
||||
if ($installer->interactive) {
|
||||
InteractiveTerm::indicateProgress('Running PHP smoke tests');
|
||||
}
|
||||
|
||||
@@ -42,6 +42,15 @@ trait unix
|
||||
// php-src patches from micro (reads SPC_MICRO_PATCHES env var)
|
||||
SourcePatcher::patchPhpSrc();
|
||||
|
||||
$microFileinfo = "{$package->getSourceDir()}/sapi/micro/php_micro_fileinfo.c";
|
||||
if (is_file($microFileinfo) && !str_contains((string) file_get_contents($microFileinfo), 'Elf32_Shdr')) {
|
||||
FileSystem::replaceFileStr(
|
||||
$microFileinfo,
|
||||
'typedef Elf32_Ehdr Elf_Ehdr;',
|
||||
'typedef Elf32_Ehdr Elf_Ehdr; typedef Elf32_Shdr Elf_Shdr;',
|
||||
);
|
||||
}
|
||||
|
||||
// patch configure.ac for musl and musl-toolchain
|
||||
$musl = SystemTarget::getTargetOS() === 'Linux' && SystemTarget::getLibc() === 'musl';
|
||||
FileSystem::backupFile(SOURCE_PATH . '/php-src/configure.ac');
|
||||
@@ -66,6 +75,7 @@ trait unix
|
||||
|
||||
#[BeforeStage('php', [self::class, 'configureForUnix'], 'php')]
|
||||
#[PatchDescription('Patch configure to use -std=gnu17 instead of -std=gnu23 for PHP <= 8.2')]
|
||||
#[PatchDescription('Strip build-time env vars from phpinfo\'s "Configure Command"')]
|
||||
public function patchBeforeConfigure(TargetPackage $package): void
|
||||
{
|
||||
if (SystemTarget::isUnix() && self::getPHPVersionID() < 80300) {
|
||||
@@ -75,6 +85,22 @@ trait unix
|
||||
"for ac_arg in '' -std=gnu17",
|
||||
);
|
||||
}
|
||||
|
||||
// strip our build-time env vars from phpinfo's "Configure Command" ('|' delimiter: PHP_BUILD_PROVIDER may contain '#')
|
||||
if (SystemTarget::isUnix()) {
|
||||
FileSystem::replaceFileStr(
|
||||
"{$package->getSourceDir()}/configure",
|
||||
'for var in CFLAGS CXXFLAGS CPPFLAGS LDFLAGS EXTRA_LDFLAGS_PROGRAM LIBS CC CXX; do',
|
||||
'for var in CFLAGS CXXFLAGS CPPFLAGS LDFLAGS EXTRA_LDFLAGS_PROGRAM LIBS CC CXX '
|
||||
. 'PKG_CONFIG PKG_CONFIG_PATH EXTENSION_DIR OPENSSL_LIBS '
|
||||
. 'PHP_BUILD_SYSTEM PHP_BUILD_PROVIDER PHP_BUILD_COMPILER PHP_BUILD_ARCH; do',
|
||||
);
|
||||
FileSystem::replaceFileStr(
|
||||
"{$package->getSourceDir()}/configure",
|
||||
'clean_configure_args=$(echo $clean_configure_args | $SED -e "s#\'$var=$val\'##")',
|
||||
'clean_configure_args=$(echo $clean_configure_args | $SED -e "s|\'$var=$val\'||")',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[Stage]
|
||||
@@ -116,6 +142,9 @@ trait unix
|
||||
if ($option = $package->getBuildOption('with-config-file-scan-dir', false)) {
|
||||
$args[] = "--with-config-file-scan-dir={$option}";
|
||||
}
|
||||
if ($option = $package->getBuildOption('with-sysconfdir', false)) {
|
||||
$args[] = "--sysconfdir={$option}";
|
||||
}
|
||||
// perform enable cli options
|
||||
$args[] = $installer->isPackageResolved('php-cli') ? '--enable-cli' : '--disable-cli';
|
||||
$args[] = $installer->isPackageResolved('php-fpm')
|
||||
@@ -543,8 +572,10 @@ trait unix
|
||||
$package->runStage([$this, 'configureForUnix']);
|
||||
$package->runStage([$this, 'makeForUnix']);
|
||||
}
|
||||
// shared extensions build in php's postInstall (php.php) so they run AFTER
|
||||
// frankenphp's main-loop build — frankenphp links libphp only, not the .so exts.
|
||||
|
||||
// shared extensions build before frankenphp so their undefined references are
|
||||
// collected into libphp's exported dynamic-symbol list.
|
||||
$package->runStage([$this, 'unixBuildSharedExt']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -331,13 +331,13 @@ class Artifact
|
||||
|
||||
/**
|
||||
* Get source build root directory.
|
||||
* It's only worked when 'source-root' is defined in artifact config.
|
||||
* It's only used when source.build-root is defined in artifact config.
|
||||
* Normally it's equal to source dir.
|
||||
*/
|
||||
public function getSourceRoot(): string
|
||||
{
|
||||
if (isset($this->config['metadata']['source-root'])) {
|
||||
return FileSystem::convertPath($this->getSourceDir() . '/' . ltrim($this->config['metadata']['source-root'], '/'));
|
||||
if (isset($this->config['source']['build-root'])) {
|
||||
return FileSystem::convertPath($this->getSourceDir() . '/' . ltrim($this->config['source']['build-root'], '/'));
|
||||
}
|
||||
return $this->getSourceDir();
|
||||
}
|
||||
|
||||
@@ -57,6 +57,16 @@ class GitHubRelease implements DownloadTypeInterface, ValidatorInterface, CheckU
|
||||
if (!is_array($data)) {
|
||||
throw new DownloaderException("Failed to get GitHub release API info for {$repo} from {$url}");
|
||||
}
|
||||
// GitHub's /releases list is ordered by publish date, so a newer-tagged prerelease
|
||||
// (e.g. 2.2.x-alpha) can precede the latest stable (2.1.x-stable). /releases/latest
|
||||
// returns the semantically latest stable release regardless of order; check it first.
|
||||
if ($prefer_stable) {
|
||||
$latest_url = str_replace('{repo}', $repo, self::API_URL) . '/latest';
|
||||
$latest = json_decode(default_shell()->executeCurl($latest_url, headers: $headers, retries: $retries) ?: '', true);
|
||||
if (is_array($latest) && isset($latest['assets'])) {
|
||||
array_unshift($data, $latest);
|
||||
}
|
||||
}
|
||||
foreach ($data as $release) {
|
||||
if ($prefer_stable && $release['prerelease'] === true) {
|
||||
continue;
|
||||
|
||||
@@ -14,17 +14,18 @@ trait GitHubTokenSetupTrait
|
||||
public static function getGitHubTokenHeadersStatic(): array
|
||||
{
|
||||
// GITHUB_TOKEN support
|
||||
if (($token = getenv('GITHUB_TOKEN')) !== false && ($user = getenv('GITHUB_USER')) !== false) {
|
||||
$token = getenv('GITHUB_TOKEN');
|
||||
if ($token === false || $token === '') {
|
||||
return [];
|
||||
}
|
||||
if (($user = getenv('GITHUB_USER')) !== false && $user !== '') {
|
||||
logger()->debug("Using 'GITHUB_TOKEN' with user {$user} for authentication");
|
||||
$encoded = base64_encode("{$user}:{$token}");
|
||||
spc_add_log_filter([$user, $token, $encoded]);
|
||||
return ["Authorization: Basic {$encoded}"];
|
||||
}
|
||||
if (($token = getenv('GITHUB_TOKEN')) !== false) {
|
||||
logger()->debug("Using 'GITHUB_TOKEN' for authentication");
|
||||
spc_add_log_filter($token);
|
||||
return ["Authorization: Bearer {$token}"];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,13 @@ class PIE implements DownloadTypeInterface, CheckUpdateInterface
|
||||
if (!$dist_url || !$dist_type) {
|
||||
throw new DownloaderException("failed to find {$name} dist info from packagist");
|
||||
}
|
||||
$extract = $config['extract'] ?? ('php-src/ext/' . strtolower(preg_replace('/^ext-/i', '', $name)));
|
||||
$name = str_replace('/', '_', $config['repo']);
|
||||
$version = $first['version'] ?? 'unknown';
|
||||
$filename = "{$name}-{$version}." . ($dist_type === 'zip' ? 'zip' : 'tar.gz');
|
||||
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . $filename;
|
||||
default_shell()->executeCurlDownload($dist_url, $path, retries: $downloader->getRetry());
|
||||
return DownloadResult::archive($filename, $config, $config['extract'] ?? null, version: $version, downloader: static::class);
|
||||
return DownloadResult::archive($filename, $config, $extract, version: $version, downloader: static::class);
|
||||
}
|
||||
|
||||
public function checkUpdate(string $name, array $config, ?string $old_version, ArtifactDownloader $downloader): CheckUpdateResult
|
||||
@@ -56,7 +57,23 @@ class PIE implements DownloadTypeInterface, CheckUpdateInterface
|
||||
if (!isset($data['packages'][$config['repo']]) || !is_array($data['packages'][$config['repo']])) {
|
||||
throw new DownloaderException("failed to find {$name} repo info from packagist");
|
||||
}
|
||||
$first = $data['packages'][$config['repo']][0] ?? [];
|
||||
// p2 metadata is minified: each entry only carries fields changed vs the previous one, '__unset' removes a field
|
||||
$releases = [];
|
||||
$current = [];
|
||||
foreach ($data['packages'][$config['repo']] as $release) {
|
||||
$current = array_merge($current, $release);
|
||||
$current = array_filter($current, static fn ($v) => $v !== '__unset');
|
||||
$releases[] = $current;
|
||||
}
|
||||
// packagist lists newest first including RC/beta/alpha — pick the newest stable release
|
||||
$first = null;
|
||||
foreach ($releases as $release) {
|
||||
if (!preg_match('/[._-]?(?:alpha|a|beta|b|rc)[._-]?\d*$/i', $release['version'] ?? '')) {
|
||||
$first = $release;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$first ??= $releases[0] ?? [];
|
||||
if (!isset($first['php-ext'])) {
|
||||
throw new DownloaderException("failed to find {$name} php-ext info from packagist, maybe not a php extension package");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace StaticPHP\Command;
|
||||
|
||||
use StaticPHP\Config\PackageConfig;
|
||||
use StaticPHP\DI\ApplicationContext;
|
||||
use StaticPHP\Doctor\Doctor;
|
||||
use StaticPHP\Exception\ValidationException;
|
||||
@@ -134,15 +135,28 @@ class CraftCommand extends BaseCommand
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
/** @return list<string> library package names transitively required by the configured extensions */
|
||||
/** @return list<string> library package names transitively required by the configured extensions and SAPIs */
|
||||
private function resolveLibsForExtensions(array $craft, bool $include_suggests): array
|
||||
{
|
||||
$exts = array_merge($craft['extensions'], $craft['shared-extensions'] ?? []);
|
||||
$ext_pkgs = array_map(fn ($x) => "ext-{$x}", $exts);
|
||||
$extra = $craft['packages'] ?? [];
|
||||
|
||||
// SAPI targets contribute their own lib deps/suggests (frankenphp → brotli/watcher,
|
||||
// php-fpm → libacl); resolve them too so the buildroot contains everything the
|
||||
// full build will need. Sapi names map to packages either directly or as php-<name>.
|
||||
$sapi_pkgs = [];
|
||||
foreach ($craft['sapi'] ?? [] as $sapi) {
|
||||
foreach ([$sapi, "php-{$sapi}"] as $candidate) {
|
||||
if (PackageLoader::hasPackage($candidate)) {
|
||||
$sapi_pkgs[] = $candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$resolved = DependencyResolver::resolve(
|
||||
array_merge($ext_pkgs, $extra),
|
||||
array_merge($ext_pkgs, $extra, $sapi_pkgs),
|
||||
include_suggests: $include_suggests,
|
||||
);
|
||||
|
||||
@@ -151,7 +165,11 @@ class CraftCommand extends BaseCommand
|
||||
if (str_starts_with($pkg_name, 'ext-') || !PackageLoader::hasPackage($pkg_name)) {
|
||||
continue;
|
||||
}
|
||||
if (PackageLoader::getPackage($pkg_name)->getType() === 'library') {
|
||||
$type = PackageLoader::getPackage($pkg_name)->getType();
|
||||
// Pure libraries, plus library-producing targets (curl ships libcurl.a): both
|
||||
// must land in the buildroot, or the full build rebuilds them on every run.
|
||||
if ($type === 'library'
|
||||
|| ($type === 'target' && PackageConfig::get($pkg_name, 'static-libs', []) !== [])) {
|
||||
$libs[] = $pkg_name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,8 +297,8 @@ class ConfigValidator
|
||||
throw new ValidationException("Artifact source object of type '{$type}' must have required field '{$field}'");
|
||||
}
|
||||
}
|
||||
// check for unknown fields
|
||||
$allowed_fields = array_merge(['type'], $required_fields, $optional_fields);
|
||||
// check for unknown fields ('build-root': optional build subdir, applies to any type)
|
||||
$allowed_fields = array_merge(['type', 'build-root'], $required_fields, $optional_fields);
|
||||
self::validateNoInvalidFields('artifact object', $item_name, $data, $allowed_fields);
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ abstract class Package
|
||||
|
||||
/**
|
||||
* Get source build root directory.
|
||||
* It's only worked when 'source-root' is defined in artifact config.
|
||||
* It's only worked when source.build-root is defined in artifact config.
|
||||
* Normally it's equal to source dir.
|
||||
*/
|
||||
public function getSourceRoot(): string
|
||||
|
||||
@@ -304,9 +304,11 @@ class PackageInstaller
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resolved package names whose build artifacts contribute to the PHP main link.
|
||||
* Excludes libraries not yet built (so SPCConfigUtil doesn't probe their .a files) and
|
||||
* shared-only extensions (they link separately into their own .so).
|
||||
* Get resolved package names filtered to only packages whose build artifacts are available.
|
||||
* This excludes library packages that haven't been built/installed yet, which naturally
|
||||
* prevents SPCConfigUtil from checking static-lib files of libraries that come after
|
||||
* the current target in the build order (e.g. 'watcher' for frankenphp isn't built
|
||||
* when 'php' is being compiled).
|
||||
*
|
||||
* @return string[] Available resolved package names
|
||||
*/
|
||||
@@ -316,12 +318,12 @@ class PackageInstaller
|
||||
array_keys($this->packages),
|
||||
function (string $name): bool {
|
||||
$pkg = $this->packages[$name] ?? null;
|
||||
// Exclude library packages whose build artifacts don't exist yet.
|
||||
// Extensions and targets are not filtered — extensions are compiled into PHP
|
||||
// and don't have standalone build artifacts.
|
||||
if ($pkg instanceof LibraryPackage && $pkg->getType() === 'library' && !$pkg->isInstalled()) {
|
||||
return false;
|
||||
}
|
||||
if ($pkg instanceof PhpExtensionPackage && $pkg->isBuildShared() && !$pkg->isBuildStatic()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
));
|
||||
|
||||
@@ -60,6 +60,19 @@ class PhpExtensionPackage extends Package
|
||||
return parent::getSourceDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Directory the extension is actually built in: cd'd into by phpize/configure/make.
|
||||
* Equals getSourceDir() unless the artifact declares source.build-root (e.g. a PIE
|
||||
* package whose config.m4 lives in an ext/ subdir).
|
||||
*/
|
||||
public function getSourceRoot(): string
|
||||
{
|
||||
if ($this->getArtifact() === null) {
|
||||
return $this->getSourceDir();
|
||||
}
|
||||
return parent::getSourceRoot();
|
||||
}
|
||||
|
||||
public function getExtensionName(): string
|
||||
{
|
||||
return str_replace('ext-', '', $this->getName());
|
||||
@@ -275,7 +288,7 @@ class PhpExtensionPackage extends Package
|
||||
$compiler_extra = trim($compiler_extra . ' -lcompiler_rt');
|
||||
GlobalEnvManager::putenv("SPC_COMPILER_EXTRA={$compiler_extra}");
|
||||
}
|
||||
$config = (new SPCConfigUtil())->getExtensionConfig($this);
|
||||
$config = new SPCConfigUtil(['no_php' => true])->getExtensionConfig($this);
|
||||
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
|
||||
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
|
||||
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
|
||||
@@ -299,7 +312,7 @@ class PhpExtensionPackage extends Package
|
||||
#[Stage]
|
||||
public function phpizeForUnix(array $env, PhpExtensionPackage $package): void
|
||||
{
|
||||
shell()->cd($package->getSourceDir())->setEnv($env)->exec(BUILD_BIN_PATH . '/phpize');
|
||||
shell()->cd($package->getSourceRoot())->setEnv($env)->exec(BUILD_BIN_PATH . '/phpize');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,7 +323,7 @@ class PhpExtensionPackage extends Package
|
||||
{
|
||||
$phpvars = getenv('SPC_EXTRA_PHP_VARS') ?: '';
|
||||
// CustomPhpConfigureArg keys are OS names ('Linux'/'Darwin'), not platform strings
|
||||
shell()->cd($package->getSourceDir())
|
||||
shell()->cd($package->getSourceRoot())
|
||||
->setEnv($env)
|
||||
->exec(
|
||||
'./configure ' . $this->getPhpConfigureArg(SystemTarget::getTargetOS(), true) .
|
||||
@@ -329,7 +342,7 @@ class PhpExtensionPackage extends Package
|
||||
$package->patchSharedLibAdd();
|
||||
$extra_ldflags = (string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS');
|
||||
$makeArgs = $extra_ldflags !== '' ? 'EXTRA_LDFLAGS=' . escapeshellarg($extra_ldflags) : '';
|
||||
shell()->cd($package->getSourceDir())
|
||||
shell()->cd($package->getSourceRoot())
|
||||
->setEnv($env)
|
||||
->exec('make clean')
|
||||
->exec("make -j{$builder->concurrency} {$makeArgs}")
|
||||
@@ -355,7 +368,7 @@ class PhpExtensionPackage extends Package
|
||||
? '-l:libstdc++.a'
|
||||
: (str_contains($sharedLibs, '-lstdc++') ? '-lstdc++' : '');
|
||||
|
||||
$makefile = $this->getSourceDir() . '/Makefile';
|
||||
$makefile = $this->getSourceRoot() . '/Makefile';
|
||||
if (!is_file($makefile)) {
|
||||
return;
|
||||
}
|
||||
@@ -390,9 +403,9 @@ class PhpExtensionPackage extends Package
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_dir($this->getSourceDir())) {
|
||||
if (!is_dir($this->getSourceRoot())) {
|
||||
throw new ValidationException(
|
||||
"Extension source directory not found: {$this->getSourceDir()}",
|
||||
"Extension source directory not found: {$this->getSourceRoot()}",
|
||||
validation_module: "Extension {$this->getName()} source"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,8 +228,15 @@ class UnixCMakeExecutor extends Executor
|
||||
"-DCMAKE_TOOLCHAIN_FILE={$this->makeCmakeToolchainFile()}",
|
||||
];
|
||||
|
||||
// EXE linker flags: base system libs + framework flags for target packages
|
||||
$exeLinkerFlags = SystemTarget::getRuntimeLibs();
|
||||
// EXE linker flags: framework flags for target packages (Darwin). On Linux the
|
||||
// runtime libs (-ldl & co.) are NOT passed here: CMake puts EXE_LINKER_FLAGS before
|
||||
// the objects/archives, where -Wl,--as-needed (Debian gcc default, and our own
|
||||
// LDFLAGS) discards them and breaks try_compile probes linking static archives that
|
||||
// need them (curl's SSL_set_quic_tls_cbs check vs libcrypto.a needing dlopen on
|
||||
// glibc < 2.34). They go into the toolchain file as CMAKE_<LANG>_STANDARD_LIBRARIES
|
||||
// instead, which cmake appends AFTER the objects — correct order, as-needed intact,
|
||||
// and the toolchain file is re-evaluated inside every try_compile.
|
||||
$exeLinkerFlags = SystemTarget::getTargetOS() === 'Linux' ? '' : SystemTarget::getRuntimeLibs();
|
||||
if ($this->package instanceof TargetPackage && SystemTarget::getTargetOS() === 'Darwin') {
|
||||
$resolvedNames = array_keys($this->installer->getResolvedPackages());
|
||||
$resolvedNames[] = $this->package->getName();
|
||||
@@ -308,6 +315,14 @@ CMAKE;
|
||||
$ranlib = getenv('SPC_DEFAULT_RANLIB') ?: (getenv('RANLIB') ?: 'ranlib');
|
||||
$toolchain .= "\nSET(CMAKE_AR \"{$ar}\")";
|
||||
$toolchain .= "\nSET(CMAKE_RANLIB \"{$ranlib}\")";
|
||||
// Runtime libs as standard libraries: appended after objects/archives on every
|
||||
// link line (incl. try_compile probes), so -Wl,--as-needed keeps the ones that
|
||||
// are actually referenced.
|
||||
$runtimeLibs = SystemTarget::getRuntimeLibs();
|
||||
if ($runtimeLibs !== '') {
|
||||
$toolchain .= "\nset(CMAKE_C_STANDARD_LIBRARIES_INIT \"{$runtimeLibs}\")";
|
||||
$toolchain .= "\nset(CMAKE_CXX_STANDARD_LIBRARIES_INIT \"{$runtimeLibs}\")";
|
||||
}
|
||||
}
|
||||
FileSystem::writeFile(SOURCE_PATH . '/toolchain.cmake', $toolchain);
|
||||
return $created = realpath(SOURCE_PATH . '/toolchain.cmake');
|
||||
|
||||
@@ -75,6 +75,16 @@ class ZigToolchain implements UnixToolchainInterface
|
||||
$extra_vars = getenv('SPC_EXTRA_PHP_VARS') ?: '';
|
||||
GlobalEnvManager::putenv("SPC_EXTRA_PHP_VARS=ac_cv_func_strlcpy=no ac_cv_func_strlcat=no {$extra_vars}");
|
||||
|
||||
// An __attribute__((ifunc)) in LTO bitcode crashes zig 0.16's lld (LLVM 21)
|
||||
// during thin-link symbol resolution
|
||||
$all_flags = $cflags . ' ' . (getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') ?: '') . ' ' . (getenv('SPC_DEFAULT_LD_FLAGS') ?: '');
|
||||
if (str_contains($all_flags, '-flto')) {
|
||||
$extra_vars = getenv('SPC_EXTRA_PHP_VARS') ?: '';
|
||||
if (!str_contains($extra_vars, 'ax_cv_have_func_attribute_ifunc')) {
|
||||
GlobalEnvManager::putenv("SPC_EXTRA_PHP_VARS={$extra_vars} ax_cv_have_func_attribute_ifunc=no");
|
||||
}
|
||||
}
|
||||
|
||||
$this->ensureCompilerRt();
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +168,9 @@ class SourcePatcher
|
||||
*/
|
||||
public static function patchMicroPhar(int $version_id): void
|
||||
{
|
||||
if (file_exists(SOURCE_PATH . '/php-src/ext/phar/phar.c.bak')) {
|
||||
return;
|
||||
}
|
||||
FileSystem::backupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c');
|
||||
FileSystem::replaceFileStr(
|
||||
SOURCE_PATH . '/php-src/ext/phar/phar.c',
|
||||
@@ -193,6 +196,12 @@ class SourcePatcher
|
||||
|
||||
public static function unpatchMicroPhar(): void
|
||||
{
|
||||
// Tolerate a missing .bak: both drivers call this, and the first restore
|
||||
// consumes the backup. Without this guard the second call throws
|
||||
// "Cannot find bak file". No .bak means the source is already pristine.
|
||||
if (!file_exists(SOURCE_PATH . '/php-src/ext/phar/phar.c.bak')) {
|
||||
return;
|
||||
}
|
||||
FileSystem::restoreBackupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c');
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ putenv('PKG_ROOT_PATH=' . PKG_ROOT_PATH);
|
||||
putenv('SOURCE_PATH=' . SOURCE_PATH);
|
||||
putenv('DOWNLOAD_PATH=' . DOWNLOAD_PATH);
|
||||
putenv('CPU_COUNT=' . CPU_COUNT);
|
||||
putenv('SPC_ARCH=' . php_uname('m'));
|
||||
putenv('GNU_ARCH=' . GNU_ARCH);
|
||||
putenv('MAC_ARCH=' . MAC_ARCH);
|
||||
|
||||
|
||||
@@ -27,12 +27,14 @@ while [[ $# -gt 0 ]]; do
|
||||
-march=*|-mcpu=*)
|
||||
OPT_NAME="${1%%=*}"
|
||||
OPT_VALUE="${1#*=}"
|
||||
# Skip armv8- flags entirely as Zig doesn't support them
|
||||
if [[ "$OPT_VALUE" == armv8-* ]]; then
|
||||
shift
|
||||
continue
|
||||
# zig rejects -march=armv8-a but accepts -mcpu=generic+v8a; rewrite
|
||||
# armv<X>[.<Y>]-a[+feat] -> generic+v<X>[_<Y>]a[+feat] so it goes through.
|
||||
if [[ "$OPT_VALUE" =~ ^armv([89])(\.([0-9]+))?-a(\+.*)?$ ]]; then
|
||||
arch_feat="v${BASH_REMATCH[1]}"
|
||||
[[ -n "${BASH_REMATCH[3]}" ]] && arch_feat="${arch_feat}_${BASH_REMATCH[3]}"
|
||||
OPT_VALUE="generic+${arch_feat}a${BASH_REMATCH[4]}"
|
||||
fi
|
||||
# replace -march=x86-64 with -march=x86_64
|
||||
# zig uses snake_case in CPU/feature names (x86-64 -> x86_64).
|
||||
OPT_VALUE="${OPT_VALUE//-/_}"
|
||||
PARSED_ARGS+=("${OPT_NAME}=${OPT_VALUE}")
|
||||
shift
|
||||
@@ -66,10 +68,13 @@ done
|
||||
|
||||
RT_DIR="${SPC_COMPILER_RT_DIR:-}"
|
||||
if [[ $IS_LINK -eq 1 && $NEED_PROFILE_RT -eq 1 && -n "$RT_DIR" && -f "$RT_DIR/libclang_rt.profile.a" ]]; then
|
||||
PARSED_ARGS+=("$RT_DIR/libclang_rt.profile.a" "-Wl,-u,__llvm_profile_runtime")
|
||||
PARSED_ARGS+=("-x" "none" "$RT_DIR/libclang_rt.profile.a" "-Wl,-u,__llvm_profile_runtime")
|
||||
fi
|
||||
if [[ $IS_LINK -eq 1 && $NEED_CRT -eq 1 && -n "$RT_DIR" && -f "$RT_DIR/clang_rt.crtbegin.o" && -f "$RT_DIR/clang_rt.crtend.o" ]]; then
|
||||
PARSED_ARGS+=("$RT_DIR/clang_rt.crtbegin.o" "$RT_DIR/clang_rt.crtend.o")
|
||||
PARSED_ARGS+=("-x" "none" "$RT_DIR/clang_rt.crtbegin.o" "$RT_DIR/clang_rt.crtend.o")
|
||||
fi
|
||||
if [[ $IS_LINK -eq 1 && -n "$RT_DIR" && -f "$RT_DIR/libclang_rt.cpu_model.a" ]]; then
|
||||
PARSED_ARGS+=("-x" "none" "$RT_DIR/libclang_rt.cpu_model.a")
|
||||
fi
|
||||
|
||||
[[ -n "$SPC_TARGET" ]] && TARGET="-target $SPC_TARGET" || TARGET=""
|
||||
|
||||
Reference in New Issue
Block a user