mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-08 17:35:36 +08:00
Compare commits
6 Commits
db794bf27b
...
4b19f4ec95
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b19f4ec95 | ||
|
|
1707d21569 | ||
|
|
70e717adb6 | ||
|
|
a88e426623 | ||
|
|
6fda358c90 | ||
|
|
09de4c9c70 |
@@ -186,6 +186,7 @@ ext-password-argon2:
|
||||
type: php-extension
|
||||
depends:
|
||||
- libargon2
|
||||
suggests:
|
||||
- ext-openssl
|
||||
php-extension:
|
||||
os:
|
||||
|
||||
@@ -27,7 +27,7 @@ class password_argon2 extends PhpExtensionPackage
|
||||
#[CustomPhpConfigureArg('Darwin')]
|
||||
public function getConfigureArg(PackageInstaller $installer, PackageBuilder $builder): string
|
||||
{
|
||||
if ($installer->getLibraryPackage('openssl') !== null) {
|
||||
if ($installer->getPhpExtensionPackage('openssl')?->isBuildStatic() || $this->isBuildShared()) {
|
||||
if (php::getPHPVersionID() >= 80500 || (php::getPHPVersionID() >= 80400 && !$builder->getOption('enable-zts'))) {
|
||||
return '--without-password-argon2'; // use --with-openssl-argon2 in openssl extension instead
|
||||
}
|
||||
|
||||
@@ -20,9 +20,8 @@ class watcher extends LibraryPackage
|
||||
if (stripos($cflags, '-fpic') === false) {
|
||||
$cflags .= ' -fPIC';
|
||||
}
|
||||
$ldflags = $this->getLibExtraLdFlags() ? ' ' . $this->getLibExtraLdFlags() : '';
|
||||
shell()->cd("{$this->getSourceDir()}/watcher-c")
|
||||
->exec(getenv('CXX') . " -c -o libwatcher-c.o ./src/watcher-c.cpp -I ./include -I ../include -std=c++17 -Wall -Wextra {$cflags}{$ldflags}")
|
||||
->exec(getenv('CXX') . " -c -o libwatcher-c.o ./src/watcher-c.cpp -I ./include -I ../include -std=c++17 -Wall -Wextra {$cflags}")
|
||||
->exec(getenv('AR') . ' rcs libwatcher-c.a libwatcher-c.o');
|
||||
|
||||
copy("{$this->getSourceDir()}/watcher-c/libwatcher-c.a", "{$this->getLibDir()}/libwatcher-c.a");
|
||||
|
||||
@@ -107,6 +107,7 @@ trait frankenphp
|
||||
InteractiveTerm::setMessage('Building frankenphp: ' . ConsoleColor::yellow('building with xcaddy'));
|
||||
shell()->cd(BUILD_LIB_PATH)
|
||||
->setEnv($env)
|
||||
->exec('go clean -cache') // fix stale include evaluation
|
||||
->exec("xcaddy build --output frankenphp {$xcaddy_modules}");
|
||||
|
||||
$builder->deployBinary(BUILD_LIB_PATH . '/frankenphp', BUILD_BIN_PATH . '/frankenphp');
|
||||
|
||||
@@ -60,7 +60,7 @@ trait unix
|
||||
}
|
||||
|
||||
if (self::getPHPVersionID() >= 80300 && self::getPHPVersionID() < 80400) {
|
||||
SourcePatcher::patchFile('spc_fix_avx512_cache_before_80400.patch', $this->getSourceDir());
|
||||
SourcePatcher::patchFile('spc_fix_avx512_cache_before_80400.patch', SOURCE_PATH . '/php-src');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -285,15 +285,19 @@ class Artifact
|
||||
* Get source extraction directory.
|
||||
*
|
||||
* Rules:
|
||||
* 1. If extract is not specified: SOURCE_PATH/{artifact_name}
|
||||
* 2. If extract is relative path: SOURCE_PATH/{value}
|
||||
* 3. If extract is absolute path: {value}
|
||||
* 4. If extract is array (dict): handled by extractor (selective extraction)
|
||||
* 1. If cache_type is 'local': use the absolute dirname recorded at download time (no symlink/copy).
|
||||
* 2. If extract is not specified: SOURCE_PATH/{artifact_name}
|
||||
* 3. If extract is relative path: SOURCE_PATH/{value}
|
||||
* 4. If extract is absolute path: {value}
|
||||
* 5. If extract is array (dict): handled by extractor (selective extraction)
|
||||
*/
|
||||
public function getSourceDir(): string
|
||||
{
|
||||
// Prefer cache extract path, fall back to config
|
||||
$cache_info = ApplicationContext::get(ArtifactCache::class)->getSourceInfo($this->name);
|
||||
if (($cache_info['cache_type'] ?? null) === 'local' && isset($cache_info['dirname'])) {
|
||||
return FileSystem::convertPath($cache_info['dirname']);
|
||||
}
|
||||
$extract = is_string($cache_info['extract'] ?? null)
|
||||
? $cache_info['extract']
|
||||
: ($this->config['source']['extract'] ?? null);
|
||||
|
||||
@@ -731,6 +731,16 @@ class ArtifactDownloader
|
||||
$binary_downloaded = $artifact->isBinaryDownloaded(compare_hash: true);
|
||||
$source_downloaded = $artifact->isSourceDownloaded(compare_hash: true);
|
||||
|
||||
if ($source_downloaded && $artifact->getName() === 'php-src' && ($requested = $this->getOption('with-php'))) {
|
||||
$info = ApplicationContext::get(ArtifactCache::class)->getSourceInfo('php-src');
|
||||
$cv = $info['version'] ?? null;
|
||||
$ct = $info['cache_type'] ?? null;
|
||||
$matches = $requested === 'git' ? $ct === 'git' : ($cv !== null && $ct !== 'git' && ($cv === $requested || str_starts_with($cv, $requested . '.')));
|
||||
if (!$matches) {
|
||||
$source_downloaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
$item_source = ['display' => 'source', 'lock' => 'source', 'config' => $artifact->getDownloadConfig('source')];
|
||||
$item_source_mirror = ['display' => 'source (mirror)', 'lock' => 'source', 'config' => $artifact->getDownloadConfig('source-mirror')];
|
||||
|
||||
|
||||
@@ -136,6 +136,12 @@ class ArtifactExtractor
|
||||
throw new WrongUsageException("Artifact source [{$name}] not downloaded, please download it first!");
|
||||
}
|
||||
|
||||
// Local (--custom-local): source lives in place at $cache_info['dirname'].
|
||||
if (($cache_info['cache_type'] ?? null) === 'local') {
|
||||
$artifact->emitAfterSourceExtract($artifact->getSourceDir());
|
||||
return SPC_STATUS_ALREADY_EXTRACTED;
|
||||
}
|
||||
|
||||
$source_file = $this->cache->getCacheFullPath($cache_info);
|
||||
$target_path = $artifact->getSourceDir();
|
||||
|
||||
@@ -171,8 +177,12 @@ class ArtifactExtractor
|
||||
return SPC_STATUS_ALREADY_EXTRACTED;
|
||||
}
|
||||
|
||||
// Remove old directory if hash mismatch
|
||||
if (is_dir($target_path)) {
|
||||
// Remove old directory if hash mismatch.
|
||||
// Guard: a symlink at $target_path (left over from older local-source handling) must be
|
||||
// unlinked directly — never recurse into the link target, that would wipe the user's tree.
|
||||
if (is_link($target_path)) {
|
||||
@unlink($target_path);
|
||||
} elseif (is_dir($target_path)) {
|
||||
logger()->notice("Source [{$name}] hash mismatch, re-extracting...");
|
||||
FileSystem::removeDir($target_path);
|
||||
}
|
||||
|
||||
@@ -154,6 +154,8 @@ class PackageInstaller
|
||||
$this->resolvePackages();
|
||||
}
|
||||
|
||||
$this->reconcilePhpSrcVersion();
|
||||
|
||||
if ($this->interactive && !$disable_delay_msg) {
|
||||
// show install or build options in terminal with beautiful output
|
||||
$this->printInstallerInfo();
|
||||
@@ -571,6 +573,67 @@ class PackageInstaller
|
||||
return null;
|
||||
}
|
||||
|
||||
private function reconcilePhpSrcVersion(): void
|
||||
{
|
||||
$src_dir = SOURCE_PATH . '/php-src';
|
||||
$cache = ApplicationContext::get(ArtifactCache::class);
|
||||
$requested = $this->options['dl-with-php'] ?? null;
|
||||
if ($requested !== null && $requested !== '' && $requested !== 'git') {
|
||||
$info = $cache->getSourceInfo('php-src') ?? [];
|
||||
$cv = $info['version'] ?? null;
|
||||
if (($info['cache_type'] ?? null) === 'git' || $cv === null
|
||||
|| ($cv !== $requested && !str_starts_with($cv, $requested . '.'))) {
|
||||
$resolved = null;
|
||||
$candidates = glob(DOWNLOAD_PATH . '/php-' . $requested . '.*.tar.xz') ?: [];
|
||||
if ($candidates !== []) {
|
||||
usort($candidates, 'strnatcmp');
|
||||
if (preg_match('/^php-([0-9.]+)\.tar\.xz$/', basename(end($candidates)), $vm)) {
|
||||
$resolved = $vm[1];
|
||||
}
|
||||
} elseif ($this->download) {
|
||||
$j = @file_get_contents('https://www.php.net/releases/index.php?json&version=' . urlencode($requested));
|
||||
$rel = is_string($j) ? json_decode($j, true) : null;
|
||||
$resolved = is_array($rel) ? ($rel['version'] ?? null) : null;
|
||||
} else {
|
||||
throw new WrongUsageException("Requested PHP '{$requested}' but no php-{$requested}.*.tar.xz in downloads/; drop --no-download or run 'bin/spc download php-src --with-php={$requested}' first.");
|
||||
}
|
||||
if ($resolved !== null) {
|
||||
$cf = DOWNLOAD_PATH . '/.cache.json';
|
||||
$j = json_decode(@file_get_contents($cf) ?: '{}', true) ?: [];
|
||||
$tarball = DOWNLOAD_PATH . "/php-{$resolved}.tar.xz";
|
||||
$j['php-src']['source'] = [
|
||||
'lock_type' => 'source', 'cache_type' => 'archive',
|
||||
'filename' => "php-{$resolved}.tar.xz",
|
||||
'extract' => $info['extract'] ?? null,
|
||||
'hash' => is_file($tarball) ? sha1_file($tarball) : null,
|
||||
'time' => time(), 'version' => $resolved,
|
||||
'config' => $info['config'] ?? ['type' => 'php-release', 'domain' => 'https://www.php.net'],
|
||||
'downloader' => $info['downloader'] ?? \StaticPHP\Artifact\Downloader\Type\PhpRelease::class,
|
||||
];
|
||||
$j['php-src']['binary'] ??= [];
|
||||
file_put_contents($cf, json_encode($j, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
ApplicationContext::set(ArtifactCache::class, $cache = new ArtifactCache());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!is_dir($src_dir) || ($info = $cache->getSourceInfo('php-src')) === null) {
|
||||
return;
|
||||
}
|
||||
if (($info['cache_type'] ?? null) === 'git') {
|
||||
if (!is_dir($src_dir . '/.git')) {
|
||||
FileSystem::removeDir($src_dir);
|
||||
}
|
||||
return;
|
||||
}
|
||||
$vh = $src_dir . '/main/php_version.h';
|
||||
if (is_file($vh)
|
||||
&& preg_match('/#define\s+PHP_VERSION\s+"([^"]+)"/', file_get_contents($vh), $m)
|
||||
&& $m[1] !== ($info['version'] ?? null)
|
||||
) {
|
||||
FileSystem::removeDir($src_dir);
|
||||
}
|
||||
}
|
||||
|
||||
private function kindLabel(Package $package): string
|
||||
{
|
||||
return match (true) {
|
||||
@@ -698,7 +761,7 @@ class PackageInstaller
|
||||
if ($package->getBuildOption('build-all') || $package->getBuildOption('build-frankenphp')) {
|
||||
$frankenphp = PackageLoader::getPackage('frankenphp');
|
||||
$this->install_packages[$frankenphp->getName()] = $frankenphp;
|
||||
$this->build_packages[$package->getName()] = $package;
|
||||
$this->build_packages[$frankenphp->getName()] = $frankenphp;
|
||||
$added = true;
|
||||
}
|
||||
$this->build_packages[$package->getName()] = $package;
|
||||
|
||||
Reference in New Issue
Block a user