From 1791b443bc8f72613350b674d228358b564f2bdb Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sun, 23 Mar 2025 15:35:25 +0700 Subject: [PATCH 01/32] add xdebug dynamic extension --- config/ext.json | 7 +++++-- config/lib.json | 6 ++++++ config/source.json | 11 ++++++++++ src/SPC/builder/extension/xdebug.php | 11 ++++++++++ src/SPC/builder/linux/library/xdebug.php | 15 ++++++++++++++ src/SPC/builder/unix/library/xdebug.php | 26 ++++++++++++++++++++++++ src/SPC/command/BuildPHPCommand.php | 24 ++++++++++++++++++++-- src/SPC/store/Downloader.php | 9 +++++++- src/SPC/util/DynamicExt.php | 8 ++++++++ 9 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 src/SPC/builder/extension/xdebug.php create mode 100644 src/SPC/builder/linux/library/xdebug.php create mode 100644 src/SPC/builder/unix/library/xdebug.php create mode 100644 src/SPC/util/DynamicExt.php diff --git a/config/ext.json b/config/ext.json index 4d6044b3..45b9c905 100644 --- a/config/ext.json +++ b/config/ext.json @@ -888,13 +888,16 @@ ] }, "xdebug": { - "type": "builtin", + "type": "external", "support": { "Windows": "wip", "BSD": "no", "Darwin": "no", - "Linux": "no" + "Linux": "wip" }, + "lib-depends": [ + "xdebug" + ], "notes": true }, "xhprof": { diff --git a/config/lib.json b/config/lib.json index 8e728ccd..3aabecd8 100644 --- a/config/lib.json +++ b/config/lib.json @@ -738,6 +738,12 @@ "libiconv" ] }, + "xdebug": { + "source": "xdebug", + "static-libs-unix": [ + "xdebug.so" + ] + }, "xz": { "source": "xz", "static-libs-unix": [ diff --git a/config/source.json b/config/source.json index e5cc9212..40c516b6 100644 --- a/config/source.json +++ b/config/source.json @@ -895,6 +895,17 @@ "path": "COPYING" } }, + "xdebug": { + "type": "ghrel", + "repo": "xdebug/xdebug", + "match": "Source code", + "prefer-stable": true, + "provide-pre-built": false, + "license": { + "type": "file", + "path": "LICENSE" + } + }, "xhprof": { "type": "url", "url": "https://pecl.php.net/get/xhprof", diff --git a/src/SPC/builder/extension/xdebug.php b/src/SPC/builder/extension/xdebug.php new file mode 100644 index 00000000..c5cd901d --- /dev/null +++ b/src/SPC/builder/extension/xdebug.php @@ -0,0 +1,11 @@ +cd($this->source_dir) + ->exec(BUILD_BIN_PATH . '/phpize') + ->exec('./configure --with-php-config=' . BUILD_BIN_PATH . '/php-config') + ->exec('make clean') + ->exec("make -j{$this->builder->concurrency}"); + copy($this->source_dir . '/modules/xdebug.so', BUILD_LIB_PATH . '/xdebug.so'); + copy($this->source_dir . '/modules/xdebug.la', BUILD_LIB_PATH . '/xdebug.la'); + } +} diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index 6bafce54..ceeaca34 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -11,6 +11,7 @@ use SPC\store\Config; use SPC\store\FileSystem; use SPC\store\SourcePatcher; use SPC\util\DependencyUtil; +use SPC\util\DynamicExt; use SPC\util\GlobalEnvManager; use SPC\util\LicenseDumper; use Symfony\Component\Console\Attribute\AsCommand; @@ -109,6 +110,18 @@ class BuildPHPCommand extends BuildCommand $include_suggest_lib = $this->getOption('with-suggested-libs'); [$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib); $display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package'])); + $dynamic_libs = $dynamic_exts = array_filter($extensions, function (string $ext) { + $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/builder/extension', 'SPC\builder\extension'); + $extension = array_find($classes, function (string $class) use ($ext) { + $a = explode('\\', $class); + return end($a) === $ext; + }); + $reflector = new \ReflectionClass($extension); + $attributes = $reflector->getAttributes(); + return array_find($attributes, fn ($attr) => $attr->getName() === DynamicExt::class) !== null; + }); + $extensions = array_diff($extensions, $dynamic_exts); + $libraries = array_diff($libraries, $dynamic_libs); // print info $indent_texts = [ @@ -153,7 +166,7 @@ class BuildPHPCommand extends BuildCommand $builder->proveLibs($libraries); // check extensions $builder->proveExts($extensions); - // validate libs and exts + // validate libs and extensions $builder->validateLibsAndExts(); // clean builds and sources @@ -183,6 +196,13 @@ class BuildPHPCommand extends BuildCommand // start to build $builder->buildPHP($rule); + if ($rule & BUILD_TARGET_EMBED) { + // build dynamic extensions + $builder->proveLibs($dynamic_libs); + // build or install libraries + $builder->setupLibs(); + } + // compile stopwatch :P $time = round(microtime(true) - START_TIME, 3); logger()->info(''); @@ -217,7 +237,7 @@ class BuildPHPCommand extends BuildCommand file_put_contents(BUILD_ROOT_PATH . '/build-libraries.json', json_encode($libraries, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); // export licenses $dumper = new LicenseDumper(); - $dumper->addExts($extensions)->addLibs($libraries)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license'); + $dumper->addExts($extensions)->addLibs($libraries)->addLibs($dynamic_libs)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license'); $path = FileSystem::convertPath("{$build_root_path}/license/"); logger()->info("License path{$fixed}: {$path}"); return static::SUCCESS; diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index 16edeeae..e2a6280f 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -73,7 +73,7 @@ class Downloader $url = $data[0]['tarball_url']; } else { $id = 0; - while ($data[$id]['prerelease'] === true) { + while (($data[$id]['prerelease'] ?? false) === true) { ++$id; } $url = $data[$id]['tarball_url'] ?? null; @@ -122,6 +122,10 @@ class Downloader if (!$match_result) { return $release['assets']; } + if ($source['match'] === 'Source code') { + $url = $release['tarball_url']; + break; + } foreach ($release['assets'] as $asset) { if (preg_match('|' . $source['match'] . '|', $asset['name'])) { $url = $asset['browser_download_url']; @@ -134,6 +138,9 @@ class Downloader throw new DownloaderException("failed to find {$name} release metadata"); } $filename = basename($url); + if ($source['match'] === 'Source code') { + $filename = $name . $filename . '.tar.gz'; + } return [$url, $filename]; } diff --git a/src/SPC/util/DynamicExt.php b/src/SPC/util/DynamicExt.php new file mode 100644 index 00000000..d5fd549d --- /dev/null +++ b/src/SPC/util/DynamicExt.php @@ -0,0 +1,8 @@ + Date: Sun, 23 Mar 2025 16:11:03 +0700 Subject: [PATCH 02/32] fix crash on windoof --- src/SPC/command/BuildPHPCommand.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index ceeaca34..3a5c17a4 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -116,6 +116,9 @@ class BuildPHPCommand extends BuildCommand $a = explode('\\', $class); return end($a) === $ext; }); + if (!$extension) { + return false; + } $reflector = new \ReflectionClass($extension); $attributes = $reflector->getAttributes(); return array_find($attributes, fn ($attr) => $attr->getName() === DynamicExt::class) !== null; From 8909b62dc45ff8316af2d8a6aa5ac136f1515aff Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 24 Mar 2025 19:25:38 +0800 Subject: [PATCH 03/32] Some prerequisites for refactor --- bin/spc-gnu-docker | 9 +++++++-- config/env.ini | 5 ++--- config/ext.json | 5 ++--- config/lib.json | 6 ------ config/source.json | 8 +++----- src/SPC/store/Config.php | 15 +++++++++++++++ src/SPC/util/GlobalEnvManager.php | 3 --- 7 files changed, 29 insertions(+), 22 deletions(-) diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker index fa84e58c..d96abbc5 100755 --- a/bin/spc-gnu-docker +++ b/bin/spc-gnu-docker @@ -12,7 +12,7 @@ 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 + if [ "$SPC_USE_SUDO" != "yes" ] && [ "$SPC_DOCKER_DEBUG" != "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' @@ -145,4 +145,9 @@ echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"' # shellcheck disable=SC2086 # shellcheck disable=SC2090 -$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@ +if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then + echo -e "\e[033m* Debug mode enabled, run docker in interactive mode.\e[0m" + $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH +else + $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@ +fi diff --git a/config/env.ini b/config/env.ini index 652b0fe6..3ef5ba0f 100644 --- a/config/env.ini +++ b/config/env.ini @@ -28,7 +28,6 @@ ; PATH: static-php-cli will add `$BUILD_BIN_PATH` to PATH. ; PKG_CONFIG: static-php-cli will set `$BUILD_BIN_PATH/pkg-config` to PKG_CONFIG. ; PKG_CONFIG_PATH: static-php-cli will set `$BUILD_LIB_PATH/pkgconfig` to PKG_CONFIG_PATH. -; SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS: the default optimization CFLAGS for compiling php. (if --no-strip option is set: `-g -O0`, else: `-g -Os`) ; ; * These vars are only be defined in LinuxBuilder and cannot be changed anywhere: ; SPC_LINUX_DEFAULT_CC: the default compiler for linux. (For alpine linux: `gcc`, default: `$GNU_ARCH-linux-musl-gcc`) @@ -98,7 +97,7 @@ SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}" ; LIBS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm" ; EXTRA_CFLAGS for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS} -fno-ident -fPIE -fPIC" +SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-ident -fPIE -fPIC" ; EXTRA_LIBS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="" ; EXTRA_LDFLAGS_PROGRAM for `make` php @@ -132,7 +131,7 @@ SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS="-I${BUILD_INCLUDE_PATH}" ; LDFLAGS for configuring php SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}" ; EXTRA_CFLAGS for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS}" +SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" ; EXTRA_LIBS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-lresolv" ; embed type for php, static (libphp.a) or shared (libphp.dylib) diff --git a/config/ext.json b/config/ext.json index 691be764..1cf1dae0 100644 --- a/config/ext.json +++ b/config/ext.json @@ -919,15 +919,14 @@ }, "xdebug": { "type": "external", + "source": "xdebug", + "target": ["shared"], "support": { "Windows": "wip", "BSD": "no", "Darwin": "no", "Linux": "wip" }, - "lib-depends": [ - "xdebug" - ], "notes": true }, "xhprof": { diff --git a/config/lib.json b/config/lib.json index a39409ed..0dae815f 100644 --- a/config/lib.json +++ b/config/lib.json @@ -751,12 +751,6 @@ "libiconv" ] }, - "xdebug": { - "source": "xdebug", - "static-libs-unix": [ - "xdebug.so" - ] - }, "xz": { "source": "xz", "static-libs-unix": [ diff --git a/config/source.json b/config/source.json index 553f0527..4a9c3cef 100644 --- a/config/source.json +++ b/config/source.json @@ -914,11 +914,9 @@ } }, "xdebug": { - "type": "ghrel", - "repo": "xdebug/xdebug", - "match": "Source code", - "prefer-stable": true, - "provide-pre-built": false, + "type": "url", + "url": "https://pecl.php.net/get/xdebug", + "filename": "xdebug.tgz", "license": { "type": "file", "path": "LICENSE" diff --git a/src/SPC/store/Config.php b/src/SPC/store/Config.php index 07ed2887..9c00715d 100644 --- a/src/SPC/store/Config.php +++ b/src/SPC/store/Config.php @@ -106,6 +106,21 @@ class Config return self::$lib; } + /** + * @throws WrongUsageException + * @throws FileSystemException + */ + public static function getExtTarget(string $name): ?array + { + if (self::$ext === null) { + self::$ext = FileSystem::loadConfigArray('ext'); + } + if (!isset(self::$ext[$name])) { + throw new WrongUsageException('ext [' . $name . '] is not supported yet'); + } + return self::$ext[$name]['target'] ?? ['static', 'shared']; + } + /** * @throws FileSystemException * @throws WrongUsageException diff --git a/src/SPC/util/GlobalEnvManager.php b/src/SPC/util/GlobalEnvManager.php index 7988244f..8ffd5d05 100644 --- a/src/SPC/util/GlobalEnvManager.php +++ b/src/SPC/util/GlobalEnvManager.php @@ -40,9 +40,6 @@ class GlobalEnvManager self::putenv('PATH=' . BUILD_ROOT_PATH . '/bin:' . getenv('PATH')); self::putenv('PKG_CONFIG=' . BUILD_BIN_PATH . '/pkg-config'); self::putenv('PKG_CONFIG_PATH=' . BUILD_ROOT_PATH . '/lib/pkgconfig'); - if ($builder instanceof BuilderBase) { - self::putenv('SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS=' . ($builder->getOption('no-strip') ? '-g -O0' : '-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64')); - } } // Define env vars for linux From 76c353e79078111335063be1b56ef7cc4155dfff Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 24 Mar 2025 22:39:45 +0800 Subject: [PATCH 04/32] Add SPC_DOCKER_DEBUG=yes option for docker build --- bin/spc-alpine-docker | 14 ++++++++ bin/spc-gnu-docker | 18 ++++++++-- src/SPC/command/BuildPHPCommand.php | 51 ++++++++++++----------------- 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/bin/spc-alpine-docker b/bin/spc-alpine-docker index 28cc4939..16609b5f 100755 --- a/bin/spc-alpine-docker +++ b/bin/spc-alpine-docker @@ -122,6 +122,20 @@ MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot" # shellcheck disable=SC2086 # shellcheck disable=SC2090 if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then + echo "* Debug mode enabled, run docker in interactive mode." + echo "* You can use 'exit' to exit the docker container." + echo "* You can use 'bin/spc' like normal builds." + echo "*" + echo "* Mounted directories:" + echo "* ./config: $(pwd)/config" + echo "* ./src: $(pwd)/src" + echo "* ./buildroot: $(pwd)/buildroot" + echo "* ./source: $(pwd)/source" + echo "* ./dist: $(pwd)/dist" + echo "* ./downloads: $(pwd)/downloads" + echo "* ./pkgroot: $(pwd)/pkgroot" + echo "*" + $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 else $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@ diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker index d96abbc5..6bc7bd4a 100755 --- a/bin/spc-gnu-docker +++ b/bin/spc-gnu-docker @@ -86,7 +86,7 @@ COPY ./composer.* /app/ ADD ./bin/setup-runtime /app/bin/setup-runtime ADD ./bin/spc /app/bin/spc RUN /app/bin/setup-runtime -RUN /app/bin/php /app/bin/composer install --no-dev --classmap-authoritative +RUN /app/bin/php /app/bin/composer install --no-dev ENV PATH="/app/bin:/cmake/bin:$PATH" ENV SPC_LIBC=glibc @@ -145,8 +145,22 @@ echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"' # shellcheck disable=SC2086 # shellcheck disable=SC2090 + if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then - echo -e "\e[033m* Debug mode enabled, run docker in interactive mode.\e[0m" + echo "* Debug mode enabled, run docker in interactive mode." + echo "* You can use 'exit' to exit the docker container." + echo "* You can use 'bin/spc' like normal builds." + echo "*" + echo "* Mounted directories:" + echo "* ./config: $(pwd)/config" + echo "* ./src: $(pwd)/src" + echo "* ./buildroot: $(pwd)/buildroot" + echo "* ./source: $(pwd)/source" + echo "* ./dist: $(pwd)/dist" + echo "* ./downloads: $(pwd)/downloads" + echo "* ./pkgroot: $(pwd)/pkgroot" + echo "*" + $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH else $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@ diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index 3a5c17a4..b10739eb 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -11,7 +11,6 @@ use SPC\store\Config; use SPC\store\FileSystem; use SPC\store\SourcePatcher; use SPC\util\DependencyUtil; -use SPC\util\DynamicExt; use SPC\util\GlobalEnvManager; use SPC\util\LicenseDumper; use Symfony\Component\Console\Attribute\AsCommand; @@ -28,10 +27,12 @@ class BuildPHPCommand extends BuildCommand $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', ''); + $this->addOption('with-dynamic', 'D', InputOption::VALUE_REQUIRED, 'Dynamic extensions to build, comma separated', ''); $this->addOption('build-micro', null, null, 'Build micro SAPI'); $this->addOption('build-cli', null, null, 'Build cli SAPI'); $this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)'); $this->addOption('build-embed', null, null, 'Build embed SAPI (not available on Windows)'); + $this->addOption('build-dev', null, null, 'Build dev things for building dynamic extensions (not available on Windows)'); $this->addOption('build-all', null, null, 'Build all SAPI'); $this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions'); $this->addOption('disable-opcache-jit', null, null, 'disable opcache jit'); @@ -53,13 +54,15 @@ class BuildPHPCommand extends BuildCommand // transform string to array $libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs')))); // transform string to array - $extensions = $this->parseExtensionList($this->getArgument('extensions')); + $dynamic_extensions = array_map('trim', array_filter(explode(',', $this->getOption('with-dynamic')))); + // transform string to array + $static_extensions = $this->parseExtensionList($this->getArgument('extensions')); // parse rule with options - $rule = $this->parseRules(); + $rule = $this->parseRules($dynamic_extensions); - if ($rule === BUILD_TARGET_NONE) { - $this->output->writeln('Please add at least one build target!'); + if ($rule === BUILD_TARGET_NONE || $rule === BUILD_TARGET_DEV) { + $this->output->writeln('Please add at least one build SAPI!'); $this->output->writeln("\t--build-cli\tBuild php-cli SAPI"); $this->output->writeln("\t--build-micro\tBuild phpmicro SAPI"); $this->output->writeln("\t--build-fpm\tBuild php-fpm SAPI"); @@ -108,33 +111,22 @@ class BuildPHPCommand extends BuildCommand $builder = BuilderProvider::makeBuilderByInput($this->input); $include_suggest_ext = $this->getOption('with-suggested-exts'); $include_suggest_lib = $this->getOption('with-suggested-libs'); - [$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib); + [$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs(array_merge($static_extensions, $dynamic_extensions), $libraries, $include_suggest_ext, $include_suggest_lib); $display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package'])); - $dynamic_libs = $dynamic_exts = array_filter($extensions, function (string $ext) { - $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/builder/extension', 'SPC\builder\extension'); - $extension = array_find($classes, function (string $class) use ($ext) { - $a = explode('\\', $class); - return end($a) === $ext; - }); - if (!$extension) { - return false; - } - $reflector = new \ReflectionClass($extension); - $attributes = $reflector->getAttributes(); - return array_find($attributes, fn ($attr) => $attr->getName() === DynamicExt::class) !== null; - }); - $extensions = array_diff($extensions, $dynamic_exts); - $libraries = array_diff($libraries, $dynamic_libs); + $display_extensions = array_map(fn ($ext) => in_array($ext, $dynamic_extensions) ? "*{$ext}" : $ext, $extensions); // print info $indent_texts = [ 'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')', 'Build SAPI' => $builder->getBuildTypeName($rule), - 'Extensions (' . count($extensions) . ')' => implode(',', $extensions), + 'Extensions (' . count($extensions) . ')' => implode(',', $display_extensions), 'Libraries (' . count($libraries) . ')' => implode(',', $display_libs), 'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes', 'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no', ]; + if (!empty($dynamic_exts) || ($rule & BUILD_TARGET_EMBED) || ($rule & BUILD_TARGET_DEV)) { + $indent_texts['Build Dev'] = 'yes'; + } if (!empty($this->input->getOption('with-config-file-path'))) { $indent_texts['Config File Path'] = $this->input->getOption('with-config-file-path'); } @@ -168,7 +160,7 @@ class BuildPHPCommand extends BuildCommand // compile libraries $builder->proveLibs($libraries); // check extensions - $builder->proveExts($extensions); + $builder->proveExts($extensions, shared_build_extensions: $dynamic_extensions); // validate libs and extensions $builder->validateLibsAndExts(); @@ -199,11 +191,9 @@ class BuildPHPCommand extends BuildCommand // start to build $builder->buildPHP($rule); - if ($rule & BUILD_TARGET_EMBED) { - // build dynamic extensions - $builder->proveLibs($dynamic_libs); - // build or install libraries - $builder->setupLibs(); + // build dynamic extensions if needed + if (!empty($dynamic_exts)) { + $builder->buildDynamicExts(); } // compile stopwatch :P @@ -240,7 +230,7 @@ class BuildPHPCommand extends BuildCommand file_put_contents(BUILD_ROOT_PATH . '/build-libraries.json', json_encode($libraries, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); // export licenses $dumper = new LicenseDumper(); - $dumper->addExts($extensions)->addLibs($libraries)->addLibs($dynamic_libs)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license'); + $dumper->addExts($extensions)->addLibs($libraries)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license'); $path = FileSystem::convertPath("{$build_root_path}/license/"); logger()->info("License path{$fixed}: {$path}"); return static::SUCCESS; @@ -262,13 +252,14 @@ class BuildPHPCommand extends BuildCommand /** * Parse build options to rule int. */ - private function parseRules(): int + private function parseRules(array $dynamic_exts = []): int { $rule = BUILD_TARGET_NONE; $rule |= ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-embed') ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE); + $rule |= ($this->getOption('build-dev') || !empty($dynamic_exts) ? BUILD_TARGET_DEV : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE); return $rule; } From aa4d4db11fc58c1315d4164951b914b75d125098 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 24 Mar 2025 23:50:12 +0800 Subject: [PATCH 05/32] Refactor, supports shared extension build now ! --- config/ext.json | 4 +- config/lib.json | 3 +- src/SPC/builder/BuilderBase.php | 49 ++++++++++++--- src/SPC/builder/Extension.php | 72 ++++++++++++++++++++++ src/SPC/builder/extension/xdebug.php | 16 ++++- src/SPC/builder/freebsd/BSDBuilder.php | 2 +- src/SPC/builder/linux/LinuxBuilder.php | 26 +++++--- src/SPC/builder/linux/library/xdebug.php | 15 ----- src/SPC/builder/macos/MacOSBuilder.php | 24 +++++--- src/SPC/builder/unix/UnixBuilderBase.php | 27 +++++++- src/SPC/builder/unix/library/libcares.php | 4 +- src/SPC/builder/unix/library/xdebug.php | 26 -------- src/SPC/builder/windows/WindowsBuilder.php | 4 +- src/SPC/command/BuildPHPCommand.php | 23 ++++++- src/SPC/store/Downloader.php | 7 --- src/SPC/store/SourcePatcher.php | 6 +- src/SPC/util/DynamicExt.php | 8 --- src/globals/defines.php | 3 +- tests/SPC/builder/BuilderTest.php | 2 +- 19 files changed, 218 insertions(+), 103 deletions(-) delete mode 100644 src/SPC/builder/linux/library/xdebug.php delete mode 100644 src/SPC/builder/unix/library/xdebug.php delete mode 100644 src/SPC/util/DynamicExt.php diff --git a/config/ext.json b/config/ext.json index 1cf1dae0..ade6099c 100644 --- a/config/ext.json +++ b/config/ext.json @@ -924,8 +924,8 @@ "support": { "Windows": "wip", "BSD": "no", - "Darwin": "no", - "Linux": "wip" + "Darwin": "partial", + "Linux": "partial" }, "notes": true }, diff --git a/config/lib.json b/config/lib.json index 0dae815f..cc9d4eb0 100644 --- a/config/lib.json +++ b/config/lib.json @@ -281,8 +281,7 @@ "headers-unix": [ "ares.h", "ares_dns.h", - "ares_nameser.h", - "ares_rules.h" + "ares_nameser.h" ] }, "libde265": { diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 0456af8b..0e864460 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -122,9 +122,12 @@ abstract class BuilderBase * * @return Extension[] */ - public function getExts(): array + public function getExts(bool $including_dynamic = true): array { - return $this->exts; + if ($including_dynamic) { + return $this->exts; + } + return array_filter($this->exts, fn ($ext) => !$ext->isBuildShared()); } /** @@ -136,7 +139,7 @@ abstract class BuilderBase public function hasCpp(): bool { // judge cpp-extension - $exts = array_keys($this->getExts()); + $exts = array_keys($this->getExts(false)); foreach ($exts as $ext) { if (Config::getExt($ext, 'cpp-extension', false) === true) { return true; @@ -170,9 +173,20 @@ abstract class BuilderBase * @throws \Throwable|WrongUsageException * @internal */ - public function proveExts(array $extensions, bool $skip_check_deps = false): void + public function proveExts(array $extensions, bool $skip_check_deps = false, array $shared_build_extensions = []): void { CustomExt::loadCustomExt(); + // judge ext + foreach ($extensions as $ext) { + // if extension does not support static && no shared build, throw exception + if (!in_array('static', Config::getExtTarget($ext)) && !in_array($ext, $shared_build_extensions)) { + throw new WrongUsageException('Extension [' . $ext . '] does not support static build !'); + } + // if extension does not support shared && no static build, throw exception + if (!in_array('shared', Config::getExtTarget($ext)) && !in_array($ext, $shared_build_extensions)) { + throw new WrongUsageException('Extension [' . $ext . '] does not support shared build !'); + } + } $this->emitPatchPoint('before-php-extract'); SourceManager::initSource(sources: ['php-src']); $this->emitPatchPoint('after-php-extract'); @@ -186,15 +200,21 @@ abstract class BuilderBase $this->emitPatchPoint('after-exts-extract'); foreach ($extensions as $extension) { $class = CustomExt::getExtClass($extension); + /** @var Extension $ext */ $ext = new $class($extension, $this); $this->addExt($ext); + if (in_array($extension, $shared_build_extensions)) { + $ext->setBuildShared(); + } else { + $ext->setBuildStatic(); + } } if ($skip_check_deps) { return; } - foreach ($this->exts as $ext) { + foreach ($this->getExts() as $ext) { $ext->checkDependency(); } $this->ext_list = $extensions; @@ -207,6 +227,17 @@ abstract class BuilderBase */ abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE); + public function buildDynamicExts(): void + { + foreach ($this->getExts() as $ext) { + if (!$ext->isBuildShared()) { + continue; + } + logger()->info('Building extension [' . $ext->getName() . '] as shared extension (' . $ext->getName() . '.so)'); + $ext->buildShared(); + } + } + /** * Generate extension enable arguments for configure. * e.g. --enable-mbstring @@ -214,10 +245,10 @@ abstract class BuilderBase * @throws FileSystemException * @throws WrongUsageException */ - public function makeExtensionArgs(): string + public function makeStaticExtensionArgs(): string { $ret = []; - foreach ($this->exts as $ext) { + foreach ($this->getExts(false) as $ext) { logger()->info($ext->getName() . ' is using ' . $ext->getConfigureArg()); $ret[] = trim($ext->getConfigureArg()); } @@ -396,7 +427,7 @@ abstract class BuilderBase foreach ($this->libs as $lib) { $lib->validate(); } - foreach ($this->exts as $ext) { + foreach ($this->getExts() as $ext) { $ext->validate(); } } @@ -441,7 +472,7 @@ abstract class BuilderBase { $php = "getExts() as $ext) { + foreach ($this->getExts(false) as $ext) { $ext_name = $ext->getDistName(); if (!empty($ext_name)) { $php .= "echo 'Running micro with {$ext_name} test' . PHP_EOL;\n"; diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index a7886cd8..eb7a9509 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -14,6 +14,12 @@ class Extension { protected array $dependencies = []; + protected bool $build_shared = false; + + protected bool $build_static = false; + + protected string $source_dir; + /** * @throws FileSystemException * @throws RuntimeException @@ -30,6 +36,18 @@ class Extension if (PHP_OS_FAMILY === 'Windows' && $unix_only) { throw new RuntimeException("{$ext_type} extension {$name} is not supported on Windows platform"); } + // set source_dir for builtin + if ($ext_type === 'builtin') { + $this->source_dir = SOURCE_PATH . '/php-src/ext/' . $this->name; + } else { + $source = Config::getExt($this->name, 'source'); + if ($source === null) { + throw new RuntimeException("{$ext_type} extension {$name} source not found"); + } + $source_path = Config::getSource($source)['path'] ?? null; + $source_path = $source_path === null ? SOURCE_PATH . '/' . $source : SOURCE_PATH . '/' . $source_path; + $this->source_dir = $source_path; + } } /** @@ -167,6 +185,11 @@ class Extension return false; } + /** + * Run shared extension check when cli is enabled + */ + public function runSharedExtensionCheckUnix(): void {} + /** * @throws RuntimeException */ @@ -231,6 +254,32 @@ class Extension // do nothing, just throw wrong usage exception if not valid } + public function buildShared(): void + { + match (PHP_OS_FAMILY) { + 'Darwin', 'Linux' => $this->buildUnixShared(), + default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'), + }; + } + + public function buildUnixShared(): void + { + // prepare configure args + shell()->cd($this->source_dir) + ->setEnv(['CFLAGS' => $this->builder->arch_c_flags]) + ->execWithEnv(BUILD_BIN_PATH . '/phpize') + ->execWithEnv('./configure ' . $this->getUnixConfigureArg() . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-static --disable-shared') + ->execWithEnv('make clean') + ->execWithEnv('make -j' . $this->builder->concurrency); + + // copy shared library + copy($this->source_dir . '/modules/' . $this->getDistName() . '.so', BUILD_LIB_PATH . '/' . $this->getDistName() . '.so'); + // check shared extension with php-cli + if (file_exists(BUILD_BIN_PATH . '/php')) { + $this->runSharedExtensionCheckUnix(); + } + } + /** * Get current extension version * @@ -241,6 +290,29 @@ class Extension return null; } + public function setBuildStatic(): void + { + $this->build_static = true; + } + + public function setBuildShared(): void + { + if (!in_array('shared', Config::getExtTarget($this->name)) || Config::getExt($this->name, 'type') === 'builtin') { + throw new WrongUsageException("Extension [{$this->name}] does not support shared build !"); + } + $this->build_shared = true; + } + + public function isBuildShared(): bool + { + return $this->build_shared; + } + + public function isBuildStatic(): bool + { + return $this->build_static; + } + /** * @throws RuntimeException */ diff --git a/src/SPC/builder/extension/xdebug.php b/src/SPC/builder/extension/xdebug.php index c5cd901d..3cbd311e 100644 --- a/src/SPC/builder/extension/xdebug.php +++ b/src/SPC/builder/extension/xdebug.php @@ -5,7 +5,17 @@ declare(strict_types=1); namespace SPC\builder\extension; use SPC\builder\Extension; -use SPC\util\DynamicExt; +use SPC\exception\RuntimeException; +use SPC\util\CustomExt; -#[DynamicExt] -class xdebug extends Extension {} +#[CustomExt('xdebug')] +class xdebug extends Extension +{ + public function runSharedExtensionCheckUnix(): void + { + [$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "zend_extension=' . BUILD_LIB_PATH . '/xdebug.so" --ri xdebug'); + if ($ret !== 0) { + throw new RuntimeException('xdebug.so not found'); + } + } +} diff --git a/src/SPC/builder/freebsd/BSDBuilder.php b/src/SPC/builder/freebsd/BSDBuilder.php index c1d41118..b2e246b3 100644 --- a/src/SPC/builder/freebsd/BSDBuilder.php +++ b/src/SPC/builder/freebsd/BSDBuilder.php @@ -118,7 +118,7 @@ class BSDBuilder extends UnixBuilderBase $config_file_scan_dir . $json_74 . $zts . - $this->makeExtensionArgs() + $this->makeStaticExtensionArgs() ); $this->emitPatchPoint('before-php-make'); diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index cd48728f..3b0527f1 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -149,6 +149,7 @@ class LinuxBuilder extends UnixBuilderBase $enable_fpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM; $enable_micro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO; $enable_embed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED; + $emable_dev = ($build_target & BUILD_TARGET_DEV) === BUILD_TARGET_DEV; $mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : ''; // prepare build php envs @@ -182,7 +183,7 @@ class LinuxBuilder extends UnixBuilderBase $json_74 . $zts . $maxExecutionTimers . - $this->makeExtensionArgs() . + $this->makeStaticExtensionArgs() . ' ' . $envs_build_php . ' ' ); @@ -203,6 +204,11 @@ class LinuxBuilder extends UnixBuilderBase logger()->info('building micro'); $this->buildMicro(); } + if ($emable_dev && !$enable_embed) { + // install dynamic php extension building + logger()->info('building dynamic php extension dev dependencies'); + $this->buildPhpDev(); + } if ($enable_embed) { logger()->info('building embed'); if ($enable_micro) { @@ -311,15 +317,15 @@ class LinuxBuilder extends UnixBuilderBase shell()->cd(SOURCE_PATH . '/php-src') ->exec('sed -i "s|//lib|/lib|g" Makefile') ->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install"); - FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'"); - FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#'); - $php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config'); - str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str); - // move mimalloc to the beginning of libs - $php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str); - // move lstdc++ to the end of libs - $php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str); - FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str); + $this->patchPhpScripts(); + } + + protected function buildPhpDev(): void + { + $vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars()); + shell()->cd(SOURCE_PATH . '/php-src') + ->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install-build install-programs install-headers"); + $this->patchPhpScripts(); } private function getMakeExtraVars(): array diff --git a/src/SPC/builder/linux/library/xdebug.php b/src/SPC/builder/linux/library/xdebug.php deleted file mode 100644 index b494bb1d..00000000 --- a/src/SPC/builder/linux/library/xdebug.php +++ /dev/null @@ -1,15 +0,0 @@ -getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : ''; @@ -176,7 +177,7 @@ class MacOSBuilder extends UnixBuilderBase $config_file_scan_dir . $json_74 . $zts . - $this->makeExtensionArgs() . ' ' . + $this->makeStaticExtensionArgs() . ' ' . $envs_build_php ); @@ -197,6 +198,11 @@ class MacOSBuilder extends UnixBuilderBase logger()->info('building micro'); $this->buildMicro(); } + if ($enableDev && !$enableEmbed) { + // install dynamic php extension building + logger()->info('building dynamic php extension dev dependencies'); + $this->buildPhpDev(); + } if ($enableEmbed) { logger()->info('building embed'); if ($enableMicro) { @@ -300,13 +306,15 @@ class MacOSBuilder extends UnixBuilderBase ->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a') ->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o') ->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o'); - FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'"); - FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#'); - $php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config'); - str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str); - // move mimalloc to the beginning of libs - $php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str); - FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str); + $this->patchPhpScripts(); + } + + protected function buildPhpDev(): void + { + $vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars()); + shell()->cd(SOURCE_PATH . '/php-src') + ->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install-build install-programs install-headers"); + $this->patchPhpScripts(); } private function getMakeExtraVars(): array diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index ed07a725..4c8df333 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -146,7 +146,7 @@ abstract class UnixBuilderBase extends BuilderBase throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]"); } - foreach ($this->exts as $ext) { + foreach ($this->getExts(false) as $ext) { logger()->debug('testing ext: ' . $ext->getName()); $ext->runCliCheckUnix(); } @@ -238,4 +238,29 @@ abstract class UnixBuilderBase extends BuilderBase logger()->info('cleaning up'); shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean'); } + + /** + * Patch phpize and php-config if needed + * @throws FileSystemException + */ + protected function patchPhpScripts(): void + { + // patch phpize + if (file_exists(BUILD_BIN_PATH . '/phpize')) { + logger()->debug('Patching phpize prefix'); + FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'"); + FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#'); + } + // patch php-config + if (file_exists(BUILD_BIN_PATH . '/php-config')) { + logger()->debug('Patching php-config prefix and libs order'); + $php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config'); + $php_config_str = str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str); + // move mimalloc to the beginning of libs + $php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str); + // move lstdc++ to the end of libs + $php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str); + FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str); + } + } } diff --git a/src/SPC/builder/unix/library/libcares.php b/src/SPC/builder/unix/library/libcares.php index 076a10c9..d99cc685 100644 --- a/src/SPC/builder/unix/library/libcares.php +++ b/src/SPC/builder/unix/library/libcares.php @@ -26,9 +26,9 @@ trait libcares { shell()->cd($this->source_dir) ->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()]) - ->execWithEnv('./configure --prefix= --enable-static --disable-shared --disable-tests') + ->execWithEnv('./configure --prefix= --enable-static --disable-shared --disable-tests --with-pic') ->execWithEnv("make -j {$this->builder->concurrency}") - ->exec('make install DESTDIR=' . BUILD_ROOT_PATH); + ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH); $this->patchPkgconfPrefix(['libcares.pc'], PKGCONF_PATCH_PREFIX); } diff --git a/src/SPC/builder/unix/library/xdebug.php b/src/SPC/builder/unix/library/xdebug.php deleted file mode 100644 index 1aecb841..00000000 --- a/src/SPC/builder/unix/library/xdebug.php +++ /dev/null @@ -1,26 +0,0 @@ -cd($this->source_dir) - ->exec(BUILD_BIN_PATH . '/phpize') - ->exec('./configure --with-php-config=' . BUILD_BIN_PATH . '/php-config') - ->exec('make clean') - ->exec("make -j{$this->builder->concurrency}"); - copy($this->source_dir . '/modules/xdebug.so', BUILD_LIB_PATH . '/xdebug.so'); - copy($this->source_dir . '/modules/xdebug.la', BUILD_LIB_PATH . '/xdebug.la'); - } -} diff --git a/src/SPC/builder/windows/WindowsBuilder.php b/src/SPC/builder/windows/WindowsBuilder.php index fb7eaa0f..7a604ca8 100644 --- a/src/SPC/builder/windows/WindowsBuilder.php +++ b/src/SPC/builder/windows/WindowsBuilder.php @@ -119,7 +119,7 @@ class WindowsBuilder extends BuilderBase ($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') . ($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') . $config_file_scan_dir . - "{$this->makeExtensionArgs()} " . + "{$this->makeStaticExtensionArgs()} " . $zts . '"' ); @@ -286,7 +286,7 @@ class WindowsBuilder extends BuilderBase throw new RuntimeException('cli failed sanity check'); } - foreach ($this->exts as $ext) { + foreach ($this->getExts(false) as $ext) { logger()->debug('testing ext: ' . $ext->getName()); $ext->runCliCheckWindows(); } diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index b10739eb..ea0b9f95 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -61,6 +61,18 @@ class BuildPHPCommand extends BuildCommand // parse rule with options $rule = $this->parseRules($dynamic_extensions); + // check dynamic extension build env + // macOS must use --no-strip option + if (!empty($dynamic_extensions) && PHP_OS_FAMILY === 'Darwin' && !$this->getOption('no-strip')) { + $this->output->writeln('MacOS does not support dynamic extension loading with stripped binary, please use --no-strip option!'); + return static::FAILURE; + } + // linux must build with glibc + if (!empty($dynamic_extensions) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') !== 'glibc') { + $this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with glibc!'); + return static::FAILURE; + } + if ($rule === BUILD_TARGET_NONE || $rule === BUILD_TARGET_DEV) { $this->output->writeln('Please add at least one build SAPI!'); $this->output->writeln("\t--build-cli\tBuild php-cli SAPI"); @@ -124,7 +136,7 @@ class BuildPHPCommand extends BuildCommand 'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes', 'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no', ]; - if (!empty($dynamic_exts) || ($rule & BUILD_TARGET_EMBED) || ($rule & BUILD_TARGET_DEV)) { + if (!empty($dynamic_extensions) || ($rule & BUILD_TARGET_EMBED) || ($rule & BUILD_TARGET_DEV)) { $indent_texts['Build Dev'] = 'yes'; } if (!empty($this->input->getOption('with-config-file-path'))) { @@ -192,7 +204,8 @@ class BuildPHPCommand extends BuildCommand $builder->buildPHP($rule); // build dynamic extensions if needed - if (!empty($dynamic_exts)) { + if (!empty($dynamic_extensions)) { + logger()->info('Building dynamic extensions ...'); $builder->buildDynamicExts(); } @@ -224,6 +237,12 @@ class BuildPHPCommand extends BuildCommand $path = FileSystem::convertPath("{$build_root_path}/bin/php-fpm"); logger()->info("Static php-fpm binary path{$fixed}: {$path}"); } + if (!empty($dynamic_extensions)) { + foreach ($dynamic_extensions as $ext) { + $path = FileSystem::convertPath("{$build_root_path}/ext/{$ext}.so"); + logger()->info("Dynamic extension path{$fixed}: {$path}"); + } + } // export metadata file_put_contents(BUILD_ROOT_PATH . '/build-extensions.json', json_encode($extensions, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index 5644a3c2..fbaeb7a7 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -127,10 +127,6 @@ class Downloader if (!$match_result) { return $release['assets']; } - if ($source['match'] === 'Source code') { - $url = $release['tarball_url']; - break; - } foreach ($release['assets'] as $asset) { if (preg_match('|' . $source['match'] . '|', $asset['name'])) { $url = $asset['browser_download_url']; @@ -143,9 +139,6 @@ class Downloader throw new DownloaderException("failed to find {$name} release metadata"); } $filename = basename($url); - if ($source['match'] === 'Source code') { - $filename = $name . $filename . '.tar.gz'; - } return [$url, $filename]; } diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php index d3ffc302..2db3498e 100644 --- a/src/SPC/store/SourcePatcher.php +++ b/src/SPC/store/SourcePatcher.php @@ -43,7 +43,7 @@ class SourcePatcher */ public static function patchBeforeBuildconf(BuilderBase $builder): void { - foreach ($builder->getExts() as $ext) { + foreach ($builder->getExts(false) as $ext) { if ($ext->patchBeforeBuildconf() === true) { logger()->info('Extension [' . $ext->getName() . '] patched before buildconf'); } @@ -86,7 +86,7 @@ class SourcePatcher */ public static function patchBeforeConfigure(BuilderBase $builder): void { - foreach ($builder->getExts() as $ext) { + foreach ($builder->getExts(false) as $ext) { if ($ext->patchBeforeConfigure() === true) { logger()->info('Extension [' . $ext->getName() . '] patched before configure'); } @@ -253,7 +253,7 @@ class SourcePatcher // } // call extension patch before make - foreach ($builder->getExts() as $ext) { + foreach ($builder->getExts(false) as $ext) { if ($ext->patchBeforeMake() === true) { logger()->info('Extension [' . $ext->getName() . '] patched before make'); } diff --git a/src/SPC/util/DynamicExt.php b/src/SPC/util/DynamicExt.php deleted file mode 100644 index d5fd549d..00000000 --- a/src/SPC/util/DynamicExt.php +++ /dev/null @@ -1,8 +0,0 @@ -assertStringContainsString('--enable-mbstring', $this->builder->makeExtensionArgs()); + $this->assertStringContainsString('--enable-mbstring', $this->builder->makeStaticExtensionArgs()); } public function testIsLibsOnly() From 625a03e799f92e299655124117657656ed122747 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 24 Mar 2025 23:51:24 +0800 Subject: [PATCH 06/32] phpstan fix --- src/SPC/builder/Extension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index eb7a9509..1ba396a7 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -266,7 +266,7 @@ class Extension { // prepare configure args shell()->cd($this->source_dir) - ->setEnv(['CFLAGS' => $this->builder->arch_c_flags]) + ->setEnv(['CFLAGS' => $this->builder->arch_c_flags ?? '']) ->execWithEnv(BUILD_BIN_PATH . '/phpize') ->execWithEnv('./configure ' . $this->getUnixConfigureArg() . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-static --disable-shared') ->execWithEnv('make clean') From 8cd69b2b707a3b6e535f3a8a83215dbb4beda9c3 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 25 Mar 2025 00:05:46 +0800 Subject: [PATCH 07/32] Support zero extension build result --- src/SPC/command/BaseCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/command/BaseCommand.php b/src/SPC/command/BaseCommand.php index 3688c249..a1610cae 100644 --- a/src/SPC/command/BaseCommand.php +++ b/src/SPC/command/BaseCommand.php @@ -165,7 +165,7 @@ abstract class BaseCommand extends Command return SPC_EXTENSION_ALIAS[$lower]; } return $lower; - }, is_array($ext_list) ? $ext_list : explode(',', $ext_list)); + }, is_array($ext_list) ? $ext_list : array_filter(explode(',', $ext_list))); // filter internals return array_values(array_filter($ls, function ($x) { From 6dec44bdc3421b64f126058f83578b59383c6df6 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 25 Mar 2025 00:17:01 +0800 Subject: [PATCH 08/32] sort-config --- config/ext.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/ext.json b/config/ext.json index ade6099c..e0caba22 100644 --- a/config/ext.json +++ b/config/ext.json @@ -920,7 +920,9 @@ "xdebug": { "type": "external", "source": "xdebug", - "target": ["shared"], + "target": [ + "shared" + ], "support": { "Windows": "wip", "BSD": "no", From fc08e5cf23922cadd404a1f4f2df548b7b9eca27 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 25 Mar 2025 00:17:15 +0800 Subject: [PATCH 09/32] Remove brotli support for shared build --- src/SPC/builder/extension/swoole.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/extension/swoole.php b/src/SPC/builder/extension/swoole.php index 78aaf339..3531c891 100644 --- a/src/SPC/builder/extension/swoole.php +++ b/src/SPC/builder/extension/swoole.php @@ -49,7 +49,9 @@ class swoole extends Extension // additional feature: c-ares, brotli, nghttp2 (can be disabled, but we enable it by default in config to support full network feature) $arg .= $this->builder->getLib('libcares') ? ' --enable-cares' : ''; - $arg .= $this->builder->getLib('brotli') ? (' --with-brotli-dir=' . BUILD_ROOT_PATH) : ''; + if (!$this->isBuildShared()) { + $arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : ''; + } $arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-dir=' . BUILD_ROOT_PATH) : ''; // additional feature: swoole-pgsql, it should depend on lib [postgresql], but it will lack of CFLAGS etc. From 84597546929b3f5d56fb4801612764ed6ae216c6 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 25 Mar 2025 13:29:55 +0800 Subject: [PATCH 10/32] Change to --enable-shared --disable-static --- src/SPC/builder/Extension.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 1ba396a7..7091aaf1 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -254,6 +254,12 @@ class Extension // do nothing, just throw wrong usage exception if not valid } + /** + * Build shared extension + * + * @throws WrongUsageException + * @throws RuntimeException + */ public function buildShared(): void { match (PHP_OS_FAMILY) { @@ -262,13 +268,18 @@ class Extension }; } + /** + * Build shared extension for Unix + * + * @throws RuntimeException + */ public function buildUnixShared(): void { // prepare configure args shell()->cd($this->source_dir) ->setEnv(['CFLAGS' => $this->builder->arch_c_flags ?? '']) ->execWithEnv(BUILD_BIN_PATH . '/phpize') - ->execWithEnv('./configure ' . $this->getUnixConfigureArg() . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-static --disable-shared') + ->execWithEnv('./configure ' . $this->getUnixConfigureArg() . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-shared --disable-static') ->execWithEnv('make clean') ->execWithEnv('make -j' . $this->builder->concurrency); From f37110605eec4972ed661ac9202b4aaaff4c5a41 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 25 Mar 2025 16:13:41 +0800 Subject: [PATCH 11/32] Remove dev build target --- src/SPC/builder/BuilderBase.php | 2 +- src/SPC/builder/linux/LinuxBuilder.php | 14 ----------- src/SPC/builder/macos/MacOSBuilder.php | 14 ----------- src/SPC/command/BuildPHPCommand.php | 34 ++++++++++++-------------- src/globals/defines.php | 3 +-- 5 files changed, 18 insertions(+), 49 deletions(-) diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 0e864460..665ce7fa 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -227,7 +227,7 @@ abstract class BuilderBase */ abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE); - public function buildDynamicExts(): void + public function buildSharedExts(): void { foreach ($this->getExts() as $ext) { if (!$ext->isBuildShared()) { diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 3b0527f1..e38714f1 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -149,7 +149,6 @@ class LinuxBuilder extends UnixBuilderBase $enable_fpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM; $enable_micro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO; $enable_embed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED; - $emable_dev = ($build_target & BUILD_TARGET_DEV) === BUILD_TARGET_DEV; $mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : ''; // prepare build php envs @@ -204,11 +203,6 @@ class LinuxBuilder extends UnixBuilderBase logger()->info('building micro'); $this->buildMicro(); } - if ($emable_dev && !$enable_embed) { - // install dynamic php extension building - logger()->info('building dynamic php extension dev dependencies'); - $this->buildPhpDev(); - } if ($enable_embed) { logger()->info('building embed'); if ($enable_micro) { @@ -320,14 +314,6 @@ class LinuxBuilder extends UnixBuilderBase $this->patchPhpScripts(); } - protected function buildPhpDev(): void - { - $vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars()); - shell()->cd(SOURCE_PATH . '/php-src') - ->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install-build install-programs install-headers"); - $this->patchPhpScripts(); - } - private function getMakeExtraVars(): array { return [ diff --git a/src/SPC/builder/macos/MacOSBuilder.php b/src/SPC/builder/macos/MacOSBuilder.php index 4da9e455..9f9ad684 100644 --- a/src/SPC/builder/macos/MacOSBuilder.php +++ b/src/SPC/builder/macos/MacOSBuilder.php @@ -146,7 +146,6 @@ class MacOSBuilder extends UnixBuilderBase $enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM; $enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO; $enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED; - $enableDev = ($build_target & BUILD_TARGET_DEV) === BUILD_TARGET_DEV; // prepare build php envs $mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : ''; @@ -198,11 +197,6 @@ class MacOSBuilder extends UnixBuilderBase logger()->info('building micro'); $this->buildMicro(); } - if ($enableDev && !$enableEmbed) { - // install dynamic php extension building - logger()->info('building dynamic php extension dev dependencies'); - $this->buildPhpDev(); - } if ($enableEmbed) { logger()->info('building embed'); if ($enableMicro) { @@ -309,14 +303,6 @@ class MacOSBuilder extends UnixBuilderBase $this->patchPhpScripts(); } - protected function buildPhpDev(): void - { - $vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars()); - shell()->cd(SOURCE_PATH . '/php-src') - ->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install-build install-programs install-headers"); - $this->patchPhpScripts(); - } - private function getMakeExtraVars(): array { return [ diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index ea0b9f95..f55bebbf 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -27,12 +27,11 @@ class BuildPHPCommand extends BuildCommand $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', ''); - $this->addOption('with-dynamic', 'D', InputOption::VALUE_REQUIRED, 'Dynamic extensions to build, comma separated', ''); + $this->addOption('with-shared', 'D', InputOption::VALUE_REQUIRED, 'Shared extensions to build, comma separated', ''); $this->addOption('build-micro', null, null, 'Build micro SAPI'); $this->addOption('build-cli', null, null, 'Build cli SAPI'); $this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)'); $this->addOption('build-embed', null, null, 'Build embed SAPI (not available on Windows)'); - $this->addOption('build-dev', null, null, 'Build dev things for building dynamic extensions (not available on Windows)'); $this->addOption('build-all', null, null, 'Build all SAPI'); $this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions'); $this->addOption('disable-opcache-jit', null, null, 'disable opcache jit'); @@ -54,26 +53,26 @@ class BuildPHPCommand extends BuildCommand // transform string to array $libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs')))); // transform string to array - $dynamic_extensions = array_map('trim', array_filter(explode(',', $this->getOption('with-dynamic')))); + $shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('with-shared')))); // transform string to array $static_extensions = $this->parseExtensionList($this->getArgument('extensions')); // parse rule with options - $rule = $this->parseRules($dynamic_extensions); + $rule = $this->parseRules($shared_extensions); // check dynamic extension build env // macOS must use --no-strip option - if (!empty($dynamic_extensions) && PHP_OS_FAMILY === 'Darwin' && !$this->getOption('no-strip')) { + if (!empty($shared_extensions) && PHP_OS_FAMILY === 'Darwin' && !$this->getOption('no-strip')) { $this->output->writeln('MacOS does not support dynamic extension loading with stripped binary, please use --no-strip option!'); return static::FAILURE; } // linux must build with glibc - if (!empty($dynamic_extensions) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') !== 'glibc') { + if (!empty($shared_extensions) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') !== 'glibc') { $this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with glibc!'); return static::FAILURE; } - if ($rule === BUILD_TARGET_NONE || $rule === BUILD_TARGET_DEV) { + if ($rule === BUILD_TARGET_NONE) { $this->output->writeln('Please add at least one build SAPI!'); $this->output->writeln("\t--build-cli\tBuild php-cli SAPI"); $this->output->writeln("\t--build-micro\tBuild phpmicro SAPI"); @@ -123,9 +122,9 @@ class BuildPHPCommand extends BuildCommand $builder = BuilderProvider::makeBuilderByInput($this->input); $include_suggest_ext = $this->getOption('with-suggested-exts'); $include_suggest_lib = $this->getOption('with-suggested-libs'); - [$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs(array_merge($static_extensions, $dynamic_extensions), $libraries, $include_suggest_ext, $include_suggest_lib); + [$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs(array_merge($static_extensions, $shared_extensions), $libraries, $include_suggest_ext, $include_suggest_lib); $display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package'])); - $display_extensions = array_map(fn ($ext) => in_array($ext, $dynamic_extensions) ? "*{$ext}" : $ext, $extensions); + $display_extensions = array_map(fn ($ext) => in_array($ext, $shared_extensions) ? "*{$ext}" : $ext, $extensions); // print info $indent_texts = [ @@ -136,7 +135,7 @@ class BuildPHPCommand extends BuildCommand 'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes', 'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no', ]; - if (!empty($dynamic_extensions) || ($rule & BUILD_TARGET_EMBED) || ($rule & BUILD_TARGET_DEV)) { + if (!empty($shared_extensions) || ($rule & BUILD_TARGET_EMBED)) { $indent_texts['Build Dev'] = 'yes'; } if (!empty($this->input->getOption('with-config-file-path'))) { @@ -172,7 +171,7 @@ class BuildPHPCommand extends BuildCommand // compile libraries $builder->proveLibs($libraries); // check extensions - $builder->proveExts($extensions, shared_build_extensions: $dynamic_extensions); + $builder->proveExts($extensions, shared_build_extensions: $shared_extensions); // validate libs and extensions $builder->validateLibsAndExts(); @@ -204,9 +203,9 @@ class BuildPHPCommand extends BuildCommand $builder->buildPHP($rule); // build dynamic extensions if needed - if (!empty($dynamic_extensions)) { - logger()->info('Building dynamic extensions ...'); - $builder->buildDynamicExts(); + if (!empty($shared_extensions)) { + logger()->info('Building shared extensions ...'); + $builder->buildSharedExts(); } // compile stopwatch :P @@ -237,8 +236,8 @@ class BuildPHPCommand extends BuildCommand $path = FileSystem::convertPath("{$build_root_path}/bin/php-fpm"); logger()->info("Static php-fpm binary path{$fixed}: {$path}"); } - if (!empty($dynamic_extensions)) { - foreach ($dynamic_extensions as $ext) { + if (!empty($shared_extensions)) { + foreach ($shared_extensions as $ext) { $path = FileSystem::convertPath("{$build_root_path}/ext/{$ext}.so"); logger()->info("Dynamic extension path{$fixed}: {$path}"); } @@ -277,8 +276,7 @@ class BuildPHPCommand extends BuildCommand $rule |= ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE); - $rule |= ($this->getOption('build-embed') ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE); - $rule |= ($this->getOption('build-dev') || !empty($dynamic_exts) ? BUILD_TARGET_DEV : BUILD_TARGET_NONE); + $rule |= ($this->getOption('build-embed') || !empty($dynamic_exts) ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE); return $rule; } diff --git a/src/globals/defines.php b/src/globals/defines.php index a7059775..46c98915 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -61,8 +61,7 @@ const BUILD_TARGET_CLI = 1; // build cli const BUILD_TARGET_MICRO = 2; // build micro const BUILD_TARGET_FPM = 4; // build fpm const BUILD_TARGET_EMBED = 8; // build embed -const BUILD_TARGET_DEV = 16; // build dev -const BUILD_TARGET_ALL = 31; // build all +const BUILD_TARGET_ALL = 15; // build all // doctor error fix policy const FIX_POLICY_DIE = 1; // die directly From df06a4bb2c0de969e9683f24d8081e9af2dbebde Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 26 Mar 2025 12:38:53 +0800 Subject: [PATCH 12/32] Fix shared extension does not build bug --- src/SPC/util/SPCConfigUtil.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index f4a121eb..01e47076 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -9,14 +9,15 @@ use SPC\builder\BuilderProvider; use SPC\builder\macos\MacOSBuilder; use SPC\store\Config; use Symfony\Component\Console\Input\ArgvInput; -use Symfony\Component\Console\Input\InputInterface; class SPCConfigUtil { - public function __construct(private ?BuilderBase $builder = null, ?InputInterface $input = null) + private ?BuilderBase $builder = null; + + public function __construct(?BuilderBase $builder = null) { - if ($builder === null) { - $this->builder = BuilderProvider::makeBuilderByInput($input ?? new ArgvInput()); + if ($builder !== null) { + $this->builder = $builder; // BuilderProvider::makeBuilderByInput($input ?? new ArgvInput()); } } @@ -25,8 +26,11 @@ class SPCConfigUtil [$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib); ob_start(); - $this->builder->proveLibs($libraries); - $this->builder->proveExts($extensions); + if ($this->builder === null) { + $this->builder = BuilderProvider::makeBuilderByInput(new ArgvInput()); + $this->builder->proveLibs($libraries); + $this->builder->proveExts($extensions); + } ob_get_clean(); $ldflags = $this->getLdflagsString(); $libs = $this->getLibsString($libraries); From ae23b721b31d96dbe2125e4b88fd65141a81cb85 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 26 Mar 2025 12:38:59 +0800 Subject: [PATCH 13/32] Fix shared extension does not build bug --- src/SPC/builder/BuilderBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 665ce7fa..0f329e62 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -202,12 +202,12 @@ abstract class BuilderBase $class = CustomExt::getExtClass($extension); /** @var Extension $ext */ $ext = new $class($extension, $this); - $this->addExt($ext); if (in_array($extension, $shared_build_extensions)) { $ext->setBuildShared(); } else { $ext->setBuildStatic(); } + $this->addExt($ext); } if ($skip_check_deps) { From 8cb93bc1fe8e9e0eb283540fdf481c49b0918523 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 26 Mar 2025 12:39:15 +0800 Subject: [PATCH 14/32] Add more exception and log --- src/SPC/builder/Extension.php | 3 +++ src/SPC/command/BuildPHPCommand.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 7091aaf1..b1943c40 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -303,6 +303,9 @@ class Extension public function setBuildStatic(): void { + if (!in_array('static', Config::getExtTarget($this->name))) { + throw new WrongUsageException("Extension [{$this->name}] does not support static build !"); + } $this->build_static = true; } diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index f55bebbf..ca258f5d 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -238,8 +238,8 @@ class BuildPHPCommand extends BuildCommand } if (!empty($shared_extensions)) { foreach ($shared_extensions as $ext) { - $path = FileSystem::convertPath("{$build_root_path}/ext/{$ext}.so"); - logger()->info("Dynamic extension path{$fixed}: {$path}"); + $path = FileSystem::convertPath("{$build_root_path}/lib/{$ext}.so"); + logger()->info("Shared extension [{$ext}] path{$fixed}: {$path}"); } } From 556455919299aa3d544e5e4567ab8d0f9d087074 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 26 Mar 2025 12:39:55 +0800 Subject: [PATCH 15/32] Change `--with-shared` to `--build-shared` --- src/SPC/command/BuildPHPCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index ca258f5d..f781c0e5 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -27,7 +27,7 @@ class BuildPHPCommand extends BuildCommand $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', ''); - $this->addOption('with-shared', 'D', InputOption::VALUE_REQUIRED, 'Shared extensions to build, comma separated', ''); + $this->addOption('build-shared', 'D', InputOption::VALUE_REQUIRED, 'Shared extensions to build, comma separated', ''); $this->addOption('build-micro', null, null, 'Build micro SAPI'); $this->addOption('build-cli', null, null, 'Build cli SAPI'); $this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)'); @@ -53,7 +53,7 @@ class BuildPHPCommand extends BuildCommand // transform string to array $libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs')))); // transform string to array - $shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('with-shared')))); + $shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared')))); // transform string to array $static_extensions = $this->parseExtensionList($this->getArgument('extensions')); From 0beb97648afc8bc5a41ca958b150d6f85159d898 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 26 Mar 2025 12:41:13 +0800 Subject: [PATCH 16/32] Fix phpstan --- src/SPC/command/SPCConfigCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/command/SPCConfigCommand.php b/src/SPC/command/SPCConfigCommand.php index 0377ace9..d3c7a0b2 100644 --- a/src/SPC/command/SPCConfigCommand.php +++ b/src/SPC/command/SPCConfigCommand.php @@ -37,7 +37,7 @@ class SPCConfigCommand extends BuildCommand $include_suggest_ext = $this->getOption('with-suggested-exts'); $include_suggest_lib = $this->getOption('with-suggested-libs'); - $util = new SPCConfigUtil(null, $this->input); + $util = new SPCConfigUtil(); $config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib); if ($this->getOption('includes')) { From acdec64144dd6d4dac012e78cd52f28be7ca8746 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 27 Mar 2025 09:36:46 +0700 Subject: [PATCH 17/32] build static and shared at the same time --- src/SPC/builder/BuilderBase.php | 35 +++++++++++++++------------ src/SPC/builder/extension/swoole.php | 4 +-- src/SPC/command/BuildPHPCommand.php | 2 +- src/SPC/command/dev/ExtVerCommand.php | 4 +-- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 0f329e62..865139bb 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -122,9 +122,9 @@ abstract class BuilderBase * * @return Extension[] */ - public function getExts(bool $including_dynamic = true): array + public function getExts(bool $including_shared = true): array { - if ($including_dynamic) { + if ($including_shared) { return $this->exts; } return array_filter($this->exts, fn ($ext) => !$ext->isBuildShared()); @@ -173,18 +173,20 @@ abstract class BuilderBase * @throws \Throwable|WrongUsageException * @internal */ - public function proveExts(array $extensions, bool $skip_check_deps = false, array $shared_build_extensions = []): void + public function proveExts(array $static_extensions, array $shared_extensions = [], bool $skip_check_deps = false): void { CustomExt::loadCustomExt(); // judge ext - foreach ($extensions as $ext) { - // if extension does not support static && no shared build, throw exception - if (!in_array('static', Config::getExtTarget($ext)) && !in_array($ext, $shared_build_extensions)) { - throw new WrongUsageException('Extension [' . $ext . '] does not support static build !'); + foreach ($static_extensions as $ext) { + // if extension does not support static build, throw exception + if (!in_array('static', Config::getExtTarget($ext))) { + throw new WrongUsageException('Extension [' . $ext . '] does not support static build!'); } - // if extension does not support shared && no static build, throw exception - if (!in_array('shared', Config::getExtTarget($ext)) && !in_array($ext, $shared_build_extensions)) { - throw new WrongUsageException('Extension [' . $ext . '] does not support shared build !'); + } + foreach ($shared_extensions as $ext) { + // if extension does not support shared build, throw exception + if (!in_array('shared', Config::getExtTarget($ext)) && !in_array($ext, $shared_extensions)) { + throw new WrongUsageException('Extension [' . $ext . '] does not support shared build!'); } } $this->emitPatchPoint('before-php-extract'); @@ -196,17 +198,18 @@ abstract class BuilderBase $this->emitPatchPoint('after-micro-extract'); } $this->emitPatchPoint('before-exts-extract'); - SourceManager::initSource(exts: $extensions); + SourceManager::initSource(exts: $static_extensions); $this->emitPatchPoint('after-exts-extract'); - foreach ($extensions as $extension) { + foreach ([...$static_extensions, ...$shared_extensions] as $extension) { $class = CustomExt::getExtClass($extension); /** @var Extension $ext */ $ext = new $class($extension, $this); - if (in_array($extension, $shared_build_extensions)) { - $ext->setBuildShared(); - } else { + if (in_array($extension, $static_extensions)) { $ext->setBuildStatic(); } + if (in_array($extension, $shared_extensions)) { + $ext->setBuildShared(); + } $this->addExt($ext); } @@ -217,7 +220,7 @@ abstract class BuilderBase foreach ($this->getExts() as $ext) { $ext->checkDependency(); } - $this->ext_list = $extensions; + $this->ext_list = [...$static_extensions, ...$shared_extensions]; } /** diff --git a/src/SPC/builder/extension/swoole.php b/src/SPC/builder/extension/swoole.php index 3531c891..3c04a298 100644 --- a/src/SPC/builder/extension/swoole.php +++ b/src/SPC/builder/extension/swoole.php @@ -49,9 +49,7 @@ class swoole extends Extension // additional feature: c-ares, brotli, nghttp2 (can be disabled, but we enable it by default in config to support full network feature) $arg .= $this->builder->getLib('libcares') ? ' --enable-cares' : ''; - if (!$this->isBuildShared()) { - $arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : ''; - } + $arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : ''; $arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-dir=' . BUILD_ROOT_PATH) : ''; // additional feature: swoole-pgsql, it should depend on lib [postgresql], but it will lack of CFLAGS etc. diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index f781c0e5..c5fa6c9e 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -171,7 +171,7 @@ class BuildPHPCommand extends BuildCommand // compile libraries $builder->proveLibs($libraries); // check extensions - $builder->proveExts($extensions, shared_build_extensions: $shared_extensions); + $builder->proveExts($extensions, shared_extensions: $shared_extensions); // validate libs and extensions $builder->validateLibsAndExts(); diff --git a/src/SPC/command/dev/ExtVerCommand.php b/src/SPC/command/dev/ExtVerCommand.php index 0f08fa9a..3154a6bb 100644 --- a/src/SPC/command/dev/ExtVerCommand.php +++ b/src/SPC/command/dev/ExtVerCommand.php @@ -6,7 +6,6 @@ namespace SPC\command\dev; use SPC\builder\BuilderProvider; use SPC\command\BaseCommand; -use SPC\store\Config; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -31,8 +30,7 @@ class ExtVerCommand extends BaseCommand // Get lib object $builder = BuilderProvider::makeBuilderByInput($this->input); - $ext_conf = Config::getExt($this->getArgument('extension')); - $builder->proveExts([$this->getArgument('extension')], true); + $builder->proveExts([$this->getArgument('extension')], [], true); // Check whether lib is extracted // if (!is_dir(SOURCE_PATH . '/' . $this->getArgument('library'))) { From 48f257f85ab0e365b469355a5030391cadb4b843 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 27 Mar 2025 11:12:19 +0700 Subject: [PATCH 18/32] unixconfigurearg needs to know if currently building shared or static --- config/env.ini | 2 +- config/ext.json | 8 ++++++++ src/SPC/builder/BuilderBase.php | 2 +- src/SPC/builder/Extension.php | 18 ++++++++++++------ src/SPC/builder/extension/amqp.php | 2 +- src/SPC/builder/extension/dba.php | 2 +- src/SPC/builder/extension/enchant.php | 2 +- src/SPC/builder/extension/event.php | 2 +- src/SPC/builder/extension/ffi.php | 2 +- src/SPC/builder/extension/gd.php | 2 +- src/SPC/builder/extension/glfw.php | 2 +- src/SPC/builder/extension/grpc.php | 2 +- src/SPC/builder/extension/imagick.php | 2 +- src/SPC/builder/extension/imap.php | 2 +- src/SPC/builder/extension/memcache.php | 2 +- src/SPC/builder/extension/memcached.php | 2 +- src/SPC/builder/extension/mongodb.php | 2 +- src/SPC/builder/extension/odbc.php | 2 +- src/SPC/builder/extension/opcache.php | 2 +- src/SPC/builder/extension/openssl.php | 2 +- src/SPC/builder/extension/pdo_odbc.php | 2 +- src/SPC/builder/extension/pgsql.php | 2 +- src/SPC/builder/extension/redis.php | 2 +- src/SPC/builder/extension/snappy.php | 2 +- src/SPC/builder/extension/spx.php | 2 +- src/SPC/builder/extension/swoole.php | 6 ++++-- .../builder/extension/swoole_hook_mysql.php | 2 +- .../builder/extension/swoole_hook_pgsql.php | 2 +- .../builder/extension/swoole_hook_sqlite.php | 2 +- src/SPC/builder/extension/xdebug.php | 2 +- src/SPC/builder/extension/xlswriter.php | 2 +- src/SPC/builder/extension/xml.php | 2 +- src/SPC/builder/extension/yac.php | 2 +- src/SPC/builder/extension/zlib.php | 2 +- src/SPC/builder/extension/zstd.php | 2 +- src/SPC/command/BuildPHPCommand.php | 2 +- src/SPC/store/Config.php | 2 +- src/SPC/util/SPCConfigUtil.php | 6 +++--- 38 files changed, 61 insertions(+), 45 deletions(-) diff --git a/config/env.ini b/config/env.ini index 3ef5ba0f..131fa07e 100644 --- a/config/env.ini +++ b/config/env.ini @@ -99,7 +99,7 @@ SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm" ; EXTRA_CFLAGS for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-ident -fPIE -fPIC" ; EXTRA_LIBS for `make` php -SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="" +SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm" ; EXTRA_LDFLAGS_PROGRAM for `make` php SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie" diff --git a/config/ext.json b/config/ext.json index e0caba22..3d99350c 100644 --- a/config/ext.json +++ b/config/ext.json @@ -771,6 +771,10 @@ "Windows": "no", "BSD": "wip" }, + "target": [ + "static", + "shared" + ], "notes": true, "type": "external", "source": "swoole", @@ -1043,6 +1047,10 @@ "support": { "BSD": "wip" }, + "target": [ + "static", + "shared" + ], "type": "builtin", "arg-type": "with-prefix", "arg-type-windows": "enable", diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 865139bb..429d950a 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -198,7 +198,7 @@ abstract class BuilderBase $this->emitPatchPoint('after-micro-extract'); } $this->emitPatchPoint('before-exts-extract'); - SourceManager::initSource(exts: $static_extensions); + SourceManager::initSource(exts: [...$static_extensions, ...$shared_extensions]); $this->emitPatchPoint('after-exts-extract'); foreach ([...$static_extensions, ...$shared_extensions] as $extension) { $class = CustomExt::getExtClass($extension); diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index b1943c40..6ada640a 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -150,7 +150,7 @@ class Extension // Windows is not supported yet } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return ''; } @@ -188,7 +188,13 @@ class Extension /** * Run shared extension check when cli is enabled */ - public function runSharedExtensionCheckUnix(): void {} + public function runSharedExtensionCheckUnix(): void + { + [$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "extension=' . BUILD_LIB_PATH . '/' . $this->getName() . '.so" --ri ' . $this->getName()); + if ($ret !== 0) { + throw new RuntimeException($this->getName() . '.so failed to load'); + } + } /** * @throws RuntimeException @@ -279,7 +285,7 @@ class Extension shell()->cd($this->source_dir) ->setEnv(['CFLAGS' => $this->builder->arch_c_flags ?? '']) ->execWithEnv(BUILD_BIN_PATH . '/phpize') - ->execWithEnv('./configure ' . $this->getUnixConfigureArg() . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-shared --disable-static') + ->execWithEnv('./configure ' . $this->getUnixConfigureArg(true) . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-shared --disable-static') ->execWithEnv('make clean') ->execWithEnv('make -j' . $this->builder->concurrency); @@ -304,15 +310,15 @@ class Extension public function setBuildStatic(): void { if (!in_array('static', Config::getExtTarget($this->name))) { - throw new WrongUsageException("Extension [{$this->name}] does not support static build !"); + throw new WrongUsageException("Extension [{$this->name}] does not support static build!"); } $this->build_static = true; } public function setBuildShared(): void { - if (!in_array('shared', Config::getExtTarget($this->name)) || Config::getExt($this->name, 'type') === 'builtin') { - throw new WrongUsageException("Extension [{$this->name}] does not support shared build !"); + if (!in_array('shared', Config::getExtTarget($this->name))) { + throw new WrongUsageException("Extension [{$this->name}] does not support shared build!"); } $this->build_shared = true; } diff --git a/src/SPC/builder/extension/amqp.php b/src/SPC/builder/extension/amqp.php index d795f47d..8fbfea24 100644 --- a/src/SPC/builder/extension/amqp.php +++ b/src/SPC/builder/extension/amqp.php @@ -23,7 +23,7 @@ class amqp extends Extension return false; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--with-amqp --with-librabbitmq-dir=' . BUILD_ROOT_PATH; } diff --git a/src/SPC/builder/extension/dba.php b/src/SPC/builder/extension/dba.php index 011e4746..bd7388f3 100644 --- a/src/SPC/builder/extension/dba.php +++ b/src/SPC/builder/extension/dba.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('dba')] class dba extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . BUILD_ROOT_PATH) : ''; return '--enable-dba' . $qdbm; diff --git a/src/SPC/builder/extension/enchant.php b/src/SPC/builder/extension/enchant.php index 26578519..c3046409 100644 --- a/src/SPC/builder/extension/enchant.php +++ b/src/SPC/builder/extension/enchant.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('enchant')] class enchant extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $glibs = [ '/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgio-2.0.a', diff --git a/src/SPC/builder/extension/event.php b/src/SPC/builder/extension/event.php index a1cc7bcc..95d9aba6 100644 --- a/src/SPC/builder/extension/event.php +++ b/src/SPC/builder/extension/event.php @@ -13,7 +13,7 @@ use SPC\util\CustomExt; #[CustomExt('event')] class event extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $arg = '--with-event-core --with-event-extra --with-event-libevent-dir=' . BUILD_ROOT_PATH; if ($this->builder->getLib('openssl')) { diff --git a/src/SPC/builder/extension/ffi.php b/src/SPC/builder/extension/ffi.php index 6f294481..51c3efac 100644 --- a/src/SPC/builder/extension/ffi.php +++ b/src/SPC/builder/extension/ffi.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('ffi')] class ffi extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--with-ffi --enable-zend-signals'; } diff --git a/src/SPC/builder/extension/gd.php b/src/SPC/builder/extension/gd.php index 707a898f..f872733b 100644 --- a/src/SPC/builder/extension/gd.php +++ b/src/SPC/builder/extension/gd.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('gd')] class gd extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $arg = '--enable-gd'; $arg .= $this->builder->getLib('freetype') ? ' --with-freetype' : ''; diff --git a/src/SPC/builder/extension/glfw.php b/src/SPC/builder/extension/glfw.php index c9d0c4f7..444b5d93 100644 --- a/src/SPC/builder/extension/glfw.php +++ b/src/SPC/builder/extension/glfw.php @@ -30,7 +30,7 @@ class glfw extends Extension return true; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH; } diff --git a/src/SPC/builder/extension/grpc.php b/src/SPC/builder/extension/grpc.php index a63bad9d..852f2933 100644 --- a/src/SPC/builder/extension/grpc.php +++ b/src/SPC/builder/extension/grpc.php @@ -44,7 +44,7 @@ class grpc extends Extension return true; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--enable-grpc=' . BUILD_ROOT_PATH . '/grpc GRPC_LIB_SUBDIR=' . BUILD_LIB_PATH; } diff --git a/src/SPC/builder/extension/imagick.php b/src/SPC/builder/extension/imagick.php index 7becb143..c73a5f29 100644 --- a/src/SPC/builder/extension/imagick.php +++ b/src/SPC/builder/extension/imagick.php @@ -22,7 +22,7 @@ class imagick extends Extension return true; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--with-imagick=' . BUILD_ROOT_PATH; } diff --git a/src/SPC/builder/extension/imap.php b/src/SPC/builder/extension/imap.php index 3aa2c284..9cc9a87f 100644 --- a/src/SPC/builder/extension/imap.php +++ b/src/SPC/builder/extension/imap.php @@ -33,7 +33,7 @@ class imap extends Extension } } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $arg = '--with-imap=' . BUILD_ROOT_PATH; if ($this->builder->getLib('openssl') !== null) { diff --git a/src/SPC/builder/extension/memcache.php b/src/SPC/builder/extension/memcache.php index eb3e2969..4625cae2 100644 --- a/src/SPC/builder/extension/memcache.php +++ b/src/SPC/builder/extension/memcache.php @@ -12,7 +12,7 @@ use SPC\util\CustomExt; #[CustomExt('memcache')] class memcache extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH; } diff --git a/src/SPC/builder/extension/memcached.php b/src/SPC/builder/extension/memcached.php index 1ef679d9..9c433954 100644 --- a/src/SPC/builder/extension/memcached.php +++ b/src/SPC/builder/extension/memcached.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('memcached')] class memcached extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $rootdir = BUILD_ROOT_PATH; $zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : "--with-zlib-dir={$rootdir}"; diff --git a/src/SPC/builder/extension/mongodb.php b/src/SPC/builder/extension/mongodb.php index 2096de05..7ba1ea33 100644 --- a/src/SPC/builder/extension/mongodb.php +++ b/src/SPC/builder/extension/mongodb.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('mongodb')] class mongodb extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $arg = ' --enable-mongodb '; $arg .= ' --with-mongodb-system-libs=no --with-mongodb-client-side-encryption=no '; diff --git a/src/SPC/builder/extension/odbc.php b/src/SPC/builder/extension/odbc.php index 6234f4e8..ac5c3e8f 100644 --- a/src/SPC/builder/extension/odbc.php +++ b/src/SPC/builder/extension/odbc.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('odbc')] class odbc extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--with-unixODBC=' . BUILD_ROOT_PATH; } diff --git a/src/SPC/builder/extension/opcache.php b/src/SPC/builder/extension/opcache.php index 5276261a..5d9dda0a 100644 --- a/src/SPC/builder/extension/opcache.php +++ b/src/SPC/builder/extension/opcache.php @@ -42,7 +42,7 @@ class opcache extends Extension return file_put_contents(SOURCE_PATH . '/php-src/.opcache_patched', '1') !== false; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--enable-opcache'; } diff --git a/src/SPC/builder/extension/openssl.php b/src/SPC/builder/extension/openssl.php index 2576b0b2..add1aede 100644 --- a/src/SPC/builder/extension/openssl.php +++ b/src/SPC/builder/extension/openssl.php @@ -23,7 +23,7 @@ class openssl extends Extension return false; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $openssl_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-openssl-dir=' . BUILD_ROOT_PATH; return '--with-openssl=' . BUILD_ROOT_PATH . $openssl_dir; diff --git a/src/SPC/builder/extension/pdo_odbc.php b/src/SPC/builder/extension/pdo_odbc.php index 4ab45904..e436f381 100644 --- a/src/SPC/builder/extension/pdo_odbc.php +++ b/src/SPC/builder/extension/pdo_odbc.php @@ -17,7 +17,7 @@ class pdo_odbc extends Extension return true; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--with-pdo-odbc=unixODBC,' . BUILD_ROOT_PATH; } diff --git a/src/SPC/builder/extension/pgsql.php b/src/SPC/builder/extension/pgsql.php index 74085b21..1c63f163 100644 --- a/src/SPC/builder/extension/pgsql.php +++ b/src/SPC/builder/extension/pgsql.php @@ -33,7 +33,7 @@ class pgsql extends Extension * @throws WrongUsageException * @throws RuntimeException */ - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { if ($this->builder->getPHPVersionID() >= 80400) { return '--with-pgsql PGSQL_CFLAGS=-I' . BUILD_INCLUDE_PATH . ' PGSQL_LIBS="-L' . BUILD_LIB_PATH . ' -lpq -lpgport -lpgcommon"'; diff --git a/src/SPC/builder/extension/redis.php b/src/SPC/builder/extension/redis.php index bffc768e..0b60075c 100644 --- a/src/SPC/builder/extension/redis.php +++ b/src/SPC/builder/extension/redis.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('redis')] class redis extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $arg = '--enable-redis'; $arg .= $this->builder->getExt('session') ? ' --enable-redis-session' : ' --disable-redis-session'; diff --git a/src/SPC/builder/extension/snappy.php b/src/SPC/builder/extension/snappy.php index 2dc2a33a..896a9be2 100644 --- a/src/SPC/builder/extension/snappy.php +++ b/src/SPC/builder/extension/snappy.php @@ -26,7 +26,7 @@ class snappy extends Extension return true; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"'; } diff --git a/src/SPC/builder/extension/spx.php b/src/SPC/builder/extension/spx.php index 6c2a6a19..dc341e39 100644 --- a/src/SPC/builder/extension/spx.php +++ b/src/SPC/builder/extension/spx.php @@ -21,7 +21,7 @@ class spx extends Extension } } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $arg = '--enable-spx'; if ($this->builder->getExt('zlib') === null) { diff --git a/src/SPC/builder/extension/swoole.php b/src/SPC/builder/extension/swoole.php index 3c04a298..6ce006b9 100644 --- a/src/SPC/builder/extension/swoole.php +++ b/src/SPC/builder/extension/swoole.php @@ -35,7 +35,7 @@ class swoole extends Extension return null; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { // enable swoole $arg = '--enable-swoole'; @@ -49,7 +49,9 @@ class swoole extends Extension // additional feature: c-ares, brotli, nghttp2 (can be disabled, but we enable it by default in config to support full network feature) $arg .= $this->builder->getLib('libcares') ? ' --enable-cares' : ''; - $arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : ''; + if (!$shared) { + $arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : ''; + } $arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-dir=' . BUILD_ROOT_PATH) : ''; // additional feature: swoole-pgsql, it should depend on lib [postgresql], but it will lack of CFLAGS etc. diff --git a/src/SPC/builder/extension/swoole_hook_mysql.php b/src/SPC/builder/extension/swoole_hook_mysql.php index 6d1d6828..e9684872 100644 --- a/src/SPC/builder/extension/swoole_hook_mysql.php +++ b/src/SPC/builder/extension/swoole_hook_mysql.php @@ -16,7 +16,7 @@ class swoole_hook_mysql extends Extension return 'swoole'; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { // pdo_mysql doesn't need to be disabled // enable swoole-hook-mysql will enable mysqli, pdo, pdo_mysql, we don't need to add any additional options diff --git a/src/SPC/builder/extension/swoole_hook_pgsql.php b/src/SPC/builder/extension/swoole_hook_pgsql.php index 08e217be..113b8eb6 100644 --- a/src/SPC/builder/extension/swoole_hook_pgsql.php +++ b/src/SPC/builder/extension/swoole_hook_pgsql.php @@ -25,7 +25,7 @@ class swoole_hook_pgsql extends Extension } } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { // enable swoole pgsql hook return '--enable-swoole-pgsql'; diff --git a/src/SPC/builder/extension/swoole_hook_sqlite.php b/src/SPC/builder/extension/swoole_hook_sqlite.php index 5de18351..7948dd29 100644 --- a/src/SPC/builder/extension/swoole_hook_sqlite.php +++ b/src/SPC/builder/extension/swoole_hook_sqlite.php @@ -25,7 +25,7 @@ class swoole_hook_sqlite extends Extension } } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { // enable swoole pgsql hook return '--enable-swoole-sqlite'; diff --git a/src/SPC/builder/extension/xdebug.php b/src/SPC/builder/extension/xdebug.php index 3cbd311e..ed592056 100644 --- a/src/SPC/builder/extension/xdebug.php +++ b/src/SPC/builder/extension/xdebug.php @@ -15,7 +15,7 @@ class xdebug extends Extension { [$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "zend_extension=' . BUILD_LIB_PATH . '/xdebug.so" --ri xdebug'); if ($ret !== 0) { - throw new RuntimeException('xdebug.so not found'); + throw new RuntimeException('xdebug.so failed to load.'); } } } diff --git a/src/SPC/builder/extension/xlswriter.php b/src/SPC/builder/extension/xlswriter.php index 475a6c07..6319ce31 100644 --- a/src/SPC/builder/extension/xlswriter.php +++ b/src/SPC/builder/extension/xlswriter.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('xlswriter')] class xlswriter extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $arg = '--with-xlswriter --enable-reader'; if ($this->builder->getLib('openssl')) { diff --git a/src/SPC/builder/extension/xml.php b/src/SPC/builder/extension/xml.php index 6242be6b..fc8bfc4d 100644 --- a/src/SPC/builder/extension/xml.php +++ b/src/SPC/builder/extension/xml.php @@ -20,7 +20,7 @@ class xml extends Extension /** * @throws RuntimeException */ - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $arg = match ($this->name) { 'xml' => '--enable-xml', diff --git a/src/SPC/builder/extension/yac.php b/src/SPC/builder/extension/yac.php index a4152e42..bb085133 100644 --- a/src/SPC/builder/extension/yac.php +++ b/src/SPC/builder/extension/yac.php @@ -19,7 +19,7 @@ class yac extends Extension return true; } - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--enable-yac --enable-igbinary --enable-json'; } diff --git a/src/SPC/builder/extension/zlib.php b/src/SPC/builder/extension/zlib.php index a9932999..86c45dbe 100644 --- a/src/SPC/builder/extension/zlib.php +++ b/src/SPC/builder/extension/zlib.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('zlib')] class zlib extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { $zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-zlib-dir=' . BUILD_ROOT_PATH; return '--with-zlib' . $zlib_dir; diff --git a/src/SPC/builder/extension/zstd.php b/src/SPC/builder/extension/zstd.php index 13311979..3a6df602 100644 --- a/src/SPC/builder/extension/zstd.php +++ b/src/SPC/builder/extension/zstd.php @@ -10,7 +10,7 @@ use SPC\util\CustomExt; #[CustomExt('zstd')] class zstd extends Extension { - public function getUnixConfigureArg(): string + public function getUnixConfigureArg(bool $shared = false): string { return '--enable-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"'; } diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index c5fa6c9e..4e690bed 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -171,7 +171,7 @@ class BuildPHPCommand extends BuildCommand // compile libraries $builder->proveLibs($libraries); // check extensions - $builder->proveExts($extensions, shared_extensions: $shared_extensions); + $builder->proveExts($static_extensions, $shared_extensions); // validate libs and extensions $builder->validateLibsAndExts(); diff --git a/src/SPC/store/Config.php b/src/SPC/store/Config.php index 9c00715d..29455fa1 100644 --- a/src/SPC/store/Config.php +++ b/src/SPC/store/Config.php @@ -118,7 +118,7 @@ class Config if (!isset(self::$ext[$name])) { throw new WrongUsageException('ext [' . $name . '] is not supported yet'); } - return self::$ext[$name]['target'] ?? ['static', 'shared']; + return self::$ext[$name]['target'] ?? ['static']; } /** diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index 01e47076..7adf723b 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -51,9 +51,9 @@ class SPCConfigUtil $libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs); } return [ - 'cflags' => $cflags, - 'ldflags' => $ldflags, - 'libs' => $libs, + 'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags), + 'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags), + 'libs' => trim(getenv('LIBS') . ' ' . $libs), ]; } From a5e4d6a5ec3ad3700481a234d200f8bed68ac129 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sun, 30 Mar 2025 23:36:23 +0700 Subject: [PATCH 19/32] xdebug and ffi compilable shared, updated notes --- config/ext.json | 10 ++++++---- docs/en/guide/extension-notes.md | 11 +++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/config/ext.json b/config/ext.json index 3d99350c..df4cd432 100644 --- a/config/ext.json +++ b/config/ext.json @@ -119,6 +119,10 @@ "Linux": "partial", "BSD": "wip" }, + "target": [ + "static", + "shared" + ], "notes": true, "arg-type": "custom", "type": "builtin", @@ -772,8 +776,7 @@ "BSD": "wip" }, "target": [ - "static", - "shared" + "static" ], "notes": true, "type": "external", @@ -1048,8 +1051,7 @@ "BSD": "wip" }, "target": [ - "static", - "shared" + "static" ], "type": "builtin", "arg-type": "with-prefix", diff --git a/docs/en/guide/extension-notes.md b/docs/en/guide/extension-notes.md index 1d9209c9..c012200d 100644 --- a/docs/en/guide/extension-notes.md +++ b/docs/en/guide/extension-notes.md @@ -76,10 +76,9 @@ and this extension cannot be compiled into php by static linking, so it cannot b ## xdebug -1. Xdebug is only buildable as a shared extension. On Linux, you need to use static-php-cli with SPC_LIBC=glibc and then compile php-xdebug from source with the option `--with-php-config=/path/to/buildroot/bin/php-config`. -2. The macOS platform can compile an xdebug extension under PHP compiled on the same platform, -extract the `xdebug.so` file, and then use the `--no-strip` parameter in static-php-cli to retain the debug symbol table and add the `ffi` extension. -The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`. +1. Xdebug is only buildable as a shared extension. On Linux, you need to use static-php-cli with SPC_LIBC=glibc. +2. When using Linux/glibc or macOS, you can compile Xdebug as a shared extension using --build-shared="xdebug". + The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`. ## xml @@ -122,8 +121,8 @@ For details on the solution, see [FAQ - Unable to use ssl](../faq/#unable-to-use ## ffi -1. Due to the limitation of Linux system, you cannot use it to load other `so` extensions in the purely static compiled state (spc defaults to pure static compilation). - Linux supports loading so extensions only if they are non-statically compiled. If you need to use the ffi extension, see [Compile PHP with GNU libc](./build-with-glibc). +1. Due to the limitation of musl libc's static linkage, you cannot use ffi because dynamic libraries cannot be loaded. + If you need to use the ffi extension, see [Compile PHP with GNU libc](./build-with-glibc). 2. macOS supports the ffi extension, but errors will occur when some kernels do not contain debugging symbols. 3. Windows x64 supports the ffi extension. From 0c6dd7a577b2eac6fd584cbd99223d752c844cad Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sun, 30 Mar 2025 23:50:15 +0700 Subject: [PATCH 20/32] warning for building an extension as both static and shared --- bin/spc-gnu-docker | 1 - src/SPC/command/BuildPHPCommand.php | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker index 8c85dd01..e063f115 100755 --- a/bin/spc-gnu-docker +++ b/bin/spc-gnu-docker @@ -160,7 +160,6 @@ if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then echo "* ./pkgroot: $(pwd)/pkgroot" echo "*" -if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then $DOCKER_EXECUTABLE run --rm -it --privileged $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH else $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@ diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index 4e690bed..d2cf1d75 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -71,6 +71,10 @@ class BuildPHPCommand extends BuildCommand $this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with glibc!'); return static::FAILURE; } + $static_and_shared = array_intersect($static_extensions, $shared_extensions); + if (!empty($static_and_shared)) { + $this->output->writeln('Building extensions [' . implode(',', $static_and_shared) . '] as both static and shared\, tests may not be accurate or fail.'); + } if ($rule === BUILD_TARGET_NONE) { $this->output->writeln('Please add at least one build SAPI!'); @@ -270,13 +274,13 @@ class BuildPHPCommand extends BuildCommand /** * Parse build options to rule int. */ - private function parseRules(array $dynamic_exts = []): int + private function parseRules(array $shared_extensions = []): int { $rule = BUILD_TARGET_NONE; $rule |= ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE); - $rule |= ($this->getOption('build-embed') || !empty($dynamic_exts) ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE); + $rule |= ($this->getOption('build-embed') || !empty($shared_extensions) ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE); $rule |= ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE); return $rule; } From f21f833aedf39dac70f454d1c7bc2bcd2f43b2b3 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sun, 30 Mar 2025 23:58:21 +0700 Subject: [PATCH 21/32] add phar?! --- src/globals/test-extensions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index c8e2f8cb..881877e6 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -15,7 +15,7 @@ declare(strict_types=1); $test_php_version = [ // '8.1', // '8.2', - // '8.3', + '8.3', '8.4', ]; @@ -42,7 +42,7 @@ $prefer_pre_built = true; // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'imagick', + 'Linux', 'Darwin' => 'imagick,phar', 'Windows' => 'pgsql,pdo_pgsql', }; From f556f375eec5d64f05ae5061212440835cff31eb Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 31 Mar 2025 00:04:55 +0700 Subject: [PATCH 22/32] add zlib... --- src/globals/test-extensions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 881877e6..c58f0413 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -42,7 +42,7 @@ $prefer_pre_built = true; // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'imagick,phar', + 'Linux', 'Darwin' => 'imagick,zlib', 'Windows' => 'pgsql,pdo_pgsql', }; From 4e67c6380894c978c85877538eb9e36c2554e221 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 31 Mar 2025 00:10:27 +0700 Subject: [PATCH 23/32] add note to sharedExtensionCheck --- src/SPC/builder/Extension.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 6ada640a..c2d924b7 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -187,6 +187,7 @@ class Extension /** * Run shared extension check when cli is enabled + * @throws RuntimeException */ public function runSharedExtensionCheckUnix(): void { @@ -194,6 +195,9 @@ class Extension if ($ret !== 0) { throw new RuntimeException($this->getName() . '.so failed to load'); } + if ($this->isBuildStatic()) { + logger()->warning($this->getName() . '.so test succeeded, but has little significance since it is also compiled in statically.'); + } } /** From 61eafa48ff4b5d696d6cb28b6109277068796dc6 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 18 Apr 2025 12:18:20 +0800 Subject: [PATCH 24/32] Add static extension filter --- src/SPC/command/BuildPHPCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index d2cf1d75..49067b0b 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -130,6 +130,10 @@ class BuildPHPCommand extends BuildCommand $display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package'])); $display_extensions = array_map(fn ($ext) => in_array($ext, $shared_extensions) ? "*{$ext}" : $ext, $extensions); + // separate static and shared extensions from $extensions + // filter rule: including shared extensions if they are in $static_extensions or $shared_extensions + $static_extensions = array_filter($extensions, fn ($ext) => !in_array($ext, $shared_extensions) || in_array($ext, $static_extensions)); + // print info $indent_texts = [ 'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')', From 7bfb8d6f53c795703bfa51c9db661b588458c5e9 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 18 Apr 2025 14:38:22 +0800 Subject: [PATCH 25/32] Use SPCConfigUtil to generate shared extension env --- src/SPC/builder/Extension.php | 13 ++++++++++++- src/SPC/util/SPCConfigUtil.php | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index c2d924b7..b250097b 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -9,6 +9,7 @@ use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; use SPC\store\Config; use SPC\store\FileSystem; +use SPC\util\SPCConfigUtil; class Extension { @@ -281,13 +282,23 @@ class Extension /** * Build shared extension for Unix * + * @throws FileSystemException * @throws RuntimeException + * @throws WrongUsageException + * @throws \ReflectionException + * @throws \Throwable */ public function buildUnixShared(): void { + $config = (new SPCConfigUtil($this->builder))->config([$this->getName()]); + $env = [ + 'CFLAGS' => $config['cflags'], + 'LDFLAGS' => $config['ldflags'], + 'LIBS' => $config['libs'], + ]; // prepare configure args shell()->cd($this->source_dir) - ->setEnv(['CFLAGS' => $this->builder->arch_c_flags ?? '']) + ->setEnv($env) ->execWithEnv(BUILD_BIN_PATH . '/phpize') ->execWithEnv('./configure ' . $this->getUnixConfigureArg(true) . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-shared --disable-static') ->execWithEnv('make clean') diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index 2d018d16..cc888d9a 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -7,6 +7,9 @@ namespace SPC\util; use SPC\builder\BuilderBase; use SPC\builder\BuilderProvider; use SPC\builder\macos\MacOSBuilder; +use SPC\exception\FileSystemException; +use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\Config; use Symfony\Component\Console\Input\ArgvInput; @@ -21,6 +24,24 @@ class SPCConfigUtil } } + /** + * Generate configuration for building PHP extensions. + * + * @param array $extensions Extension name list + * @param array $libraries Additional library name list + * @param bool $include_suggest_ext Include suggested extensions + * @param bool $include_suggest_lib Include suggested libraries + * @return array{ + * cflags: string, + * ldflags: string, + * libs: string + * } + * @throws \ReflectionException + * @throws FileSystemException + * @throws RuntimeException + * @throws WrongUsageException + * @throws \Throwable + */ public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false): array { [$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib); From b452f7f32a806c6142cad13b45d8b5904bfebb49 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 18 Apr 2025 14:38:42 +0800 Subject: [PATCH 26/32] Add default shared target --- src/SPC/store/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/store/Config.php b/src/SPC/store/Config.php index ad837dbc..16f925c6 100644 --- a/src/SPC/store/Config.php +++ b/src/SPC/store/Config.php @@ -137,7 +137,7 @@ class Config if (!isset(self::$ext[$name])) { throw new WrongUsageException('ext [' . $name . '] is not supported yet'); } - return self::$ext[$name]['target'] ?? ['static']; + return self::$ext[$name]['target'] ?? ['static', 'shared']; } /** From 2da750d5f9e9193adf4363f9e3e58c256c51ea83 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Fri, 18 Apr 2025 14:50:58 +0800 Subject: [PATCH 27/32] Fix phpunit, add skip extraction arg for SPCConfigUtil new builder --- src/SPC/builder/BuilderBase.php | 25 ++++++++++++++----------- src/SPC/util/SPCConfigUtil.php | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 614b223a..59f371ef 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -173,7 +173,7 @@ abstract class BuilderBase * @throws \Throwable|WrongUsageException * @internal */ - public function proveExts(array $static_extensions, array $shared_extensions = [], bool $skip_check_deps = false): void + public function proveExts(array $static_extensions, array $shared_extensions = [], bool $skip_check_deps = false, bool $skip_extract = false): void { CustomExt::loadCustomExt(); // judge ext @@ -189,17 +189,20 @@ abstract class BuilderBase throw new WrongUsageException('Extension [' . $ext . '] does not support shared build!'); } } - $this->emitPatchPoint('before-php-extract'); - SourceManager::initSource(sources: ['php-src'], source_only: true); - $this->emitPatchPoint('after-php-extract'); - if ($this->getPHPVersionID() >= 80000) { - $this->emitPatchPoint('before-micro-extract'); - SourceManager::initSource(sources: ['micro'], source_only: true); - $this->emitPatchPoint('after-micro-extract'); + if (!$skip_extract) { + $this->emitPatchPoint('before-php-extract'); + SourceManager::initSource(sources: ['php-src'], source_only: true); + $this->emitPatchPoint('after-php-extract'); + if ($this->getPHPVersionID() >= 80000) { + $this->emitPatchPoint('before-micro-extract'); + SourceManager::initSource(sources: ['micro'], source_only: true); + $this->emitPatchPoint('after-micro-extract'); + } + $this->emitPatchPoint('before-exts-extract'); + SourceManager::initSource(exts: [...$static_extensions, ...$shared_extensions]); + $this->emitPatchPoint('after-exts-extract'); } - $this->emitPatchPoint('before-exts-extract'); - SourceManager::initSource(exts: [...$static_extensions, ...$shared_extensions]); - $this->emitPatchPoint('after-exts-extract'); + foreach ([...$static_extensions, ...$shared_extensions] as $extension) { $class = CustomExt::getExtClass($extension); /** @var Extension $ext */ diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php index cc888d9a..e0b92a2e 100644 --- a/src/SPC/util/SPCConfigUtil.php +++ b/src/SPC/util/SPCConfigUtil.php @@ -50,7 +50,7 @@ class SPCConfigUtil if ($this->builder === null) { $this->builder = BuilderProvider::makeBuilderByInput(new ArgvInput()); $this->builder->proveLibs($libraries); - $this->builder->proveExts($extensions); + $this->builder->proveExts($extensions, skip_extract: true); } ob_get_clean(); $ldflags = $this->getLdflagsString(); From f40170ee6f7fa3385b5e9616ba0cb3881b106e7a Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 18 Apr 2025 15:43:54 +0700 Subject: [PATCH 28/32] update extension tests to support shared extensions --- src/globals/test-extensions.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 9de7fb5a..57cb9933 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -30,7 +30,7 @@ $test_os = [ ]; // whether enable thread safe -$zts = false; +$zts = true; $no_strip = false; @@ -46,6 +46,12 @@ $extensions = match (PHP_OS_FAMILY) { 'Windows' => 'pgsql,pdo_pgsql', }; +// If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). +$shared_extensions = match (PHP_OS_FAMILY) { + 'Linux' => 'apcu,ffi,xdebug,xsl,zip', + 'Windows', 'Darwin' => '', +}; + // If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`). $with_libs = match (PHP_OS_FAMILY) { 'Linux', 'Darwin' => '', @@ -87,6 +93,7 @@ if (!isset($argv[1])) { $trim_value = "\r\n \t,"; $final_extensions = trim(trim($extensions, $trim_value) . ',' . _getCombination($base_combination), $trim_value); +$download_extensions = trim($final_extensions . ',' . $shared_extensions, $trim_value); $final_libs = trim($with_libs, $trim_value); if (PHP_OS_FAMILY === 'Windows') { @@ -107,7 +114,7 @@ function quote2(string $param): string // generate download command if ($argv[1] === 'download_cmd') { $down_cmd = 'download '; - $down_cmd .= '--for-extensions=' . quote2($final_extensions) . ' '; + $down_cmd .= '--for-extensions=' . quote2($download_extensions) . ' '; $down_cmd .= '--for-libs=' . quote2($final_libs) . ' '; $down_cmd .= '--with-php=' . quote2($argv[3]) . ' '; $down_cmd .= '--ignore-cache-sources=php-src '; @@ -128,6 +135,7 @@ if ($argv[1] === 'install_upx_cmd') { if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') { $build_cmd = 'build '; $build_cmd .= quote2($final_extensions) . ' '; + $build_cmd .= $shared_extensions ? '--build-shared=' . quote2($shared_extensions) . ' ' : ''; $build_cmd .= $zts ? '--enable-zts ' : ''; $build_cmd .= $no_strip ? '--no-strip ' : ''; $build_cmd .= $upx ? '--with-upx-pack ' : ''; From d34fa0ba4e903fb43c68538d400a47b9b845d5a5 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 18 Apr 2025 16:03:49 +0700 Subject: [PATCH 29/32] check for SPC_LIBC --- src/globals/test-extensions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 57cb9933..51bc028a 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -135,7 +135,7 @@ if ($argv[1] === 'install_upx_cmd') { if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') { $build_cmd = 'build '; $build_cmd .= quote2($final_extensions) . ' '; - $build_cmd .= $shared_extensions ? '--build-shared=' . quote2($shared_extensions) . ' ' : ''; + $build_cmd .= $shared_extensions && getenv('SPC_LIBC') === 'glibc' ? '--build-shared=' . quote2($shared_extensions) . ' ' : ''; $build_cmd .= $zts ? '--enable-zts ' : ''; $build_cmd .= $no_strip ? '--no-strip ' : ''; $build_cmd .= $upx ? '--with-upx-pack ' : ''; From cf24b88bc856a97b1a652f54839d589647d5acaf Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sat, 19 Apr 2025 14:43:51 +0800 Subject: [PATCH 30/32] Add final full test --- src/globals/test-extensions.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 51bc028a..8241ae2e 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -13,8 +13,8 @@ declare(strict_types=1); // test php version (8.1 ~ 8.4 available, multiple for matrix) $test_php_version = [ - // '8.1', - // '8.2', + '8.1', + '8.2', '8.3', '8.4', ]; @@ -25,6 +25,7 @@ $test_os = [ 'macos-14', 'ubuntu-latest', 'ubuntu-22.04', + 'ubuntu-24.04', 'ubuntu-22.04-arm', 'ubuntu-24.04-arm', ]; @@ -42,13 +43,13 @@ $prefer_pre_built = false; // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). $extensions = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'imagick,zlib', + 'Linux', 'Darwin' => 'phar', 'Windows' => 'pgsql,pdo_pgsql', }; // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). $shared_extensions = match (PHP_OS_FAMILY) { - 'Linux' => 'apcu,ffi,xdebug,xsl,zip', + 'Linux' => 'xdebug', 'Windows', 'Darwin' => '', }; @@ -62,7 +63,7 @@ $with_libs = match (PHP_OS_FAMILY) { // You can use `common`, `bulk`, `minimal` or `none`. // note: combination is only available for *nix platform. Windows must use `none` combination $base_combination = match (PHP_OS_FAMILY) { - 'Linux', 'Darwin' => 'minimal', + 'Linux', 'Darwin' => 'common', 'Windows' => 'none', }; @@ -165,9 +166,9 @@ echo match ($argv[1]) { $prefix = match ($argv[2] ?? null) { 'windows-latest', 'windows-2022', 'windows-2019', 'windows-2025' => 'powershell.exe -file .\bin\spc.ps1 ', - 'ubuntu-latest', 'ubuntu-24.04', 'ubuntu-24.04-arm' => './bin/spc ', + 'ubuntu-latest' => 'bin/spc-alpine-docker ', + 'ubuntu-24.04', 'ubuntu-24.04-arm' => './bin/spc ', 'ubuntu-22.04', 'ubuntu-22.04-arm' => 'bin/spc-gnu-docker ', - 'ubuntu-20.04' => 'bin/spc-alpine-docker ', default => 'bin/spc ', }; From 9fe09f57f6e07bd944977426439d4e829e60d1a1 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sat, 19 Apr 2025 15:04:29 +0800 Subject: [PATCH 31/32] Add Chinese docs and additional option docs --- docs/en/guide/manual-build.md | 1 + docs/zh/guide/extension-notes.md | 13 +++++++------ docs/zh/guide/manual-build.md | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/en/guide/manual-build.md b/docs/en/guide/manual-build.md index d38e2b85..c935f5c8 100644 --- a/docs/en/guide/manual-build.md +++ b/docs/en/guide/manual-build.md @@ -314,6 +314,7 @@ You can try to use the following commands: - `--with-suggested-exts`: Add `ext-suggests` as dependencies when compiling - `--with-suggested-libs`: Add `lib-suggests` as dependencies when compiling - `--with-upx-pack`: Use UPX to reduce the size of the binary file after compilation (you need to use `bin/spc install-pkg upx` to install upx first) +- `--build-shared=XXX,YYY`: compile the specified extension into a shared library (the default is to compile into a static library) For hardcoding INI options, it works for cli, micro, embed sapi. Here is a simple example where we preset a larger `memory_limit` and disable the `system` function: diff --git a/docs/zh/guide/extension-notes.md b/docs/zh/guide/extension-notes.md index 6ff2dfc0..762d2df9 100644 --- a/docs/zh/guide/extension-notes.md +++ b/docs/zh/guide/extension-notes.md @@ -74,9 +74,9 @@ bin/spc build gd --with-libs=freetype,libjpeg,libavif,libwebp --build-cli ## xdebug -1. Xdebug 只能作为共享扩展构建。在 Linux 上,您需要使用带有 `SPC_LIBC=glibc` 的 static-php-cli,然后使用选项 `--with-php-config=/path/to/buildroot/bin/php-config` 从源代码编译 php-xdebug。 -2. macOS 平台可以通过在相同平台编译的 PHP 下编译一个 xdebug 扩展,并提取其中的 `xdebug.so` 文件,再在 static-php-cli 中使用 `--no-strip` 参数保留调试符号表,同时加入 `ffi` 扩展。 - 编译的 `./php` 二进制可以通过指定 INI 配置并运行,例如`./php -d 'zend_extension=xdebug.so' your-code.php`。 +1. Xdebug 只能作为共享扩展进行构建。在 Linux 上,您需要使用 static-php-cli 并设置 SPC_LIBC=glibc。 +2. 使用 Linux/glibc 或 macOS 时,您可以使用 `--build-shared=xdebug` 将 Xdebug 编译为共享扩展。 + 编译后的 `./php` 二进制文件可以通过指定 INI 文件进行配置和运行,例如 `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`。 ## xml @@ -117,9 +117,10 @@ pgsql 16.2 修复了这个 Bug,现在正常工作了。 ## ffi -1. 因为 Linux 系统的限制,纯静态编译的状态下(spc 默认编译结果为纯静态)无法使用它加载其他 `so` 扩展。Linux 支持加载 so 扩展的前提是非静态编译。如果你需要使用 ffi 扩展,请参见 [编译 GNU libc 的 PHP](./build-with-glibc)。 -2. macOS 支持 ffi 扩展,但是部分内核下不包含调试符号时会出现错误。 -3. Windows 支持 ffi 扩展。 +1. 由于 musl libc 静态链接的限制,无法加载动态库,因此无法使用 ffi。 + 如果您需要使用 ffi 扩展,请参阅 [使用 GNU libc 编译 PHP](./build-with-glibc)。 +2. macOS 支持 ffi 扩展,但某些内核不包含调试符号时会出现错误。 +3. Windows x64 支持 ffi 扩展。 ## xhprof diff --git a/docs/zh/guide/manual-build.md b/docs/zh/guide/manual-build.md index 7a573704..955d98c8 100644 --- a/docs/zh/guide/manual-build.md +++ b/docs/zh/guide/manual-build.md @@ -272,6 +272,7 @@ bin/spc build mysqlnd,pdo_mysql --build-all --debug - `--with-suggested-exts`: 编译时将 `ext-suggests` 也作为编译依赖加入 - `--with-suggested-libs`: 编译时将 `lib-suggests` 也作为编译依赖加入 - `--with-upx-pack`: 编译后使用 UPX 减小二进制文件体积(需先使用 `bin/spc install-pkg upx` 安装 upx) +- `--build-shared=XXX,YYY`: 编译时将指定的扩展编译为共享库(默认编译为静态库) 硬编码 INI 选项适用于 cli、micro、embed。有关硬编码 INI 选项,下面是一个简单的例子,我们预设一个更大的 `memory_limit`,并且禁用 `system` 函数: From 0f5f60e477bd46d1711ceeca8a3eee58b5324832 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sat, 19 Apr 2025 15:18:48 +0800 Subject: [PATCH 32/32] Fix gnu static extension build test --- .github/workflows/tests.yml | 2 +- src/globals/test-extensions.php | 74 +++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7648873a..a8fd17a1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -197,5 +197,5 @@ jobs: run: php src/globals/test-extensions.php build_cmd ${{ matrix.os }} ${{ matrix.php }} - name: "Run Build Tests (build - embed for non-windows)" - if: matrix.os != 'windows-latest' + if: ${{ !startsWith(matrix.os, 'windows-') }} run: php src/globals/test-extensions.php build_embed_cmd ${{ matrix.os }} ${{ matrix.php }} diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 8241ae2e..1553443e 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -132,11 +132,39 @@ if ($argv[1] === 'install_upx_cmd') { $install_upx_cmd = 'install-pkg upx'; } +$prefix = match ($argv[2] ?? null) { + 'windows-latest', 'windows-2022', 'windows-2019', 'windows-2025' => 'powershell.exe -file .\bin\spc.ps1 ', + 'ubuntu-latest' => 'bin/spc-alpine-docker ', + 'ubuntu-24.04', 'ubuntu-24.04-arm' => './bin/spc ', + 'ubuntu-22.04', 'ubuntu-22.04-arm' => 'bin/spc-gnu-docker ', + default => 'bin/spc ', +}; + +// shared_extension build +if ($shared_extensions) { + switch ($argv[2] ?? null) { + case 'ubuntu-22.04': + case 'ubuntu-22.04-arm': + $shared_cmd = ' --build-shared=' . quote2($shared_extensions) . ' '; + break; + case 'macos-13': + case 'macos-14': + $shared_cmd = ' --build-shared=' . quote2($shared_extensions) . ' '; + $no_strip = true; + break; + default: + $shared_cmd = ''; + break; + } +} else { + $shared_cmd = ''; +} + // generate build command if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') { $build_cmd = 'build '; $build_cmd .= quote2($final_extensions) . ' '; - $build_cmd .= $shared_extensions && getenv('SPC_LIBC') === 'glibc' ? '--build-shared=' . quote2($shared_extensions) . ' ' : ''; + $build_cmd .= $shared_cmd; $build_cmd .= $zts ? '--enable-zts ' : ''; $build_cmd .= $no_strip ? '--no-strip ' : ''; $build_cmd .= $upx ? '--with-upx-pack ' : ''; @@ -164,31 +192,25 @@ echo match ($argv[1]) { default => '', }; -$prefix = match ($argv[2] ?? null) { - 'windows-latest', 'windows-2022', 'windows-2019', 'windows-2025' => 'powershell.exe -file .\bin\spc.ps1 ', - 'ubuntu-latest' => 'bin/spc-alpine-docker ', - 'ubuntu-24.04', 'ubuntu-24.04-arm' => './bin/spc ', - 'ubuntu-22.04', 'ubuntu-22.04-arm' => 'bin/spc-gnu-docker ', - default => 'bin/spc ', -}; - -if ($argv[1] === 'download_cmd') { - passthru($prefix . $down_cmd, $retcode); -} elseif ($argv[1] === 'build_cmd') { - passthru($prefix . $build_cmd . ' --build-cli --build-micro', $retcode); -} elseif ($argv[1] === 'build_embed_cmd') { - if (str_starts_with($argv[2], 'windows-')) { - // windows does not accept embed SAPI - passthru($prefix . $build_cmd . ' --build-cli', $retcode); - } else { - passthru($prefix . $build_cmd . ' --build-embed', $retcode); - } -} elseif ($argv[1] === 'doctor_cmd') { - passthru($prefix . $doctor_cmd, $retcode); -} elseif ($argv[1] === 'install_upx_cmd') { - passthru($prefix . $install_upx_cmd, $retcode); -} else { - $retcode = 0; +switch ($argv[1] ?? null) { + case 'download_cmd': + passthru($prefix . $down_cmd, $retcode); + break; + case 'build_cmd': + passthru($prefix . $build_cmd . ' --build-cli --build-micro', $retcode); + break; + case 'build_embed_cmd': + passthru($prefix . $build_cmd . (str_starts_with($argv[2], 'windows-') ? ' --build-cli' : ' --build-embed'), $retcode); + break; + case 'doctor_cmd': + passthru($prefix . $doctor_cmd, $retcode); + break; + case 'install_upx_cmd': + passthru($prefix . $install_upx_cmd, $retcode); + break; + default: + $retcode = 0; + break; } exit($retcode);