[v3] Add musl-wrapper and musl-toolchain installation support (#984)

This commit is contained in:
Jerry Ma
2025-12-05 15:32:32 +08:00
committed by GitHub
parent 93a697ebbf
commit 106b55d4e7
5 changed files with 71 additions and 25 deletions

View File

@@ -8,6 +8,9 @@
} }
} }
}, },
"musl-wrapper": {
"source": "https://musl.libc.org/releases/musl-1.2.5.tar.gz"
},
"php-src": { "php-src": {
"source": { "source": {
"type": "php-release" "type": "php-release"
@@ -28,8 +31,16 @@
}, },
"musl-toolchain": { "musl-toolchain": {
"binary": { "binary": {
"linux-x86_64": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/x86_64-musl-toolchain.tgz", "linux-x86_64": {
"linux-aarch64": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/aarch64-musl-toolchain.tgz" "type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/x86_64-musl-toolchain.tgz",
"extract": "{pkg_root_path}/musl-toolchain"
},
"linux-aarch64": {
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/aarch64-musl-toolchain.tgz",
"extract": "{pkg_root_path}/musl-toolchain"
}
} }
}, },
"pkg-config": { "pkg-config": {

View File

@@ -320,7 +320,7 @@ class ArtifactDownloader
$skipped = []; $skipped = [];
foreach ($this->artifacts as $artifact) { foreach ($this->artifacts as $artifact) {
++$current; ++$current;
if ($this->downloadWithType($artifact, $current, $count) === SPC_DOWNLOAD_STATUS_SKIPPED) { if ($this->downloadWithType($artifact, $current, $count, interactive: $interactive) === SPC_DOWNLOAD_STATUS_SKIPPED) {
$skipped[] = $artifact->getName(); $skipped[] = $artifact->getName();
continue; continue;
} }
@@ -358,7 +358,7 @@ class ArtifactDownloader
return $this->options[$name] ?? $default; return $this->options[$name] ?? $default;
} }
private function downloadWithType(Artifact $artifact, int $current, int $total, bool $parallel = false): int private function downloadWithType(Artifact $artifact, int $current, int $total, bool $parallel = false, bool $interactive = true): int
{ {
$queue = $this->generateQueue($artifact); $queue = $this->generateQueue($artifact);
// already downloaded // already downloaded
@@ -379,7 +379,7 @@ class ArtifactDownloader
}; };
$try_h = $try ? 'Try downloading' : 'Downloading'; $try_h = $try ? 'Try downloading' : 'Downloading';
logger()->info("{$try_h} artifact '{$artifact->getName()}' {$item['display']} ..."); logger()->info("{$try_h} artifact '{$artifact->getName()}' {$item['display']} ...");
if ($parallel === false) { if ($parallel === false && $interactive) {
InteractiveTerm::indicateProgress("[{$current}/{$total}] Downloading artifact " . ConsoleColor::green($artifact->getName()) . " {$item['display']} from {$type_display_name} ..."); InteractiveTerm::indicateProgress("[{$current}/{$total}] Downloading artifact " . ConsoleColor::green($artifact->getName()) . " {$item['display']} from {$type_display_name} ...");
} }
// is valid download type // is valid download type
@@ -413,13 +413,13 @@ class ArtifactDownloader
} }
// process lock // process lock
ApplicationContext::get(ArtifactCache::class)->lock($artifact, $item['lock'], $lock, SystemTarget::getCurrentPlatformString()); ApplicationContext::get(ArtifactCache::class)->lock($artifact, $item['lock'], $lock, SystemTarget::getCurrentPlatformString());
if ($parallel === false) { if ($parallel === false && $interactive) {
$ver = $lock->hasVersion() ? (' (' . ConsoleColor::yellow($lock->version) . ')') : ''; $ver = $lock->hasVersion() ? (' (' . ConsoleColor::yellow($lock->version) . ')') : '';
InteractiveTerm::finish('Downloaded ' . ($verified ? 'and verified ' : '') . 'artifact ' . ConsoleColor::green($artifact->getName()) . $ver . " {$item['display']} ."); InteractiveTerm::finish('Downloaded ' . ($verified ? 'and verified ' : '') . 'artifact ' . ConsoleColor::green($artifact->getName()) . $ver . " {$item['display']} .");
} }
return SPC_DOWNLOAD_STATUS_SUCCESS; return SPC_DOWNLOAD_STATUS_SUCCESS;
} catch (DownloaderException|ExecutionException $e) { } catch (DownloaderException|ExecutionException $e) {
if ($parallel === false) { if ($parallel === false && $interactive) {
InteractiveTerm::finish("Download artifact {$artifact->getName()} {$item['display']} failed !", false); InteractiveTerm::finish("Download artifact {$artifact->getName()} {$item['display']} failed !", false);
InteractiveTerm::error("Failed message: {$e->getMessage()}", true); InteractiveTerm::error("Failed message: {$e->getMessage()}", true);
} }

View File

@@ -78,12 +78,17 @@ class ArtifactExtractor
/** /**
* Extract a single artifact. * Extract a single artifact.
* *
* @param Artifact $artifact The artifact to extract * @param Artifact|string $artifact The artifact to extract
* @param bool $force_source If true, always extract source (ignore binary) * @param bool $force_source If true, always extract source (ignore binary)
*/ */
public function extract(Artifact $artifact, bool $force_source = false): int public function extract(Artifact|string $artifact, bool $force_source = false): int
{ {
$name = $artifact->getName(); if (is_string($artifact)) {
$name = $artifact;
$artifact = ArtifactLoader::getArtifactInstance($name);
} else {
$name = $artifact->getName();
}
// Already extracted in this session // Already extracted in this session
if (isset($this->extracted[$name])) { if (isset($this->extracted[$name])) {

View File

@@ -4,13 +4,20 @@ declare(strict_types=1);
namespace StaticPHP\Doctor\Item; namespace StaticPHP\Doctor\Item;
use StaticPHP\Artifact\ArtifactCache;
use StaticPHP\Artifact\ArtifactDownloader;
use StaticPHP\Artifact\ArtifactExtractor;
use StaticPHP\Attribute\Doctor\CheckItem; use StaticPHP\Attribute\Doctor\CheckItem;
use StaticPHP\Attribute\Doctor\FixItem; use StaticPHP\Attribute\Doctor\FixItem;
use StaticPHP\Attribute\Doctor\OptionalCheck; use StaticPHP\Attribute\Doctor\OptionalCheck;
use StaticPHP\DI\ApplicationContext;
use StaticPHP\Doctor\CheckResult; use StaticPHP\Doctor\CheckResult;
use StaticPHP\Runtime\Shell\Shell;
use StaticPHP\Toolchain\MuslToolchain; use StaticPHP\Toolchain\MuslToolchain;
use StaticPHP\Toolchain\ZigToolchain; use StaticPHP\Toolchain\ZigToolchain;
use StaticPHP\Util\FileSystem; use StaticPHP\Util\FileSystem;
use StaticPHP\Util\InteractiveTerm;
use StaticPHP\Util\SourcePatcher;
use StaticPHP\Util\System\LinuxUtil; use StaticPHP\Util\System\LinuxUtil;
#[OptionalCheck([self::class, 'optionalCheck'])] #[OptionalCheck([self::class, 'optionalCheck'])]
@@ -51,23 +58,46 @@ class LinuxMuslCheck
#[FixItem('fix-musl-wrapper')] #[FixItem('fix-musl-wrapper')]
public function fixMusl(): bool public function fixMusl(): bool
{ {
// TODO: implement musl-wrapper installation $downloader = new ArtifactDownloader();
// This should: $downloader->add('musl-wrapper')->download(false);
// 1. Download musl source using Downloader::downloadSource() $extractor = new ArtifactExtractor(ApplicationContext::get(ArtifactCache::class));
// 2. Extract the source using FileSystem::extractSource() $extractor->extract('musl-wrapper');
// 3. Apply CVE patches using SourcePatcher::patchFile()
// 4. Build and install musl wrapper // Apply CVE-2025-26519 patch and install musl wrapper
// 5. Add path using putenv instead of editing /etc/profile SourcePatcher::patchFile('musl-1.2.5_CVE-2025-26519_0001.patch', SOURCE_PATH . '/musl-wrapper');
return false; SourcePatcher::patchFile('musl-1.2.5_CVE-2025-26519_0002.patch', SOURCE_PATH . '/musl-wrapper');
$prefix = '';
if (get_current_user() !== 'root') {
$prefix = 'sudo ';
logger()->warning('Current user is not root, using sudo for running command');
}
shell()->cd(SOURCE_PATH . '/musl-wrapper')
->exec('CC=gcc CXX=g++ AR=ar LD=ld ./configure --disable-gcc-wrapper')
->exec('CC=gcc CXX=g++ AR=ar LD=ld make -j')
->exec("CC=gcc CXX=g++ AR=ar LD=ld {$prefix}make install");
return true;
} }
#[FixItem('fix-musl-cross-make')] #[FixItem('fix-musl-cross-make')]
public function fixMuslCrossMake(): bool public function fixMuslCrossMake(): bool
{ {
// TODO: implement musl-cross-make installation // sudo
// This should: $prefix = '';
// 1. Install musl-toolchain package using PackageManager::installPackage() if (get_current_user() !== 'root') {
// 2. Copy toolchain files to /usr/local/musl $prefix = 'sudo ';
return false; logger()->warning('Current user is not root, using sudo for running command');
}
Shell::passthruCallback(function () {
InteractiveTerm::advance();
});
$downloader = new ArtifactDownloader();
$extractor = new ArtifactExtractor(ApplicationContext::get(ArtifactCache::class));
$downloader->add('musl-toolchain')->download(false);
$extractor->extract('musl-toolchain');
$pkg_root = PKG_ROOT_PATH . '/musl-toolchain';
shell()->exec("{$prefix}cp -rf {$pkg_root}/* /usr/local/musl");
FileSystem::removeDir($pkg_root);
return true;
} }
} }

View File

@@ -91,7 +91,7 @@ class LinuxUtil extends UnixUtil
{ {
return [ return [
// debian-like // debian-like
'debian', 'ubuntu', 'Deepin', 'debian', 'ubuntu', 'Deepin', 'neon',
// rhel-like // rhel-like
'redhat', 'redhat',
// centos // centos