From ae569316ff3234aadaa3331e9eccd8b583045120 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 20:54:01 +0800 Subject: [PATCH 1/9] Remove go download from doctor --- src/SPC/builder/traits/UnixGoCheckTrait.php | 83 --------------------- src/SPC/doctor/item/BSDToolCheckList.php | 6 -- src/SPC/doctor/item/LinuxToolCheckList.php | 8 -- src/SPC/doctor/item/MacOSToolCheckList.php | 8 -- 4 files changed, 105 deletions(-) delete mode 100644 src/SPC/builder/traits/UnixGoCheckTrait.php diff --git a/src/SPC/builder/traits/UnixGoCheckTrait.php b/src/SPC/builder/traits/UnixGoCheckTrait.php deleted file mode 100644 index 12e3d005..00000000 --- a/src/SPC/builder/traits/UnixGoCheckTrait.php +++ /dev/null @@ -1,83 +0,0 @@ -findCommand('go', $paths) === null) { - $this->installGo(); - } - - $gobin = getenv('GOBIN') ?: (getenv('HOME') . '/go/bin'); - putenv("GOBIN={$gobin}"); - - $paths[] = $gobin; - - if ($this->findCommand('xcaddy', $paths) === null) { - shell(true)->exec('go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest'); - } - - return CheckResult::ok(); - } - - private function installGo(): bool - { - $prefix = ''; - if (get_current_user() !== 'root') { - $prefix = 'sudo '; - logger()->warning('Current user is not root, using sudo for running command'); - } - - $arch = php_uname('m'); - $go_arch = match ($arch) { - 'x86_64' => 'amd64', - 'aarch64' => 'arm64', - default => $arch - }; - $os = strtolower(PHP_OS_FAMILY); - - $go_version = '1.24.4'; - $go_filename = "go{$go_version}.{$os}-{$go_arch}.tar.gz"; - $go_url = "https://go.dev/dl/{$go_filename}"; - - logger()->info("Downloading Go {$go_version} for {$go_arch}"); - - try { - // Download Go binary - Downloader::downloadFile('go', $go_url, $go_filename); - - // Extract the tarball - FileSystem::extractSource('go', SPC_SOURCE_ARCHIVE, DOWNLOAD_PATH . "/{$go_filename}"); - - // Move to /usr/local/go - logger()->info('Installing Go to /usr/local/go'); - shell()->exec("{$prefix}rm -rf /usr/local/go"); - shell()->exec("{$prefix}mv " . SOURCE_PATH . '/go /usr/local/'); - - if (!str_contains(getenv('PATH'), '/usr/local/go/bin')) { - logger()->info('Adding Go to PATH'); - shell()->exec("{$prefix}echo 'export PATH=\$PATH:/usr/local/go/bin' >> /etc/profile"); - putenv('PATH=' . getenv('PATH') . ':/usr/local/go/bin'); - } - - logger()->info('Go has been installed successfully'); - return true; - } catch (RuntimeException $e) { - logger()->error('Failed to install Go: ' . $e->getMessage()); - return false; - } - } -} diff --git a/src/SPC/doctor/item/BSDToolCheckList.php b/src/SPC/doctor/item/BSDToolCheckList.php index 97f0ccf9..2505227b 100644 --- a/src/SPC/doctor/item/BSDToolCheckList.php +++ b/src/SPC/doctor/item/BSDToolCheckList.php @@ -47,12 +47,6 @@ class BSDToolCheckList return CheckResult::ok(); } - #[AsCheckItem('if xcaddy is installed', limit_os: 'BSD')] - public function checkXcaddy(): ?CheckResult - { - return $this->checkGoAndXcaddy(); - } - #[AsFixItem('build-tools-bsd')] public function fixBuildTools(array $missing): bool { diff --git a/src/SPC/doctor/item/LinuxToolCheckList.php b/src/SPC/doctor/item/LinuxToolCheckList.php index 07f6b5fb..56235b0c 100644 --- a/src/SPC/doctor/item/LinuxToolCheckList.php +++ b/src/SPC/doctor/item/LinuxToolCheckList.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace SPC\doctor\item; use SPC\builder\linux\SystemUtil; -use SPC\builder\traits\UnixGoCheckTrait; use SPC\builder\traits\UnixSystemUtilTrait; use SPC\doctor\AsCheckItem; use SPC\doctor\AsFixItem; @@ -15,7 +14,6 @@ use SPC\exception\RuntimeException; class LinuxToolCheckList { use UnixSystemUtilTrait; - use UnixGoCheckTrait; public const TOOLS_ALPINE = [ 'make', 'bison', 'flex', @@ -89,12 +87,6 @@ class LinuxToolCheckList return CheckResult::ok(); } - #[AsCheckItem('if xcaddy is installed', limit_os: 'Linux')] - public function checkXcaddy(): ?CheckResult - { - return $this->checkGoAndXcaddy(); - } - #[AsCheckItem('if cmake version >= 3.18', limit_os: 'Linux')] public function checkCMakeVersion(): ?CheckResult { diff --git a/src/SPC/doctor/item/MacOSToolCheckList.php b/src/SPC/doctor/item/MacOSToolCheckList.php index 57ba8157..b4043a1d 100644 --- a/src/SPC/doctor/item/MacOSToolCheckList.php +++ b/src/SPC/doctor/item/MacOSToolCheckList.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace SPC\doctor\item; -use SPC\builder\traits\UnixGoCheckTrait; use SPC\builder\traits\UnixSystemUtilTrait; use SPC\doctor\AsCheckItem; use SPC\doctor\AsFixItem; @@ -14,7 +13,6 @@ use SPC\exception\RuntimeException; class MacOSToolCheckList { use UnixSystemUtilTrait; - use UnixGoCheckTrait; /** @var string[] MacOS 环境下编译依赖的命令 */ public const REQUIRED_COMMANDS = [ @@ -36,12 +34,6 @@ class MacOSToolCheckList 'glibtoolize', ]; - #[AsCheckItem('if xcaddy is installed', limit_os: 'Darwin')] - public function checkXcaddy(): ?CheckResult - { - return $this->checkGoAndXcaddy(); - } - #[AsCheckItem('if homebrew has installed', limit_os: 'Darwin', level: 998)] public function checkBrew(): ?CheckResult { From 8e2dffc3b5cfcf1587a77fe8136ad6b5ff2551ab Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 20:54:54 +0800 Subject: [PATCH 2/9] Add frankenphp sapi embed build at build command, not constant --- src/SPC/builder/BuilderBase.php | 23 +++++++++++++++++++++++ src/SPC/command/BuildPHPCommand.php | 5 ++++- src/globals/defines.php | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index 7fc78e44..fd4788f8 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -404,6 +404,9 @@ abstract class BuilderBase if (($type & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED) { $ls[] = 'embed'; } + if (($type & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP) { + $ls[] = 'frankenphp'; + } return implode(', ', $ls); } @@ -510,6 +513,26 @@ abstract class BuilderBase } } + public function checkBeforeBuildPHP(int $rule): void + { + if (($rule & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP) { + // frankenphp only support linux and macOS + if (!in_array(PHP_OS_FAMILY, ['Linux', 'Darwin'])) { + throw new WrongUsageException('FrankenPHP SAPI is only available on Linux and macOS!'); + } + // frankenphp needs package go-mod-frankenphp installed + $pkg_dir = PKG_ROOT_PATH . '/go-mod-frankenphp-' . arch2gnu(php_uname('m')) . '-' . osfamily2shortname(); + if (!file_exists("{$pkg_dir}/bin/go") || !file_exists("{$pkg_dir}/bin/xcaddy")) { + global $argv; + throw new WrongUsageException("FrankenPHP SAPI requires go-mod-frankenphp package, please install it first: {$argv[0]} install-pkg go-mod-frankenphp"); + } + // frankenphp needs libxml2 libs + if (!$this->getLib('libxml2')) { + throw new WrongUsageException('FrankenPHP SAPI requires libxml2 library, please include `xml` extension in your build.'); + } + } + } + /** * Generate micro extension test php code. */ diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php index 72d6a686..29cedf8f 100644 --- a/src/SPC/command/BuildPHPCommand.php +++ b/src/SPC/command/BuildPHPCommand.php @@ -196,6 +196,9 @@ class BuildPHPCommand extends BuildCommand // validate libs and extensions $builder->validateLibsAndExts(); + // check some things before building all the things + $builder->checkBeforeBuildPHP($rule); + // clean builds and sources if ($this->input->getOption('with-clean')) { logger()->info('Cleaning source and previous build dir...'); @@ -316,7 +319,7 @@ class BuildPHPCommand extends BuildCommand $rule |= BUILD_TARGET_EMBED; f_putenv('SPC_CMD_VAR_PHP_EMBED_TYPE=' . ($embed === 'static' ? 'static' : 'shared')); } - $rule |= ($this->getOption('build-frankenphp') ? BUILD_TARGET_FRANKENPHP : BUILD_TARGET_NONE); + $rule |= ($this->getOption('build-frankenphp') ? (BUILD_TARGET_FRANKENPHP | 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 aebd4d5f..ab37ace9 100644 --- a/src/globals/defines.php +++ b/src/globals/defines.php @@ -62,7 +62,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_FRANKENPHP = BUILD_TARGET_EMBED | 16; // build frankenphp +const BUILD_TARGET_FRANKENPHP = 16; // build frankenphp const BUILD_TARGET_ALL = BUILD_TARGET_CLI | BUILD_TARGET_MICRO | BUILD_TARGET_FPM | BUILD_TARGET_EMBED | BUILD_TARGET_FRANKENPHP; // build all // doctor error fix policy From f709f3bb18406b50ac102326478b99f4e8ef6dd1 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 20:55:24 +0800 Subject: [PATCH 3/9] Add custom package downloader and extractor --- src/SPC/store/Downloader.php | 22 ++++++++++++++++++---- src/SPC/store/PackageManager.php | 15 +++++++++++++++ src/SPC/store/pkg/CustomPackage.php | 17 +++++++++++++++++ src/globals/functions.php | 11 +++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 src/SPC/store/pkg/CustomPackage.php diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php index b0c663d3..e5cc6aae 100644 --- a/src/SPC/store/Downloader.php +++ b/src/SPC/store/Downloader.php @@ -9,6 +9,7 @@ use SPC\exception\DownloaderException; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; +use SPC\store\pkg\CustomPackage; use SPC\store\source\CustomSourceBase; /** @@ -385,10 +386,13 @@ class Downloader ]); break; case 'custom': // Custom download method, like API-based download or other - $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source'); + $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/pkg', 'SPC\store\pkg'); foreach ($classes as $class) { - if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) { - (new $class())->fetch($force); + if (is_a($class, CustomPackage::class, true) && $class !== CustomPackage::class) { + $cls = new $class(); + if (in_array($name, $cls->getSupportName())) { + (new $class())->fetch($name, $force, $pkg); + } break; } } @@ -708,7 +712,6 @@ class Downloader } } // If lock file exists for current arch and glibc target, skip downloading - if (!$force && $download_as === SPC_DOWNLOAD_PRE_BUILT && isset($lock[$lock_name = self::getPreBuiltLockName($name)])) { // lock name with env if ( @@ -719,6 +722,17 @@ class Downloader return true; } } + + // If lock file exists, skip downloading for source mode + if (!$force && $download_as === SPC_DOWNLOAD_PACKAGE && isset($lock[$name])) { + if ( + $lock[$name]['source_type'] === SPC_SOURCE_ARCHIVE && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename']) || + $lock[$name]['source_type'] === SPC_SOURCE_GIT && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname']) + ) { + logger()->notice("Package [{$name}] already downloaded: " . ($lock[$name]['filename'] ?? $lock[$name]['dirname'])); + return true; + } + } return false; } } diff --git a/src/SPC/store/PackageManager.php b/src/SPC/store/PackageManager.php index ca930228..7e8ae3fd 100644 --- a/src/SPC/store/PackageManager.php +++ b/src/SPC/store/PackageManager.php @@ -6,6 +6,7 @@ namespace SPC\store; use SPC\exception\FileSystemException; use SPC\exception\WrongUsageException; +use SPC\store\pkg\CustomPackage; class PackageManager { @@ -32,6 +33,20 @@ class PackageManager // Download package Downloader::downloadPackage($pkg_name, $config, $force); + if (Config::getPkg($pkg_name)['type'] === 'custom') { + // Custom extract function + $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/pkg', 'SPC\store\pkg'); + foreach ($classes as $class) { + if (is_a($class, CustomPackage::class, true) && $class !== CustomPackage::class) { + $cls = new $class(); + if (in_array($pkg_name, $cls->getSupportName())) { + (new $class())->extract($pkg_name); + break; + } + } + } + return; + } // After download, read lock file name $lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true); $source_type = $lock[$pkg_name]['source_type']; diff --git a/src/SPC/store/pkg/CustomPackage.php b/src/SPC/store/pkg/CustomPackage.php new file mode 100644 index 00000000..89edb17e --- /dev/null +++ b/src/SPC/store/pkg/CustomPackage.php @@ -0,0 +1,17 @@ + 'win', + 'Darwin' => 'macos', + 'Linux' => 'linux', + 'BSD' => 'bsd', + default => throw new WrongUsageException('Not support os: ' . PHP_OS_FAMILY), + }; +} + function shell(?bool $debug = null): UnixShell { /* @noinspection PhpUnhandledExceptionInspection */ From 92284e92c9aaf73a997e2662a02da4f9d7bb6bb6 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 20:56:07 +0800 Subject: [PATCH 4/9] Refactor go and frankenphp downloads and builds --- config/pkg.json | 12 +++++ src/SPC/builder/unix/UnixBuilderBase.php | 52 +++++++++++++------ src/SPC/store/pkg/GoModFrankenphp.php | 64 ++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 src/SPC/store/pkg/GoModFrankenphp.php diff --git a/config/pkg.json b/config/pkg.json index 5760c0b1..a2ec8a14 100644 --- a/config/pkg.json +++ b/config/pkg.json @@ -42,5 +42,17 @@ "extract-files": { "upx-*-win64/upx.exe": "{pkg_root_path}/bin/upx.exe" } + }, + "go-mod-frankenphp-x86_64-linux": { + "type": "custom" + }, + "go-mod-frankenphp-aarch64-linux": { + "type": "custom" + }, + "go-mod-frankenphp-x86_64-macos": { + "type": "custom" + }, + "go-mod-frankenphp-aarch64-macos": { + "type": "custom" } } diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 9801d47b..44756955 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -219,6 +219,19 @@ abstract class UnixBuilderBase extends BuilderBase throw new RuntimeException('embed failed sanity check: run failed. Error message: ' . implode("\n", $output)); } } + + // sanity check for frankenphp + if (($build_target & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP) { + logger()->info('running frankenphp sanity check'); + $frankenphp = BUILD_BIN_PATH . '/frankenphp'; + if (!file_exists($frankenphp)) { + throw new RuntimeException('FrankenPHP binary not found: ' . $frankenphp); + } + [$ret, $output] = shell()->execWithResult($frankenphp . ' -v'); + if ($ret !== 0 || !str_contains(implode('', $output), 'FrankenPHP')) { + throw new RuntimeException('FrankenPHP failed sanity check: ret[' . $ret . ']. out[' . implode('', $output) . ']'); + } + } } /** @@ -285,16 +298,19 @@ abstract class UnixBuilderBase extends BuilderBase */ protected function buildFrankenphp(): void { - $path = getenv('PATH'); - $xcaddyPath = getenv('GOBIN') ?: (getenv('HOME') . '/go/bin'); - if (!str_contains($path, $xcaddyPath)) { - $path = $path . ':' . $xcaddyPath; - } - $path = BUILD_BIN_PATH . ':' . $path; - f_putenv("PATH={$path}"); + $os = match (PHP_OS_FAMILY) { + 'Linux' => 'linux', + 'Windows' => 'win', + 'Darwin' => 'macos', + 'BSD' => 'freebsd', + default => throw new RuntimeException('Unsupported OS: ' . PHP_OS_FAMILY), + }; + $arch = arch2gnu(php_uname('m')); + + // define executables for go and xcaddy + $go_exec = PKG_ROOT_PATH . "/go-mod-frankenphp-{$arch}-{$os}/bin/go"; + $xcaddy_exec = PKG_ROOT_PATH . "/go-mod-frankenphp-{$arch}-{$os}/bin/xcaddy"; - $brotliLibs = $this->getLib('brotli') !== null ? '-lbrotlienc -lbrotlidec -lbrotlicommon' : ''; - $watcherLibs = $this->getLib('watcher') !== null ? '-lwatcher-c' : ''; $nobrotli = $this->getLib('brotli') === null ? ',nobrotli' : ''; $nowatcher = $this->getLib('watcher') === null ? ',nowatcher' : ''; $xcaddyModules = getenv('SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES'); @@ -303,7 +319,7 @@ abstract class UnixBuilderBase extends BuilderBase $xcaddyModules = '--with github.com/dunglas/frankenphp ' . $xcaddyModules; } if ($this->getLib('brotli') === null && str_contains($xcaddyModules, '--with github.com/dunglas/caddy-cbrotli')) { - logger()->warning('caddy-cbrotli module is enabled, but broli library is not built. Disabling caddy-cbrotli.'); + logger()->warning('caddy-cbrotli module is enabled, but brotli library is not built. Disabling caddy-cbrotli.'); $xcaddyModules = str_replace('--with github.com/dunglas/caddy-cbrotli', '', $xcaddyModules); } $lrt = PHP_OS_FAMILY === 'Linux' ? '-lrt' : ''; @@ -313,14 +329,20 @@ abstract class UnixBuilderBase extends BuilderBase if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') { $libphpVersion = preg_replace('/\.\d$/', '', $libphpVersion); } - $debugFlags = $this->getOption('--with-debug') ? "'-w -s' " : ''; + $debugFlags = $this->getOption('--with-debug') ? "'-w -s' " : ''; + + $config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list, with_dependencies: true); $env = [ + 'PATH' => PKG_ROOT_PATH . "/go-mod-frankenphp-{$arch}-{$os}/bin:" . getenv('PATH'), + 'GOROOT' => PKG_ROOT_PATH . "/go-mod-frankenphp-{$arch}-{$os}", + 'GOBIN' => PKG_ROOT_PATH . "/go-mod-frankenphp-{$arch}-{$os}/bin", + 'GOPATH' => PKG_ROOT_PATH . '/go', 'CGO_ENABLED' => '1', - 'CGO_CFLAGS' => '$(php-config --includes) -I$(php-config --include-dir)/..', - 'CGO_LDFLAGS' => '$(php-config --ldflags) -L' . BUILD_LIB_PATH . " $(php-config --libs) {$brotliLibs} {$watcherLibs} -lphp {$lrt}", + 'CGO_CFLAGS' => $config['cflags'], + 'CGO_LDFLAGS' => "{$config['ldflags']} {$config['libs']} {$lrt}", 'XCADDY_GO_BUILD_FLAGS' => '-buildmode=pie ' . - '-ldflags \\"-linkmode=external -extldflags \'-pie\' '. $debugFlags . + '-ldflags \"-linkmode=external -extldflags \'-pie\' ' . $debugFlags . '-X \'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ' . "{$frankenPhpVersion} PHP {$libphpVersion} Caddy'\\\" " . "-tags=nobadger,nomysql,nopgx{$nobrotli}{$nowatcher}", @@ -328,6 +350,6 @@ abstract class UnixBuilderBase extends BuilderBase ]; shell()->cd(BUILD_BIN_PATH) ->setEnv($env) - ->exec('xcaddy build --output frankenphp ' . $xcaddyModules); + ->exec("{$xcaddy_exec} build --output frankenphp {$xcaddyModules}"); } } diff --git a/src/SPC/store/pkg/GoModFrankenphp.php b/src/SPC/store/pkg/GoModFrankenphp.php new file mode 100644 index 00000000..bede5d22 --- /dev/null +++ b/src/SPC/store/pkg/GoModFrankenphp.php @@ -0,0 +1,64 @@ + 'amd64', + 'aarch64' => 'arm64', + default => throw new \InvalidArgumentException('Unsupported architecture: ' . $name), + }; + $os = match (explode('-', $name)[4]) { + 'linux' => 'linux', + 'macos' => 'darwin', + default => throw new \InvalidArgumentException('Unsupported OS: ' . $name), + }; + $go_version = '1.24.4'; + $config = [ + 'type' => 'url', + 'url' => "https://go.dev/dl/go{$go_version}.{$os}-{$arch}.tar.gz", + ]; + Downloader::downloadPackage($name, $config, $force); + } + + public function extract(string $name): void + { + $pkgroot = PKG_ROOT_PATH; + $lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true); + $source_type = $lock[$name]['source_type']; + $filename = DOWNLOAD_PATH . '/' . ($lock[$name]['filename'] ?? $lock[$name]['dirname']); + $extract = $lock[$name]['move_path'] === null ? (PKG_ROOT_PATH . "{$pkgroot}/{$name}") : $lock[$name]['move_path']; + + FileSystem::extractPackage($name, $source_type, $filename, $extract); + + // install xcaddy + $go_exec = PKG_ROOT_PATH . "{$pkgroot}/{$name}/bin/go"; + // $xcaddy_exec = PKG_ROOT_PATH . "$pkgroot/$name/bin/xcaddy"; + shell()->appendEnv([ + 'PATH' => "{$pkgroot}/{$name}/bin:" . getenv('PATH'), + 'GOROOT' => "{$pkgroot}/{$name}", + 'GOBIN' => "{$pkgroot}/{$name}/bin", + 'GOPATH' => "{$pkgroot}/go", + ]) + ->exec("{$go_exec} install github.com/caddyserver/xcaddy/cmd/xcaddy@latest"); + // TODO: Here to download dependencies for xcaddy and frankenphp first + } +} From d6858e18df118c9160e97301fa871038593a478a Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 20:57:14 +0800 Subject: [PATCH 5/9] phpstan fix --- src/globals/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/globals/functions.php b/src/globals/functions.php index 32f0514e..998b2d1c 100644 --- a/src/globals/functions.php +++ b/src/globals/functions.php @@ -105,7 +105,7 @@ function osfamily2dir(): string function osfamily2shortname(): string { return match (PHP_OS_FAMILY) { - 'Windows', 'WINNT', 'Cygwin' => 'win', + 'Windows' => 'win', 'Darwin' => 'macos', 'Linux' => 'linux', 'BSD' => 'bsd', From 74b1dda884a447258df20c7696fa9a07872367d7 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 21:06:08 +0800 Subject: [PATCH 6/9] Fix test-extensions.php --- src/globals/test-extensions.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 44243140..77e0f71d 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -40,6 +40,9 @@ $no_strip = false; // compress with upx $upx = false; +// whether to test frankenphp build, only available for macos and linux +$frankenphp = false; + // prefer downloading pre-built packages to speed up the build process $prefer_pre_built = false; @@ -177,7 +180,7 @@ if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') { $build_cmd .= $no_strip ? '--no-strip ' : ''; $build_cmd .= $upx ? '--with-upx-pack ' : ''; $build_cmd .= $final_libs === '' ? '' : ('--with-libs=' . quote2($final_libs) . ' '); - $build_cmd .= str_starts_with($argv[2], 'windows-') ? '' : '--build-fpm --build-frankenphp'; + $build_cmd .= str_starts_with($argv[2], 'windows-') ? '' : '--build-fpm '; $build_cmd .= '--debug '; } @@ -208,7 +211,7 @@ switch ($argv[1] ?? null) { 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); + passthru($prefix . $build_cmd . (str_starts_with($argv[2], 'windows-') ? ' --build-cli' : (' --build-embed' . ($frankenphp ? ' --build-frankenphp' : ''))), $retcode); break; case 'doctor_cmd': passthru($prefix . $doctor_cmd, $retcode); From 4ecaffd9085846091e825d300b1b29d64056b763 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 21:08:05 +0800 Subject: [PATCH 7/9] Fix test-extensions.php --- src/globals/test-extensions.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/globals/test-extensions.php b/src/globals/test-extensions.php index 77e0f71d..79acc984 100644 --- a/src/globals/test-extensions.php +++ b/src/globals/test-extensions.php @@ -41,7 +41,7 @@ $no_strip = false; $upx = false; // whether to test frankenphp build, only available for macos and linux -$frankenphp = false; +$frankenphp = true; // prefer downloading pre-built packages to speed up the build process $prefer_pre_built = false; @@ -211,6 +211,12 @@ switch ($argv[1] ?? null) { passthru($prefix . $build_cmd . ' --build-cli --build-micro', $retcode); break; case 'build_embed_cmd': + if ($frankenphp) { + passthru("{$prefix}install-pkg go-mod-frankenphp --debug", $retcode); + if ($retcode !== 0) { + break; + } + } passthru($prefix . $build_cmd . (str_starts_with($argv[2], 'windows-') ? ' --build-cli' : (' --build-embed' . ($frankenphp ? ' --build-frankenphp' : ''))), $retcode); break; case 'doctor_cmd': From becee5b42671d2b54316460bad699c8cb18aead1 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 21:27:07 +0800 Subject: [PATCH 8/9] Use version instead of -v --- src/SPC/builder/unix/UnixBuilderBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php index 44756955..d424c594 100644 --- a/src/SPC/builder/unix/UnixBuilderBase.php +++ b/src/SPC/builder/unix/UnixBuilderBase.php @@ -227,7 +227,7 @@ abstract class UnixBuilderBase extends BuilderBase if (!file_exists($frankenphp)) { throw new RuntimeException('FrankenPHP binary not found: ' . $frankenphp); } - [$ret, $output] = shell()->execWithResult($frankenphp . ' -v'); + [$ret, $output] = shell()->execWithResult("{$frankenphp} version"); if ($ret !== 0 || !str_contains(implode('', $output), 'FrankenPHP')) { throw new RuntimeException('FrankenPHP failed sanity check: ret[' . $ret . ']. out[' . implode('', $output) . ']'); } From a76f49f92739d03c683e08ed7cc6e66a9849c83d Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 18 Jun 2025 21:56:36 +0800 Subject: [PATCH 9/9] Remove libxml2 requirement for linux --- src/SPC/builder/BuilderBase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php index fd4788f8..daa27765 100644 --- a/src/SPC/builder/BuilderBase.php +++ b/src/SPC/builder/BuilderBase.php @@ -527,8 +527,8 @@ abstract class BuilderBase throw new WrongUsageException("FrankenPHP SAPI requires go-mod-frankenphp package, please install it first: {$argv[0]} install-pkg go-mod-frankenphp"); } // frankenphp needs libxml2 libs - if (!$this->getLib('libxml2')) { - throw new WrongUsageException('FrankenPHP SAPI requires libxml2 library, please include `xml` extension in your build.'); + if (PHP_OS_FAMILY === 'Darwin' && !$this->getLib('libxml2')) { + throw new WrongUsageException('FrankenPHP SAPI for macOS requires libxml2 library, please include `xml` extension in your build.'); } } }