From c8fa767576f43ab81ba57546a75903e8bf8a4dd3 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 20 Aug 2023 19:51:45 +0800 Subject: [PATCH] Do some code quality check and fix #126 --- bin/setup-runtime | 18 +- bin/spc | 8 +- bin/spc-alpine-docker | 12 +- config/ext.json | 44 ++-- config/lib.json | 38 +-- config/source.json | 58 ++--- src/SPC/ConsoleApplication.php | 11 +- src/SPC/builder/BuilderBase.php | 131 ++++++---- src/SPC/builder/BuilderProvider.php | 18 +- src/SPC/builder/Extension.php | 3 +- src/SPC/builder/LibraryBase.php | 81 +++--- src/SPC/builder/extension/bz2.php | 4 +- src/SPC/builder/extension/curl.php | 7 +- src/SPC/builder/extension/event.php | 7 +- src/SPC/builder/extension/glfw.php | 4 + src/SPC/builder/extension/iconv.php | 23 ++ src/SPC/builder/extension/imagick.php | 11 + src/SPC/builder/extension/memcache.php | 10 +- src/SPC/builder/extension/pdo_sqlite.php | 3 +- src/SPC/builder/extension/pgsql.php | 3 +- src/SPC/builder/extension/readline.php | 3 +- src/SPC/builder/extension/ssh2.php | 3 +- src/SPC/builder/extension/swow.php | 4 + src/SPC/builder/linux/LinuxBuilder.php | 244 +++++++++--------- src/SPC/builder/linux/SystemUtil.php | 8 +- .../linux/library/LinuxLibraryBase.php | 6 +- src/SPC/builder/linux/library/icu.php | 2 +- src/SPC/builder/linux/library/libpng.php | 19 +- src/SPC/builder/linux/library/libxml2.php | 6 +- src/SPC/builder/linux/library/nghttp2.php | 13 +- src/SPC/builder/linux/library/openssl.php | 16 +- src/SPC/builder/macos/MacOSBuilder.php | 169 ++++++------ src/SPC/builder/macos/SystemUtil.php | 9 +- .../macos/library/MacOSLibraryBase.php | 5 +- src/SPC/builder/macos/library/curl.php | 6 +- src/SPC/builder/macos/library/glfw.php | 9 +- src/SPC/builder/macos/library/icu.php | 2 +- src/SPC/builder/macos/library/libffi.php | 31 +-- .../builder/macos/library/libmemcached.php | 2 +- src/SPC/builder/macos/library/libpng.php | 8 +- src/SPC/builder/macos/library/libxml2.php | 15 +- src/SPC/builder/macos/library/nghttp2.php | 11 +- src/SPC/builder/macos/library/openssl.php | 13 +- src/SPC/builder/traits/UnixBuilderTrait.php | 24 +- src/SPC/builder/traits/UnixLibraryTrait.php | 9 +- .../builder/traits/UnixSystemUtilTrait.php | 28 +- src/SPC/builder/unix/library/brotli.php | 6 + src/SPC/builder/unix/library/curl.php | 8 +- src/SPC/builder/unix/library/freetype.php | 13 +- src/SPC/builder/unix/library/gmp.php | 9 +- src/SPC/builder/unix/library/imagemagick.php | 9 +- src/SPC/builder/unix/library/libavif.php | 10 +- src/SPC/builder/unix/library/libevent.php | 9 +- src/SPC/builder/unix/library/libiconv.php | 2 +- src/SPC/builder/unix/library/libjpeg.php | 10 +- src/SPC/builder/unix/library/libsodium.php | 2 +- src/SPC/builder/unix/library/libssh2.php | 8 +- src/SPC/builder/unix/library/libwebp.php | 11 +- src/SPC/builder/unix/library/libyaml.php | 4 +- src/SPC/builder/unix/library/libzip.php | 8 +- src/SPC/builder/unix/library/ncurses.php | 2 +- src/SPC/builder/unix/library/onig.php | 9 +- src/SPC/builder/unix/library/pkgconfig.php | 16 +- src/SPC/builder/unix/library/postgresql.php | 2 +- src/SPC/builder/unix/library/readline.php | 9 +- src/SPC/builder/unix/library/sqlite.php | 2 +- src/SPC/builder/unix/library/xz.php | 11 +- src/SPC/builder/unix/library/zlib.php | 9 +- src/SPC/builder/unix/library/zstd.php | 8 +- src/SPC/command/BaseCommand.php | 21 +- src/SPC/command/BuildCliCommand.php | 36 +-- src/SPC/command/BuildCommand.php | 3 - src/SPC/command/BuildLibsCommand.php | 4 +- src/SPC/command/DeployCommand.php | 9 +- src/SPC/command/DoctorCommand.php | 2 +- src/SPC/command/DownloadCommand.php | 4 +- src/SPC/command/DumpLicenseCommand.php | 4 +- src/SPC/command/ExtractCommand.php | 12 +- src/SPC/command/MicroCombineCommand.php | 2 +- src/SPC/command/dev/AllExtCommand.php | 6 +- src/SPC/command/dev/ExtInfoCommand.php | 10 +- src/SPC/command/dev/PhpVerCommand.php | 2 +- src/SPC/command/dev/SortConfigCommand.php | 2 +- src/SPC/doctor/CheckListHandler.php | 10 +- src/SPC/doctor/CheckResult.php | 4 +- src/SPC/doctor/item/LinuxMuslCheck.php | 6 +- src/SPC/doctor/item/LinuxToolCheckList.php | 6 + src/SPC/exception/ExceptionHandler.php | 12 +- src/SPC/store/Config.php | 5 +- src/SPC/store/CurlHook.php | 2 +- src/SPC/store/Downloader.php | 121 +++------ src/SPC/store/FileSystem.php | 73 ++++-- src/SPC/store/SourceExtractor.php | 7 + src/SPC/store/SourcePatcher.php | 32 +-- src/SPC/store/source/PhpSource.php | 4 +- src/SPC/store/source/PostgreSQLSource.php | 15 +- src/SPC/util/ConfigValidator.php | 8 +- src/SPC/util/DependencyUtil.php | 11 +- src/SPC/util/Patcher.php | 12 +- src/SPC/util/UnixShell.php | 3 + src/globals/defines.php | 15 +- src/globals/functions.php | 22 +- src/globals/tests/bcmath.php | 2 - src/globals/tests/dom.php | 2 - 104 files changed, 1040 insertions(+), 785 deletions(-) create mode 100644 src/SPC/builder/extension/iconv.php diff --git a/bin/setup-runtime b/bin/setup-runtime index 48144f97..06ebd749 100755 --- a/bin/setup-runtime +++ b/bin/setup-runtime @@ -22,7 +22,7 @@ esac # set project dir __DIR__=$(cd "$(dirname "$0")" && pwd) -__PROJECT__=$(cd ${__DIR__}/../ && pwd) +__PROJECT__=$(cd "${__DIR__}"/../ && pwd) # set download dir __PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.6-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz" @@ -52,17 +52,17 @@ china) esac -test -d ${__PROJECT__}/downloads || mkdir ${__PROJECT__}/downloads +test -d "${__PROJECT__}"/downloads || mkdir "${__PROJECT__}"/downloads # download static php binary -test -f ${__PROJECT__}/downloads/runtime.tar.gz || { echo "Downloading $__PHP_RUNTIME_URL__ ..." && curl -#fSL -o ${__PROJECT__}/downloads/runtime.tar.gz "$__PHP_RUNTIME_URL__" ; } -test -f ${__DIR__}/php || { tar -xf ${__PROJECT__}/downloads/runtime.tar.gz -C ${__DIR__}/ ; } -chmod +x ${__DIR__}/php +test -f "${__PROJECT__}"/downloads/runtime.tar.gz || { echo "Downloading $__PHP_RUNTIME_URL__ ..." && curl -#fSL -o "${__PROJECT__}"/downloads/runtime.tar.gz "$__PHP_RUNTIME_URL__" ; } +test -f "${__DIR__}"/php || { tar -xf "${__PROJECT__}"/downloads/runtime.tar.gz -C "${__DIR__}"/ ; } +chmod +x "${__DIR__}"/php # download composer -test -f ${__DIR__}/composer || curl -#fSL -o ${__DIR__}/composer "$__COMPOSER_URL__" -chmod +x ${__DIR__}/composer +test -f "${__DIR__}"/composer || curl -#fSL -o "${__DIR__}"/composer "$__COMPOSER_URL__" +chmod +x "${__DIR__}"/composer # sanity check for php and composer -${__DIR__}/php -v >/dev/null || { echo "Failed to run php" && exit 1; } -${__DIR__}/php ${__DIR__}/composer --version >/dev/null || { echo "Failed to run composer" && exit 1; } +"${__DIR__}"/php -v >/dev/null || { echo "Failed to run php" && exit 1; } +"${__DIR__}"/php "${__DIR__}"/composer --version >/dev/null || { echo "Failed to run composer" && exit 1; } echo "Setup runtime OK!" echo "runtime bin path needs to add manually by command below:" diff --git a/bin/spc b/bin/spc index 960f24ff..58749f61 100755 --- a/bin/spc +++ b/bin/spc @@ -1,6 +1,9 @@ #!/usr/bin/env php run(); + (new ConsoleApplication())->run(); } catch (Exception $e) { - \SPC\exception\ExceptionHandler::getInstance()->handle($e); + ExceptionHandler::getInstance()->handle($e); } diff --git a/bin/spc-alpine-docker b/bin/spc-alpine-docker index 7f444426..3d135791 100755 --- a/bin/spc-alpine-docker +++ b/bin/spc-alpine-docker @@ -2,18 +2,18 @@ # This file is using docker to run commands -self_dir=$(cd "$(dirname "$0")";pwd) - # Detect docker can run if ! which docker >/dev/null; then echo "Docker is not installed, please install docker first !" exit 1 fi DOCKER_EXECUTABLE="docker" +# shellcheck disable=SC2046 if [ $(id -u) -ne 0 ]; then if ! docker info > /dev/null 2>&1; then if [ "$SPC_USE_SUDO" != "yes" ]; then echo "Docker command requires sudo" + # shellcheck disable=SC2039 echo -n 'To use sudo to run docker, run "export SPC_USE_SUDO=yes" and run command again' exit 1 fi @@ -33,6 +33,7 @@ x86_64) ;; aarch64) ALPINE_FROM=multiarch/alpine:aarch64-edge + # shellcheck disable=SC2039 echo -e "\e[033m* Using different arch needs to setup qemu-static for docker !\e[0m" $DOCKER_EXECUTABLE run --rm --privileged multiarch/qemu-user-static:register --reset > /dev/null ;; @@ -65,10 +66,10 @@ ADD ./bin /app/bin RUN composer update --no-dev EOF ) - echo "$ALPINE_DOCKERFILE" > $(pwd)/Dockerfile + echo "$ALPINE_DOCKERFILE" > "$(pwd)"/Dockerfile $DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH . - rm $(pwd)/Dockerfile + rm "$(pwd)"/Dockerfile fi # Check if in ci (local terminal can execute with -it) @@ -79,4 +80,5 @@ else fi # Run docker -$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT=$(pwd) -v $(pwd)/config:/app/config -v $(pwd)/src:/app/src -v $(pwd)/buildroot:/app/buildroot -v $(pwd)/source:/app/source -v $(pwd)/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@ +# shellcheck disable=SC2068 +$DOCKER_EXECUTABLE run --rm "$INTERACT" -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@ diff --git a/config/ext.json b/config/ext.json index df9da7fa..3bac3fa0 100644 --- a/config/ext.json +++ b/config/ext.json @@ -53,19 +53,6 @@ "sockets" ] }, - "memcached": { - "type": "external", - "source": "memcached", - "arg-type": "custom", - "cpp-extension": true, - "lib-depends": [ - "libmemcached" - ], - "ext-depends": [ - "session", - "zlib" - ] - }, "exif": { "type": "builtin" }, @@ -113,6 +100,14 @@ "gettext" ] }, + "glfw": { + "type": "external", + "arg-type": "custom", + "source": "ext-glfw", + "lib-depends": [ + "glfw" + ] + }, "gmp": { "type": "builtin", "arg-type": "with-prefix", @@ -135,14 +130,6 @@ "imagemagick" ] }, - "glfw": { - "type": "external", - "arg-type": "custom", - "source": "ext-glfw", - "lib-depends": [ - "glfw" - ] - }, "imap": { "type": "builtin", "arg-type": "with", @@ -196,6 +183,19 @@ "session" ] }, + "memcached": { + "type": "external", + "source": "memcached", + "arg-type": "custom", + "cpp-extension": true, + "lib-depends": [ + "libmemcached" + ], + "ext-depends": [ + "session", + "zlib" + ] + }, "mongodb": { "type": "external", "source": "mongodb", @@ -485,4 +485,4 @@ "zstd" ] } -} +} \ No newline at end of file diff --git a/config/lib.json b/config/lib.json index 03ff7bb3..d07a069a 100644 --- a/config/lib.json +++ b/config/lib.json @@ -15,18 +15,6 @@ "brotli" ] }, - "glfw": { - "source": "ext-glfw", - "static-libs-unix": [ - "libglfw3.a" - ], - "frameworks": [ - "CoreVideo", - "OpenGL", - "Cocoa", - "IOKit" - ] - }, "bzip2": { "source": "bzip2", "static-libs-unix": [ @@ -96,6 +84,18 @@ "brotli" ] }, + "glfw": { + "source": "ext-glfw", + "static-libs-unix": [ + "libglfw3.a" + ], + "frameworks": [ + "CoreVideo", + "OpenGL", + "Cocoa", + "IOKit" + ] + }, "gmp": { "source": "gmp", "static-libs-unix": [ @@ -200,6 +200,13 @@ "libmcrypt.a" ] }, + "libmemcached": { + "source": "libmemcached", + "static-libs-unix": [ + "libmemcached.a", + "libmemcachedutil.a" + ] + }, "libpng": { "source": "libpng", "static-libs-unix": [ @@ -474,13 +481,6 @@ "zconf.h" ] }, - "libmemcached": { - "source": "libmemcached", - "static-libs-unix": [ - "libmemcached.a", - "libmemcachedutil.a" - ] - }, "zstd": { "source": "zstd", "static-libs-unix": [ diff --git a/config/source.json b/config/source.json index b4ba3e74..e1fa90ad 100644 --- a/config/source.json +++ b/config/source.json @@ -6,15 +6,6 @@ "path": "LICENSE" } }, - "ext-glfw": { - "type": "git", - "url": "https://github.com/mario-deluna/php-glfw", - "rev": "master", - "license": { - "type": "file", - "path": "LICENSE" - } - }, "apcu": { "type": "url", "url": "https://pecl.php.net/get/APCu", @@ -25,25 +16,6 @@ "path": "LICENSE" } }, - "memcached": { - "type": "url", - "url": "https://pecl.php.net/get/memcached", - "path": "php-src/ext/memcached", - "filename": "memcached.tgz", - "license": { - "type": "file", - "path": "LICENSE" - } - }, - "libmemcached": { - "type": "git", - "url": "https://github.com/crazywhalecc/libmemcached-macos.git", - "rev": "master", - "license": { - "type": "file", - "path": "COPYING" - } - }, "brotli": { "type": "ghtar", "repo": "google/brotli", @@ -79,6 +51,15 @@ "path": "LICENSE" } }, + "ext-glfw": { + "type": "git", + "url": "https://github.com/mario-deluna/php-glfw", + "rev": "master", + "license": { + "type": "file", + "path": "LICENSE" + } + }, "ext-imagick": { "type": "url", "url": "https://pecl.php.net/get/imagick", @@ -213,6 +194,15 @@ "path": "COPYING" } }, + "libmemcached": { + "type": "git", + "url": "https://github.com/crazywhalecc/libmemcached-macos.git", + "rev": "master", + "license": { + "type": "file", + "path": "COPYING" + } + }, "libpng": { "type": "git", "url": "https://git.code.sf.net/p/libpng/code", @@ -290,6 +280,16 @@ "path": "COPYING" } }, + "memcached": { + "type": "url", + "url": "https://pecl.php.net/get/memcached", + "path": "php-src/ext/memcached", + "filename": "memcached.tgz", + "license": { + "type": "file", + "path": "LICENSE" + } + }, "micro": { "type": "git", "path": "php-src/sapi/micro", @@ -476,4 +476,4 @@ "path": "LICENSE" } } -} +} \ No newline at end of file diff --git a/src/SPC/ConsoleApplication.php b/src/SPC/ConsoleApplication.php index c9f1814e..b687278e 100644 --- a/src/SPC/ConsoleApplication.php +++ b/src/SPC/ConsoleApplication.php @@ -10,11 +10,11 @@ use Symfony\Component\Console\Command\HelpCommand; use Symfony\Component\Console\Command\ListCommand; /** - * spc 应用究级入口 + * static-php-cli console app entry */ class ConsoleApplication extends Application { - public const VERSION = '2.0-rc5'; + public const VERSION = '2.0.0'; /** * @throws \ReflectionException @@ -26,10 +26,10 @@ class ConsoleApplication extends Application global $argv; - // 生产环境不显示详细的调试错误,只使用 symfony console 自带的错误显示 + // Detailed debugging errors are not displayed in the production environment. Only the error display provided by Symfony console is used. $this->setCatchExceptions(file_exists(ROOT_DIR . '/.prod') || !in_array('--debug', $argv)); - // 通过扫描目录 src/static-php-cli/command/ 添加子命令 + // Add subcommands by scanning the directory src/static-php-cli/command/ $commands = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/command', 'SPC\\command'); $phar = class_exists('\\Phar') && \Phar::running() || !class_exists('\\Phar'); $commands = array_filter($commands, function ($y) use ($phar) { @@ -46,9 +46,6 @@ class ConsoleApplication extends Application $this->addCommands(array_map(function ($x) { return new $x(); }, $commands)); } - /** - * 重载以去除一些不必要的默认命令 - */ protected function getDefaultCommands(): array { return [new HelpCommand(), new ListCommand()]; diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index e6763049..1c3c84fb 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -15,43 +15,32 @@ use SPC\util\DependencyUtil; abstract class BuilderBase { - /** @var bool 是否启用 ZTS 线程安全 */ - public bool $zts = false; - - /** @var string 编译目标架构 */ - public string $arch; - - /** @var string GNU 格式的编译目标架构 */ - public string $gnu_arch; - - /** @var int 编译进程数 */ + /** @var int Concurrency */ public int $concurrency = 1; - /** @var array 要编译的 libs 列表 */ + /** @var array libraries */ protected array $libs = []; - /** @var array 要编译的扩展列表 */ + /** @var array extensions */ protected array $exts = []; - /** @var array 要编译的扩展列表(仅名字列表,用于最后生成编译的扩展列表给 micro) */ - protected array $plain_extensions = []; - - /** @var bool 本次编译是否只编译 libs,不编译 PHP */ + /** @var bool compile libs only (just mark it) */ protected bool $libs_only = false; - /** @var bool 是否 strip 最终的二进制 */ - protected bool $strip = true; + /** @var array compile options */ + protected array $options = []; /** - * 构建指定列表的 libs + * Build libraries * + * @param array $libraries Libraries to build * @throws FileSystemException * @throws RuntimeException * @throws WrongUsageException */ public function buildLibs(array $libraries): void { - // 通过扫描目录查找 lib + // search all supported libs $support_lib_list = []; $classes = FileSystem::getClassesPsr4( ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library', @@ -63,19 +52,22 @@ abstract class BuilderBase } } - // 如果传入了空,则默认检查和安置所有支持的lib,libraries为要build的,support_lib_list为支持的列表 + // if no libs specified, compile all supported libs if ($libraries === [] && $this->isLibsOnly()) { $libraries = array_keys($support_lib_list); } + + // pkg-config must be compiled first, whether it is specified or not if (!in_array('pkg-config', $libraries)) { array_unshift($libraries, 'pkg-config'); } - // 排序 libs,根据依赖计算一个新的列表出来 + // append dependencies $libraries = DependencyUtil::getLibsByDeps($libraries); - // 过滤不支持的库后添加 + // add lib object for builder foreach ($libraries as $library) { + // if some libs are not supported (but in config "lib.json", throw exception) if (!isset($support_lib_list[$library])) { throw new RuntimeException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!'); } @@ -83,14 +75,15 @@ abstract class BuilderBase $this->addLib($lib); } - // 计算依赖,经过这里的遍历,如果没有抛出异常,说明依赖符合要求,可以继续下面的 + // calculate and check dependencies foreach ($this->libs as $lib) { $lib->calcDependency(); } + // extract sources SourceExtractor::initSource(libs: $libraries); - // 构建库 + // build all libs foreach ($this->libs as $lib) { match ($lib->tryBuild()) { BUILD_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] build success'), @@ -102,9 +95,9 @@ abstract class BuilderBase } /** - * 添加要编译的 Lib 库 + * Add library to build. * - * @param LibraryBase $library Lib 库对象 + * @param LibraryBase $library Library object */ public function addLib(LibraryBase $library): void { @@ -112,9 +105,7 @@ abstract class BuilderBase } /** - * 获取要编译的 Lib 库对象 - * - * @param string $name 库名称 + * Get library object by name. */ public function getLib(string $name): ?LibraryBase { @@ -122,9 +113,7 @@ abstract class BuilderBase } /** - * 添加要编译的扩展 - * - * @param Extension $extension 扩展对象 + * Add extension to build. */ public function addExt(Extension $extension): void { @@ -132,9 +121,7 @@ abstract class BuilderBase } /** - * 获取要编译的扩展对象 - * - * @param string $name 扩展名称 + * Get extension object by name. */ public function getExt(string $name): ?Extension { @@ -142,7 +129,7 @@ abstract class BuilderBase } /** - * 获取所有要编译的扩展对象 + * Get all extension objects. * * @return Extension[] */ @@ -152,10 +139,9 @@ abstract class BuilderBase } /** - * 检查 C++ 扩展是否存在 + * Check if there is a cpp extension. * * @throws FileSystemException - * @throws RuntimeException * @throws WrongUsageException */ public function hasCppExtension(): bool @@ -173,7 +159,7 @@ abstract class BuilderBase } /** - * 设置本次 Builder 是否为仅编译库的模式 + * Set libs only mode. */ public function setLibsOnly(bool $status = true): void { @@ -181,7 +167,7 @@ abstract class BuilderBase } /** - * 检验 ext 扩展列表是否合理,并声明 Extension 对象,检查扩展的依赖 + * Verify the list of "ext" extensions for validity and declare an Extension object to check the dependencies of the extensions. * * @throws FileSystemException * @throws RuntimeException @@ -203,26 +189,21 @@ abstract class BuilderBase } foreach ($this->exts as $ext) { - // 检查下依赖就行了,作用是导入依赖给 Extension 对象,今后可以对库依赖进行选择性处理 $ext->checkDependency(); } - - $this->plain_extensions = $extensions; } /** - * 开始构建 PHP + * Start to build PHP * - * @param int $build_target 规则 - * @param bool $bloat 保留 + * @param int $build_target Build target, see BUILD_TARGET_* */ - abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE, bool $bloat = false); + abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE); /** - * 生成依赖的扩展编译启用参数 - * 例如 --enable-mbstring 等 + * Generate extension enable arguments for configure. + * e.g. --enable-mbstring * - * @throws RuntimeException * @throws FileSystemException * @throws WrongUsageException */ @@ -237,7 +218,7 @@ abstract class BuilderBase } /** - * 返回是否只编译 libs 的模式 + * Get libs only mode. */ public function isLibsOnly(): bool { @@ -245,7 +226,7 @@ abstract class BuilderBase } /** - * 获取当前即将编译的 PHP 的版本 ID,五位数那个 + * Get PHP Version ID from php-src/main/php_version.h */ public function getPHPVersionID(): int { @@ -254,6 +235,11 @@ abstract class BuilderBase return intval($match[1]); } + /** + * Get build type name string to display. + * + * @param int $type Build target type + */ public function getBuildTypeName(int $type): string { $ls = []; @@ -269,13 +255,46 @@ abstract class BuilderBase return implode(', ', $ls); } - public function setStrip(bool $strip): void + /** + * Get builder options (maybe changed by user) + * + * @param string $key Option key + * @param mixed $default If not exists, return this value + */ + public function getOption(string $key, mixed $default = null): mixed { - $this->strip = $strip; + return $this->options[$key] ?? $default; } /** - * 检查是否存在 lib 库对应的源码,如果不存在,则抛出异常 + * Get all builder options + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * Set builder options if not exists. + */ + public function setOptionIfNotExist(string $key, mixed $value): void + { + if (!isset($this->options[$key])) { + $this->options[$key] = $value; + } + } + + /** + * Set builder options. + */ + public function setOption(string $key, mixed $value): void + { + $this->options[$key] = $value; + } + + /** + * Check if all libs are downloaded. + * If not, throw exception. * * @throws RuntimeException */ diff --git a/src/SPC/builder/BuilderProvider.php b/src/SPC/builder/BuilderProvider.php index a4e54032..b0578ac5 100644 --- a/src/SPC/builder/BuilderProvider.php +++ b/src/SPC/builder/BuilderProvider.php @@ -6,7 +6,7 @@ namespace SPC\builder; use SPC\builder\linux\LinuxBuilder; use SPC\builder\macos\MacOSBuilder; -use SPC\builder\windows\WindowsBuilder; +use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; use Symfony\Component\Console\Input\InputInterface; @@ -17,7 +17,9 @@ use Symfony\Component\Console\Input\InputInterface; class BuilderProvider { /** + * @throws FileSystemException * @throws RuntimeException + * @throws WrongUsageException */ public static function makeBuilderByInput(InputInterface $input): BuilderBase { @@ -27,18 +29,8 @@ class BuilderProvider // vs_ver: $input->getOption('vs-ver'), // arch: $input->getOption('arch'), // ), - 'Darwin' => new MacOSBuilder( - cc: $input->getOption('cc'), - cxx: $input->getOption('cxx'), - arch: $input->getOption('arch'), - zts: $input->hasOption('enable-zts') ? $input->getOption('enable-zts') : false, - ), - 'Linux' => new LinuxBuilder( - cc: $input->getOption('cc'), - cxx: $input->getOption('cxx'), - arch: $input->getOption('arch'), - zts: $input->hasOption('enable-zts') ? $input->getOption('enable-zts') : false, - ), + 'Darwin' => new MacOSBuilder($input->getOptions()), + 'Linux' => new LinuxBuilder($input->getOptions()), default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'), }; } diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 24118844..d9edc6b5 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -34,7 +34,7 @@ class Extension /** * 获取开启该扩展的 PHP 编译添加的参数 * - * @throws FileSystemException|RuntimeException + * @throws FileSystemException * @throws WrongUsageException */ public function getConfigureArg(): string @@ -56,7 +56,6 @@ class Extension * 根据 ext 的 arg-type 获取对应开启的参数,一般都是 --enable-xxx 和 --with-xxx * * @throws FileSystemException - * @throws RuntimeException * @throws WrongUsageException */ public function getEnableArg(): string diff --git a/src/SPC/builder/LibraryBase.php b/src/SPC/builder/LibraryBase.php index 5b0828dd..e9d7abd1 100644 --- a/src/SPC/builder/LibraryBase.php +++ b/src/SPC/builder/LibraryBase.php @@ -7,20 +7,16 @@ namespace SPC\builder; use SPC\builder\macos\library\MacOSLibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\Config; -/** - * Lib 库的基类操作对象 - */ abstract class LibraryBase { - /** @var string lib 依赖名称,必须重写 */ + /** @var string */ public const NAME = 'unknown'; - /** @var string lib 依赖的根目录 */ protected string $source_dir; - /** @var array 依赖列表 */ protected array $dependencies = []; /** @@ -35,7 +31,7 @@ abstract class LibraryBase } /** - * 获取 lib 库的根目录 + * Get current lib source root dir. */ public function getSourceDir(): string { @@ -43,10 +39,9 @@ abstract class LibraryBase } /** - * 获取当前 lib 库的所有依赖列表 + * Get current lib dependencies. * - * @param bool $recursive 是否递归获取(默认为 False) - * @return array 依赖的 Map + * @return array */ public function getDependencies(bool $recursive = false): array { @@ -55,7 +50,6 @@ abstract class LibraryBase return $this->dependencies; } - // 下面为递归获取依赖列表,根据依赖顺序 $deps = []; $added = 1; @@ -78,20 +72,21 @@ abstract class LibraryBase } /** - * 计算依赖列表,不符合依赖将抛出异常 + * Calculate dependencies for current library. * * @throws RuntimeException * @throws FileSystemException + * @throws WrongUsageException */ public function calcDependency(): void { - // 先从配置文件添加依赖,这里根据不同的操作系统分别选择不同的元信息 + // Add dependencies from the configuration file. Here, choose different metadata based on the operating system. /* - 选择规则: - 如果是 Windows 系统,则依次尝试有无 lib-depends-windows、lib-depends-win、lib-depends。 - 如果是 macOS 系统,则依次尝试 lib-depends-darwin、lib-depends-unix、lib-depends。 - 如果是 Linux 系统,则依次尝试 lib-depends-linux、lib-depends-unix、lib-depends。 - */ + Rules: + If it is a Windows system, try the following dependencies in order: lib-depends-windows, lib-depends-win, lib-depends. + If it is a macOS system, try the following dependencies in order: lib-depends-darwin, lib-depends-unix, lib-depends. + If it is a Linux system, try the following dependencies in order: lib-depends-linux, lib-depends-unix, lib-depends. + */ foreach (Config::getLib(static::NAME, 'lib-depends', []) as $dep_name) { $this->addLibraryDependency($dep_name); } @@ -101,11 +96,10 @@ abstract class LibraryBase } /** - * 获取当前库编译出来获取到的静态库文件列表 + * Get config static libs. * - * @return string[] 获取编译出来后的需要的静态库文件列表 * @throws FileSystemException - * @throws RuntimeException + * @throws WrongUsageException */ public function getStaticLibs(): array { @@ -113,11 +107,10 @@ abstract class LibraryBase } /** - * 获取当前 lib 编译出来的 C Header 文件列表 + * Get config headers. * - * @return string[] 获取编译出来后需要的 C Header 文件列表 * @throws FileSystemException - * @throws RuntimeException + * @throws WrongUsageException */ public function getHeaders(): array { @@ -125,14 +118,19 @@ abstract class LibraryBase } /** - * 证明该库是否已编译好且就绪,如果没有就绪,内部会调用 build 来进行构建该库 + * Try to build this library, before build, we check first. + * + * BUILD_STATUS_OK if build success + * BUILD_STATUS_ALREADY if already built + * BUILD_STATUS_FAILED if build failed * * @throws RuntimeException * @throws FileSystemException + * @throws WrongUsageException */ public function tryBuild(bool $force_build = false): int { - // 传入 true,表明直接编译 + // force means just build if ($force_build) { logger()->info('Building required library [' . static::NAME . ']'); $this->patchBeforeBuild(); @@ -140,31 +138,31 @@ abstract class LibraryBase return BUILD_STATUS_OK; } - // 看看这些库是不是存在,如果不存在,则调用编译并返回结果状态 + // check if these libraries exist, if not, invoke compilation and return the result status foreach ($this->getStaticLibs() as $name) { if (!file_exists(BUILD_LIB_PATH . "/{$name}")) { $this->tryBuild(true); return BUILD_STATUS_OK; } } - // 头文件同理 + // header files the same foreach ($this->getHeaders() as $name) { if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) { $this->tryBuild(true); return BUILD_STATUS_OK; } } - // pkg-config 做特殊处理,如果是 pkg-config 就检查有没有 pkg-config 二进制 + // pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists if ($this instanceof MacOSLibraryBase && static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) { $this->tryBuild(true); return BUILD_STATUS_OK; } - // 到这里说明所有的文件都存在,就跳过编译 + // if all the files exist at this point, skip the compilation process return BUILD_STATUS_ALREADY; } /** - * Patch before build, overwrite this and return true to patch libs + * Patch before build, overwrite this and return true to patch libs. */ public function patchBeforeBuild(): bool { @@ -172,35 +170,32 @@ abstract class LibraryBase } /** - * 获取构建当前 lib 的 Builder 对象 + * Get current builder object. */ abstract public function getBuilder(): BuilderBase; /** - * 构建该库需要调用的命令和操作 + * Build this library. * * @throws RuntimeException */ abstract protected function build(); /** - * 添加 lib 库的依赖库 + * Add lib dependency * - * @param string $name 依赖名称 - * @param bool $optional 是否是可选依赖(默认为 False) * @throws RuntimeException */ protected function addLibraryDependency(string $name, bool $optional = false): void { - // Log::i("add $name as dep of {$this->name}"); $dep_lib = $this->getBuilder()->getLib($name); - if (!$dep_lib) { - if (!$optional) { - throw new RuntimeException(static::NAME . " requires library {$name}"); - } - logger()->debug('enabling ' . static::NAME . " without {$name}"); - } else { + if ($dep_lib) { $this->dependencies[$name] = $dep_lib; + return; } + if (!$optional) { + throw new RuntimeException(static::NAME . " requires library {$name}"); + } + logger()->debug('enabling ' . static::NAME . " without {$name}"); } } diff --git a/src/SPC/builder/extension/bz2.php b/src/SPC/builder/extension/bz2.php index c11060f1..88f22e56 100644 --- a/src/SPC/builder/extension/bz2.php +++ b/src/SPC/builder/extension/bz2.php @@ -7,6 +7,7 @@ namespace SPC\builder\extension; use SPC\builder\Extension; use SPC\builder\macos\MacOSBuilder; use SPC\exception\FileSystemException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; use SPC\util\CustomExt; @@ -15,11 +16,12 @@ class bz2 extends Extension { /** * @throws FileSystemException + * @throws WrongUsageException */ public function patchBeforeConfigure(): bool { $frameworks = $this->builder instanceof MacOSBuilder ? ' ' . $this->builder->getFrameworks(true) . ' ' : ''; - FileSystem::replaceFile(SOURCE_PATH . '/php-src/configure', REPLACE_FILE_PREG, '/-lbz2/', $this->getLibFilesString() . $frameworks); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-lbz2/', $this->getLibFilesString() . $frameworks); return true; } } diff --git a/src/SPC/builder/extension/curl.php b/src/SPC/builder/extension/curl.php index c733efeb..d4f8b078 100644 --- a/src/SPC/builder/extension/curl.php +++ b/src/SPC/builder/extension/curl.php @@ -7,12 +7,16 @@ namespace SPC\builder\extension; use SPC\builder\Extension; use SPC\builder\macos\MacOSBuilder; use SPC\exception\FileSystemException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; use SPC\util\CustomExt; #[CustomExt('curl')] class curl extends Extension { + /** + * @throws FileSystemException + */ public function patchBeforeBuildconf(): bool { logger()->info('patching before-configure for curl checks'); @@ -42,11 +46,12 @@ class curl extends Extension /** * @throws FileSystemException + * @throws WrongUsageException */ public function patchBeforeConfigure(): bool { $frameworks = $this->builder instanceof MacOSBuilder ? ' ' . $this->builder->getFrameworks(true) . ' ' : ''; - FileSystem::replaceFile(SOURCE_PATH . '/php-src/configure', REPLACE_FILE_PREG, '/-lcurl/', $this->getLibFilesString() . $frameworks); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-lcurl/', $this->getLibFilesString() . $frameworks); return true; } } diff --git a/src/SPC/builder/extension/event.php b/src/SPC/builder/extension/event.php index 5dd0bf75..7339ad17 100644 --- a/src/SPC/builder/extension/event.php +++ b/src/SPC/builder/extension/event.php @@ -31,12 +31,7 @@ class event extends Extension */ public function patchBeforeConfigure(): bool { - FileSystem::replaceFile( - SOURCE_PATH . '/php-src/configure', - REPLACE_FILE_PREG, - '/-levent_openssl/', - $this->getLibFilesString() - ); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-levent_openssl/', $this->getLibFilesString()); return true; } } diff --git a/src/SPC/builder/extension/glfw.php b/src/SPC/builder/extension/glfw.php index 7a52bb7c..2920dbf6 100644 --- a/src/SPC/builder/extension/glfw.php +++ b/src/SPC/builder/extension/glfw.php @@ -5,12 +5,16 @@ declare(strict_types=1); namespace SPC\builder\extension; use SPC\builder\Extension; +use SPC\exception\RuntimeException; use SPC\store\FileSystem; use SPC\util\CustomExt; #[CustomExt('glfw')] class glfw extends Extension { + /** + * @throws RuntimeException + */ public function patchBeforeBuildconf(): bool { FileSystem::copyDir(SOURCE_PATH . '/ext-glfw', SOURCE_PATH . '/php-src/ext/glfw'); diff --git a/src/SPC/builder/extension/iconv.php b/src/SPC/builder/extension/iconv.php new file mode 100644 index 00000000..6e2df2e5 --- /dev/null +++ b/src/SPC/builder/extension/iconv.php @@ -0,0 +1,23 @@ +builder->getOption('extra-libs', ''); + if (!str_contains($extra_libs, '-liconv')) { + $extra_libs .= ' -liconv'; + } + $this->builder->setOption('extra-libs', $extra_libs); + return true; + } +} diff --git a/src/SPC/builder/extension/imagick.php b/src/SPC/builder/extension/imagick.php index ed456e17..217b7aa9 100644 --- a/src/SPC/builder/extension/imagick.php +++ b/src/SPC/builder/extension/imagick.php @@ -10,6 +10,17 @@ use SPC\util\CustomExt; #[CustomExt('imagick')] class imagick extends Extension { + public function patchBeforeBuildconf(): bool + { + // linux need to link library manually, we add it to extra-libs + $extra_libs = $this->builder->getOption('extra-libs', ''); + if (!str_contains($extra_libs, 'libMagickCore')) { + $extra_libs .= ' /usr/lib/libMagick++-7.Q16HDRI.a /usr/lib/libMagickCore-7.Q16HDRI.a /usr/lib/libMagickWand-7.Q16HDRI.a'; + } + $this->builder->setOption('extra-libs', $extra_libs); + return true; + } + public function getUnixConfigureArg(): string { return '--with-imagick=' . BUILD_ROOT_PATH; diff --git a/src/SPC/builder/extension/memcache.php b/src/SPC/builder/extension/memcache.php index 38d00be0..eb3e2969 100644 --- a/src/SPC/builder/extension/memcache.php +++ b/src/SPC/builder/extension/memcache.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace SPC\builder\extension; use SPC\builder\Extension; +use SPC\exception\FileSystemException; use SPC\store\FileSystem; use SPC\util\CustomExt; @@ -16,17 +17,18 @@ class memcache extends Extension return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH; } + /** + * @throws FileSystemException + */ public function patchBeforeBuildconf(): bool { - FileSystem::replaceFile( + FileSystem::replaceFileStr( SOURCE_PATH . '/php-src/ext/memcache/config9.m4', - REPLACE_FILE_STR, 'if test -d $abs_srcdir/src ; then', 'if test -d $abs_srcdir/main ; then' ); - FileSystem::replaceFile( + FileSystem::replaceFileStr( SOURCE_PATH . '/php-src/ext/memcache/config9.m4', - REPLACE_FILE_STR, 'export CPPFLAGS="$CPPFLAGS $INCLUDES"', 'export CPPFLAGS="$CPPFLAGS $INCLUDES -I$abs_srcdir/main"' ); diff --git a/src/SPC/builder/extension/pdo_sqlite.php b/src/SPC/builder/extension/pdo_sqlite.php index 5e9250d7..a33dbbba 100644 --- a/src/SPC/builder/extension/pdo_sqlite.php +++ b/src/SPC/builder/extension/pdo_sqlite.php @@ -17,9 +17,8 @@ class pdo_sqlite extends Extension */ public function patchBeforeConfigure(): bool { - FileSystem::replaceFile( + FileSystem::replaceFileRegex( SOURCE_PATH . '/php-src/configure', - REPLACE_FILE_PREG, '/sqlite3_column_table_name=yes/', 'sqlite3_column_table_name=no' ); diff --git a/src/SPC/builder/extension/pgsql.php b/src/SPC/builder/extension/pgsql.php index a5be7ea4..8b447a16 100644 --- a/src/SPC/builder/extension/pgsql.php +++ b/src/SPC/builder/extension/pgsql.php @@ -17,9 +17,8 @@ class pgsql extends Extension */ public function patchBeforeConfigure(): bool { - FileSystem::replaceFile( + FileSystem::replaceFileRegex( SOURCE_PATH . '/php-src/configure', - REPLACE_FILE_PREG, '/-lpq/', $this->getLibFilesString() ); diff --git a/src/SPC/builder/extension/readline.php b/src/SPC/builder/extension/readline.php index a5b09ea8..c66e7afa 100644 --- a/src/SPC/builder/extension/readline.php +++ b/src/SPC/builder/extension/readline.php @@ -17,9 +17,8 @@ class readline extends Extension */ public function patchBeforeConfigure(): bool { - FileSystem::replaceFile( + FileSystem::replaceFileRegex( SOURCE_PATH . '/php-src/configure', - REPLACE_FILE_PREG, '/-lncurses/', $this->getLibFilesString() ); diff --git a/src/SPC/builder/extension/ssh2.php b/src/SPC/builder/extension/ssh2.php index cf966ae6..eeabaa72 100644 --- a/src/SPC/builder/extension/ssh2.php +++ b/src/SPC/builder/extension/ssh2.php @@ -17,9 +17,8 @@ class ssh2 extends Extension */ public function patchBeforeConfigure(): bool { - FileSystem::replaceFile( + FileSystem::replaceFileRegex( SOURCE_PATH . '/php-src/configure', - REPLACE_FILE_PREG, '/-lssh2/', $this->getLibFilesString() ); diff --git a/src/SPC/builder/extension/swow.php b/src/SPC/builder/extension/swow.php index 515a81e1..fdea5a6e 100644 --- a/src/SPC/builder/extension/swow.php +++ b/src/SPC/builder/extension/swow.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace SPC\builder\extension; use SPC\builder\Extension; +use SPC\exception\RuntimeException; use SPC\util\CustomExt; use SPC\util\Util; @@ -19,6 +20,9 @@ class swow extends Extension return $arg; } + /** + * @throws RuntimeException + */ public function patchBeforeBuildconf(): bool { if (Util::getPHPVersionID() >= 80000 && !is_link(SOURCE_PATH . '/php-src/ext/swow')) { diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index e088b0d6..e27c2f34 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -12,94 +12,90 @@ use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; use SPC\store\SourcePatcher; -/** - * Linux 系统环境下的构建器 - */ class LinuxBuilder extends BuilderBase { - /** 编译的 Unix 工具集 */ + /** Unix compatible builder methods */ use UnixBuilderTrait; - /** @var string[] Linux 环境下编译依赖的命令 */ - public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake']; - - /** @var string 使用的 libc */ + /** @var string Using libc [musl,glibc] */ public string $libc; - /** @var array 特殊架构下的 cflags */ + /** @var array Tune cflags */ public array $tune_c_flags; - /** @var string pkg-config 环境变量 */ + /** @var string pkg-config env, including PKG_CONFIG_PATH, PKG_CONFIG */ public string $pkgconf_env; - /** @var string 交叉编译变量 */ - public string $cross_compile_prefix = ''; - - public string $note_section = "Je pense, donc je suis\0"; - + /** @var bool Micro patch phar flag */ private bool $phar_patched = false; /** + * @throws FileSystemException * @throws RuntimeException * @throws WrongUsageException */ - public function __construct(?string $cc = null, ?string $cxx = null, ?string $arch = null, bool $zts = false) + public function __construct(array $options = []) { - // 初始化一些默认参数 - $this->cc = $cc ?? match (SystemUtil::getOSRelease()['dist']) { + $this->options = $options; + + // ---------- set necessary options ---------- + // set C Compiler (default: alpine: gcc, others: musl-gcc) + $this->setOptionIfNotExist('cc', match (SystemUtil::getOSRelease()['dist']) { 'alpine' => 'gcc', default => 'musl-gcc' - }; - $this->cxx = $cxx ?? 'g++'; - $this->arch = $arch ?? php_uname('m'); - $this->gnu_arch = arch2gnu($this->arch); - $this->zts = $zts; - $this->libc = 'musl'; // SystemUtil::selectLibc($this->cc); + }); + // set C++ Compiler (default: g++) + $this->setOptionIfNotExist('cxx', 'g++'); + // set arch (default: current) + $this->setOptionIfNotExist('arch', php_uname('m')); + $this->setOptionIfNotExist('gnu-arch', arch2gnu($this->getOption('arch'))); - // 根据 CPU 线程数设置编译进程数 + // ---------- set necessary compile environments ---------- + // set libc + $this->libc = 'musl'; // SystemUtil::selectLibc($this->cc); + // concurrency $this->concurrency = SystemUtil::getCpuCount(); - // 设置 cflags - $this->arch_c_flags = SystemUtil::getArchCFlags($this->cc, $this->arch); - $this->arch_cxx_flags = SystemUtil::getArchCFlags($this->cxx, $this->arch); - $this->tune_c_flags = SystemUtil::checkCCFlags(SystemUtil::getTuneCFlags($this->arch), $this->cc); - // 设置 cmake + // cflags + $this->arch_c_flags = SystemUtil::getArchCFlags($this->getOption('cc'), $this->getOption('arch')); + $this->arch_cxx_flags = SystemUtil::getArchCFlags($this->getOption('cxx'), $this->getOption('arch')); + $this->tune_c_flags = SystemUtil::checkCCFlags(SystemUtil::getTuneCFlags($this->getOption('arch')), $this->getOption('cc')); + // cmake toolchain $this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile( - os: 'Linux', - target_arch: $this->arch, - cflags: $this->arch_c_flags, - cc: $this->cc, - cxx: $this->cxx + 'Linux', + $this->getOption('arch'), + $this->arch_c_flags, + $this->getOption('cc'), + $this->getOption('cxx'), ); - // 设置 pkgconfig - $this->pkgconf_env = 'PKG_CONFIG="' . BUILD_ROOT_PATH . '/bin/pkg-config" PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig"'; - // 设置 configure 依赖的环境变量 - $this->configure_env = - $this->pkgconf_env . ' ' . - "CC='{$this->cc}' " . - "CXX='{$this->cxx}' " . - (php_uname('m') === $this->arch ? '' : "CFLAGS='{$this->arch_c_flags}'"); - // 交叉编译依赖的,TODO - if (php_uname('m') !== $this->arch) { + // pkg-config + $vars = [ + 'PKG_CONFIG' => BUILD_ROOT_PATH . '/bin/pkg-config', + 'PKG_CONFIG_PATH' => BUILD_LIB_PATH . '/pkgconfig', + ]; + $this->pkgconf_env = SystemUtil::makeEnvVarString($vars); + // configure environment + $this->configure_env = SystemUtil::makeEnvVarString([ + ...$vars, + 'CC' => $this->getOption('cc'), + 'CXX' => $this->getOption('cxx'), + ]); + // cross-compile does not support yet + /*if (php_uname('m') !== $this->arch) { $this->cross_compile_prefix = SystemUtil::getCrossCompilePrefix($this->cc, $this->arch); logger()->info('using cross compile prefix: ' . $this->cross_compile_prefix); $this->configure_env .= " CROSS_COMPILE='{$this->cross_compile_prefix}'"; - } + }*/ - $missing = []; - foreach (self::REQUIRED_COMMANDS as $cmd) { - if (SystemUtil::findCommand($cmd) === null) { - $missing[] = $cmd; - } - } - if (!empty($missing)) { - throw new WrongUsageException('missing system commands: ' . implode(', ', $missing)); - } - - // 创立 pkg-config 和放头文件的目录 + // create pkgconfig and include dir (some libs cannot create them automatically) f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true); f_mkdir(BUILD_INCLUDE_PATH, recursive: true); } + /** + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + */ public function makeAutoconfArgs(string $name, array $libSpecs): string { $ret = ''; @@ -124,32 +120,22 @@ class LinuxBuilder extends BuilderBase /** * @throws RuntimeException * @throws FileSystemException + * @throws WrongUsageException */ - public function buildPHP(int $build_target = BUILD_TARGET_NONE, bool $with_clean = false, bool $bloat = false) + public function buildPHP(int $build_target = BUILD_TARGET_NONE): void { - if (!$bloat) { - $extra_libs = implode(' ', $this->getAllStaticLibFiles()); + // ---------- Update extra-libs ---------- + $extra_libs = $this->getOption('extra-libs', ''); + // non-bloat linking + if (!$this->getOption('bloat', false)) { + $extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles()); } else { - logger()->info('bloat linking'); - $extra_libs = implode( - ' ', - array_map( - fn ($x) => "-Xcompiler {$x}", - array_filter($this->getAllStaticLibFiles()) - ) - ); + $extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", array_filter($this->getAllStaticLibFiles()))); } + // add libstdc++, some extensions or libraries need it (C++ cannot be linked statically) + $extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCppExtension() ? '-lc++ ' : ''); + $this->setOption('extra-libs', $extra_libs); - if ($this->hasCppExtension()) { - $extra_libs .= ' -lstdc++'; - } - if ($this->getExt('imagick')) { - $extra_libs .= ' /usr/lib/libMagick++-7.Q16HDRI.a /usr/lib/libMagickCore-7.Q16HDRI.a /usr/lib/libMagickWand-7.Q16HDRI.a'; - } - - $envs = $this->pkgconf_env . ' ' . - "CC='{$this->cc}' " . - "CXX='{$this->cxx}' "; $cflags = $this->arch_c_flags; $use_lld = ''; @@ -159,7 +145,7 @@ class LinuxBuilder extends BuilderBase $cflags .= ' -static-libgcc -I"' . BUILD_INCLUDE_PATH . '"'; break; case 'musl': - if (str_ends_with($this->cc, 'clang') && SystemUtil::findCommand('lld')) { + if (str_ends_with($this->getOption('cc'), 'clang') && SystemUtil::findCommand('lld')) { $use_lld = '-Xcompiler -fuse-ld=lld'; } break; @@ -167,7 +153,12 @@ class LinuxBuilder extends BuilderBase throw new WrongUsageException('libc ' . $this->libc . ' is not implemented yet'); } - $envs = "{$envs} CFLAGS='{$cflags}' LIBS='-ldl -lpthread'"; + $envs = $this->pkgconf_env . ' ' . SystemUtil::makeEnvVarString([ + 'CC' => $this->getOption('cc'), + 'CXX' => $this->getOption('cxx'), + 'CFLAGS' => $cflags, + 'LIBS' => '-ldl -lpthread', + ]); SourcePatcher::patchBeforeBuildconf($this); @@ -175,11 +166,8 @@ class LinuxBuilder extends BuilderBase SourcePatcher::patchBeforeConfigure($this); - if ($this->getPHPVersionID() < 80000) { - $json_74 = '--enable-json '; - } else { - $json_74 = ''; - } + $json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : ''; + $zts = $this->getOption('enable-zts', false) ? '--enable-zts ' : ''; shell()->cd(SOURCE_PATH . '/php-src') ->exec( @@ -194,24 +182,16 @@ class LinuxBuilder extends BuilderBase '--enable-cli ' . '--enable-fpm ' . $json_74 . + $zts . '--enable-micro=all-static ' . - ($this->zts ? '--enable-zts' : '') . ' ' . $this->makeExtensionArgs() . ' ' . $envs ); SourcePatcher::patchBeforeMake($this); - file_put_contents('/tmp/comment', $this->note_section); - - // 清理 $this->cleanMake(); - if ($bloat) { - logger()->info('bloat linking'); - $extra_libs = "-Wl,--whole-archive {$extra_libs} -Wl,--no-whole-archive"; - } - if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) { logger()->info('building cli'); $this->buildCli($extra_libs, $use_lld); @@ -225,7 +205,7 @@ class LinuxBuilder extends BuilderBase $this->buildMicro($extra_libs, $use_lld, $cflags); } - if (php_uname('m') === $this->arch) { + if (php_uname('m') === $this->getOption('arch')) { $this->sanityCheck($build_target); } @@ -235,30 +215,34 @@ class LinuxBuilder extends BuilderBase } /** + * Build cli sapi + * * @throws RuntimeException + * @throws FileSystemException */ public function buildCli(string $extra_libs, string $use_lld): void { + $vars = SystemUtil::makeEnvVarString([ + 'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)), + 'EXTRA_LIBS' => $extra_libs, + 'EXTRA_LDFLAGS_PROGRAM' => "{$use_lld} -all-static", + ]); shell()->cd(SOURCE_PATH . '/php-src') ->exec('sed -i "s|//lib|/lib|g" Makefile') - ->exec( - 'make -j' . $this->concurrency . - ' EXTRA_CFLAGS="-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)) . '" ' . - "EXTRA_LIBS=\"{$extra_libs}\" " . - "EXTRA_LDFLAGS_PROGRAM='{$use_lld} -all-static' " . - 'cli' - ); + ->exec("make -j{$this->concurrency} {$vars} cli"); + + if (!$this->getOption('no-strip', false)) { + shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')->exec('strip --strip-all php'); + } - shell()->cd(SOURCE_PATH . '/php-src/sapi/cli') - ->exec("{$this->cross_compile_prefix}objcopy --only-keep-debug php php.debug") - ->exec('elfedit --output-osabi linux php') - ->exec("{$this->cross_compile_prefix}strip --strip-all php") - ->exec("{$this->cross_compile_prefix}objcopy --update-section .comment=/tmp/comment --add-gnu-debuglink=php.debug --remove-section=.note php"); $this->deployBinary(BUILD_TARGET_CLI); } /** + * Build phpmicro sapi + * * @throws RuntimeException + * @throws FileSystemException */ public function buildMicro(string $extra_libs, string $use_lld, string $cflags): void { @@ -270,43 +254,45 @@ class LinuxBuilder extends BuilderBase SourcePatcher::patchMicro(['phar']); } + $enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : ''; + $vars = SystemUtil::makeEnvVarString([ + 'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)) . $enable_fake_cli, + 'EXTRA_LIBS' => $extra_libs, + 'EXTRA_LDFLAGS_PROGRAM' => "{$cflags} {$use_lld} -all-static", + ]); shell()->cd(SOURCE_PATH . '/php-src') ->exec('sed -i "s|//lib|/lib|g" Makefile') - ->exec( - "make -j{$this->concurrency} " . - 'EXTRA_CFLAGS=' . quote('-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags))) . ' ' . - 'EXTRA_LIBS=' . quote($extra_libs) . ' ' . - 'EXTRA_LDFLAGS_PROGRAM=' . quote("{$cflags} {$use_lld}" . ' -all-static', "'") . ' ' . - 'micro' - ); + ->exec("make -j{$this->concurrency} {$vars} micro"); - shell()->cd(SOURCE_PATH . '/php-src/sapi/micro')->exec("{$this->cross_compile_prefix}strip --strip-all micro.sfx"); + if (!$this->getOption('no-strip', false)) { + shell()->cd(SOURCE_PATH . '/php-src/sapi/micro')->exec('strip --strip-all micro.sfx'); + } $this->deployBinary(BUILD_TARGET_MICRO); } /** - * 构建 fpm + * Build fpm sapi * - * @throws FileSystemException|RuntimeException + * @throws FileSystemException + * @throws RuntimeException */ public function buildFpm(string $extra_libs, string $use_lld): void { + $vars = SystemUtil::makeEnvVarString([ + 'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)), + 'EXTRA_LIBS' => $extra_libs, + 'EXTRA_LDFLAGS_PROGRAM' => "{$use_lld} -all-static", + ]); + shell()->cd(SOURCE_PATH . '/php-src') ->exec('sed -i "s|//lib|/lib|g" Makefile') - ->exec( - 'make -j' . $this->concurrency . - ' EXTRA_CFLAGS="-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)) . '" ' . - "EXTRA_LIBS=\"{$extra_libs}\" " . - "EXTRA_LDFLAGS_PROGRAM='{$use_lld} -all-static' " . - 'fpm' - ); + ->exec("make -j{$this->concurrency} {$vars} fpm"); + + if (!$this->getOption('no-strip', false)) { + shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm')->exec('strip --strip-all php-fpm'); + } - shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm') - ->exec("{$this->cross_compile_prefix}objcopy --only-keep-debug php-fpm php-fpm.debug") - ->exec('elfedit --output-osabi linux php-fpm') - ->exec("{$this->cross_compile_prefix}strip --strip-all php-fpm") - ->exec("{$this->cross_compile_prefix}objcopy --update-section .comment=/tmp/comment --add-gnu-debuglink=php-fpm.debug --remove-section=.note php-fpm"); $this->deployBinary(BUILD_TARGET_FPM); } } diff --git a/src/SPC/builder/linux/SystemUtil.php b/src/SPC/builder/linux/SystemUtil.php index 5f2df6a3..13bc44b8 100644 --- a/src/SPC/builder/linux/SystemUtil.php +++ b/src/SPC/builder/linux/SystemUtil.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace SPC\builder\linux; -use JetBrains\PhpStorm\ArrayShape; use SPC\builder\traits\UnixSystemUtilTrait; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; @@ -13,7 +12,7 @@ class SystemUtil { use UnixSystemUtilTrait; - #[ArrayShape(['dist' => 'mixed|string', 'ver' => 'mixed|string'])] + /** @noinspection PhpMissingBreakStatementInspection */ public static function getOSRelease(): array { $ret = [ @@ -81,6 +80,8 @@ class SystemUtil /** * @throws RuntimeException + * @throws WrongUsageException + * @throws WrongUsageException */ public static function getArchCFlags(string $cc, string $arch): string { @@ -129,6 +130,7 @@ class SystemUtil /** * @throws RuntimeException + * @noinspection PhpUnused */ public static function getCrossCompilePrefix(string $cc, string $arch): string { @@ -159,6 +161,7 @@ class SystemUtil return null; } + /** @noinspection PhpUnused */ public static function findStaticLibs(array $names): ?array { $ret = []; @@ -187,6 +190,7 @@ class SystemUtil return null; } + /** @noinspection PhpUnused */ public static function findHeaders(array $names): ?array { $ret = []; diff --git a/src/SPC/builder/linux/library/LinuxLibraryBase.php b/src/SPC/builder/linux/library/LinuxLibraryBase.php index e3d9878e..5ec8c7c2 100644 --- a/src/SPC/builder/linux/library/LinuxLibraryBase.php +++ b/src/SPC/builder/linux/library/LinuxLibraryBase.php @@ -8,7 +8,9 @@ use SPC\builder\BuilderBase; use SPC\builder\LibraryBase; use SPC\builder\linux\LinuxBuilder; use SPC\builder\traits\UnixLibraryTrait; +use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; abstract class LinuxLibraryBase extends LibraryBase { @@ -37,6 +39,8 @@ abstract class LinuxLibraryBase extends LibraryBase /** * @throws RuntimeException + * @throws FileSystemException + * @throws WrongUsageException */ public function tryBuild(bool $force_build = false): int { @@ -71,7 +75,7 @@ abstract class LinuxLibraryBase extends LibraryBase return BUILD_STATUS_ALREADY; } - protected function makeFakePkgconfs() + protected function makeFakePkgconfs(): void { $workspace = BUILD_ROOT_PATH; if ($workspace === '/') { diff --git a/src/SPC/builder/linux/library/icu.php b/src/SPC/builder/linux/library/icu.php index c6ef6c37..39125675 100644 --- a/src/SPC/builder/linux/library/icu.php +++ b/src/SPC/builder/linux/library/icu.php @@ -8,7 +8,7 @@ class icu extends LinuxLibraryBase { public const NAME = 'icu'; - protected function build() + protected function build(): void { $root = BUILD_ROOT_PATH; $cppflag = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1"'; diff --git a/src/SPC/builder/linux/library/libpng.php b/src/SPC/builder/linux/library/libpng.php index 54f3357c..81456389 100644 --- a/src/SPC/builder/linux/library/libpng.php +++ b/src/SPC/builder/linux/library/libpng.php @@ -23,24 +23,26 @@ namespace SPC\builder\linux\library; use SPC\builder\linux\SystemUtil; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; class libpng extends LinuxLibraryBase { public const NAME = 'libpng'; + /** + * @throws FileSystemException + */ public function patchBeforeBuild(): bool { - FileSystem::replaceFile( + FileSystem::replaceFileStr( SOURCE_PATH . '/libpng/configure', - REPLACE_FILE_STR, '-lz', BUILD_LIB_PATH . '/libz.a' ); if (SystemUtil::getOSRelease()['dist'] === 'alpine') { - FileSystem::replaceFile( + FileSystem::replaceFileStr( SOURCE_PATH . '/libpng/configure', - REPLACE_FILE_STR, '-lm', '/usr/lib/libm.a' ); @@ -49,12 +51,13 @@ class libpng extends LinuxLibraryBase } /** - * @throws RuntimeException * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException */ - public function build() + public function build(): void { - $optimizations = match ($this->builder->arch) { + $optimizations = match ($this->builder->getOption('arch')) { 'x86_64' => '--enable-intel-sse ', 'arm64' => '--enable-arm-neon ', default => '', @@ -64,7 +67,7 @@ class libpng extends LinuxLibraryBase ->exec('chmod +x ./install-sh') ->exec( "{$this->builder->configure_env} ./configure " . - "--host={$this->builder->gnu_arch}-unknown-linux " . + "--host={$this->builder->getOption('gnu-arch')}-unknown-linux " . '--disable-shared ' . '--enable-static ' . '--enable-hardware-optimizations ' . diff --git a/src/SPC/builder/linux/library/libxml2.php b/src/SPC/builder/linux/library/libxml2.php index 0389b3ea..7a26578b 100644 --- a/src/SPC/builder/linux/library/libxml2.php +++ b/src/SPC/builder/linux/library/libxml2.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace SPC\builder\linux\library; +use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\FileSystem; @@ -13,14 +14,15 @@ class libxml2 extends LinuxLibraryBase /** * @throws RuntimeException + * @throws FileSystemException */ - public function build() + public function build(): void { $enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF'; $enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF'; $enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF'; - [$lib, $include, $destdir] = SEPARATED_PATH; + [, , $destdir] = SEPARATED_PATH; FileSystem::resetDir($this->source_dir . '/build'); shell()->cd($this->source_dir . '/build') diff --git a/src/SPC/builder/linux/library/nghttp2.php b/src/SPC/builder/linux/library/nghttp2.php index 733b562d..8246a2eb 100644 --- a/src/SPC/builder/linux/library/nghttp2.php +++ b/src/SPC/builder/linux/library/nghttp2.php @@ -20,11 +20,20 @@ declare(strict_types=1); namespace SPC\builder\linux\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; + class nghttp2 extends LinuxLibraryBase { public const NAME = 'nghttp2'; - public function build() + /** + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + */ + public function build(): void { $args = $this->builder->makeAutoconfArgs(static::NAME, [ 'zlib' => null, @@ -49,7 +58,7 @@ class nghttp2 extends LinuxLibraryBase "{$this->builder->configure_env} ./configure " . '--enable-static ' . '--disable-shared ' . - "--host={$this->builder->gnu_arch}-unknown-linux " . + "--host={$this->builder->getOption('gnu-arch')}-unknown-linux " . '--enable-lib-only ' . '--with-boost=no ' . $args . ' ' . diff --git a/src/SPC/builder/linux/library/openssl.php b/src/SPC/builder/linux/library/openssl.php index d5cfa7cb..af3400b6 100644 --- a/src/SPC/builder/linux/library/openssl.php +++ b/src/SPC/builder/linux/library/openssl.php @@ -23,26 +23,28 @@ namespace SPC\builder\linux\library; use SPC\builder\linux\SystemUtil; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; class openssl extends LinuxLibraryBase { public const NAME = 'openssl'; /** - * @throws RuntimeException * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException */ - public function build() + public function build(): void { - [$lib,$include,$destdir] = SEPARATED_PATH; + [,,$destdir] = SEPARATED_PATH; $extra = ''; $ex_lib = '-ldl -pthread'; $env = $this->builder->pkgconf_env . " CFLAGS='{$this->builder->arch_c_flags}'"; - $env .= " CC='{$this->builder->cc} -static -idirafter " . BUILD_INCLUDE_PATH . + $env .= " CC='{$this->builder->getOption('cc')} -static -idirafter " . BUILD_INCLUDE_PATH . ' -idirafter /usr/include/ ' . - ' -idirafter /usr/include/' . $this->builder->arch . '-linux-gnu/ ' . + ' -idirafter /usr/include/' . $this->builder->getOption('arch') . '-linux-gnu/ ' . "' "; // lib:zlib $zlib = $this->builder->getLib('zlib'); @@ -58,7 +60,7 @@ class openssl extends LinuxLibraryBase $ex_lib = trim($ex_lib); - $clang_postfix = SystemUtil::getCCType($this->builder->cc) === 'clang' ? '-clang' : ''; + $clang_postfix = SystemUtil::getCCType($this->builder->getOption('cc')) === 'clang' ? '-clang' : ''; shell()->cd($this->source_dir) ->exec( @@ -68,7 +70,7 @@ class openssl extends LinuxLibraryBase '-static ' . "{$zlib_extra}" . 'no-legacy ' . - "linux-{$this->builder->arch}{$clang_postfix}" + "linux-{$this->builder->getOption('arch')}{$clang_postfix}" ) ->exec('make clean') ->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"") diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index 5e48629e..eb92a279 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -12,57 +12,56 @@ use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; use SPC\store\SourcePatcher; -/** - * macOS 系统环境下的构建器 - * 源于 Config,但因为感觉叫 Config 不太合适,就换成了 Builder - */ class MacOSBuilder extends BuilderBase { - /** 编译的 Unix 工具集 */ + /** Unix compatible builder methods */ use UnixBuilderTrait; - /** @var bool 标记是否 patch 了 phar */ + /** @var bool Micro patch phar flag */ private bool $phar_patched = false; /** - * @param null|string $cc C编译器名称,如果不传入则默认使用clang - * @param null|string $cxx C++编译器名称,如果不传入则默认使用clang++ - * @param null|string $arch 当前架构,如果不传入则默认使用当前系统架构 * @throws RuntimeException * @throws WrongUsageException + * @throws FileSystemException */ - public function __construct(?string $cc = null, ?string $cxx = null, ?string $arch = null, bool $zts = false) + public function __construct(array $options = []) { - // 如果是 Debug 模式,才使用 set -x 显示每条执行的命令 - $this->set_x = defined('DEBUG_MODE') ? 'set -x' : 'true'; - // 初始化一些默认参数 - $this->cc = $cc ?? 'clang'; - $this->cxx = $cxx ?? 'clang++'; - $this->arch = $arch ?? php_uname('m'); - $this->gnu_arch = arch2gnu($this->arch); - $this->zts = $zts; - // 根据 CPU 线程数设置编译进程数 - $this->concurrency = SystemUtil::getCpuCount(); - // 设置 cflags - $this->arch_c_flags = SystemUtil::getArchCFlags($this->arch); - $this->arch_cxx_flags = SystemUtil::getArchCFlags($this->arch); - // 设置 cmake - $this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->arch, $this->arch_c_flags); - // 设置 configure 依赖的环境变量 - $this->configure_env = - 'PKG_CONFIG="' . BUILD_ROOT_PATH . '/bin/pkg-config" ' . - 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig/" ' . - "CC='{$this->cc}' " . - "CXX='{$this->cxx}' " . - "CFLAGS='{$this->arch_c_flags} -Wimplicit-function-declaration -Os'"; + $this->options = $options; - // 创立 pkg-config 和放头文件的目录 + // ---------- set necessary options ---------- + // set C Compiler (default: clang) + $this->setOptionIfNotExist('cc', 'clang'); + // set C++ Composer (default: clang++) + $this->setOptionIfNotExist('cxx', 'clang++'); + // set arch (default: current) + $this->setOptionIfNotExist('arch', php_uname('m')); + $this->setOptionIfNotExist('gnu-arch', arch2gnu($this->getOption('arch'))); + + // ---------- set necessary compile environments ---------- + // concurrency + $this->concurrency = SystemUtil::getCpuCount(); + // cflags + $this->arch_c_flags = SystemUtil::getArchCFlags($this->getOption('arch')); + $this->arch_cxx_flags = SystemUtil::getArchCFlags($this->getOption('arch')); + // cmake toolchain + $this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->getOption('arch'), $this->arch_c_flags); + // configure environment + $this->configure_env = SystemUtil::makeEnvVarString([ + 'PKG_CONFIG' => BUILD_ROOT_PATH . '/bin/pkg-config', + 'PKG_CONFIG_PATH' => BUILD_LIB_PATH . '/pkgconfig/', + 'CC' => $this->getOption('cc'), + 'CXX' => $this->getOption('cxx'), + 'CFLAGS' => "{$this->arch_c_flags} -Wimplicit-function-declaration -Os", + ]); + + // create pkgconfig and include dir (some libs cannot create them automatically) f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true); f_mkdir(BUILD_INCLUDE_PATH, recursive: true); } /** - * 生成库构建采用的 autoconf 参数列表 + * [deprecated] 生成库构建采用的 autoconf 参数列表 * * @param string $name 要构建的 lib 库名,传入仅供输出日志 * @param array $lib_specs 依赖的 lib 库的 autoconf 文件 @@ -76,7 +75,6 @@ class MacOSBuilder extends BuilderBase $arr = $arr ?? []; $disableArgs = $arr[0] ?? null; - $prefix = $arr[1] ?? null; if ($lib instanceof MacOSLibraryBase) { logger()->info("{$name} \033[32;1mwith\033[0;1m {$libName} support"); $ret .= '--with-' . $libName . '=yes '; @@ -89,9 +87,11 @@ class MacOSBuilder extends BuilderBase } /** - * 返回 macOS 系统依赖的框架列表 + * Get dynamically linked macOS frameworks * - * @param bool $asString 是否以字符串形式返回(默认为 False) + * @param bool $asString If true, return as string + * @throws FileSystemException + * @throws WrongUsageException */ public function getFrameworks(bool $asString = false): array|string { @@ -118,50 +118,43 @@ class MacOSBuilder extends BuilderBase } /** + * Just start to build statically linked php binary + * * @param int $build_target build target - * @param bool $bloat just raw add all lib files * @throws FileSystemException * @throws RuntimeException * @throws WrongUsageException */ - public function buildPHP(int $build_target = BUILD_TARGET_NONE, bool $bloat = false): void + public function buildPHP(int $build_target = BUILD_TARGET_NONE): void { - $extra_libs = $this->getFrameworks(true) . ' ' . ($this->hasCppExtension() ? '-lc++ ' : ''); - if (!$bloat) { - $extra_libs .= implode(' ', $this->getAllStaticLibFiles()); + // ---------- Update extra-libs ---------- + $extra_libs = $this->getOption('extra-libs', ''); + // add macOS frameworks + $extra_libs .= (empty($extra_libs) ? '' : ' ') . $this->getFrameworks(true); + // add libc++, some extensions or libraries need it (C++ cannot be linked statically) + $extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCppExtension() ? '-lc++ ' : ''); + if (!$this->getOption('bloat', false)) { + $extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles()); } else { logger()->info('bloat linking'); - $extra_libs .= implode( - ' ', - array_map( - fn ($x) => "-Wl,-force_load,{$x}", - array_filter($this->getAllStaticLibFiles()) - ) - ); + $extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Wl,-force_load,{$x}", array_filter($this->getAllStaticLibFiles()))); } + $this->setOption('extra-libs', $extra_libs); - // patch before buildconf SourcePatcher::patchBeforeBuildconf($this); shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force'); SourcePatcher::patchBeforeConfigure($this); - if ($this->getLib('libxml2') || $this->getExt('iconv')) { - $extra_libs .= ' -liconv'; - } - - if ($this->getPHPVersionID() < 80000) { - $json_74 = '--enable-json '; - } else { - $json_74 = ''; - } + $json_74 = $this->getPHPVersionID() < 80000 ? '--enable-json ' : ''; + $zts = $this->getOption('enable-zts', false) ? '--enable-zts ' : ''; shell()->cd(SOURCE_PATH . '/php-src') ->exec( './configure ' . '--prefix= ' . - '--with-valgrind=no ' . // 不检测内存泄漏 + '--with-valgrind=no ' . // Not detect memory leak '--enable-shared=no ' . '--enable-static=yes ' . "CFLAGS='{$this->arch_c_flags} -Werror=unknown-warning-option' " . @@ -170,9 +163,9 @@ class MacOSBuilder extends BuilderBase '--disable-phpdbg ' . '--enable-cli ' . '--enable-fpm ' . - $json_74 . '--enable-micro ' . - ($this->zts ? '--enable-zts' : '') . ' ' . + $json_74 . + $zts . $this->makeExtensionArgs() . ' ' . $this->configure_env ); @@ -183,18 +176,18 @@ class MacOSBuilder extends BuilderBase if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) { logger()->info('building cli'); - $this->buildCli($extra_libs); + $this->buildCli(); } if (($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) { logger()->info('building fpm'); - $this->buildFpm($extra_libs); + $this->buildFpm(); } if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) { logger()->info('building micro'); - $this->buildMicro($extra_libs); + $this->buildMicro(); } - if (php_uname('m') === $this->arch) { + if (php_uname('m') === $this->getOption('arch')) { $this->sanityCheck($build_target); } @@ -204,27 +197,32 @@ class MacOSBuilder extends BuilderBase } /** - * 构建 cli + * Build cli sapi * * @throws RuntimeException * @throws FileSystemException */ - public function buildCli(string $extra_libs): void + public function buildCli(): void { + $vars = SystemUtil::makeEnvVarString([ + 'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size + 'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS need it) + ]); + $shell = shell()->cd(SOURCE_PATH . '/php-src'); - $shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" cli"); - if ($this->strip) { + $shell->exec("make -j{$this->concurrency} {$vars} cli"); + if (!$this->getOption('no-strip', false)) { $shell->exec('dsymutil -f sapi/cli/php')->exec('strip sapi/cli/php'); } $this->deployBinary(BUILD_TARGET_CLI); } /** - * 构建 phpmicro + * Build phpmicro sapi * * @throws FileSystemException|RuntimeException */ - public function buildMicro(string $extra_libs): void + public function buildMicro(): void { if ($this->getPHPVersionID() < 80000) { throw new RuntimeException('phpmicro only support PHP >= 8.0!'); @@ -234,22 +232,39 @@ class MacOSBuilder extends BuilderBase SourcePatcher::patchMicro(['phar']); } + $enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : ''; + $vars = [ + // with debug information, optimize for size, remove identifiers, patch fake cli for micro + 'EXTRA_CFLAGS' => '-g -Os -fno-ident' . $enable_fake_cli, + // link resolv library (macOS need it) + 'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", + ]; + if (!$this->getOption('no-strip', false)) { + $vars['STRIP'] = 'dsymutil -f '; + } + $vars = SystemUtil::makeEnvVarString($vars); + shell()->cd(SOURCE_PATH . '/php-src') - ->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" " . ($this->strip ? 'STRIP="dsymutil -f " ' : '') . 'micro'); + ->exec("make -j{$this->concurrency} {$vars} micro"); $this->deployBinary(BUILD_TARGET_MICRO); } /** - * 构建 fpm + * Build fpm sapi * * @throws RuntimeException * @throws FileSystemException */ - public function buildFpm(string $extra_libs): void + public function buildFpm(): void { + $vars = SystemUtil::makeEnvVarString([ + 'EXTRA_CFLAGS' => '-g -Os', // with debug information, but optimize for size + 'EXTRA_LIBS' => "{$this->getOption('extra-libs')} -lresolv", // link resolv library (macOS need it) + ]); + $shell = shell()->cd(SOURCE_PATH . '/php-src'); - $shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" fpm"); - if ($this->strip) { + $shell->exec("make -j{$this->concurrency} {$vars} fpm"); + if (!$this->getOption('no-strip', false)) { $shell->exec('dsymutil -f sapi/fpm/php-fpm')->exec('strip sapi/fpm/php-fpm'); } $this->deployBinary(BUILD_TARGET_FPM); diff --git a/src/SPC/builder/macos/SystemUtil.php b/src/SPC/builder/macos/SystemUtil.php index e810ae22..22d7847e 100644 --- a/src/SPC/builder/macos/SystemUtil.php +++ b/src/SPC/builder/macos/SystemUtil.php @@ -10,11 +10,11 @@ use SPC\exception\WrongUsageException; class SystemUtil { - /** macOS 兼容 unix 的系统工具 */ + /** Unix System Util Compatible */ use UnixSystemUtilTrait; /** - * 获取系统 CPU 逻辑内核数 + * Get Logic CPU Count for macOS * * @throws RuntimeException */ @@ -29,9 +29,10 @@ class SystemUtil } /** - * 获取不同架构对应的 cflags 参数 + * Get Target Arch CFlags * - * @param string $arch 架构名称 + * @param string $arch Arch Name + * @return string return Arch CFlags string * @throws WrongUsageException */ public static function getArchCFlags(string $arch): string diff --git a/src/SPC/builder/macos/library/MacOSLibraryBase.php b/src/SPC/builder/macos/library/MacOSLibraryBase.php index 3401e168..336a21b0 100644 --- a/src/SPC/builder/macos/library/MacOSLibraryBase.php +++ b/src/SPC/builder/macos/library/MacOSLibraryBase.php @@ -8,6 +8,8 @@ use SPC\builder\BuilderBase; use SPC\builder\LibraryBase; use SPC\builder\macos\MacOSBuilder; use SPC\builder\traits\UnixLibraryTrait; +use SPC\exception\FileSystemException; +use SPC\exception\WrongUsageException; use SPC\store\Config; abstract class MacOSLibraryBase extends LibraryBase @@ -27,7 +29,8 @@ abstract class MacOSLibraryBase extends LibraryBase } /** - * 获取当前 lib 库依赖的 macOS framework + * @throws WrongUsageException + * @throws FileSystemException */ public function getFrameworks(): array { diff --git a/src/SPC/builder/macos/library/curl.php b/src/SPC/builder/macos/library/curl.php index fa031de5..c590c003 100644 --- a/src/SPC/builder/macos/library/curl.php +++ b/src/SPC/builder/macos/library/curl.php @@ -34,15 +34,13 @@ class curl extends MacOSLibraryBase */ public function patchBeforeBuild(): bool { - FileSystem::replaceFile( + FileSystem::replaceFileRegex( SOURCE_PATH . '/curl/CMakeLists.txt', - REPLACE_FILE_PREG, '/NOT COREFOUNDATION_FRAMEWORK/m', 'FALSE' ); - FileSystem::replaceFile( + FileSystem::replaceFileRegex( SOURCE_PATH . '/curl/CMakeLists.txt', - REPLACE_FILE_PREG, '/NOT SYSTEMCONFIGURATION_FRAMEWORK/m', 'FALSE' ); diff --git a/src/SPC/builder/macos/library/glfw.php b/src/SPC/builder/macos/library/glfw.php index 113bede1..c2ca2e74 100644 --- a/src/SPC/builder/macos/library/glfw.php +++ b/src/SPC/builder/macos/library/glfw.php @@ -4,11 +4,18 @@ declare(strict_types=1); namespace SPC\builder\macos\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; + class glfw extends MacOSLibraryBase { public const NAME = 'glfw'; - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + */ + protected function build(): void { // compile! shell()->cd(SOURCE_PATH . '/ext-glfw/vendor/glfw') diff --git a/src/SPC/builder/macos/library/icu.php b/src/SPC/builder/macos/library/icu.php index dd7967a1..11a5663e 100644 --- a/src/SPC/builder/macos/library/icu.php +++ b/src/SPC/builder/macos/library/icu.php @@ -8,7 +8,7 @@ class icu extends MacOSLibraryBase { public const NAME = 'icu'; - protected function build() + protected function build(): void { $root = BUILD_ROOT_PATH; shell()->cd($this->source_dir . '/source') diff --git a/src/SPC/builder/macos/library/libffi.php b/src/SPC/builder/macos/library/libffi.php index 2c67cb46..74bc9ce6 100644 --- a/src/SPC/builder/macos/library/libffi.php +++ b/src/SPC/builder/macos/library/libffi.php @@ -1,39 +1,30 @@ - * - * lwmbs is licensed under Mulan PSL v2. You can use this - * software according to the terms and conditions of the - * Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: - * - * http://license.coscl.org.cn/MulanPSL2 - * - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, - * WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * - * See the Mulan PSL v2 for more details. - */ declare(strict_types=1); namespace SPC\builder\macos\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; + class libffi extends MacOSLibraryBase { public const NAME = 'libffi'; - protected function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + protected function build(): void { - [$lib, , $destdir] = SEPARATED_PATH; + [, , $destdir] = SEPARATED_PATH; shell()->cd($this->source_dir) ->exec( "{$this->builder->configure_env} ./configure " . '--enable-static ' . '--disable-shared ' . - "--host={$this->builder->arch}-apple-darwin " . - "--target={$this->builder->arch}-apple-darwin " . + "--host={$this->builder->getOption('arch')}-apple-darwin " . + "--target={$this->builder->getOption('arch')}-apple-darwin " . '--prefix= ' // use prefix=/ ) ->exec('make clean') diff --git a/src/SPC/builder/macos/library/libmemcached.php b/src/SPC/builder/macos/library/libmemcached.php index c6b74bb4..6eb906f9 100644 --- a/src/SPC/builder/macos/library/libmemcached.php +++ b/src/SPC/builder/macos/library/libmemcached.php @@ -11,7 +11,7 @@ class libmemcached extends MacOSLibraryBase { public const NAME = 'libmemcached'; - public function build() + public function build(): void { $rootdir = BUILD_ROOT_PATH; diff --git a/src/SPC/builder/macos/library/libpng.php b/src/SPC/builder/macos/library/libpng.php index 7b05dcd9..868270d3 100644 --- a/src/SPC/builder/macos/library/libpng.php +++ b/src/SPC/builder/macos/library/libpng.php @@ -22,6 +22,7 @@ namespace SPC\builder\macos\library; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; class libpng extends MacOSLibraryBase { @@ -30,10 +31,11 @@ class libpng extends MacOSLibraryBase /** * @throws FileSystemException * @throws RuntimeException + * @throws WrongUsageException */ - protected function build() + protected function build(): void { - $optimizations = match ($this->builder->arch) { + $optimizations = match ($this->builder->getOption('arch')) { 'x86_64' => '--enable-intel-sse ', 'arm64' => '--enable-arm-neon ', default => '', @@ -43,7 +45,7 @@ class libpng extends MacOSLibraryBase ->exec('chmod +x ./install-sh') ->exec( "{$this->builder->configure_env} ./configure " . - "--host={$this->builder->gnu_arch}-apple-darwin " . + "--host={$this->builder->getOption('gnu-arch')}-apple-darwin " . '--disable-shared ' . '--enable-static ' . '--enable-hardware-optimizations ' . diff --git a/src/SPC/builder/macos/library/libxml2.php b/src/SPC/builder/macos/library/libxml2.php index 53fa1e52..1ebf0aa9 100644 --- a/src/SPC/builder/macos/library/libxml2.php +++ b/src/SPC/builder/macos/library/libxml2.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace SPC\builder\macos\library; +use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\FileSystem; @@ -13,14 +14,22 @@ class libxml2 extends MacOSLibraryBase /** * @throws RuntimeException + * @throws FileSystemException */ - protected function build() + protected function build(): void { + // macOS need to link iconv dynamically, we add it to extra-libs + $extra_libs = $this->builder->getOption('extra-libs', ''); + if (!str_contains($extra_libs, '-liconv')) { + $extra_libs .= ' -liconv'; + } + $this->builder->setOption('extra-libs', $extra_libs); + $enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF'; - $enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF'; + // $enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF'; $enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF'; - [$lib, $include, $destdir] = SEPARATED_PATH; + [, , $destdir] = SEPARATED_PATH; FileSystem::resetDir($this->source_dir . '/build'); shell()->cd($this->source_dir . '/build') diff --git a/src/SPC/builder/macos/library/nghttp2.php b/src/SPC/builder/macos/library/nghttp2.php index 62518c24..c1943840 100644 --- a/src/SPC/builder/macos/library/nghttp2.php +++ b/src/SPC/builder/macos/library/nghttp2.php @@ -20,11 +20,18 @@ declare(strict_types=1); namespace SPC\builder\macos\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; + class nghttp2 extends MacOSLibraryBase { public const NAME = 'nghttp2'; - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + */ + protected function build(): void { $args = $this->builder->makeAutoconfArgs(static::NAME, [ 'zlib' => null, @@ -49,7 +56,7 @@ class nghttp2 extends MacOSLibraryBase "{$this->builder->configure_env} " . ' ./configure ' . '--enable-static ' . '--disable-shared ' . - "--host={$this->builder->gnu_arch}-apple-darwin " . + "--host={$this->builder->getOption('gnu-arch')}-apple-darwin " . '--enable-lib-only ' . '--with-boost=no ' . $args . ' ' . diff --git a/src/SPC/builder/macos/library/openssl.php b/src/SPC/builder/macos/library/openssl.php index 89c778a0..8ac99b7f 100644 --- a/src/SPC/builder/macos/library/openssl.php +++ b/src/SPC/builder/macos/library/openssl.php @@ -20,11 +20,20 @@ declare(strict_types=1); namespace SPC\builder\macos\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; + class openssl extends MacOSLibraryBase { public const NAME = 'openssl'; - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + */ + protected function build(): void { [$lib,,$destdir] = SEPARATED_PATH; @@ -43,7 +52,7 @@ class openssl extends MacOSLibraryBase '--prefix=/ ' . // use prefix=/ "--libdir={$lib} " . '--openssldir=/System/Library/OpenSSL ' . - "darwin64-{$this->builder->arch}-cc" + "darwin64-{$this->builder->getOption('arch')}-cc" ) ->exec('make clean') ->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"") diff --git a/src/SPC/builder/traits/UnixBuilderTrait.php b/src/SPC/builder/traits/UnixBuilderTrait.php index 49b952d0..8dafe20a 100644 --- a/src/SPC/builder/traits/UnixBuilderTrait.php +++ b/src/SPC/builder/traits/UnixBuilderTrait.php @@ -7,31 +7,27 @@ namespace SPC\builder\traits; use SPC\builder\linux\LinuxBuilder; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; trait UnixBuilderTrait { - /** @var string 设置的命令前缀,设置为 set -x 可以在终端打印命令 */ - public string $set_x = 'set -x'; - - /** @var string C 编译器命令 */ - public string $cc; - - /** @var string C++ 编译器命令 */ - public string $cxx; - - /** @var string cflags 参数 */ + /** @var string cflags */ public string $arch_c_flags; - /** @var string C++ flags 参数 */ + /** @var string C++ flags */ public string $arch_cxx_flags; /** @var string cmake toolchain file */ public string $cmake_toolchain_file; - /** @var string configure 环境依赖的变量 */ + /** @var string configure environments */ public string $configure_env; + /** + * @throws WrongUsageException + * @throws FileSystemException + */ public function getAllStaticLibFiles(): array { $libs = []; @@ -125,7 +121,7 @@ trait UnixBuilderTrait } /** - * 清理编译好的文件 + * Run php clean * * @throws RuntimeException */ @@ -141,7 +137,7 @@ trait UnixBuilderTrait public function makeCmakeArgs(): string { [$lib, $include] = SEPARATED_PATH; - $extra = $this instanceof LinuxBuilder ? '-DCMAKE_C_COMPILER=' . $this->cc . ' ' : ''; + $extra = $this instanceof LinuxBuilder ? '-DCMAKE_C_COMPILER=' . $this->getOption('cc') . ' ' : ''; return $extra . '-DCMAKE_BUILD_TYPE=Release ' . '-DCMAKE_INSTALL_PREFIX=/ ' . "-DCMAKE_INSTALL_LIBDIR={$lib} " . diff --git a/src/SPC/builder/traits/UnixLibraryTrait.php b/src/SPC/builder/traits/UnixLibraryTrait.php index 4bc210fa..2f988945 100644 --- a/src/SPC/builder/traits/UnixLibraryTrait.php +++ b/src/SPC/builder/traits/UnixLibraryTrait.php @@ -7,6 +7,7 @@ namespace SPC\builder\traits; use SPC\builder\LibraryBase; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; trait UnixLibraryTrait @@ -16,6 +17,7 @@ trait UnixLibraryTrait /** * @throws RuntimeException * @throws FileSystemException + * @throws WrongUsageException */ public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string { @@ -43,6 +45,11 @@ trait UnixLibraryTrait return implode($sep, $ret); } + /** + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + */ public function makeAutoconfEnv(string $prefix = null): string { if ($prefix === null) { @@ -82,7 +89,7 @@ trait UnixLibraryTrait * remove libtool archive files * * @throws FileSystemException - * @throws RuntimeException + * @throws WrongUsageException */ public function cleanLaFiles(): void { diff --git a/src/SPC/builder/traits/UnixSystemUtilTrait.php b/src/SPC/builder/traits/UnixSystemUtilTrait.php index 6e25ab7a..5aa325ab 100644 --- a/src/SPC/builder/traits/UnixSystemUtilTrait.php +++ b/src/SPC/builder/traits/UnixSystemUtilTrait.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace SPC\builder\traits; +use SPC\exception\FileSystemException; use SPC\store\FileSystem; /** @@ -14,11 +15,12 @@ trait UnixSystemUtilTrait /** * 生成 toolchain.cmake,用于 cmake 构建 * - * @param string $os 操作系统代号 - * @param string $target_arch 目标架构 - * @param string $cflags CFLAGS 参数 - * @param null|string $cc CC 参数(默认空) - * @param null|string $cxx CXX 参数(默认空) + * @param string $os 操作系统代号 + * @param string $target_arch 目标架构 + * @param string $cflags CFLAGS 参数 + * @param null|string $cc CC 参数(默认空) + * @param null|string $cxx CXX 参数(默认空) + * @throws FileSystemException */ public static function makeCmakeToolchainFile( string $os, @@ -76,4 +78,20 @@ CMAKE; } return null; } + + /** + * @param array $vars Variables, like: ["CFLAGS" => "-Ixxx"] + * @return string like: CFLAGS="-Ixxx" + */ + public static function makeEnvVarString(array $vars): string + { + $str = ''; + foreach ($vars as $key => $value) { + if ($str !== '') { + $str .= ' '; + } + $str .= $key . '=' . escapeshellarg($value); + } + return $str; + } } diff --git a/src/SPC/builder/unix/library/brotli.php b/src/SPC/builder/unix/library/brotli.php index 21869601..3dae0814 100644 --- a/src/SPC/builder/unix/library/brotli.php +++ b/src/SPC/builder/unix/library/brotli.php @@ -4,10 +4,16 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\store\FileSystem; trait brotli { + /** + * @throws FileSystemException + * @throws RuntimeException + */ protected function build(): void { FileSystem::resetDir($this->source_dir . '/build-dir'); diff --git a/src/SPC/builder/unix/library/curl.php b/src/SPC/builder/unix/library/curl.php index fe03acf6..aa5ef28a 100644 --- a/src/SPC/builder/unix/library/curl.php +++ b/src/SPC/builder/unix/library/curl.php @@ -4,11 +4,17 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\store\FileSystem; trait curl { - protected function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + protected function build(): void { $extra = ''; // lib:openssl diff --git a/src/SPC/builder/unix/library/freetype.php b/src/SPC/builder/unix/library/freetype.php index 18b77997..ee7bc9aa 100644 --- a/src/SPC/builder/unix/library/freetype.php +++ b/src/SPC/builder/unix/library/freetype.php @@ -4,11 +4,19 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; trait freetype { - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + */ + protected function build(): void { $suggested = $this->builder->getLib('libpng') ? '--with-png' : '--without-png'; $suggested .= ' '; @@ -27,9 +35,8 @@ trait freetype ->exec("make -j{$this->builder->concurrency}") ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['freetype2.pc']); - FileSystem::replaceFile( + FileSystem::replaceFileStr( BUILD_ROOT_PATH . '/lib/pkgconfig/freetype2.pc', - REPLACE_FILE_STR, ' -L/lib ', ' -L' . BUILD_ROOT_PATH . '/lib ' ); diff --git a/src/SPC/builder/unix/library/gmp.php b/src/SPC/builder/unix/library/gmp.php index 934e9b02..bc95a3eb 100644 --- a/src/SPC/builder/unix/library/gmp.php +++ b/src/SPC/builder/unix/library/gmp.php @@ -4,9 +4,16 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; + trait gmp { - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + */ + protected function build(): void { shell()->cd($this->source_dir) ->exec( diff --git a/src/SPC/builder/unix/library/imagemagick.php b/src/SPC/builder/unix/library/imagemagick.php index 6f1fd461..f1530b76 100644 --- a/src/SPC/builder/unix/library/imagemagick.php +++ b/src/SPC/builder/unix/library/imagemagick.php @@ -4,10 +4,16 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\store\FileSystem; trait imagemagick { + /** + * @throws RuntimeException + * @throws FileSystemException + */ protected function build(): void { $extra = '--without-jxl --without-xml --without-zstd --without-x --disable-openmp '; @@ -46,9 +52,8 @@ trait imagemagick ]; $this->patchPkgconfPrefix($filelist); foreach ($filelist as $file) { - FileSystem::replaceFile( + FileSystem::replaceFileRegex( BUILD_LIB_PATH . '/pkgconfig/' . $file, - REPLACE_FILE_PREG, '#includearchdir=/include/ImageMagick-7#m', 'includearchdir=${prefix}/include/ImageMagick-7' ); diff --git a/src/SPC/builder/unix/library/libavif.php b/src/SPC/builder/unix/library/libavif.php index ac27a5d9..56b17bdb 100644 --- a/src/SPC/builder/unix/library/libavif.php +++ b/src/SPC/builder/unix/library/libavif.php @@ -4,11 +4,19 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; trait libavif { - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + */ + protected function build(): void { // CMake needs a clean build directory FileSystem::resetDir($this->source_dir . '/build'); diff --git a/src/SPC/builder/unix/library/libevent.php b/src/SPC/builder/unix/library/libevent.php index 66de81b7..59e59f53 100644 --- a/src/SPC/builder/unix/library/libevent.php +++ b/src/SPC/builder/unix/library/libevent.php @@ -4,11 +4,17 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\store\FileSystem; trait libevent { - protected function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + protected function build(): void { // CMake needs a clean build directory FileSystem::resetDir($this->source_dir . '/build'); @@ -29,6 +35,5 @@ trait libevent ) ->exec("cmake --build . -j {$this->builder->concurrency}") ->exec('make install'); - // patch pkgconfig } } diff --git a/src/SPC/builder/unix/library/libiconv.php b/src/SPC/builder/unix/library/libiconv.php index 12ca1ada..dacfab1e 100644 --- a/src/SPC/builder/unix/library/libiconv.php +++ b/src/SPC/builder/unix/library/libiconv.php @@ -6,7 +6,7 @@ namespace SPC\builder\unix\library; trait libiconv { - protected function build() + protected function build(): void { [,,$destdir] = SEPARATED_PATH; diff --git a/src/SPC/builder/unix/library/libjpeg.php b/src/SPC/builder/unix/library/libjpeg.php index 65da0c08..88845c49 100644 --- a/src/SPC/builder/unix/library/libjpeg.php +++ b/src/SPC/builder/unix/library/libjpeg.php @@ -4,11 +4,19 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\FileSystem; trait libjpeg { - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + */ + protected function build(): void { // CMake needs a clean build directory FileSystem::resetDir($this->source_dir . '/build'); diff --git a/src/SPC/builder/unix/library/libsodium.php b/src/SPC/builder/unix/library/libsodium.php index 2f093d03..f12727d7 100644 --- a/src/SPC/builder/unix/library/libsodium.php +++ b/src/SPC/builder/unix/library/libsodium.php @@ -6,7 +6,7 @@ namespace SPC\builder\unix\library; trait libsodium { - protected function build() + protected function build(): void { $root = BUILD_ROOT_PATH; shell()->cd($this->source_dir) diff --git a/src/SPC/builder/unix/library/libssh2.php b/src/SPC/builder/unix/library/libssh2.php index c0dccdf2..04aa5882 100644 --- a/src/SPC/builder/unix/library/libssh2.php +++ b/src/SPC/builder/unix/library/libssh2.php @@ -4,11 +4,17 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\store\FileSystem; trait libssh2 { - protected function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + protected function build(): void { $enable_zlib = $this->builder->getLib('zlib') !== null ? 'ON' : 'OFF'; diff --git a/src/SPC/builder/unix/library/libwebp.php b/src/SPC/builder/unix/library/libwebp.php index f6e7a596..ce7bd58e 100644 --- a/src/SPC/builder/unix/library/libwebp.php +++ b/src/SPC/builder/unix/library/libwebp.php @@ -4,9 +4,18 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; + trait libwebp { - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + */ + protected function build(): void { [,,$destdir] = SEPARATED_PATH; diff --git a/src/SPC/builder/unix/library/libyaml.php b/src/SPC/builder/unix/library/libyaml.php index 58ea9fe3..b35cd25f 100644 --- a/src/SPC/builder/unix/library/libyaml.php +++ b/src/SPC/builder/unix/library/libyaml.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\FileSystem; @@ -11,8 +12,9 @@ trait libyaml { /** * @throws RuntimeException + * @throws FileSystemException */ - protected function build() + protected function build(): void { // prepare cmake/config.h.in if (!is_file(SOURCE_PATH . '/libyaml/cmake/config.h.in')) { diff --git a/src/SPC/builder/unix/library/libzip.php b/src/SPC/builder/unix/library/libzip.php index b4b8f99f..f21678ae 100644 --- a/src/SPC/builder/unix/library/libzip.php +++ b/src/SPC/builder/unix/library/libzip.php @@ -4,11 +4,17 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\store\FileSystem; trait libzip { - protected function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + protected function build(): void { $extra = ''; // lib:bzip2 diff --git a/src/SPC/builder/unix/library/ncurses.php b/src/SPC/builder/unix/library/ncurses.php index f09246eb..f3ec2636 100644 --- a/src/SPC/builder/unix/library/ncurses.php +++ b/src/SPC/builder/unix/library/ncurses.php @@ -6,7 +6,7 @@ namespace SPC\builder\unix\library; trait ncurses { - protected function build() + protected function build(): void { shell()->cd($this->source_dir) ->exec( diff --git a/src/SPC/builder/unix/library/onig.php b/src/SPC/builder/unix/library/onig.php index 72969d79..e9414ab2 100644 --- a/src/SPC/builder/unix/library/onig.php +++ b/src/SPC/builder/unix/library/onig.php @@ -4,9 +4,16 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; + trait onig { - protected function build() + /** + * @throws FileSystemException + * @throws RuntimeException + */ + protected function build(): void { [,,$destdir] = SEPARATED_PATH; diff --git a/src/SPC/builder/unix/library/pkgconfig.php b/src/SPC/builder/unix/library/pkgconfig.php index 6cc475d9..822371a8 100644 --- a/src/SPC/builder/unix/library/pkgconfig.php +++ b/src/SPC/builder/unix/library/pkgconfig.php @@ -6,20 +6,16 @@ namespace SPC\builder\unix\library; trait pkgconfig { - protected function build() + protected function build(): void { $macos_env = 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig/" ' . - "CC='{$this->builder->cc}' " . - "CXX='{$this->builder->cxx}' " . + "CC='{$this->builder->getOption('cc')}' " . + "CXX='{$this->builder->getOption('cxx')}' " . "CFLAGS='{$this->builder->arch_c_flags} -Wimplicit-function-declaration' "; $linux_env = 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig" ' . - "CC='{$this->builder->cc}' " . - "CXX='{$this->builder->cxx}' "; + "CC='{$this->builder->getOption('cc')}' " . + "CXX='{$this->builder->getOption('cxx')}' "; - $extra = match (PHP_OS_FAMILY) { - 'Darwin' => '', - default => '--with-internal-glib ', - }; shell()->cd($this->source_dir) ->exec( match (PHP_OS_FAMILY) { @@ -29,7 +25,7 @@ trait pkgconfig './configure ' . '--disable-shared ' . '--enable-static ' . - $extra . + '--with-internal-glib ' . '--prefix=' . BUILD_ROOT_PATH . ' ' . '--without-sysroot ' . '--without-system-include-path ' . diff --git a/src/SPC/builder/unix/library/postgresql.php b/src/SPC/builder/unix/library/postgresql.php index 40b39c41..b2fa4b27 100644 --- a/src/SPC/builder/unix/library/postgresql.php +++ b/src/SPC/builder/unix/library/postgresql.php @@ -15,7 +15,7 @@ trait postgresql * @throws RuntimeException * @throws FileSystemException */ - protected function build() + protected function build(): void { $builddir = BUILD_ROOT_PATH; $env = $this->builder->configure_env; diff --git a/src/SPC/builder/unix/library/readline.php b/src/SPC/builder/unix/library/readline.php index 31ea26aa..fc865238 100644 --- a/src/SPC/builder/unix/library/readline.php +++ b/src/SPC/builder/unix/library/readline.php @@ -4,9 +4,16 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; + trait readline { - protected function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + protected function build(): void { shell()->cd($this->source_dir) ->exec( diff --git a/src/SPC/builder/unix/library/sqlite.php b/src/SPC/builder/unix/library/sqlite.php index add31e53..f9947df7 100644 --- a/src/SPC/builder/unix/library/sqlite.php +++ b/src/SPC/builder/unix/library/sqlite.php @@ -6,7 +6,7 @@ namespace SPC\builder\unix\library; trait sqlite { - protected function build() + protected function build(): void { shell()->cd($this->source_dir) ->exec("{$this->builder->configure_env} ./configure --enable-static --disable-shared --prefix=") diff --git a/src/SPC/builder/unix/library/xz.php b/src/SPC/builder/unix/library/xz.php index 006ed6c2..1f214b3a 100644 --- a/src/SPC/builder/unix/library/xz.php +++ b/src/SPC/builder/unix/library/xz.php @@ -4,16 +4,23 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; + trait xz { - public function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + public function build(): void { shell()->cd($this->source_dir) ->exec( "{$this->builder->configure_env} ./configure " . '--enable-static ' . '--disable-shared ' . - "--host={$this->builder->gnu_arch}-unknown-linux " . + "--host={$this->builder->getOption('gnu-arch')}-unknown-linux " . '--disable-scripts ' . '--disable-doc ' . '--with-libiconv ' . diff --git a/src/SPC/builder/unix/library/zlib.php b/src/SPC/builder/unix/library/zlib.php index 542d918d..5dd0ee10 100644 --- a/src/SPC/builder/unix/library/zlib.php +++ b/src/SPC/builder/unix/library/zlib.php @@ -4,9 +4,16 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; + trait zlib { - protected function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + protected function build(): void { [,,$destdir] = SEPARATED_PATH; diff --git a/src/SPC/builder/unix/library/zstd.php b/src/SPC/builder/unix/library/zstd.php index f6b4ea32..de375b25 100644 --- a/src/SPC/builder/unix/library/zstd.php +++ b/src/SPC/builder/unix/library/zstd.php @@ -4,11 +4,17 @@ declare(strict_types=1); namespace SPC\builder\unix\library; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\store\FileSystem; trait zstd { - protected function build() + /** + * @throws RuntimeException + * @throws FileSystemException + */ + protected function build(): void { FileSystem::resetDir($this->source_dir . '/build/cmake/build'); shell()->cd($this->source_dir . '/build/cmake/build') diff --git a/src/SPC/command/BaseCommand.php b/src/SPC/command/BaseCommand.php index fe3775e1..998336e9 100644 --- a/src/SPC/command/BaseCommand.php +++ b/src/SPC/command/BaseCommand.php @@ -17,16 +17,8 @@ abstract class BaseCommand extends Command { protected bool $no_motd = false; - /** - * 输入 - */ protected InputInterface $input; - /** - * 输出 - * - * 一般来说同样会是 ConsoleOutputInterface - */ protected OutputInterface $output; public function __construct(string $name = null) @@ -36,12 +28,12 @@ abstract class BaseCommand extends Command $this->addOption('no-motd', null, null, 'Disable motd'); } - public function initialize(InputInterface $input, OutputInterface $output) + public function initialize(InputInterface $input, OutputInterface $output): void { if ($input->getOption('no-motd')) { $this->no_motd = true; } - // 注册全局错误处理器 + set_error_handler(static function ($error_no, $error_msg, $error_file, $error_line) { $tips = [ E_WARNING => ['PHP Warning: ', 'warning'], @@ -77,6 +69,9 @@ abstract class BaseCommand extends Command } } + /** + * @throws WrongUsageException + */ abstract public function handle(): int; protected function execute(InputInterface $input, OutputInterface $output): int @@ -93,7 +88,6 @@ abstract class BaseCommand extends Command } return static::FAILURE; } catch (\Throwable $e) { - // 不开 debug 模式就不要再显示复杂的调试栈信息了 if ($this->getOption('debug')) { ExceptionHandler::getInstance()->handle($e); } else { @@ -118,11 +112,6 @@ abstract class BaseCommand extends Command return $this->input->getArgument($name); } - /** - * 是否应该执行 - * - * @return bool 返回 true 以继续执行,返回 false 以中断执行 - */ protected function shouldExecute(): bool { return true; diff --git a/src/SPC/command/BuildCliCommand.php b/src/SPC/command/BuildCliCommand.php index f1427ed6..517f30d7 100644 --- a/src/SPC/command/BuildCliCommand.php +++ b/src/SPC/command/BuildCliCommand.php @@ -18,7 +18,7 @@ use ZM\Logger\ConsoleColor; #[AsCommand('build', 'build CLI binary')] class BuildCliCommand extends BuildCommand { - public function configure() + public function configure(): void { $this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated'); $this->addOption('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', ''); @@ -29,17 +29,16 @@ class BuildCliCommand extends BuildCommand $this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions'); $this->addOption('enable-zts', null, null, 'enable ZTS support'); $this->addOption('with-hardcoded-ini', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Patch PHP source code, inject hardcoded INI'); + $this->addOption('with-micro-fake-cli', null, null, 'Enable phpmicro fake cli'); } public function handle(): int { - // 从参数中获取要编译的 libraries,并转换为数组 + // transform string to array $libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs')))); - // 从参数中获取要编译的 extensions,并转换为数组 + // transform string to array $extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions')))); - define('BUILD_ALL_STATIC', true); - $rule = BUILD_TARGET_NONE; $rule = $rule | ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE); $rule = $rule | ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE); @@ -54,9 +53,9 @@ class BuildCliCommand extends BuildCommand return static::FAILURE; } try { - // 构建对象 + // create builder $builder = BuilderProvider::makeBuilderByInput($this->input); - // 根据提供的扩展列表获取依赖库列表并编译 + // calculate dependencies [$extensions, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps($extensions, $libraries); /* @phpstan-ignore-next-line */ logger()->info('Build target: ' . ConsoleColor::yellow($builder->getBuildTypeName($rule))); @@ -68,12 +67,11 @@ class BuildCliCommand extends BuildCommand logger()->warning('some extensions will be enabled due to dependencies: ' . implode(',', $not_included)); } sleep(2); - // 编译和检查库是否完整 + // compile libraries $builder->buildLibs($libraries); - // 执行扩展检测 + // check extensions $builder->proveExts($extensions); - // strip - $builder->setStrip(!$this->getOption('no-strip')); + // Process -I option $custom_ini = []; foreach ($this->input->getOption('with-hardcoded-ini') as $value) { @@ -84,11 +82,15 @@ class BuildCliCommand extends BuildCommand if (!empty($custom_ini)) { SourcePatcher::patchHardcodedINI($custom_ini); } - // 构建 - $builder->buildPHP($rule, $this->getOption('bloat')); - // 统计时间 + + // start to build + $builder->buildPHP($rule); + + // compile stopwatch :P $time = round(microtime(true) - START_TIME, 3); logger()->info('Build complete, used ' . $time . ' s !'); + + // ---------- When using bin/spc-alpine-docker, the build root path is different from the host system ---------- $build_root_path = BUILD_ROOT_PATH; $cwd = getcwd(); $fixed = ''; @@ -106,15 +108,17 @@ class BuildCliCommand extends BuildCommand if (($rule & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) { logger()->info('Static php-fpm binary path' . $fixed . ': ' . $build_root_path . '/bin/php-fpm'); } - // 导出相关元数据 + + // export metadata file_put_contents(BUILD_ROOT_PATH . '/build-extensions.json', json_encode($extensions, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); file_put_contents(BUILD_ROOT_PATH . '/build-libraries.json', json_encode($libraries, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); - // 导出 LICENSE + // export licenses $dumper = new LicenseDumper(); $dumper->addExts($extensions)->addLibs($libraries)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license'); logger()->info('License path' . $fixed . ': ' . $build_root_path . '/license/'); return static::SUCCESS; } catch (WrongUsageException $e) { + // WrongUsageException is not an exception, it's a user error, so we just print the error message logger()->critical($e->getMessage()); return static::FAILURE; } catch (\Throwable $e) { diff --git a/src/SPC/command/BuildCommand.php b/src/SPC/command/BuildCommand.php index 11507546..8a721189 100644 --- a/src/SPC/command/BuildCommand.php +++ b/src/SPC/command/BuildCommand.php @@ -12,7 +12,6 @@ abstract class BuildCommand extends BaseCommand { parent::__construct($name); - // 根据运行的操作系统分配允许不同的命令行参数,Windows 需要额外的 VS 和 SDK等,*nix 需要提供架构 switch (PHP_OS_FAMILY) { case 'Windows': $this->addOption('with-sdk-binary-dir', null, InputOption::VALUE_REQUIRED, 'path to binary sdk'); @@ -29,9 +28,7 @@ abstract class BuildCommand extends BaseCommand break; } - // 是否在编译 make 前清除旧的文件 $this->addOption('with-clean', null, null, 'fresh build, `make clean` before `make`'); - // 是否采用强制链接,让链接器强制加载静态库文件 $this->addOption('bloat', null, null, 'add all libraries into binary'); } } diff --git a/src/SPC/command/BuildLibsCommand.php b/src/SPC/command/BuildLibsCommand.php index cc1471eb..be49f86a 100644 --- a/src/SPC/command/BuildLibsCommand.php +++ b/src/SPC/command/BuildLibsCommand.php @@ -15,14 +15,14 @@ use Symfony\Component\Console\Output\OutputInterface; #[AsCommand('build:libs', 'Build dependencies')] class BuildLibsCommand extends BuildCommand { - public function configure() + public function configure(): void { $this->addArgument('libraries', InputArgument::REQUIRED, 'The libraries will be compiled, comma separated'); $this->addOption('clean', null, null, 'Clean old download cache and source before fetch'); $this->addOption('all', 'A', null, 'Build all libs that static-php-cli needed'); } - public function initialize(InputInterface $input, OutputInterface $output) + public function initialize(InputInterface $input, OutputInterface $output): void { // --all 等于 "" if ($input->getOption('all')) { diff --git a/src/SPC/command/DeployCommand.php b/src/SPC/command/DeployCommand.php index 5dd5ddee..b5353619 100644 --- a/src/SPC/command/DeployCommand.php +++ b/src/SPC/command/DeployCommand.php @@ -16,7 +16,7 @@ use function Laravel\Prompts\text; #[AsCommand('deploy', 'Deploy static-php-cli self to an .phar application')] class DeployCommand extends BaseCommand { - public function configure() + public function configure(): void { $this->addArgument('target', InputArgument::OPTIONAL, 'The file or directory to pack.'); $this->addOption('auto-phar-fix', null, InputOption::VALUE_NONE, 'Automatically fix ini option.'); @@ -25,6 +25,9 @@ class DeployCommand extends BaseCommand $this->addOption('with-dev', 'd', InputOption::VALUE_NONE, 'Automatically use dev composer dependencies'); } + /** + * @throws \PharException + */ public function handle(): int { $composer = require ROOT_DIR . '/vendor/composer/installed.php'; @@ -149,9 +152,9 @@ class DeployCommand extends BaseCommand return static::SUCCESS; } - private function progress(int $max = 0): ProgressBar + private function progress(): ProgressBar { - $progress = new ProgressBar($this->output, $max); + $progress = new ProgressBar($this->output, 0); $progress->setBarCharacter('⚬'); $progress->setEmptyBarCharacter('⚬'); $progress->setProgressCharacter('➤'); diff --git a/src/SPC/command/DoctorCommand.php b/src/SPC/command/DoctorCommand.php index eacaf26b..74fc48b8 100644 --- a/src/SPC/command/DoctorCommand.php +++ b/src/SPC/command/DoctorCommand.php @@ -10,7 +10,7 @@ use Symfony\Component\Console\Attribute\AsCommand; #[AsCommand('doctor', 'Diagnose whether the current environment can compile normally')] class DoctorCommand extends BaseCommand { - public function configure() + public function configure(): void { $this->addOption('auto-fix', null, null, 'Automatically fix failed items (if possible)'); } diff --git a/src/SPC/command/DownloadCommand.php b/src/SPC/command/DownloadCommand.php index 9d2e05a8..b1977459 100644 --- a/src/SPC/command/DownloadCommand.php +++ b/src/SPC/command/DownloadCommand.php @@ -23,7 +23,7 @@ class DownloadCommand extends BaseCommand protected string $php_major_ver; - public function configure() + public function configure(): void { $this->addArgument('sources', InputArgument::REQUIRED, 'The sources will be compiled, comma separated'); $this->addOption('shallow-clone', null, null, 'Clone shallow'); @@ -35,7 +35,7 @@ class DownloadCommand extends BaseCommand $this->addOption('from-zip', 'Z', InputOption::VALUE_REQUIRED, 'Fetch from zip archive'); } - public function initialize(InputInterface $input, OutputInterface $output) + public function initialize(InputInterface $input, OutputInterface $output): void { // --all 等于 "" "",也就是所有东西都要下载 if ($input->getOption('all') || $input->getOption('clean') || $input->getOption('from-zip')) { diff --git a/src/SPC/command/DumpLicenseCommand.php b/src/SPC/command/DumpLicenseCommand.php index ea4d377a..98b5a4fe 100644 --- a/src/SPC/command/DumpLicenseCommand.php +++ b/src/SPC/command/DumpLicenseCommand.php @@ -18,7 +18,7 @@ use Symfony\Component\Console\Input\InputOption; #[AsCommand('dump-license', 'Dump licenses for required libraries')] class DumpLicenseCommand extends BaseCommand { - public function configure() + public function configure(): void { $this->addOption('by-extensions', null, InputOption::VALUE_REQUIRED, 'Dump by extensions and related libraries', null); $this->addOption('without-php', null, InputOption::VALUE_NONE, 'Dump without php-src'); @@ -39,7 +39,7 @@ class DumpLicenseCommand extends BaseCommand // 从参数中获取要编译的 extensions,并转换为数组 $extensions = array_map('trim', array_filter(explode(',', $this->getOption('by-extensions')))); // 根据提供的扩展列表获取依赖库列表并编译 - [$extensions, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps($extensions); + [$extensions, $libraries] = DependencyUtil::getExtLibsByDeps($extensions); $dumper->addExts($extensions); $dumper->addLibs($libraries); if (!$this->getOption('without-php')) { diff --git a/src/SPC/command/ExtractCommand.php b/src/SPC/command/ExtractCommand.php index e9c69fdd..84768866 100644 --- a/src/SPC/command/ExtractCommand.php +++ b/src/SPC/command/ExtractCommand.php @@ -5,6 +5,9 @@ declare(strict_types=1); namespace SPC\command; use SPC\builder\traits\UnixSystemUtilTrait; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\SourceExtractor; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; @@ -14,13 +17,16 @@ class ExtractCommand extends BaseCommand { use UnixSystemUtilTrait; - protected string $php_major_ver; - - public function configure() + public function configure(): void { $this->addArgument('sources', InputArgument::REQUIRED, 'The sources will be compiled, comma separated'); } + /** + * @throws WrongUsageException + * @throws FileSystemException + * @throws RuntimeException + */ public function handle(): int { $sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources')))); diff --git a/src/SPC/command/MicroCombineCommand.php b/src/SPC/command/MicroCombineCommand.php index 2c209033..1b14979a 100644 --- a/src/SPC/command/MicroCombineCommand.php +++ b/src/SPC/command/MicroCombineCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Input\InputOption; #[AsCommand('micro:combine', 'Combine micro.sfx and php code together')] class MicroCombineCommand extends BaseCommand { - public function configure() + public function configure(): void { $this->addArgument('file', InputArgument::REQUIRED, 'The php or phar file to be combined'); $this->addOption('with-micro', 'M', InputOption::VALUE_REQUIRED, 'Customize your micro.sfx file'); diff --git a/src/SPC/command/dev/AllExtCommand.php b/src/SPC/command/dev/AllExtCommand.php index c8a18495..7c77b5c5 100644 --- a/src/SPC/command/dev/AllExtCommand.php +++ b/src/SPC/command/dev/AllExtCommand.php @@ -5,17 +5,21 @@ declare(strict_types=1); namespace SPC\command\dev; use SPC\command\BaseCommand; +use SPC\exception\FileSystemException; use SPC\store\Config; use Symfony\Component\Console\Attribute\AsCommand; #[AsCommand('dev:ext-all', 'Dev command', ['list-ext'])] class AllExtCommand extends BaseCommand { - public function configure() + public function configure(): void { $this->addOption('line', 'l', null, 'Show with separate lines'); } + /** + * @throws FileSystemException + */ public function handle(): int { $this->output->writeln(implode($this->input->getOption('line') ? PHP_EOL : ',', array_keys(Config::getExts()))); diff --git a/src/SPC/command/dev/ExtInfoCommand.php b/src/SPC/command/dev/ExtInfoCommand.php index 1175b2af..fbab7db6 100644 --- a/src/SPC/command/dev/ExtInfoCommand.php +++ b/src/SPC/command/dev/ExtInfoCommand.php @@ -5,6 +5,9 @@ declare(strict_types=1); namespace SPC\command\dev; use SPC\command\BaseCommand; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\Config; use SPC\util\DependencyUtil; use Symfony\Component\Console\Attribute\AsCommand; @@ -13,11 +16,16 @@ use Symfony\Component\Console\Input\InputArgument; #[AsCommand('dev:ext-info', 'Dev command')] class ExtInfoCommand extends BaseCommand { - public function configure() + public function configure(): void { $this->addArgument('extensions', InputArgument::REQUIRED, 'The extension name you need to get info'); } + /** + * @throws WrongUsageException + * @throws FileSystemException + * @throws RuntimeException + */ public function handle(): int { $extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions')))); diff --git a/src/SPC/command/dev/PhpVerCommand.php b/src/SPC/command/dev/PhpVerCommand.php index b307f1c5..57374753 100644 --- a/src/SPC/command/dev/PhpVerCommand.php +++ b/src/SPC/command/dev/PhpVerCommand.php @@ -12,7 +12,7 @@ use Symfony\Component\Console\Output\OutputInterface; #[AsCommand('dev:php-ver', 'Dev command')] class PhpVerCommand extends BaseCommand { - public function initialize(InputInterface $input, OutputInterface $output) + public function initialize(InputInterface $input, OutputInterface $output): void { $this->no_motd = true; parent::initialize($input, $output); diff --git a/src/SPC/command/dev/SortConfigCommand.php b/src/SPC/command/dev/SortConfigCommand.php index 39e32f31..11360fd0 100644 --- a/src/SPC/command/dev/SortConfigCommand.php +++ b/src/SPC/command/dev/SortConfigCommand.php @@ -18,7 +18,7 @@ use Symfony\Component\Console\Input\InputArgument; #[AsCommand('dev:sort-config', 'After config edited, sort it by alphabet', ['sort-config'])] class SortConfigCommand extends BaseCommand { - public function configure() + public function configure(): void { $this->addArgument('config-name', InputArgument::REQUIRED, 'Your config to be sorted, you can sort "lib", "source" and "ext".'); } diff --git a/src/SPC/doctor/CheckListHandler.php b/src/SPC/doctor/CheckListHandler.php index f627e632..414c89f9 100644 --- a/src/SPC/doctor/CheckListHandler.php +++ b/src/SPC/doctor/CheckListHandler.php @@ -24,11 +24,14 @@ class CheckListHandler * @throws FileSystemException * @throws RuntimeException */ - public function __construct(private InputInterface $input, private OutputInterface $output, bool $include_manual = false) + public function __construct(private readonly InputInterface $input, private readonly OutputInterface $output, bool $include_manual = false) { $this->loadCheckList($include_manual); } + /** + * @throws RuntimeException + */ public function runSingleCheck(string $item_name, int $fix_policy = FIX_POLICY_DIE): void { foreach ($this->check_list as $item) { @@ -127,7 +130,10 @@ class CheckListHandler usort($this->check_list, fn ($a, $b) => $a->level > $b->level ? -1 : ($a->level == $b->level ? 0 : 1)); } - private function emitFix(CheckResult $result) + /** + * @throws RuntimeException + */ + private function emitFix(CheckResult $result): void { pcntl_signal(SIGINT, function () { $this->output->writeln('You cancelled fix'); diff --git a/src/SPC/doctor/CheckResult.php b/src/SPC/doctor/CheckResult.php index 4a1394d4..112c14ae 100644 --- a/src/SPC/doctor/CheckResult.php +++ b/src/SPC/doctor/CheckResult.php @@ -6,7 +6,7 @@ namespace SPC\doctor; class CheckResult { - public function __construct(private bool $ok, private ?string $message = null, private string $fix_item = '', private array $fix_params = []) + public function __construct(private readonly bool $ok, private readonly ?string $message = null, private string $fix_item = '', private array $fix_params = []) { } @@ -40,7 +40,7 @@ class CheckResult return $this->ok; } - public function setFixItem(string $fix_item = '', array $fix_params = []) + public function setFixItem(string $fix_item = '', array $fix_params = []): void { $this->fix_item = $fix_item; $this->fix_params = $fix_params; diff --git a/src/SPC/doctor/item/LinuxMuslCheck.php b/src/SPC/doctor/item/LinuxMuslCheck.php index c9cb956b..05fa2bd2 100644 --- a/src/SPC/doctor/item/LinuxMuslCheck.php +++ b/src/SPC/doctor/item/LinuxMuslCheck.php @@ -12,11 +12,11 @@ use SPC\exception\RuntimeException; class LinuxMuslCheck { + /** @noinspection PhpUnused */ #[AsCheckItem('if musl-libc is installed', limit_os: 'Linux')] public function checkMusl(): ?CheckResult { $file = '/lib/ld-musl-x86_64.so.1'; - $result = null; if (file_exists($file)) { return CheckResult::ok(); } @@ -29,6 +29,10 @@ class LinuxMuslCheck }; } + /** + * @throws RuntimeException + * @noinspection PhpUnused + */ #[AsFixItem('fix-musl')] public function fixMusl(array $distro): bool { diff --git a/src/SPC/doctor/item/LinuxToolCheckList.php b/src/SPC/doctor/item/LinuxToolCheckList.php index f563e79f..68ab6f79 100644 --- a/src/SPC/doctor/item/LinuxToolCheckList.php +++ b/src/SPC/doctor/item/LinuxToolCheckList.php @@ -30,6 +30,7 @@ class LinuxToolCheckList 'bzip2', 'cmake', 'patch', ]; + /** @noinspection PhpUnused */ #[AsCheckItem('if necessary tools are installed', limit_os: 'Linux')] public function checkCliTools(): ?CheckResult { @@ -54,6 +55,7 @@ class LinuxToolCheckList return CheckResult::ok(); } + /** @noinspection PhpUnused */ #[AsCheckItem('if necessary packages are installed', limit_os: 'Linux')] public function checkSystemOSPackages(): ?CheckResult { @@ -67,6 +69,10 @@ class LinuxToolCheckList return CheckResult::ok(); } + /** + * @throws RuntimeException + * @noinspection PhpUnused + */ #[AsFixItem('install-linux-tools')] public function fixBuildTools(array $distro, array $missing): bool { diff --git a/src/SPC/exception/ExceptionHandler.php b/src/SPC/exception/ExceptionHandler.php index 0f03efba..f4bebbf1 100644 --- a/src/SPC/exception/ExceptionHandler.php +++ b/src/SPC/exception/ExceptionHandler.php @@ -6,9 +6,9 @@ namespace SPC\exception; class ExceptionHandler { - protected $whoops; + protected mixed $whoops; - private static $obj; + private static ?ExceptionHandler $obj = null; private function __construct() { @@ -32,14 +32,6 @@ class ExceptionHandler return self::$obj; } - public function getWhoops() - { - return $this->whoops; - } - - /** - * 处理异常 - */ public function handle(\Throwable $e): void { if (is_null($this->whoops)) { diff --git a/src/SPC/store/Config.php b/src/SPC/store/Config.php index 2f6e992b..3a449dfd 100644 --- a/src/SPC/store/Config.php +++ b/src/SPC/store/Config.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace SPC\store; use SPC\exception\FileSystemException; -use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; /** @@ -83,7 +82,6 @@ class Config /** * @throws FileSystemException - * @throws RuntimeException * @throws WrongUsageException */ public static function getExt(string $name, ?string $key = null, mixed $default = null) @@ -126,6 +124,9 @@ class Config return self::$ext; } + /** + * @throws FileSystemException + */ public static function getSources(): array { if (self::$source === null) { diff --git a/src/SPC/store/CurlHook.php b/src/SPC/store/CurlHook.php index 2cf7b15b..ce27cf3d 100644 --- a/src/SPC/store/CurlHook.php +++ b/src/SPC/store/CurlHook.php @@ -13,7 +13,7 @@ class CurlHook * @param string $url 修改的链接 * @param array $headers 修改的 headers */ - public static function setupGithubToken(string &$method, string &$url, array &$headers): void + public static function setupGithubToken(string $method, string $url, array &$headers): void { if (!getenv('GITHUB_TOKEN')) { return; diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index d8aada0f..997545f7 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -4,23 +4,22 @@ declare(strict_types=1); namespace SPC\store; -use JetBrains\PhpStorm\ArrayShape; use SPC\exception\DownloaderException; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\source\CustomSourceBase; /** - * 资源下载器 + * Source Downloader. */ class Downloader { /** - * 获取 BitBucket 仓库的最新 Tag + * Get latest version from BitBucket tag * - * @param string $name 资源名称 - * @param array $source 资源的元信息,包含字段 repo - * @return array 返回下载 url 链接和文件名 + * @param string $name source name + * @param array $source source meta info: [repo] + * @return array [url, filename] * @throws DownloaderException */ public static function getLatestBitbucketTag(string $name, array $source): array @@ -49,10 +48,13 @@ class Downloader } /** - * 获取 GitHub 最新的打包地址和文件名 + * Get latest version from GitHub tarball + * + * @param string $name source name + * @param array $source source meta info: [repo] + * @param string $type type of tarball, default is 'releases' + * @return array [url, filename] * - * @param string $name 包名称 - * @param array $source 源信息 * @throws DownloaderException */ public static function getLatestGithubTarball(string $name, array $source, string $type = 'releases'): array @@ -82,10 +84,11 @@ class Downloader } /** - * 获取 GitHub 最新的 Release 下载信息 + * Get latest version from GitHub release (uploaded archive) * - * @param string $name 资源名 - * @param array $source 资源的元信息,包含字段 repo、match + * @param string $name source name + * @param array $source source meta info: [repo, match] + * @return array [url, filename] * @throws DownloaderException */ public static function getLatestGithubRelease(string $name, array $source): array @@ -111,10 +114,11 @@ class Downloader } /** - * 获取文件列表的资源链接和名称 + * Get latest version from file list (regex based crawler) * - * @param string $name 资源名称 - * @param array $source 资源元信息,包含 url、regex + * @param string $name source name + * @param array $source source meta info: [url, regex] + * @return array [url, filename] * @throws DownloaderException */ public static function getFromFileList(string $name, array $source): array @@ -149,6 +153,8 @@ class Downloader } /** + * Just download file using system curl command, and lock it + * * @throws DownloaderException * @throws RuntimeException * @throws FileSystemException @@ -168,6 +174,11 @@ class Downloader self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path]); } + /** + * Try to lock source. + * + * @throws FileSystemException + */ public static function lockSource(string $name, array $data): void { if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) { @@ -180,40 +191,11 @@ class Downloader } /** - * 通过链接下载资源到本地并解压 + * Download git source, and lock it. * - * @param string $name 资源名称 - * @param string $url 下载链接 - * @param string $filename 下载到下载目录的目标文件名称,例如 xz.tar.gz - * @param null|string $path 如果指定了此参数,则会移动该资源目录到目标目录 * @throws FileSystemException * @throws RuntimeException - * @throws DownloaderException */ - public static function downloadUrl(string $name, string $url, string $filename, ?string $path = null): void - { - if (!file_exists(DOWNLOAD_PATH . "/{$filename}")) { - logger()->debug("downloading {$url}"); - self::curlDown(url: $url, path: DOWNLOAD_PATH . "/{$filename}"); - } else { - logger()->notice("{$filename} already exists"); - } - FileSystem::extractSource($name, DOWNLOAD_PATH . "/{$filename}"); - if ($path) { - $path = FileSystem::convertPath(SOURCE_PATH . "/{$path}"); - $src_path = FileSystem::convertPath(SOURCE_PATH . "/{$name}"); - switch (PHP_OS_FAMILY) { - case 'Windows': - f_passthru('move "' . $src_path . '" "' . $path . '"'); - break; - case 'Linux': - case 'Darwin': - f_passthru('mv "' . $src_path . '" "' . $path . '"'); - break; - } - } - } - public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null): void { $download_path = DOWNLOAD_PATH . "/{$name}"; @@ -257,10 +239,10 @@ class Downloader } /** - * 拉取资源 + * Download source by name and meta. * - * @param string $name 资源名称 - * @param null|array $source 资源参数,包含 type、path、rev、url、filename、regex、license + * @param string $name source name + * @param null|array $source source meta info: [type, path, rev, url, filename, regex, license] * @throws DownloaderException * @throws FileSystemException * @throws RuntimeException @@ -291,35 +273,35 @@ class Downloader try { switch ($source['type']) { - case 'bitbuckettag': // 从 BitBucket 的 Tag 拉取 + case 'bitbuckettag': // BitBucket Tag [$url, $filename] = self::getLatestBitbucketTag($name, $source); self::downloadFile($name, $url, $filename, $source['path'] ?? null); break; - case 'ghtar': // 从 GitHub 的 TarBall 拉取 + case 'ghtar': // GitHub Release (tar) [$url, $filename] = self::getLatestGithubTarball($name, $source); self::downloadFile($name, $url, $filename, $source['path'] ?? null); break; - case 'ghtagtar': // 根据 GitHub 的 Tag 拉取相应版本的 Tar + case 'ghtagtar': // GitHub Tag (tar) [$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags'); self::downloadFile($name, $url, $filename, $source['path'] ?? null); break; - case 'ghrel': // 通过 GitHub Release 来拉取 + case 'ghrel': // GitHub Release (uploaded) [$url, $filename] = self::getLatestGithubRelease($name, $source); self::downloadFile($name, $url, $filename, $source['path'] ?? null); break; - case 'filelist': // 通过网站提供的 filelist 使用正则提取后拉取 + case 'filelist': // Basic File List (regex based crawler) [$url, $filename] = self::getFromFileList($name, $source); self::downloadFile($name, $url, $filename, $source['path'] ?? null); break; - case 'url': // 通过直链拉取 + case 'url': // Direct download URL $url = $source['url']; $filename = $source['filename'] ?? basename($source['url']); self::downloadFile($name, $url, $filename, $source['path'] ?? null); break; - case 'git': // 通过拉回 Git 仓库的形式拉取 + case 'git': // Git repo self::downloadGit($name, $source['url'], $source['rev'], $source['path'] ?? null); break; - case 'custom': // 自定义,可能是通过复杂 API 形式获取的文件,需要手写 crawler + case 'custom': // Custom download method, like API-based download or other $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\\store\\source'); foreach ($classes as $class) { if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) { @@ -332,7 +314,8 @@ class Downloader throw new DownloaderException('unknown source type: ' . $source['type']); } } catch (RuntimeException $e) { - // 因为某些时候通过命令行下载的文件在失败后不会删除,这里检测到文件存在需要手动删一下 + // Because sometimes files downloaded through the command line are not automatically deleted after a failure. + // Here we need to manually delete the file if it is detected to exist. if (isset($filename) && file_exists(DOWNLOAD_PATH . '/' . $filename)) { logger()->warning('Deleting download file: ' . $filename); unlink(DOWNLOAD_PATH . '/' . $filename); @@ -342,27 +325,7 @@ class Downloader } /** - * 获取 PHP x.y 的具体版本号,例如通过 8.1 来获取 8.1.10 - * - * @throws DownloaderException - */ - #[ArrayShape(['type' => 'string', 'path' => 'string', 'rev' => 'string', 'url' => 'string'])] - public static function getLatestPHPInfo(string $major_version): array - { - // 查找最新的小版本号 - $info = json_decode(self::curlExec(url: "https://www.php.net/releases/index.php?json&version={$major_version}"), true); - $version = $info['version']; - - // 从官网直接下载 - return [ - 'type' => 'url', - 'url' => "https://www.php.net/distributions/php-{$version}.tar.gz", - // 'url' => "https://mirrors.zhamao.xin/php/php-{$version}.tar.gz", - ]; - } - - /** - * 使用 curl 命令拉取元信息 + * Use curl command to get http response * * @throws DownloaderException */ @@ -408,7 +371,7 @@ class Downloader } /** - * 使用 curl 命令下载文件 + * Use curl to download sources from url * * @throws DownloaderException * @throws RuntimeException diff --git a/src/SPC/store/FileSystem.php b/src/SPC/store/FileSystem.php index ab0028ef..f4bf8664 100644 --- a/src/SPC/store/FileSystem.php +++ b/src/SPC/store/FileSystem.php @@ -55,23 +55,25 @@ class FileSystem /** * @throws FileSystemException */ - public static function replaceFile(string $filename, int $replace_type = REPLACE_FILE_STR, mixed $callback_or_search = null, mixed $to_replace = null): bool|int + public static function replaceFileStr(string $filename, mixed $search = null, mixed $replace = null): bool|int { - logger()->debug('Replacing file with type[' . $replace_type . ']: ' . $filename); - $file = self::readFile($filename); - switch ($replace_type) { - case REPLACE_FILE_STR: - default: - $file = str_replace($callback_or_search, $to_replace, $file); - break; - case REPLACE_FILE_PREG: - $file = preg_replace($callback_or_search, $to_replace, $file); - break; - case REPLACE_FILE_USER: - $file = $callback_or_search($file); - break; - } - return file_put_contents($filename, $file); + return self::replaceFile($filename, REPLACE_FILE_STR, $search, $replace); + } + + /** + * @throws FileSystemException + */ + public static function replaceFileRegex(string $filename, mixed $search = null, mixed $replace = null): bool|int + { + return self::replaceFile($filename, REPLACE_FILE_PREG, $search, $replace); + } + + /** + * @throws FileSystemException + */ + public static function replaceFileUser(string $filename, mixed $callback = null): bool|int + { + return self::replaceFile($filename, REPLACE_FILE_USER, $callback); } /** @@ -117,6 +119,9 @@ class FileSystem return null; } + /** + * @throws RuntimeException + */ public static function copyDir(string $from, string $to): void { $dst_path = FileSystem::convertPath($to); @@ -384,6 +389,9 @@ class FileSystem return rmdir($dir); } + /** + * @throws FileSystemException + */ public static function createDir(string $path): void { if (!is_dir($path) && !f_mkdir($path, 0755, true) && !is_dir($path)) { @@ -391,7 +399,11 @@ class FileSystem } } - public static function writeFile(string $path, $content, ...$args): bool|string|int + /** + * @param mixed ...$args Arguments passed to file_put_contents + * @throws FileSystemException + */ + public static function writeFile(string $path, mixed $content, ...$args): bool|string|int { $dir = pathinfo($path, PATHINFO_DIRNAME); if (!is_dir($dir) && !mkdir($dir, 0755, true)) { @@ -413,7 +425,7 @@ class FileSystem self::createDir($dir_name); } - public static function addSourceExtractHook(string $name, callable $callback) + public static function addSourceExtractHook(string $name, callable $callback): void { self::$_extract_hook[$name][] = $callback; } @@ -425,14 +437,35 @@ class FileSystem */ public static function isRelativePath(string $path): bool { - // 适配 Windows 的多盘符目录形式 if (DIRECTORY_SEPARATOR === '\\') { return !(strlen($path) > 2 && ctype_alpha($path[0]) && $path[1] === ':'); } return strlen($path) > 0 && $path[0] !== '/'; } - private static function emitSourceExtractHook(string $name) + /** + * @throws FileSystemException + */ + private static function replaceFile(string $filename, int $replace_type = REPLACE_FILE_STR, mixed $callback_or_search = null, mixed $to_replace = null): bool|int + { + logger()->debug('Replacing file with type[' . $replace_type . ']: ' . $filename); + $file = self::readFile($filename); + switch ($replace_type) { + case REPLACE_FILE_STR: + default: + $file = str_replace($callback_or_search, $to_replace, $file); + break; + case REPLACE_FILE_PREG: + $file = preg_replace($callback_or_search, $to_replace, $file); + break; + case REPLACE_FILE_USER: + $file = $callback_or_search($file); + break; + } + return file_put_contents($filename, $file); + } + + private static function emitSourceExtractHook(string $name): void { foreach ((self::$_extract_hook[$name] ?? []) as $hook) { if ($hook() === true) { diff --git a/src/SPC/store/SourceExtractor.php b/src/SPC/store/SourceExtractor.php index 8842b890..4a68bef8 100644 --- a/src/SPC/store/SourceExtractor.php +++ b/src/SPC/store/SourceExtractor.php @@ -4,10 +4,17 @@ declare(strict_types=1); namespace SPC\store; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; class SourceExtractor { + /** + * @throws WrongUsageException + * @throws FileSystemException + * @throws RuntimeException + */ public static function initSource(?array $sources = null, ?array $libs = null, ?array $exts = null): void { if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) { diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index 4bcc8d31..970f22c0 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -11,7 +11,7 @@ use SPC\exception\RuntimeException; class SourcePatcher { - public static function init() + public static function init(): void { // FileSystem::addSourceExtractHook('swow', [SourcePatcher::class, 'patchSwow']); FileSystem::addSourceExtractHook('micro', [SourcePatcher::class, 'patchMicro']); @@ -46,9 +46,13 @@ class SourcePatcher } } // patch capstone - FileSystem::replaceFile(SOURCE_PATH . '/php-src/configure', REPLACE_FILE_PREG, '/have_capstone="yes"/', 'have_capstone="no"'); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/have_capstone="yes"/', 'have_capstone="no"'); } + /** + * @throws RuntimeException + * @throws FileSystemException + */ public static function patchMicro(?array $list = null, bool $reverse = false): bool { if (!file_exists(SOURCE_PATH . '/php-src/sapi/micro/php_micro.c')) { @@ -66,7 +70,7 @@ class SourcePatcher if ($major_ver === '74') { return false; } - $check = !defined('DEBUG_MODE') ? ' -q' : ''; + // $check = !defined('DEBUG_MODE') ? ' -q' : ''; // f_passthru('cd ' . SOURCE_PATH . '/php-src && git checkout' . $check . ' HEAD'); $default = [ @@ -113,15 +117,13 @@ class SourcePatcher return true; } + /** + * @throws FileSystemException + */ public static function patchOpenssl11Darwin(): bool { if (PHP_OS_FAMILY === 'Darwin' && !file_exists(SOURCE_PATH . '/openssl/VERSION.dat') && file_exists(SOURCE_PATH . '/openssl/test/v3ext.c')) { - FileSystem::replaceFile( - SOURCE_PATH . '/openssl/test/v3ext.c', - REPLACE_FILE_STR, - '#include ', - '#include ' . PHP_EOL . '#include ' - ); + FileSystem::replaceFileStr(SOURCE_PATH . '/openssl/test/v3ext.c', '#include ', '#include ' . PHP_EOL . '#include '); return true; } return false; @@ -134,10 +136,10 @@ class SourcePatcher { // Try to fix debian environment build lack HAVE_STRLCAT problem if ($builder instanceof LinuxBuilder) { - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_STRLCPY 1$/m', ''); - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_STRLCAT 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCPY 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', ''); } - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_OPENPTY 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', ''); // call extension patch before make foreach ($builder->getExts() as $ext) { @@ -158,7 +160,7 @@ class SourcePatcher $micro_c_bak = SOURCE_PATH . '/php-src/sapi/micro/php_micro.c.bak'; // Try to reverse backup file - $find_pattern = 'const char HARDCODED_INI[] ='; + $find_str = 'const char HARDCODED_INI[] ='; $patch_str = ''; foreach ($ini as $key => $value) { $patch_str .= "\"{$key}={$value}\\n\"\n"; @@ -178,8 +180,8 @@ class SourcePatcher } // Patch it - FileSystem::replaceFile($cli_c, REPLACE_FILE_STR, $find_pattern, $patch_str); - FileSystem::replaceFile($micro_c, REPLACE_FILE_STR, $find_pattern, $patch_str); + FileSystem::replaceFileStr($cli_c, $find_str, $patch_str); + FileSystem::replaceFileStr($micro_c, $find_str, $patch_str); return true; } diff --git a/src/SPC/store/source/PhpSource.php b/src/SPC/store/source/PhpSource.php index 44998e4e..f23f63ea 100644 --- a/src/SPC/store/source/PhpSource.php +++ b/src/SPC/store/source/PhpSource.php @@ -6,6 +6,7 @@ namespace SPC\store\source; use JetBrains\PhpStorm\ArrayShape; use SPC\exception\DownloaderException; +use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\store\Downloader; @@ -16,8 +17,9 @@ class PhpSource extends CustomSourceBase /** * @throws DownloaderException * @throws RuntimeException + * @throws FileSystemException */ - public function fetch() + public function fetch(): void { $major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.1'; Downloader::downloadSource('php-src', self::getLatestPHPInfo($major)); diff --git a/src/SPC/store/source/PostgreSQLSource.php b/src/SPC/store/source/PostgreSQLSource.php index cd8a095d..66276db0 100644 --- a/src/SPC/store/source/PostgreSQLSource.php +++ b/src/SPC/store/source/PostgreSQLSource.php @@ -4,20 +4,31 @@ declare(strict_types=1); namespace SPC\store\source; +use SPC\exception\DownloaderException; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; use SPC\store\Downloader; class PostgreSQLSource extends CustomSourceBase { public const NAME = 'postgresql'; - public function fetch() + /** + * @throws DownloaderException + * @throws RuntimeException + * @throws FileSystemException + */ + public function fetch(): void { Downloader::downloadSource('postgresql', self::getLatestInfo()); } + /** + * @throws DownloaderException + */ public function getLatestInfo(): array { - [$url, $filename, $version] = Downloader::getFromFileList('postgresql', [ + [, $filename, $version] = Downloader::getFromFileList('postgresql', [ 'url' => 'https://www.postgresql.org/ftp/source/', 'regex' => '/href="(?v(?[^"]+)\/)"/', ]); diff --git a/src/SPC/util/ConfigValidator.php b/src/SPC/util/ConfigValidator.php index 9b818fb7..0126ddf9 100644 --- a/src/SPC/util/ConfigValidator.php +++ b/src/SPC/util/ConfigValidator.php @@ -49,10 +49,9 @@ class ConfigValidator } /** - * @param mixed $data * @throws ValidationException */ - public static function validateLibs($data, array $source_data = []): void + public static function validateLibs(mixed $data, array $source_data = []): void { is_array($data) || throw new ValidationException('lib.json is broken'); foreach ($data as $name => $lib) { @@ -64,7 +63,10 @@ class ConfigValidator } } - public static function validateExts($data, array $source_data = []): void + /** + * @throws ValidationException + */ + public static function validateExts(mixed $data): void { is_array($data) || throw new ValidationException('ext.json is broken'); } diff --git a/src/SPC/util/DependencyUtil.php b/src/SPC/util/DependencyUtil.php index d030966d..ba0d839c 100644 --- a/src/SPC/util/DependencyUtil.php +++ b/src/SPC/util/DependencyUtil.php @@ -15,18 +15,17 @@ use SPC\store\Config; class DependencyUtil { /** - * 根据需要的 ext 列表获取依赖的 lib 列表,同时根据依赖关系排序 + * Obtain the dependent lib list according to the required ext list, and sort according to the dependency * - * @param array $exts 要获取 libs 依赖的列表 - * @param array $additional_libs 额外要添加的库列表,用于激活 lib-suggests 触发的额外库特性 - * @return array 返回一个包含三个数组的数组,第一个是排序后的 ext 列表,第二个是排序后的 lib 列表,第三个是没有传入但是依赖了的 ext 列表 + * @param array $exts extensions list + * @param array $additional_libs List of additional libraries to add to activate the extra library features triggered by lib-suggests + * @return array Returns an array containing three arrays, [extensions, libraries, not included extensions] * @throws WrongUsageException * @throws RuntimeException * @throws FileSystemException */ public static function getExtLibsByDeps(array $exts, array $additional_libs = []): array { - // 先对扩展列表进行一个依赖筛选 $sorted = []; $visited = []; $not_included_exts = []; @@ -49,7 +48,7 @@ class DependencyUtil } } $libs = $additional_libs; - // 遍历每一个 ext 的 libs + foreach ($final as $ext) { if (!in_array($ext, $exts)) { $not_included_exts[] = $ext; diff --git a/src/SPC/util/Patcher.php b/src/SPC/util/Patcher.php index 3f7f7660..1419606e 100644 --- a/src/SPC/util/Patcher.php +++ b/src/SPC/util/Patcher.php @@ -19,17 +19,17 @@ class Patcher switch ($libc) { case 'musl_wrapper': // bad checks - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_STRLCPY 1$/m', ''); - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_STRLCAT 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCPY 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', ''); // no break case 'musl': - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_FUNC_ATTRIBUTE_IFUNC 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_FUNC_ATTRIBUTE_IFUNC 1$/m', ''); break; case 'glibc': // avoid lcrypt dependency - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_CRYPT 1$/m', ''); - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_CRYPT_R 1$/m', ''); - FileSystem::replaceFile(SOURCE_PATH . '/php-src/main/php_config.h', REPLACE_FILE_PREG, '/^#define HAVE_CRYPT_H 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_CRYPT 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_CRYPT_R 1$/m', ''); + FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_CRYPT_H 1$/m', ''); break; default: throw new RuntimeException('not implemented'); diff --git a/src/SPC/util/UnixShell.php b/src/SPC/util/UnixShell.php index 565182ea..5fd730f9 100644 --- a/src/SPC/util/UnixShell.php +++ b/src/SPC/util/UnixShell.php @@ -63,6 +63,9 @@ class UnixShell return $this; } + /** + * @throws RuntimeException + */ public function execWithEnv(string $cmd): UnixShell { return $this->exec($this->getEnvString() . ' ' . $cmd); diff --git a/src/globals/defines.php b/src/globals/defines.php index fb66869e..28473296 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -39,11 +39,11 @@ const BUILD_STATUS_ALREADY = 1; const BUILD_STATUS_FAILED = 2; // build target type -const BUILD_TARGET_NONE = 0; -const BUILD_TARGET_CLI = 1; -const BUILD_TARGET_MICRO = 2; -const BUILD_TARGET_FPM = 4; -const BUILD_TARGET_ALL = 7; +const BUILD_TARGET_NONE = 0; // no target +const BUILD_TARGET_CLI = 1; // build cli +const BUILD_TARGET_MICRO = 2; // build micro +const BUILD_TARGET_FPM = 4; // build fpm +const BUILD_TARGET_ALL = 7; // build all // doctor error fix policy const FIX_POLICY_DIE = 1; // die directly @@ -57,9 +57,4 @@ const PKGCONF_PATCH_LIBDIR = 4; const PKGCONF_PATCH_INCLUDEDIR = 8; const PKGCONF_PATCH_ALL = 15; -// Custom download type -const DOWNLOAD_TYPE_NONE = 0; -const DOWNLOAD_TYPE_ARCHIVE = 1; -const DOWNLOAD_TYPE_DIR = 2; - ConsoleLogger::$date_format = 'H:i:s'; diff --git a/src/globals/functions.php b/src/globals/functions.php index 5f6cc29f..7f411624 100644 --- a/src/globals/functions.php +++ b/src/globals/functions.php @@ -8,17 +8,15 @@ use SPC\util\UnixShell; use ZM\Logger\ConsoleLogger; /** - * 判断传入的数组是否为关联数组 - * - * @param mixed $array + * Judge if an array is an associative array */ -function is_assoc_array($array): bool +function is_assoc_array(mixed $array): bool { return is_array($array) && (!empty($array) && array_keys($array) !== range(0, count($array) - 1)); } /** - * 助手方法,返回一个 Logger 实例 + * Return a logger instance */ function logger(): LoggerInterface { @@ -30,7 +28,8 @@ function logger(): LoggerInterface } /** - * @param string $arch 架构名称转换为 GNU 标准形式 + * Transfer architecture name to gnu triplet + * * @throws WrongUsageException */ function arch2gnu(string $arch): string @@ -50,7 +49,7 @@ function quote(string $str, string $quote = '"'): string } /** - * 将不同系统环境的编译使用工具集的文件夹名称进行一个返回 + * Get Family name of current OS * * @throws WrongUsageException */ @@ -66,7 +65,7 @@ function osfamily2dir(): string } /** - * 执行shell,直接输出在终端,出现错误抛出异常 + * Execute the shell command, and the output will be directly printed in the terminal. If there is an error, an exception will be thrown * * @throws \SPC\exception\RuntimeException */ @@ -92,12 +91,9 @@ function f_passthru(string $cmd): ?bool } /** - * 执行命令,不输出内容,返回执行结果和内容 - * - * @param mixed $output - * @param mixed $result_code + * Execute a command, return the output and result code */ -function f_exec(string $command, &$output, &$result_code): bool|string +function f_exec(string $command, mixed &$output, mixed &$result_code): bool|string { logger()->debug('Running command (no output) : ' . $command); return exec($command, $output, $result_code); diff --git a/src/globals/tests/bcmath.php b/src/globals/tests/bcmath.php index bad5f8f6..0190aa78 100644 --- a/src/globals/tests/bcmath.php +++ b/src/globals/tests/bcmath.php @@ -1,7 +1,5 @@