Conversation
Commented out older PHP versions and Windows 2025 in the test configuration. Updated the extensions to test for Linux and Darwin.
Co-authored-by: Marc <m@pyc.ac>
There was a problem hiding this comment.
Pull request overview
This pull request represents a significant refactoring effort to modernize the extension handling system from v2 to v3.0. The PR introduces a comprehensive smoke testing framework, refactors FrankenPHP build logic, updates branding from "static-php-cli" to "StaticPHP", and makes numerous improvements to the build system architecture. Key changes include moving from a monolithic builder approach to a more modular package-based architecture with proper dependency handling and validation.
Changes:
- Added comprehensive smoke test framework for CLI, CGI, micro, embed, and FrankenPHP SAPIs with configurable test skipping via
--no-smoke-testoption - Refactored FrankenPHP build process with new smoke tests and improved handling of the
--with-frankenphp-appoption - Rebranded product from "static-php-cli" to "StaticPHP" across documentation and code
- Added new extension support (apcu) and improved libavif build configuration with optional dependencies
- Enhanced build system with better error handling, build tracking file rename, and improved Makefile path handling
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/globals/test-extensions.php | Modified test configuration to focus on pgsql extension testing (significantly reduced coverage) |
| src/StaticPHP/Util/BuildRootTracker.php | Renamed tracker file from .spc-tracker.json to .build.json |
| src/StaticPHP/Package/PhpExtensionPackage.php | Added comprehensive smoke test methods and improved extension name handling |
| src/StaticPHP/Command/Dev/LintConfigCommand.php | Added MOTD suppression and "No changes" output message |
| src/SPC/store/pkg/GoXcaddy.php | Fixed path handling to use hardcoded 'go-xcaddy' directory |
| src/SPC/builder/unix/library/postgresql.php | Removed aarch64 glibc 2.17 patches (moved to new architecture) |
| src/SPC/builder/unix/library/libavif.php | Added optional library dependencies for improved build flexibility |
| src/SPC/builder/unix/UnixBuilderBase.php | Added quote trimming for FrankenPHP app path and ServerHeader build flag |
| src/SPC/ConsoleApplication.php | Version bump to 2.8.3 |
| src/Package/Target/php/unix.php | Major refactoring with new smoke test framework, removed old patches, added sed fix for Makefile paths |
| src/Package/Target/php/frankenphp.php | Renamed methods, added smoke tests, refactored app processing |
| src/Package/Target/php.php | Added frankenphp trait usage and --no-smoke-test option |
| src/Package/Library/postgresql.php | Made explicit_bzero patch macOS-specific |
| src/Package/Library/libacl.php | Added patch description annotation |
| config/source.json | Disabled pre-built flag for libavif |
| config/lib.json | Added libavif dependencies and suggestions |
| config/pkg/ext/ext-apcu.yml | New extension configuration file |
| README.md | Updated branding to StaticPHP |
| README-zh.md | Updated branding to StaticPHP (Chinese) |
| .github/workflows/build-unix.yml | Added with-suggested-libs option and debug log upload |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| /** | ||
| * Run smoke test for the extension on Unix CLI. | ||
| * Override this method in a subclass。 |
There was a problem hiding this comment.
The comment contains a Chinese period character (。) instead of an English period. This should be changed to maintain consistency with the English codebase.
| * Override this method in a subclass。 | |
| * Override this method in a subclass. |
| #[Stage] | ||
| public function buildconfForUnix(TargetPackage $package): void | ||
| { | ||
| InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('./buildconf')); | ||
| V2CompatLayer::emitPatchPoint('before-php-buildconf'); | ||
| // run ./buildconf | ||
| shell()->cd($package->getSourceDir())->exec(getenv('SPC_CMD_PREFIX_PHP_BUILDCONF')); | ||
| } |
There was a problem hiding this comment.
The removal of the TSRM patch for musl TLS symbol visibility and the configure command info patch may cause issues on certain platforms. The patchTSRMBeforeUnixMake method that was removed handled important edge cases for musl builds with non-static toolchains. Verify that these patches are no longer needed or have been moved elsewhere in the codebase.
| public function patchBeforeBuild(): bool | ||
| { | ||
| // fix aarch64 build on glibc 2.17 (e.g. CentOS 7) | ||
| if (SPCTarget::getLibcVersion() === '2.17' && GNU_ARCH === 'aarch64') { | ||
| try { | ||
| FileSystem::replaceFileStr("{$this->source_dir}/src/port/pg_popcount_aarch64.c", 'HWCAP_SVE', '0'); | ||
| FileSystem::replaceFileStr( | ||
| "{$this->source_dir}/src/port/pg_crc32c_armv8_choose.c", | ||
| '#if defined(__linux__) && !defined(__aarch64__) && !defined(HWCAP2_CRC32)', | ||
| '#if defined(__linux__) && !defined(HWCAP_CRC32)' | ||
| ); | ||
| } catch (FileSystemException) { | ||
| // allow file not-existence to make it compatible with old and new version | ||
| } | ||
| } | ||
| // skip the test on platforms where libpq infrastructure may be provided by statically-linked libraries | ||
| FileSystem::replaceFileStr("{$this->source_dir}/src/interfaces/libpq/Makefile", 'invokes exit\'; exit 1;', 'invokes exit\';'); | ||
| // disable shared libs build |
There was a problem hiding this comment.
The removal of PostgreSQL patches for aarch64 builds on glibc 2.17 systems may break builds on older CentOS 7 systems. While the patch description mentions this is to fix compatibility issues, the patches in the new file (src/Package/Library/postgresql.php) still contain this code, so this removal appears to be an incomplete refactoring. Verify that the old file is no longer used and the new implementation covers all necessary cases.
| if (SystemTarget::getTargetOS() === 'Darwin') { | ||
| // on macOS, explicit_bzero is available but causes build failure due to detection issues, so we fake it as unavailable | ||
| shell()->cd($package->getSourceDir()) | ||
| ->exec('sed -i.backup "s/ac_cv_func_explicit_bzero\" = xyes/ac_cv_func_explicit_bzero\" = x_fake_yes/" ./configure'); | ||
| } |
There was a problem hiding this comment.
The PostgreSQL explicit_bzero patch is now only applied on Darwin (macOS), but was previously applied unconditionally. If this function causes issues on other platforms, those builds may now fail. Consider documenting why this is macOS-specific or verifying that other platforms don't need this workaround.
| $frankenphpAppPath = $this->getOption('with-frankenphp-app'); | ||
|
|
||
| if ($frankenphpAppPath) { | ||
| $frankenphpAppPath = trim($frankenphpAppPath, "\"'"); |
There was a problem hiding this comment.
The trimming of quotes from the frankenphpAppPath is duplicated in both UnixBuilderBase.php (line 368) and in the new implementation. This suggests that both code paths might still be in use, or this is dead code. Verify which implementation is being used and ensure consistency.
| $valid_tests = ['cli', 'cgi', 'micro', 'micro-exts', 'embed', 'frankenphp']; | ||
| // compat: --without-micro-ext-test is equivalent to --no-smoke-test=micro-exts | ||
| if ($builder->getOption('without-micro-ext-test', false)) { | ||
| $valid_tests = array_diff($valid_tests, ['micro-exts']); | ||
| } | ||
| if (is_array($option)) { | ||
| /* | ||
| 1. if option is not in valid tests, throw WrongUsageException | ||
| 2. if all passed options are valid, remove them from $valid_tests, and run the remaining tests | ||
| */ | ||
| foreach ($option as $test) { | ||
| if (!in_array($test, $valid_tests, true)) { | ||
| throw new WrongUsageException("Invalid value for --no-smoke-test: {$test}. Valid values are: " . implode(', ', $valid_tests)); | ||
| } | ||
| $valid_tests = array_diff($valid_tests, [$test]); | ||
| } | ||
| } elseif ($option === 'all') { | ||
| $valid_tests = []; | ||
| } | ||
| // run cli tests | ||
| if (in_array('cli', $valid_tests, true) && $installer->isPackageResolved('php-cli')) { | ||
| $package->runStage([$this, 'smokeTestCliForUnix']); | ||
| } | ||
| // run cgi tests | ||
| if (in_array('cgi', $valid_tests, true) && $installer->isPackageResolved('php-cgi')) { | ||
| $package->runStage([$this, 'smokeTestCgiForUnix']); | ||
| } | ||
| // run micro tests | ||
| if (in_array('micro', $valid_tests, true) && $installer->isPackageResolved('php-micro')) { | ||
| $skipExtTest = !in_array('micro-exts', $valid_tests, true); | ||
| $package->runStage([$this, 'smokeTestMicroForUnix'], ['skipExtTest' => $skipExtTest]); | ||
| } | ||
| // run embed tests | ||
| if (in_array('embed', $valid_tests, true) && $installer->isPackageResolved('php-embed')) { | ||
| $package->runStage([$this, 'smokeTestEmbedForUnix']); | ||
| } |
There was a problem hiding this comment.
The smokeTestForUnix method doesn't include a check for 'frankenphp' in the valid_tests array, even though 'frankenphp' is listed as a valid test option on line 359. The FrankenPHP smoke test is executed separately in the build method (line 405), but users who specify --no-smoke-test=frankenphp will have their option validated but not respected. Consider either removing 'frankenphp' from valid_tests or adding the corresponding test execution logic.
| @@ -26,12 +26,12 @@ | |||
| // 'macos-15-intel', // bin/spc for x86_64 | |||
| // 'macos-15', // bin/spc for arm64 | |||
| // 'ubuntu-latest', // bin/spc-alpine-docker for x86_64 | |||
| // 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 | |||
| // 'ubuntu-24.04', // bin/spc for x86_64 | |||
| // 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 | |||
| // 'ubuntu-24.04-arm', // bin/spc for arm64 | |||
| 'ubuntu-22.04', // bin/spc-gnu-docker for x86_64 | |||
| 'ubuntu-24.04', // bin/spc for x86_64 | |||
| 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64 | |||
| 'ubuntu-24.04-arm', // bin/spc for arm64 | |||
| // 'windows-2022', // .\bin\spc.ps1 | |||
| 'windows-2025', | |||
| // 'windows-2025', | |||
| ]; | |||
|
|
|||
| // whether enable thread safe | |||
| @@ -50,13 +50,13 @@ | |||
|
|
|||
| // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). | |||
| $extensions = match (PHP_OS_FAMILY) { | |||
| 'Linux', 'Darwin' => 'mysqli,gmp', | |||
| 'Linux', 'Darwin' => 'pgsql', | |||
| 'Windows' => 'com_dotnet', | |||
| }; | |||
|
|
|||
| // If you want to test shared extensions, add them below (comma separated, example `bcmath,openssl`). | |||
| $shared_extensions = match (PHP_OS_FAMILY) { | |||
| 'Linux' => 'grpc,mysqlnd_parsec,mysqlnd_ed25519', | |||
| 'Linux' => '', | |||
There was a problem hiding this comment.
The test configuration has commented out all PHP versions except 8.5, and changed the extension tests from 'mysqli,gmp' to 'pgsql'. While this may be intentional for testing specific extensions during the refactor, it significantly reduces test coverage. Consider uncommenting the other PHP versions and platform configurations to ensure comprehensive testing once the pgsql extension refactoring is complete.
| private static function escapeInlineTest(string $code): string | ||
| { | ||
| return str_replace( | ||
| ['<?php', 'declare(strict_types=1);', "\n", '"', '$', '!'], | ||
| ['', '', '', '\"', '\$', '"\'!\'"'], | ||
| $code | ||
| ); | ||
| } |
There was a problem hiding this comment.
The escapeInlineTest method may not handle all edge cases safely. The current implementation replaces '!' with '"'!'"' which could cause issues with certain test code patterns. Additionally, the method doesn't handle other special shell characters like backticks, semicolons, or pipe operators that could break the shell command. Consider using a more robust escaping mechanism or validating that test files don't contain problematic patterns.
| InteractiveTerm::setMessage('Building frankenphp: ' . ConsoleColor::yellow('processing --with-frankenphp-app option')); | ||
| $package->runStage([$this, 'processFrankenphpApp']); |
There was a problem hiding this comment.
The InteractiveTerm::setMessage call for 'processing --with-frankenphp-app option' was removed from inside processFrankenphpApp (line 143 removed) and is now set before calling the method (line 33 added). However, this message will always be displayed even when no app path is provided. Consider moving the message back inside processFrankenphpApp to only display it when the option is actually being processed.
| $frankenphpAppPath = $package->getBuildOption('with-frankenphp-app'); | ||
|
|
||
| if ($frankenphpAppPath) { | ||
| InteractiveTerm::setMessage('Building frankenphp: ' . ConsoleColor::yellow('processing --with-frankenphp-app option')); | ||
| if (!is_dir($frankenphpAppPath)) { | ||
| throw new WrongUsageException("The path provided to --with-frankenphp-app is not a valid directory: {$frankenphpAppPath}"); |
There was a problem hiding this comment.
The new processFrankenphpApp implementation is missing the quote trimming logic that was added to UnixBuilderBase.php (line 368). If users pass quoted paths via command line, the directory existence check will fail. Consider adding 'trim($frankenphpAppPath, ""'")' before the is_dir check to maintain consistency and handle quoted paths properly.
| with-suggested-libs: | ||
| description: Build with suggested libs | ||
| type: boolean | ||
| default: false |
There was a problem hiding this comment.
we should default to true here imo, like we do for Downloader
There was a problem hiding this comment.
I'm looking for a simpler way to build using GHA, instead of letting people fork it. Like reusable workflow or writing setup-static-php. WDYT?
Reusable workflow may be easier than writing custom action but considering already widely-used, we should think long-term.
There was a problem hiding this comment.
We should definitely create a github action that builds all required libraries for an extension and then prepares the build environment for an extension by source.
It could be used by PIE extension maintainers to ship precompiled binaries of their extensions with PIE that are statically linked.
What does this PR do?
Refactor extensions from v2.
Other tasks
dev:dump-stagesanddev:dump-capabilitiescommanddev:get-testcommand for GitHub Actions (3.0: Auto-detect changes and produce tests on demand #1005)Extensions