Suggestions

This commit is contained in:
crazywhalecc 2025-06-29 16:00:17 +08:00
parent 0598eff9c5
commit 977fbaa8ef
No known key found for this signature in database
GPG Key ID: 1F4BDD59391F2680
30 changed files with 196 additions and 215 deletions

View File

@ -56,7 +56,7 @@ SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES="--with github.com/dunglas/frankenphp/cadd
[windows] [windows]
; build target: win7-static ; build target: win7-static
SPC_TARGET=msvc-static SPC_TARGET=native
; php-sdk-binary-tools path ; php-sdk-binary-tools path
PHP_SDK_PATH="${WORKING_DIR}\php-sdk-binary-tools" PHP_SDK_PATH="${WORKING_DIR}\php-sdk-binary-tools"
; upx executable path ; upx executable path
@ -75,7 +75,9 @@ SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime
; - musl-static (default): pure static linking, using musl-libc, can run on any linux distro. ; - musl-static (default): pure static linking, using musl-libc, can run on any linux distro.
; - musl: static linking with dynamic linking to musl-libc, can run on musl-based linux distro. ; - musl: static linking with dynamic linking to musl-libc, can run on musl-based linux distro.
; - glibc: static linking with dynamic linking to glibc, can run on glibc-based linux distro. ; - glibc: static linking with dynamic linking to glibc, can run on glibc-based linux distro.
SPC_TARGET=musl-static
; include PATH for musl libc.
SPC_LIBC=musl
; compiler environments ; compiler environments
CC=${SPC_LINUX_DEFAULT_CC} CC=${SPC_LINUX_DEFAULT_CC}
CXX=${SPC_LINUX_DEFAULT_CXX} CXX=${SPC_LINUX_DEFAULT_CXX}
@ -122,7 +124,7 @@ SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie"
[macos] [macos]
; build target: macho or macho (possibly we could support macho-universal in the future) ; build target: macho or macho (possibly we could support macho-universal in the future)
; Currently we do not support universal and cross-compilation for macOS. ; Currently we do not support universal and cross-compilation for macOS.
SPC_TARGET=macho SPC_TARGET=native
; compiler environments ; compiler environments
CC=clang CC=clang
CXX=clang++ CXX=clang++

View File

@ -10,6 +10,7 @@ use SPC\exception\WrongUsageException;
use SPC\store\Config; use SPC\store\Config;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\util\SPCConfigUtil; use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
class Extension class Extension
{ {
@ -532,6 +533,11 @@ class Extension
$sharedLibString .= '-l' . $lib . ' '; $sharedLibString .= '-l' . $lib . ' ';
} }
} }
// move static libstdc++ to shared if we are on non-full-static build target
if (!SPCTarget::isStaticTarget() && in_array(SPCTarget::getLibc(), SPCTarget::LIBC_LIST)) {
$staticLibString .= ' -lstdc++';
$sharedLibString = str_replace('-lstdc++', '', $sharedLibString);
}
return [trim($staticLibString), trim($sharedLibString)]; return [trim($staticLibString), trim($sharedLibString)];
} }

View File

@ -6,7 +6,6 @@ namespace SPC\builder\extension;
use SPC\builder\Extension; use SPC\builder\Extension;
use SPC\util\CustomExt; use SPC\util\CustomExt;
use SPC\util\SPCTarget;
#[CustomExt('imagick')] #[CustomExt('imagick')]
class imagick extends Extension class imagick extends Extension
@ -16,15 +15,4 @@ class imagick extends Extension
$disable_omp = ' ac_cv_func_omp_pause_resource_all=no'; $disable_omp = ' ac_cv_func_omp_pause_resource_all=no';
return '--with-imagick=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . $disable_omp; return '--with-imagick=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . $disable_omp;
} }
protected function getStaticAndSharedLibs(): array
{
// on centos 7, it will use the symbol _ZTINSt6thread6_StateE, which is not defined in system libstdc++.so.6
[$static, $shared] = parent::getStaticAndSharedLibs();
if (SPCTarget::isTarget(SPCTarget::GLIBC)) {
$static .= ' -lstdc++';
$shared = str_replace('-lstdc++', '', $shared);
}
return [$static, $shared];
}
} }

View File

@ -6,7 +6,6 @@ namespace SPC\builder\linux;
use SPC\builder\traits\UnixSystemUtilTrait; use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\util\SPCTarget;
class SystemUtil class SystemUtil
{ {
@ -189,12 +188,12 @@ class SystemUtil
/** /**
* Get libc version string from ldd * Get libc version string from ldd
*/ */
public static function getLibcVersionIfExists(): ?string public static function getLibcVersionIfExists(string $libc): ?string
{ {
if (self::$libc_version !== null) { if (self::$libc_version !== null) {
return self::$libc_version; return self::$libc_version;
} }
if (SPCTarget::isTarget(SPCTarget::GLIBC)) { if ($libc === 'glibc') {
$result = shell()->execWithResult('ldd --version', false); $result = shell()->execWithResult('ldd --version', false);
if ($result[0] !== 0) { if ($result[0] !== 0) {
return null; return null;
@ -209,7 +208,7 @@ class SystemUtil
} }
return null; return null;
} }
if (SPCTarget::isTarget(SPCTarget::MUSL_STATIC)) { if ($libc === 'musl') {
if (self::isMuslDist()) { if (self::isMuslDist()) {
$result = shell()->execWithResult('ldd 2>&1', false); $result = shell()->execWithResult('ldd 2>&1', false);
} else { } else {

View File

@ -17,7 +17,7 @@ class icu extends LinuxLibraryBase
{ {
$cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -DPIC -fPIC"'; $cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -DPIC -fPIC"';
$cxxflags = 'CXXFLAGS="-std=c++17 -DPIC -fPIC -fno-ident"'; $cxxflags = 'CXXFLAGS="-std=c++17 -DPIC -fPIC -fno-ident"';
$ldflags = SPCTarget::isTarget(SPCTarget::MUSL_STATIC) ? 'LDFLAGS="-static"' : ''; $ldflags = SPCTarget::isStaticTarget() ? 'LDFLAGS="-static"' : '';
shell()->cd($this->source_dir . '/source')->initializeEnv($this) shell()->cd($this->source_dir . '/source')->initializeEnv($this)
->exec( ->exec(
"{$cppflags} {$cxxflags} {$ldflags} " . "{$cppflags} {$cxxflags} {$ldflags} " .

View File

@ -29,6 +29,7 @@ class MacOSBuilder extends UnixBuilderBase
// apply global environment variables // apply global environment variables
GlobalEnvManager::init(); GlobalEnvManager::init();
GlobalEnvManager::afterInit();
// ---------- set necessary compile vars ---------- // ---------- set necessary compile vars ----------
// concurrency // concurrency

View File

@ -201,7 +201,7 @@ abstract class UnixBuilderBase extends BuilderBase
$util = new SPCConfigUtil($this); $util = new SPCConfigUtil($this);
$config = $util->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs')); $config = $util->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
$lens = "{$config['cflags']} {$config['ldflags']} {$config['libs']}"; $lens = "{$config['cflags']} {$config['ldflags']} {$config['libs']}";
if (SPCTarget::isTarget(SPCTarget::MUSL_STATIC)) { if (SPCTarget::isStaticTarget()) {
$lens .= ' -static'; $lens .= ' -static';
} }
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens); [$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens);
@ -335,7 +335,7 @@ abstract class UnixBuilderBase extends BuilderBase
$debugFlags = $this->getOption('no-strip') ? "'-w -s' " : ''; $debugFlags = $this->getOption('no-strip') ? "'-w -s' " : '';
$extLdFlags = "-extldflags '-pie'"; $extLdFlags = "-extldflags '-pie'";
$muslTags = ''; $muslTags = '';
if (SPCTarget::isTarget(SPCTarget::MUSL_STATIC)) { if (SPCTarget::isStaticTarget()) {
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000'"; $extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000'";
$muslTags = 'static_build,'; $muslTags = 'static_build,';
} }

View File

@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor; use SPC\util\executor\UnixAutoconfExecutor;
use SPC\util\SPCTarget; use SPC\util\SPCTarget;
@ -15,6 +16,7 @@ trait imagemagick
/** /**
* @throws RuntimeException * @throws RuntimeException
* @throws FileSystemException * @throws FileSystemException
* @throws WrongUsageException
*/ */
protected function build(): void protected function build(): void
{ {
@ -36,11 +38,11 @@ trait imagemagick
'--without-x', '--without-x',
); );
// special: linux musl-static needs `-static` // special: linux-static target needs `-static`
$ldflags = !SPCTarget::isTarget(SPCTarget::MUSL_STATIC) ? ('-static -ldl') : '-ldl'; $ldflags = SPCTarget::isStaticTarget() ? ('-static -ldl') : '-ldl';
// special: macOS needs -iconv // special: macOS needs -iconv
$libs = SPCTarget::isTarget(SPCTarget::MACHO) ? '-liconv' : ''; $libs = SPCTarget::getTargetOS() === 'Darwin' ? '-liconv' : '';
$ac->appendEnv([ $ac->appendEnv([
'LDFLAGS' => $ldflags, 'LDFLAGS' => $ldflags,

View File

@ -12,7 +12,7 @@ trait ldap
{ {
public function patchBeforeBuild(): bool public function patchBeforeBuild(): bool
{ {
$extra = SPCTarget::isTarget(SPCTarget::GLIBC) ? '-ldl -lpthread -lm -lresolv -lutil' : ''; $extra = SPCTarget::getLibc() === 'glibc' ? '-ldl -lpthread -lm -lresolv -lutil' : '';
FileSystem::replaceFileStr($this->source_dir . '/configure', '"-lssl -lcrypto', '"-lssl -lcrypto -lz ' . $extra); FileSystem::replaceFileStr($this->source_dir . '/configure', '"-lssl -lcrypto', '"-lssl -lcrypto -lz ' . $extra);
return true; return true;
} }

View File

@ -14,9 +14,9 @@ trait mimalloc
$cmake = UnixCMakeExecutor::create($this) $cmake = UnixCMakeExecutor::create($this)
->addConfigureArgs( ->addConfigureArgs(
'-DMI_BUILD_SHARED=OFF', '-DMI_BUILD_SHARED=OFF',
'-DMI_INSTALL_TOPLEVEL=ON' '-DMI_INSTALL_TOPLEVEL=ON',
); );
if (SPCTarget::isTarget(SPCTarget::MUSL) || SPCTarget::isTarget(SPCTarget::MUSL_STATIC)) { if (SPCTarget::getLibc() === 'musl') {
$cmake->addConfigureArgs('-DMI_LIBC_MUSL=ON'); $cmake->addConfigureArgs('-DMI_LIBC_MUSL=ON');
} }
$cmake->build(); $cmake->build();

View File

@ -51,7 +51,7 @@ trait postgresql
$error_exec_cnt += $output[0] === 0 ? 0 : 1; $error_exec_cnt += $output[0] === 0 ? 0 : 1;
if (!empty($output[1][0])) { if (!empty($output[1][0])) {
$ldflags = $output[1][0]; $ldflags = $output[1][0];
$envs .= SPCTarget::isTarget(SPCTarget::MUSL_STATIC) ? " LDFLAGS=\"{$ldflags} -static\" " : " LDFLAGS=\"{$ldflags}\" "; $envs .= SPCTarget::isStaticTarget() ? " LDFLAGS=\"{$ldflags} -static\" " : " LDFLAGS=\"{$ldflags}\" ";
} }
$output = shell()->execWithResult("pkg-config --libs-only-l --static {$packages}"); $output = shell()->execWithResult("pkg-config --libs-only-l --static {$packages}");
$error_exec_cnt += $output[0] === 0 ? 0 : 1; $error_exec_cnt += $output[0] === 0 ? 0 : 1;

View File

@ -34,6 +34,7 @@ class WindowsBuilder extends BuilderBase
$this->options = $options; $this->options = $options;
GlobalEnvManager::init(); GlobalEnvManager::init();
GlobalEnvManager::afterInit();
// ---------- set necessary options ---------- // ---------- set necessary options ----------
// set sdk (require visual studio 16 or 17) // set sdk (require visual studio 16 or 17)

View File

@ -64,8 +64,8 @@ class BuildPHPCommand extends BuildCommand
// check dynamic extension build env // check dynamic extension build env
// linux must build with glibc // linux must build with glibc
if (!empty($shared_extensions) && SPCTarget::isTarget(SPCTarget::MUSL_STATIC)) { if (!empty($shared_extensions) && SPCTarget::isStaticTarget()) {
$this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with glibc!'); $this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with shared target!');
return static::FAILURE; return static::FAILURE;
} }
$static_and_shared = array_intersect($static_extensions, $shared_extensions); $static_and_shared = array_intersect($static_extensions, $shared_extensions);

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace SPC\command; namespace SPC\command;
use SPC\builder\linux\SystemUtil;
use SPC\builder\traits\UnixSystemUtilTrait; use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\exception\DownloaderException; use SPC\exception\DownloaderException;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
@ -224,12 +223,8 @@ class DownloadCommand extends BaseCommand
'{name}' => $source, '{name}' => $source,
'{arch}' => arch2gnu(php_uname('m')), '{arch}' => arch2gnu(php_uname('m')),
'{os}' => strtolower(PHP_OS_FAMILY), '{os}' => strtolower(PHP_OS_FAMILY),
'{libc}' => match (getenv('SPC_TARGET')) { '{libc}' => SPCTarget::getLibc() ?? 'default',
SPCTarget::MUSL_STATIC, SPCTarget::MUSL => 'musl', '{libcver}' => SPCTarget::getLibcVersion() ?? 'default',
SPCTarget::GLIBC => 'glibc',
default => 'default',
},
'{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default',
]; ];
$find = str_replace(array_keys($replace), array_values($replace), Config::getPreBuilt('match-pattern')); $find = str_replace(array_keys($replace), array_values($replace), Config::getPreBuilt('match-pattern'));
// find filename in asset list // find filename in asset list

View File

@ -6,7 +6,6 @@ namespace SPC\command\dev;
use SPC\builder\BuilderProvider; use SPC\builder\BuilderProvider;
use SPC\builder\LibraryBase; use SPC\builder\LibraryBase;
use SPC\builder\linux\SystemUtil;
use SPC\command\BuildCommand; use SPC\command\BuildCommand;
use SPC\exception\ExceptionHandler; use SPC\exception\ExceptionHandler;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
@ -77,12 +76,8 @@ class PackLibCommand extends BuildCommand
'{name}' => $lib->getName(), '{name}' => $lib->getName(),
'{arch}' => arch2gnu(php_uname('m')), '{arch}' => arch2gnu(php_uname('m')),
'{os}' => strtolower(PHP_OS_FAMILY), '{os}' => strtolower(PHP_OS_FAMILY),
'{libc}' => match (getenv('SPC_TARGET')) { '{libc}' => SPCTarget::getLibc() ?? 'default',
SPCTarget::MUSL_STATIC, SPCTarget::MUSL => 'musl', '{libcver}' => SPCTarget::getLibcVersion() ?? 'default',
SPCTarget::GLIBC => 'glibc',
default => 'default',
},
'{libcver}' => SystemUtil::getLibcVersionIfExists() ?? 'default',
]; ];
// detect suffix, for proper tar option // detect suffix, for proper tar option
$tar_option = $this->getTarOptionFromSuffix(Config::getPreBuilt('match-pattern')); $tar_option = $this->getTarOptionFromSuffix(Config::getPreBuilt('match-pattern'));

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace SPC\store; namespace SPC\store;
use SPC\builder\linux\SystemUtil;
use SPC\exception\DownloaderException; use SPC\exception\DownloaderException;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
@ -594,12 +593,8 @@ class Downloader
{ {
$os_family = PHP_OS_FAMILY; $os_family = PHP_OS_FAMILY;
$gnu_arch = getenv('GNU_ARCH') ?: 'unknown'; $gnu_arch = getenv('GNU_ARCH') ?: 'unknown';
$libc = match (getenv('SPC_TARGET')) { $libc = SPCTarget::getLibc();
SPCTarget::MUSL_STATIC, SPCTarget::MUSL => 'musl', $libc_version = SPCTarget::getLibcVersion() ?? 'default';
SPCTarget::GLIBC => 'glibc',
default => 'default',
};
$libc_version = SystemUtil::getLibcVersionIfExists() ?? 'default';
return "{$source}-{$os_family}-{$gnu_arch}-{$libc}-{$libc_version}"; return "{$source}-{$os_family}-{$gnu_arch}-{$libc}-{$libc_version}";
} }

View File

@ -11,6 +11,7 @@ use SPC\builder\unix\UnixBuilderBase;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\util\SPCTarget;
class SourcePatcher class SourcePatcher
{ {
@ -456,7 +457,7 @@ class SourcePatcher
public static function patchFfiCentos7FixO3strncmp(): bool public static function patchFfiCentos7FixO3strncmp(): bool
{ {
if (PHP_OS_FAMILY !== 'Linux' || SystemUtil::getLibcVersionIfExists() > '2.17') { if (!($ver = SPCTarget::getLibcVersion()) || version_compare($ver, '2.17', '>')) {
return false; return false;
} }
if (!file_exists(SOURCE_PATH . '/php-src/main/php_version.h')) { if (!file_exists(SOURCE_PATH . '/php-src/main/php_version.h')) {

View File

@ -7,7 +7,6 @@ namespace SPC\store\pkg;
use SPC\store\Downloader; use SPC\store\Downloader;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\store\LockFile; use SPC\store\LockFile;
use SPC\util\GlobalEnvManager;
class GoXcaddy extends CustomPackage class GoXcaddy extends CustomPackage
{ {
@ -62,7 +61,6 @@ class GoXcaddy extends CustomPackage
FileSystem::extractPackage($name, $source_type, $filename, $extract); FileSystem::extractPackage($name, $source_type, $filename, $extract);
GlobalEnvManager::init();
// install xcaddy // install xcaddy
shell() shell()
->appendEnv([ ->appendEnv([

View File

@ -2,30 +2,25 @@
declare(strict_types=1); declare(strict_types=1);
namespace SPC\util\toolchain; namespace SPC\toolchain;
use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil; use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil;
use SPC\builder\linux\SystemUtil as LinuxSystemUtil; use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
use SPC\builder\macos\SystemUtil as MacOSSystemUtil; use SPC\builder\macos\SystemUtil as MacOSSystemUtil;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
use SPC\util\SPCTarget;
class ClangNativeToolchain implements ToolchainInterface class ClangNativeToolchain implements ToolchainInterface
{ {
public function initEnv(string $target): void public function initEnv(): 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_CC=clang');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=clang++'); GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=clang++');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar'); GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld'); GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld');
} }
public function afterInit(string $target): void public function afterInit(): void
{ {
// check clang exists // check clang exists
match (PHP_OS_FAMILY) { match (PHP_OS_FAMILY) {

View File

@ -2,30 +2,25 @@
declare(strict_types=1); declare(strict_types=1);
namespace SPC\util\toolchain; namespace SPC\toolchain;
use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil; use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil;
use SPC\builder\linux\SystemUtil as LinuxSystemUtil; use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
use SPC\builder\macos\SystemUtil as MacOSSystemUtil; use SPC\builder\macos\SystemUtil as MacOSSystemUtil;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
use SPC\util\SPCTarget;
class GccNativeToolchain implements ToolchainInterface class GccNativeToolchain implements ToolchainInterface
{ {
public function initEnv(string $target): void public function initEnv(): 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_CC=gcc');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=g++'); GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=g++');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar'); GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar');
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld.gold'); GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld.gold');
} }
public function afterInit(string $target): void public function afterInit(): void
{ {
// check gcc exists // check gcc exists
match (PHP_OS_FAMILY) { match (PHP_OS_FAMILY) {

View File

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

View File

@ -2,20 +2,15 @@
declare(strict_types=1); declare(strict_types=1);
namespace SPC\util\toolchain; namespace SPC\toolchain;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
use SPC\util\SPCTarget;
class MuslToolchain implements ToolchainInterface class MuslToolchain implements ToolchainInterface
{ {
public function initEnv(string $target): void public function initEnv(): 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'); $arch = getenv('GNU_ARCH');
// Set environment variables for musl toolchain // Set environment variables for musl toolchain
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CC={$arch}-linux-musl-gcc"); GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CC={$arch}-linux-musl-gcc");
@ -29,7 +24,7 @@ class MuslToolchain implements ToolchainInterface
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_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 public function afterInit(): void
{ {
$arch = getenv('GNU_ARCH'); $arch = getenv('GNU_ARCH');
// append LD_LIBRARY_PATH to $configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE'); // append LD_LIBRARY_PATH to $configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');

View File

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

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace SPC\toolchain;
use SPC\builder\linux\SystemUtil;
use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager;
class ToolchainManager
{
public const array OS_DEFAULT_TOOLCHAIN = [
'Linux' => MuslToolchain::class, // use musl toolchain by default, after zig pr merged, change this to ZigToolchain::class
'Windows' => MSVCToolchain::class,
'Darwin' => ClangNativeToolchain::class,
'BSD' => ClangNativeToolchain::class,
];
/**
* @throws WrongUsageException
*/
public static function initToolchain(): void
{
$libc = getenv('SPC_LIBC');
if ($libc !== false) {
// uncomment this when zig pr is merged
// logger()->warning('SPC_LIBC is deprecated, please use SPC_TARGET instead.');
$toolchain = match ($libc) {
'musl' => SystemUtil::isMuslDist() ? GccNativeToolchain::class : MuslToolchain::class,
'glibc' => !SystemUtil::isMuslDist() ? GccNativeToolchain::class : throw new WrongUsageException('SPC_TARGET must be musl-static or musl for musl dist.'),
default => throw new WrongUsageException('Unsupported SPC_LIBC value: ' . $libc),
};
} else {
$toolchain = self::OS_DEFAULT_TOOLCHAIN[PHP_OS_FAMILY];
}
$toolchainClass = $toolchain;
/* @var ToolchainInterface $toolchainClass */
(new $toolchainClass())->initEnv();
GlobalEnvManager::putenv("SPC_TOOLCHAIN={$toolchain}");
}
public static function afterInitToolchain(): void
{
if (!getenv('SPC_TOOLCHAIN')) {
throw new WrongUsageException('SPC_TOOLCHAIN not set');
}
$toolchain = getenv('SPC_TOOLCHAIN');
/* @var ToolchainInterface $toolchain */
(new $toolchain())->afterInit();
}
}

View File

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

View File

@ -4,9 +4,9 @@ declare(strict_types=1);
namespace SPC\util; namespace SPC\util;
use SPC\builder\linux\SystemUtil;
use SPC\exception\RuntimeException; use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\toolchain\ToolchainManager;
/** /**
* Environment variable manager * Environment variable manager
@ -63,30 +63,7 @@ class GlobalEnvManager
} }
} }
// deprecated: convert SPC_LIBC to SPC_TARGET ToolchainManager::initToolchain();
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);
// apply second time // apply second time
$ini2 = self::readIniFile(); $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 public static function afterInit(): void
{ {
SPCTarget::afterInitTargetForToolchain(); ToolchainManager::afterInitToolchain();
} }
/** /**

View File

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

View File

@ -4,13 +4,8 @@ declare(strict_types=1);
namespace SPC\util; namespace SPC\util;
use SPC\builder\linux\SystemUtil;
use SPC\exception\WrongUsageException; 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. * SPC build target constants and toolchain initialization.
@ -18,86 +13,75 @@ use SPC\util\toolchain\ZigToolchain;
*/ */
class SPCTarget class SPCTarget
{ {
public const MUSL = 'musl'; public const array LIBC_LIST = [
'musl',
public const MUSL_STATIC = 'musl-static'; 'glibc',
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 static function isTarget(string $target): bool /**
{ * Returns whether the target is a full-static target.
$env = getenv('SPC_TARGET'); */
if ($env === false) {
return false;
}
$env = strtolower($env);
// ver
$env = explode('@', $env)[0];
return $env === $target;
}
public static function isStaticTarget(): bool public static function isStaticTarget(): bool
{ {
$env = getenv('SPC_TARGET'); $env = getenv('SPC_TARGET');
if ($env === false) { $libc = getenv('SPC_LIBC');
return false; // 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); // TODO: add zig target parser here
// ver return false;
$env = explode('@', $env)[0];
return str_ends_with($env, '-static');
} }
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'); $target = getenv('SPC_TARGET');
$toolchain = strtolower($toolchain); if ($target === false) {
if (isset(self::TOOLCHAIN_LIST[$toolchain])) { return PHP_OS_FAMILY;
$toolchainClass = self::TOOLCHAIN_LIST[$toolchain];
/* @var ToolchainInterface $toolchainClass */
(new $toolchainClass())->initEnv($target);
} }
GlobalEnvManager::putenv("SPC_TOOLCHAIN={$toolchain}"); // TODO: zig target parser like below?
} return match (true) {
str_contains($target, 'linux') => 'Linux',
public static function afterInitTargetForToolchain() str_contains($target, 'macos') => 'Darwin',
{ str_contains($target, 'windows') => 'Windows',
if (!getenv('SPC_TOOLCHAIN')) { default => throw new WrongUsageException('Cannot parse target.'),
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;
} }
} }

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,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.
}
}