From 29dc5e4ea7014ec619e1596ae002d62deb3c0fe2 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 6 Aug 2025 20:47:48 +0800 Subject: [PATCH] Chore --- .../windows/library/WindowsLibraryBase.php | 50 ------------------- .../builder/windows/library/libffi_win.php | 34 +++++++------ .../builder/windows/library/libiconv_win.php | 27 ++++++---- src/SPC/doctor/item/BSDToolCheckList.php | 8 +-- .../util/executor/UnixAutoconfExecutor.php | 45 ++++++++++++----- src/globals/defines.php | 6 +++ src/globals/functions.php | 45 +++++++++++++++-- src/globals/internal-env.php | 25 +++++----- 8 files changed, 131 insertions(+), 109 deletions(-) diff --git a/src/SPC/builder/windows/library/WindowsLibraryBase.php b/src/SPC/builder/windows/library/WindowsLibraryBase.php index 076afa03..dfc221c9 100644 --- a/src/SPC/builder/windows/library/WindowsLibraryBase.php +++ b/src/SPC/builder/windows/library/WindowsLibraryBase.php @@ -7,10 +7,6 @@ namespace SPC\builder\windows\library; use SPC\builder\BuilderBase; use SPC\builder\LibraryBase; use SPC\builder\windows\WindowsBuilder; -use SPC\exception\FileSystemException; -use SPC\exception\RuntimeException; -use SPC\exception\WrongUsageException; -use SPC\store\FileSystem; abstract class WindowsLibraryBase extends LibraryBase { @@ -23,50 +19,4 @@ abstract class WindowsLibraryBase extends LibraryBase { return $this->builder; } - - /** - * @throws RuntimeException - * @throws FileSystemException - * @throws WrongUsageException - */ - public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string - { - $libs = $include_self ? [$this] : []; - if ($recursive) { - array_unshift($libs, ...array_values($this->getDependencies(recursive: true))); - } - - $sep = match ($style) { - 'autoconf' => ' ', - 'cmake' => ';', - default => throw new RuntimeException('style only support autoconf and cmake'), - }; - $ret = []; - foreach ($libs as $lib) { - $libFiles = []; - foreach ($lib->getStaticLibs() as $name) { - $name = str_replace(' ', '\ ', FileSystem::convertPath(BUILD_LIB_PATH . "/{$name}")); - $name = str_replace('"', '\"', $name); - $libFiles[] = $name; - } - array_unshift($ret, implode($sep, $libFiles)); - } - return implode($sep, $ret); - } - - /** - * Create a nmake wrapper file. - * - * @param string $content nmake wrapper content - * @param string $default_filename default nmake wrapper filename - * @throws FileSystemException - */ - public function makeNmakeWrapper(string $content, string $default_filename = ''): string - { - if ($default_filename === '') { - $default_filename = $this->source_dir . '\nmake_wrapper.bat'; - } - FileSystem::writeFile($default_filename, $content); - return 'nmake_wrapper.bat'; - } } diff --git a/src/SPC/builder/windows/library/libffi_win.php b/src/SPC/builder/windows/library/libffi_win.php index 07bc909a..8d92acdf 100644 --- a/src/SPC/builder/windows/library/libffi_win.php +++ b/src/SPC/builder/windows/library/libffi_win.php @@ -5,36 +5,42 @@ declare(strict_types=1); namespace SPC\builder\windows\library; use SPC\builder\windows\SystemUtil; -use SPC\exception\RuntimeException; +use SPC\exception\EnvironmentException; use SPC\store\FileSystem; class libffi_win extends WindowsLibraryBase { public const NAME = 'libffi-win'; - protected function build() - { - $vs_ver_dir = match (SystemUtil::findVisualStudio()['version']) { - 'vs17' => '/win32/vs17_x64', - 'vs16' => '/win32/vs16_x64', - default => throw new RuntimeException('Current VS version is not supported yet!'), - }; + private string $vs_ver_dir; + public function validate(): void + { + $this->vs_ver_dir = match ($ver = SystemUtil::findVisualStudio()['version']) { + 'vs17' => '\win32\vs17_x64', + 'vs16' => '\win32\vs16_x64', + default => throw new EnvironmentException("Current VS version {$ver} is not supported !"), + }; + } + + protected function build(): void + { // start build - cmd()->cd($this->source_dir . $vs_ver_dir) + cmd()->cd($this->source_dir . $this->vs_ver_dir) ->execWithWrapper( $this->builder->makeSimpleWrapper('msbuild'), 'libffi-msvc.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64' ); FileSystem::createDir(BUILD_LIB_PATH); FileSystem::createDir(BUILD_INCLUDE_PATH); - copy($this->source_dir . $vs_ver_dir . '\x64\Release\libffi.lib', BUILD_LIB_PATH . '\libffi.lib'); - copy($this->source_dir . $vs_ver_dir . '\x64\Release\libffi.pdb', BUILD_LIB_PATH . '\libffi.pdb'); - copy($this->source_dir . '\include\ffi.h', BUILD_INCLUDE_PATH . '\ffi.h'); + + FileSystem::copy("{$this->source_dir}{$this->vs_ver_dir}\\x64\\Release\\libffi.lib", BUILD_LIB_PATH . '\libffi.lib'); + FileSystem::copy("{$this->source_dir}{$this->vs_ver_dir}\\x64\\Release\\libffi.pdb", BUILD_LIB_PATH . '\libffi.pdb'); + FileSystem::copy($this->source_dir . '\include\ffi.h', BUILD_INCLUDE_PATH . '\ffi.h'); FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\ffi.h', '#define LIBFFI_H', "#define LIBFFI_H\n#define FFI_BUILDING"); - copy($this->source_dir . '\src\x86\ffitarget.h', BUILD_INCLUDE_PATH . '\ffitarget.h'); - copy($this->source_dir . '\fficonfig.h', BUILD_INCLUDE_PATH . '\fficonfig.h'); + FileSystem::copy($this->source_dir . '\src\x86\ffitarget.h', BUILD_INCLUDE_PATH . '\ffitarget.h'); + FileSystem::copy($this->source_dir . '\fficonfig.h', BUILD_INCLUDE_PATH . '\fficonfig.h'); // copy($this->source_dir . '\msvc_build\out\static-Release\X64\libffi.lib', BUILD_LIB_PATH . '\libffi.lib'); // copy($this->source_dir . '\msvc_build\include\ffi.h', BUILD_INCLUDE_PATH . '\ffi.h'); diff --git a/src/SPC/builder/windows/library/libiconv_win.php b/src/SPC/builder/windows/library/libiconv_win.php index 4f638530..36d7e79e 100644 --- a/src/SPC/builder/windows/library/libiconv_win.php +++ b/src/SPC/builder/windows/library/libiconv_win.php @@ -5,31 +5,36 @@ declare(strict_types=1); namespace SPC\builder\windows\library; use SPC\builder\windows\SystemUtil; -use SPC\exception\RuntimeException; +use SPC\exception\EnvironmentException; use SPC\store\FileSystem; class libiconv_win extends WindowsLibraryBase { public const NAME = 'libiconv-win'; - protected function build() - { - $vs_ver_dir = match (SystemUtil::findVisualStudio()['version']) { - 'vs17' => '/MSVC17', - 'vs16' => '/MSVC16', - default => throw new RuntimeException('Current VS version is not supported yet!'), - }; + private string $vs_ver_dir = ''; + public function validate(): void + { + $this->vs_ver_dir = match ($ver = SystemUtil::findVisualStudio()['version']) { + 'vs17' => '\MSVC17', + 'vs16' => '\MSVC16', + default => throw new EnvironmentException("Current VS version {$ver} is not supported yet!"), + }; + } + + protected function build(): void + { // start build - cmd()->cd($this->source_dir . $vs_ver_dir) + cmd()->cd($this->source_dir . $this->vs_ver_dir) ->execWithWrapper( $this->builder->makeSimpleWrapper('msbuild'), 'libiconv.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64' ); FileSystem::createDir(BUILD_LIB_PATH); FileSystem::createDir(BUILD_INCLUDE_PATH); - copy($this->source_dir . $vs_ver_dir . '\x64\lib\libiconv.lib', BUILD_LIB_PATH . '\libiconv.lib'); - copy($this->source_dir . $vs_ver_dir . '\x64\lib\libiconv_a.lib', BUILD_LIB_PATH . '\libiconv_a.lib'); + copy("{$this->source_dir}{$this->vs_ver_dir}\\x64\\lib\\libiconv.lib", BUILD_LIB_PATH . '\libiconv.lib'); + copy("{$this->source_dir}{$this->vs_ver_dir}\\x64\\lib\\libiconv_a.lib", BUILD_LIB_PATH . '\libiconv_a.lib'); copy($this->source_dir . '\source\include\iconv.h', BUILD_INCLUDE_PATH . '\iconv.h'); } } diff --git a/src/SPC/doctor/item/BSDToolCheckList.php b/src/SPC/doctor/item/BSDToolCheckList.php index 2505227b..8a744953 100644 --- a/src/SPC/doctor/item/BSDToolCheckList.php +++ b/src/SPC/doctor/item/BSDToolCheckList.php @@ -8,7 +8,6 @@ use SPC\builder\traits\UnixSystemUtilTrait; use SPC\doctor\AsCheckItem; use SPC\doctor\AsFixItem; use SPC\doctor\CheckResult; -use SPC\exception\RuntimeException; class BSDToolCheckList { @@ -56,11 +55,8 @@ class BSDToolCheckList } else { $prefix = ''; } - try { - shell(true)->exec("ASSUME_ALWAYS_YES=yes {$prefix}pkg install -y " . implode(' ', $missing)); - } catch (RuntimeException) { - return false; - } + shell(true)->exec("ASSUME_ALWAYS_YES=yes {$prefix}pkg install -y " . implode(' ', $missing)); + return true; } } diff --git a/src/SPC/util/executor/UnixAutoconfExecutor.php b/src/SPC/util/executor/UnixAutoconfExecutor.php index 16c4fbc3..075d7fd3 100644 --- a/src/SPC/util/executor/UnixAutoconfExecutor.php +++ b/src/SPC/util/executor/UnixAutoconfExecutor.php @@ -7,7 +7,7 @@ namespace SPC\util\executor; use SPC\builder\freebsd\library\BSDLibraryBase; use SPC\builder\linux\library\LinuxLibraryBase; use SPC\builder\macos\library\MacOSLibraryBase; -use SPC\exception\RuntimeException; +use SPC\exception\SPCException; use SPC\util\shell\UnixShell; class UnixAutoconfExecutor extends Executor @@ -34,8 +34,7 @@ class UnixAutoconfExecutor extends Executor $args = array_diff($args, $this->ignore_args); $configure_args = implode(' ', $args); - $this->shell->exec("./configure {$configure_args}"); - return $this; + return $this->seekLogFileOnException(fn () => $this->shell->exec("./configure {$configure_args}")); } public function getConfigureArgsString(): string @@ -53,15 +52,17 @@ class UnixAutoconfExecutor extends Executor */ public function make(string $target = '', false|string $with_install = 'install', bool $with_clean = true, array $after_env_vars = []): static { - if ($with_clean) { - $this->shell->exec('make clean'); - } - $after_env_vars_str = $after_env_vars !== [] ? shell()->setEnv($after_env_vars)->getEnvString() : ''; - $this->shell->exec("make -j{$this->library->getBuilder()->concurrency} {$target} {$after_env_vars_str}"); - if ($with_install !== false) { - $this->shell->exec("make {$with_install}"); - } - return $this; + return $this->seekLogFileOnException(function () use ($target, $with_install, $with_clean, $after_env_vars) { + if ($with_clean) { + $this->shell->exec('make clean'); + } + $after_env_vars_str = $after_env_vars !== [] ? shell()->setEnv($after_env_vars)->getEnvString() : ''; + $this->shell->exec("make -j{$this->library->getBuilder()->concurrency} {$target} {$after_env_vars_str}"); + if ($with_install !== false) { + $this->shell->exec("make {$with_install}"); + } + return $this->shell; + }); } public function exec(string $cmd): static @@ -141,4 +142,24 @@ class UnixAutoconfExecutor extends Executor 'LDFLAGS' => "-L{$this->library->getLibDir()}", ]); } + + /** + * When an exception occurs, this method will check if the config log file exists. + */ + private function seekLogFileOnException(mixed $callable): static + { + try { + $callable(); + return $this; + } catch (SPCException $e) { + if (file_exists("{$this->library->getSourceDir()}/config.log")) { + logger()->debug("Config log file found: {$this->library->getSourceDir()}/config.log"); + $log_file = "lib.{$this->library->getName()}.console.log"; + logger()->debug('Saved config log file to: ' . SPC_LOGS_DIR . "/{$log_file}"); + $e->addExtraLogFile("{$this->library->getName()} library config.log", $log_file); + copy("{$this->library->getSourceDir()}/config.log", SPC_LOGS_DIR . "/{$log_file}"); + } + throw $e; + } + } } diff --git a/src/globals/defines.php b/src/globals/defines.php index ab37ace9..2574cd09 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -90,5 +90,11 @@ const SPC_SOURCE_ARCHIVE = 'archive'; // download as archive const SPC_SOURCE_GIT = 'git'; // download as git repository const SPC_SOURCE_LOCAL = 'local'; // download as local directory +// spc logs dir +const SPC_LOGS_DIR = WORKING_DIR . DIRECTORY_SEPARATOR . 'log'; +const SPC_OUTPUT_LOG = SPC_LOGS_DIR . DIRECTORY_SEPARATOR . 'spc.output.log'; +const SPC_SHELL_LOG = SPC_LOGS_DIR . DIRECTORY_SEPARATOR . 'spc.shell.log'; +const SPC_ENV_LOG = SPC_LOGS_DIR . DIRECTORY_SEPARATOR . 'spc.env.log'; + ConsoleLogger::$date_format = 'H:i:s'; ConsoleLogger::$format = '[%date%] [%level_short%] %body%'; diff --git a/src/globals/functions.php b/src/globals/functions.php index 9dd1c17c..71127960 100644 --- a/src/globals/functions.php +++ b/src/globals/functions.php @@ -5,8 +5,8 @@ declare(strict_types=1); use Psr\Log\LoggerInterface; use SPC\builder\BuilderBase; use SPC\builder\BuilderProvider; +use SPC\exception\ExecutionException; use SPC\exception\InterruptException; -use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; use SPC\util\shell\UnixShell; use SPC\util\shell\WindowsCmd; @@ -165,7 +165,7 @@ function f_passthru(string $cmd): ?bool } $ret = passthru($cmd, $code); if ($code !== 0) { - throw new RuntimeException('Command run failed with code[' . $code . ']: ' . $cmd, $code); + throw new ExecutionException($cmd, "Direct command run failed with code: {$code}", $code); } return $ret; } @@ -203,7 +203,7 @@ function f_putenv(string $env): bool function get_cmake_version(): ?string { try { - [,$output] = shell()->execWithResult('cmake --version', false); + [,$output] = shell(false)->execWithResult('cmake --version', false); if (preg_match('/cmake version ([\d.]+)/i', $output[0], $matches)) { return $matches[1]; } @@ -244,3 +244,42 @@ function clean_spaces(string $string): string { return trim(preg_replace('/\s+/', ' ', $string)); } + +/** + * Register a callback function to handle keyboard interrupts (Ctrl+C). + * + * @param callable $callback callback function to handle keyboard interrupts + */ +function keyboard_interrupt_register(callable $callback): void +{ + if (PHP_OS_FAMILY === 'Windows') { + sapi_windows_set_ctrl_handler($callback); + } elseif (extension_loaded('pcntl')) { + pcntl_signal(SIGINT, $callback); + } +} + +/** + * Unregister the keyboard interrupt handler. + * + * This function is used to remove the previously registered keyboard interrupt handler. + * It should be called when you no longer need to handle keyboard interrupts. + */ +function keyboard_interrupt_unregister(): void +{ + if (PHP_OS_FAMILY === 'Windows') { + sapi_windows_set_ctrl_handler(null); + } elseif (extension_loaded('pcntl')) { + pcntl_signal(SIGINT, SIG_IGN); + } +} + +/** + * Strip ANSI color codes from a string. + */ +function strip_ansi_colors(string $text): string +{ + // Regular expression to match ANSI escape sequences + // Including color codes, cursor control, clear screen and other control sequences + return preg_replace('/\e\[[0-9;]*[a-zA-Z]/', '', $text); +} diff --git a/src/globals/internal-env.php b/src/globals/internal-env.php index 22918fdf..5b6fe57f 100644 --- a/src/globals/internal-env.php +++ b/src/globals/internal-env.php @@ -8,7 +8,6 @@ use SPC\builder\macos\SystemUtil as MacOSSystemUtil; use SPC\builder\windows\SystemUtil as WindowsSystemUtil; use SPC\ConsoleApplication; use SPC\store\FileSystem; -use SPC\util\GlobalEnvManager; // static-php-cli version string const SPC_VERSION = ConsoleApplication::VERSION; @@ -47,15 +46,15 @@ define('SEPARATED_PATH', [ ]); // add these to env vars with same name -GlobalEnvManager::putenv('SPC_VERSION=' . SPC_VERSION); -GlobalEnvManager::putenv('BUILD_ROOT_PATH=' . BUILD_ROOT_PATH); -GlobalEnvManager::putenv('BUILD_INCLUDE_PATH=' . BUILD_INCLUDE_PATH); -GlobalEnvManager::putenv('BUILD_LIB_PATH=' . BUILD_LIB_PATH); -GlobalEnvManager::putenv('BUILD_BIN_PATH=' . BUILD_BIN_PATH); -GlobalEnvManager::putenv('PKG_ROOT_PATH=' . PKG_ROOT_PATH); -GlobalEnvManager::putenv('SOURCE_PATH=' . SOURCE_PATH); -GlobalEnvManager::putenv('DOWNLOAD_PATH=' . DOWNLOAD_PATH); -GlobalEnvManager::putenv('CPU_COUNT=' . CPU_COUNT); -GlobalEnvManager::putenv('SPC_ARCH=' . php_uname('m')); -GlobalEnvManager::putenv('GNU_ARCH=' . GNU_ARCH); -GlobalEnvManager::putenv('MAC_ARCH=' . MAC_ARCH); +putenv('SPC_VERSION=' . SPC_VERSION); +putenv('BUILD_ROOT_PATH=' . BUILD_ROOT_PATH); +putenv('BUILD_INCLUDE_PATH=' . BUILD_INCLUDE_PATH); +putenv('BUILD_LIB_PATH=' . BUILD_LIB_PATH); +putenv('BUILD_BIN_PATH=' . BUILD_BIN_PATH); +putenv('PKG_ROOT_PATH=' . PKG_ROOT_PATH); +putenv('SOURCE_PATH=' . SOURCE_PATH); +putenv('DOWNLOAD_PATH=' . DOWNLOAD_PATH); +putenv('CPU_COUNT=' . CPU_COUNT); +putenv('SPC_ARCH=' . php_uname('m')); +putenv('GNU_ARCH=' . GNU_ARCH); +putenv('MAC_ARCH=' . MAC_ARCH);