2023-03-21 00:25:46 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace SPC\builder\linux;
|
|
|
|
|
|
|
|
|
|
use SPC\builder\traits\UnixSystemUtilTrait;
|
|
|
|
|
use SPC\exception\RuntimeException;
|
|
|
|
|
|
|
|
|
|
class SystemUtil
|
|
|
|
|
{
|
|
|
|
|
use UnixSystemUtilTrait;
|
|
|
|
|
|
2023-08-20 19:51:45 +08:00
|
|
|
/** @noinspection PhpMissingBreakStatementInspection */
|
2023-03-21 00:25:46 +08:00
|
|
|
public static function getOSRelease(): array
|
|
|
|
|
{
|
|
|
|
|
$ret = [
|
|
|
|
|
'dist' => 'unknown',
|
|
|
|
|
'ver' => 'unknown',
|
|
|
|
|
];
|
|
|
|
|
switch (true) {
|
2023-10-14 13:55:51 +08:00
|
|
|
case file_exists('/etc/centos-release'):
|
|
|
|
|
$lines = file('/etc/centos-release');
|
|
|
|
|
goto rh;
|
|
|
|
|
case file_exists('/etc/redhat-release'):
|
|
|
|
|
$lines = file('/etc/redhat-release');
|
|
|
|
|
rh:
|
|
|
|
|
foreach ($lines as $line) {
|
|
|
|
|
if (preg_match('/release\s+(\d*(\.\d+)*)/', $line, $matches)) {
|
|
|
|
|
$ret['dist'] = 'redhat';
|
|
|
|
|
$ret['ver'] = $matches[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2023-03-21 00:25:46 +08:00
|
|
|
case file_exists('/etc/os-release'):
|
|
|
|
|
$lines = file('/etc/os-release');
|
|
|
|
|
foreach ($lines as $line) {
|
|
|
|
|
if (preg_match('/^ID=(.*)$/', $line, $matches)) {
|
|
|
|
|
$ret['dist'] = $matches[1];
|
|
|
|
|
}
|
|
|
|
|
if (preg_match('/^VERSION_ID=(.*)$/', $line, $matches)) {
|
|
|
|
|
$ret['ver'] = $matches[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$ret['dist'] = trim($ret['dist'], '"\'');
|
|
|
|
|
$ret['ver'] = trim($ret['ver'], '"\'');
|
|
|
|
|
if (strcasecmp($ret['dist'], 'centos') === 0) {
|
|
|
|
|
$ret['dist'] = 'redhat';
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return $ret;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-16 14:09:49 +02:00
|
|
|
public static function isMuslDist(): bool
|
|
|
|
|
{
|
|
|
|
|
return static::getOSRelease()['dist'] === 'alpine';
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-21 00:25:46 +08:00
|
|
|
public static function getCpuCount(): int
|
|
|
|
|
{
|
|
|
|
|
$ncpu = 1;
|
|
|
|
|
|
|
|
|
|
if (is_file('/proc/cpuinfo')) {
|
|
|
|
|
$cpuinfo = file_get_contents('/proc/cpuinfo');
|
|
|
|
|
preg_match_all('/^processor/m', $cpuinfo, $matches);
|
|
|
|
|
$ncpu = count($matches[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $ncpu;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @throws RuntimeException
|
|
|
|
|
*/
|
|
|
|
|
public static function getCCType(string $cc): string
|
|
|
|
|
{
|
|
|
|
|
return match (true) {
|
|
|
|
|
str_ends_with($cc, 'c++'), str_ends_with($cc, 'cc'), str_ends_with($cc, 'g++'), str_ends_with($cc, 'gcc') => 'gcc',
|
|
|
|
|
$cc === 'clang++', $cc === 'clang', str_starts_with($cc, 'musl-clang') => 'clang',
|
|
|
|
|
default => throw new RuntimeException("unknown cc type: {$cc}"),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @throws RuntimeException
|
2023-08-20 19:51:45 +08:00
|
|
|
* @noinspection PhpUnused
|
2023-03-21 00:25:46 +08:00
|
|
|
*/
|
|
|
|
|
public static function getCrossCompilePrefix(string $cc, string $arch): string
|
|
|
|
|
{
|
|
|
|
|
return match (static::getCCType($cc)) {
|
|
|
|
|
// guessing clang toolchains
|
|
|
|
|
'clang' => match ($arch) {
|
|
|
|
|
'x86_64' => 'x86_64-linux-gnu-',
|
|
|
|
|
'arm64', 'aarch64' => 'aarch64-linux-gnu-',
|
|
|
|
|
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
|
|
|
|
},
|
|
|
|
|
// remove gcc postfix
|
|
|
|
|
'gcc' => str_replace('-cc', '', str_replace('-gcc', '', $cc)) . '-',
|
|
|
|
|
default => throw new RuntimeException('unsupported cc'),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static function findStaticLib(string $name): ?array
|
|
|
|
|
{
|
|
|
|
|
$paths = getenv('LIBPATH');
|
|
|
|
|
if (!$paths) {
|
2023-05-10 02:04:08 +08:00
|
|
|
$paths = '/lib:/lib64:/usr/lib:/usr/lib64:/usr/local/lib:/usr/local/lib64:';
|
2023-03-21 00:25:46 +08:00
|
|
|
}
|
|
|
|
|
foreach (explode(':', $paths) as $path) {
|
|
|
|
|
if (file_exists("{$path}/{$name}")) {
|
|
|
|
|
return ["{$path}", "{$name}"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-20 19:51:45 +08:00
|
|
|
/** @noinspection PhpUnused */
|
2023-03-21 00:25:46 +08:00
|
|
|
public static function findStaticLibs(array $names): ?array
|
|
|
|
|
{
|
|
|
|
|
$ret = [];
|
|
|
|
|
foreach ($names as $name) {
|
|
|
|
|
$path = static::findStaticLib($name);
|
|
|
|
|
if (!$path) {
|
|
|
|
|
logger()->warning("static library {$name} not found");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
$ret[] = $path;
|
|
|
|
|
}
|
|
|
|
|
return $ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static function findHeader(string $name): ?array
|
|
|
|
|
{
|
|
|
|
|
$paths = getenv('INCLUDEPATH');
|
|
|
|
|
if (!$paths) {
|
|
|
|
|
$paths = '/include:/usr/include:/usr/local/include';
|
|
|
|
|
}
|
|
|
|
|
foreach (explode(':', $paths) as $path) {
|
|
|
|
|
if (file_exists("{$path}/{$name}") || is_dir("{$path}/{$name}")) {
|
|
|
|
|
return ["{$path}", "{$name}"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-20 19:51:45 +08:00
|
|
|
/** @noinspection PhpUnused */
|
2023-03-21 00:25:46 +08:00
|
|
|
public static function findHeaders(array $names): ?array
|
|
|
|
|
{
|
|
|
|
|
$ret = [];
|
|
|
|
|
foreach ($names as $name) {
|
|
|
|
|
$path = static::findHeader($name);
|
|
|
|
|
if (!$path) {
|
|
|
|
|
logger()->warning("header {$name} not found");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
$ret[] = $path;
|
|
|
|
|
}
|
|
|
|
|
return $ret;
|
|
|
|
|
}
|
2024-01-08 23:34:17 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get fully-supported linux distros.
|
|
|
|
|
*
|
|
|
|
|
* @return string[] List of supported Linux distro name for doctor
|
|
|
|
|
*/
|
|
|
|
|
public static function getSupportedDistros(): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
|
|
|
|
// debian-like
|
|
|
|
|
'debian', 'ubuntu', 'Deepin',
|
|
|
|
|
// rhel-like
|
|
|
|
|
'redhat',
|
|
|
|
|
// alpine
|
|
|
|
|
'alpine',
|
2024-04-13 16:12:05 +08:00
|
|
|
// arch
|
|
|
|
|
'arch', 'manjaro',
|
2024-01-08 23:34:17 +08:00
|
|
|
];
|
|
|
|
|
}
|
2023-03-21 00:25:46 +08:00
|
|
|
}
|