Suggestions

This commit is contained in:
crazywhalecc
2025-06-29 16:00:17 +08:00
parent 0598eff9c5
commit 977fbaa8ef
30 changed files with 196 additions and 215 deletions

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace SPC\util;
use SPC\builder\linux\SystemUtil;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\toolchain\ToolchainManager;
/**
* Environment variable manager
@@ -63,30 +63,7 @@ class GlobalEnvManager
}
}
// deprecated: convert SPC_LIBC to SPC_TARGET
if (getenv('SPC_LIBC') !== false) {
logger()->warning('SPC_LIBC is deprecated, please use SPC_TARGET instead.');
$target = match (getenv('SPC_LIBC')) {
'musl' => SPCTarget::MUSL_STATIC,
'musl-shared' => SPCTarget::MUSL,
'glibc' => SPCTarget::GLIBC,
default => throw new WrongUsageException('Unsupported SPC_LIBC value: ' . getenv('SPC_LIBC')),
};
self::putenv("SPC_TARGET={$target}");
self::putenv('SPC_LIBC');
}
// auto-select toolchain based on target and OS temporarily
// TODO: use 'zig' instead of 'gcc-native' when ZigToolchain is implemented
$toolchain = match (SPCTarget::getTargetName()) {
SPCTarget::MUSL_STATIC, SPCTarget::MUSL => SystemUtil::isMuslDist() ? 'gcc-native' : 'musl',
SPCTarget::MACHO => 'clang-native',
SPCTarget::MSVC_STATIC => 'msvc',
SPCTarget::GLIBC => !SystemUtil::isMuslDist() ? 'gcc-native' : throw new WrongUsageException('SPC_TARGET must be musl-static or musl for musl dist.'),
default => throw new WrongUsageException('Unknown SPC_TARGET: ' . getenv('SPC_TARGET')),
};
SPCTarget::initTargetForToolchain($toolchain);
ToolchainManager::initToolchain();
// apply second time
$ini2 = self::readIniFile();
@@ -123,9 +100,15 @@ class GlobalEnvManager
}
}
/**
* Initialize the toolchain after the environment variables are set.
* The toolchain or environment availability check is done here.
*
* @throws WrongUsageException
*/
public static function afterInit(): void
{
SPCTarget::afterInitTargetForToolchain();
ToolchainManager::afterInitToolchain();
}
/**

View File

@@ -55,7 +55,7 @@ class SPCConfigUtil
ob_get_clean();
$ldflags = $this->getLdflagsString();
$libs = $this->getLibsString($libraries, $with_dependencies);
if (SPCTarget::isTarget(SPCTarget::MACHO)) {
if (SPCTarget::getTargetOS() === 'Darwin') {
$libs .= " {$this->getFrameworksString($extensions)}";
}
$cflags = $this->getIncludesString();

View File

@@ -4,13 +4,8 @@ declare(strict_types=1);
namespace SPC\util;
use SPC\builder\linux\SystemUtil;
use SPC\exception\WrongUsageException;
use SPC\util\toolchain\ClangNativeToolchain;
use SPC\util\toolchain\GccNativeToolchain;
use SPC\util\toolchain\MSVCToolchain;
use SPC\util\toolchain\MuslToolchain;
use SPC\util\toolchain\ToolchainInterface;
use SPC\util\toolchain\ZigToolchain;
/**
* SPC build target constants and toolchain initialization.
@@ -18,86 +13,75 @@ use SPC\util\toolchain\ZigToolchain;
*/
class SPCTarget
{
public const MUSL = 'musl';
public const MUSL_STATIC = 'musl-static';
public const GLIBC = 'glibc';
public const MACHO = 'macho';
public const MSVC_STATIC = 'msvc-static';
public const TOOLCHAIN_LIST = [
'musl' => MuslToolchain::class,
'gcc-native' => GccNativeToolchain::class,
'clang-native' => ClangNativeToolchain::class,
'msvc' => MSVCToolchain::class,
'zig' => ZigToolchain::class,
public const array LIBC_LIST = [
'musl',
'glibc',
];
public static function isTarget(string $target): bool
{
$env = getenv('SPC_TARGET');
if ($env === false) {
return false;
}
$env = strtolower($env);
// ver
$env = explode('@', $env)[0];
return $env === $target;
}
/**
* Returns whether the target is a full-static target.
*/
public static function isStaticTarget(): bool
{
$env = getenv('SPC_TARGET');
if ($env === false) {
return false;
$libc = getenv('SPC_LIBC');
// if SPC_LIBC is set, it means the target is static, remove it when 3.0 is released
if ($libc === 'musl') {
return true;
}
$env = strtolower($env);
// ver
$env = explode('@', $env)[0];
return str_ends_with($env, '-static');
// TODO: add zig target parser here
return false;
}
public static function initTargetForToolchain(string $toolchain): void
/**
* Returns the libc type if set, for other OS, it will always return null.
*/
public static function getLibc(): ?string
{
$env = getenv('SPC_TARGET');
$libc = getenv('SPC_LIBC');
if ($libc !== false) {
return $libc;
}
// TODO: zig target parser
return null;
}
/**
* Returns the libc version if set, for other OS, it will always return null.
*/
public static function getLibcVersion(): ?string
{
$env = getenv('SPC_TARGET');
$libc = getenv('SPC_LIBC');
if ($libc !== false) {
// legacy method: get a version from system
return SystemUtil::getLibcVersionIfExists($libc);
}
// TODO: zig target parser
return null;
}
/**
* Returns the target OS family, e.g. Linux, Darwin, Windows, BSD.
* Currently, we only support native building.
*
* @return 'BSD'|'Darwin'|'Linux'|'Windows'
* @throws WrongUsageException
*/
public static function getTargetOS(): string
{
$target = getenv('SPC_TARGET');
$toolchain = strtolower($toolchain);
if (isset(self::TOOLCHAIN_LIST[$toolchain])) {
$toolchainClass = self::TOOLCHAIN_LIST[$toolchain];
/* @var ToolchainInterface $toolchainClass */
(new $toolchainClass())->initEnv($target);
if ($target === false) {
return PHP_OS_FAMILY;
}
GlobalEnvManager::putenv("SPC_TOOLCHAIN={$toolchain}");
}
public static function afterInitTargetForToolchain()
{
if (!getenv('SPC_TOOLCHAIN')) {
throw new WrongUsageException('SPC_TOOLCHAIN not set');
}
$toolchain = getenv('SPC_TOOLCHAIN');
if (!isset(self::TOOLCHAIN_LIST[$toolchain])) {
throw new WrongUsageException("Unknown toolchain: {$toolchain}");
}
$toolchainClass = self::TOOLCHAIN_LIST[$toolchain];
(new $toolchainClass())->afterInit(getenv('SPC_TARGET'));
}
public static function getTargetName(): ?string
{
$target = getenv('SPC_TARGET');
$target = strtolower($target);
// ver
return explode('@', $target)[0];
}
public static function getTargetSuffix(): ?string
{
$target = getenv('SPC_TARGET');
$target = strtolower($target);
// ver
return explode('@', $target)[1] ?? null;
// TODO: zig target parser like below?
return match (true) {
str_contains($target, 'linux') => 'Linux',
str_contains($target, 'macos') => 'Darwin',
str_contains($target, 'windows') => 'Windows',
default => throw new WrongUsageException('Cannot parse target.'),
};
}
}

View File

@@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\util\toolchain;
use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil;
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
use SPC\builder\macos\SystemUtil as MacOSSystemUtil;
use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager;
use SPC\util\SPCTarget;
class ClangNativeToolchain implements ToolchainInterface
{
public function initEnv(string $target): void
{
// native toolchain does not support versioning
if (SPCTarget::getTargetSuffix() !== null) {
throw new WrongUsageException('Clang native toolchain does not support versioning.');
}
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CC=clang');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=clang++');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld');
}
public function afterInit(string $target): void
{
// check clang exists
match (PHP_OS_FAMILY) {
'Linux' => LinuxSystemUtil::findCommand('clang++') ?? throw new WrongUsageException('Clang++ not found, please install it or manually set CC/CXX to a valid path.'),
'Darwin' => MacOSSystemUtil::findCommand('clang++') ?? throw new WrongUsageException('Clang++ not found, please install it or set CC/CXX to a valid path.'),
'BSD' => FreeBSDSystemUtil::findCommand('clang++') ?? throw new WrongUsageException('Clang++ not found, please install it or set CC/CXX to a valid path.'),
default => throw new WrongUsageException('Clang is not supported on ' . PHP_OS_FAMILY . '.'),
};
}
}

View File

@@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\util\toolchain;
use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil;
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
use SPC\builder\macos\SystemUtil as MacOSSystemUtil;
use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager;
use SPC\util\SPCTarget;
class GccNativeToolchain implements ToolchainInterface
{
public function initEnv(string $target): void
{
// native toolchain does not support versioning
if (SPCTarget::getTargetSuffix() !== null) {
throw new WrongUsageException('gcc native toolchain does not support versioning.');
}
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CC=gcc');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=g++');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld.gold');
}
public function afterInit(string $target): void
{
// check gcc exists
match (PHP_OS_FAMILY) {
'Linux' => LinuxSystemUtil::findCommand('g++') ?? throw new WrongUsageException('g++ not found, please install it or set CC/CXX to a valid path.'),
'Darwin' => MacOSSystemUtil::findCommand('g++') ?? throw new WrongUsageException('g++ not found, please install it or set CC/CXX to a valid path.'),
'BSD' => FreeBSDSystemUtil::findCommand('g++') ?? throw new WrongUsageException('g++ not found, please install it or set CC/CXX to a valid path.'),
default => throw new \RuntimeException('GCC is not supported on ' . PHP_OS_FAMILY . '.'),
};
}
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\util\toolchain;
class MSVCToolchain implements ToolchainInterface
{
public function initEnv(string $target): void {}
public function afterInit(string $target): void {}
}

View File

@@ -1,44 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\util\toolchain;
use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager;
use SPC\util\SPCTarget;
class MuslToolchain implements ToolchainInterface
{
public function initEnv(string $target): void
{
// Check if the target is musl-static (the musl(-shared) target is not supported yet)
if (!in_array($target, [SPCTarget::MUSL_STATIC/* , SPCTarget::MUSL */], true)) {
throw new WrongUsageException('MuslToolchain can only be used with the "musl-static" target.');
}
$arch = getenv('GNU_ARCH');
// Set environment variables for musl toolchain
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CC={$arch}-linux-musl-gcc");
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CXX={$arch}-linux-musl-g++");
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_AR={$arch}-linux-musl-ar");
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_LD={$arch}-linux-musl-ld");
GlobalEnvManager::addPathIfNotExists('/usr/local/musl/bin');
GlobalEnvManager::addPathIfNotExists("/usr/local/musl/{$arch}-linux-musl/bin");
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_LD_LIBRARY_PATH=/usr/local/musl/lib:/usr/local/musl/{$arch}-linux-musl/lib");
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_LIBRARY_PATH=/usr/local/musl/lib:/usr/local/musl/{$arch}-linux-musl/lib");
}
public function afterInit(string $target): void
{
$arch = getenv('GNU_ARCH');
// append LD_LIBRARY_PATH to $configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
$configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
$ld_library_path = getenv('SPC_LINUX_DEFAULT_LD_LIBRARY_PATH');
GlobalEnvManager::putenv("SPC_CMD_PREFIX_PHP_CONFIGURE=LD_LIBRARY_PATH=\"{$ld_library_path}\" {$configure}");
if (!file_exists("/usr/local/musl/{$arch}-linux-musl/lib/libc.a")) {
throw new WrongUsageException('You are building with musl-libc target in glibc distro, but musl-toolchain is not installed, please install musl-toolchain first. (You can use `doctor` command to install it)');
}
}
}

View File

@@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\util\toolchain;
interface ToolchainInterface
{
/**
* Initialize the environment for the given target.
*/
public function initEnv(string $target): void;
/**
* Perform actions after the environment has been initialized for the given target.
*/
public function afterInit(string $target): void;
}

View File

@@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\util\toolchain;
class ZigToolchain implements ToolchainInterface
{
public function initEnv(string $target): void
{
// TODO: Implement zig
}
public function afterInit(string $target): void
{
// TODO: Implement afterInit() method.
}
}