From e9c27dee1fe44029b16d78aca2d8aa4d63f903fe Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Wed, 4 Feb 2026 15:28:10 +0800 Subject: [PATCH] Add go-xcaddy,musl-toolchain,php,upx, and also glfw linux support --- config/artifact/glfw.yml | 9 +++ config/artifact/php-src.yml | 7 ++ config/pkg.ext.json | 21 ------ config/pkg.target.json | 66 ---------------- config/pkg/ext/ext-glfw.yml | 5 ++ config/pkg/lib/glfw.yml | 6 ++ config/pkg/target/go-xcaddy.yml | 6 ++ config/pkg/target/musl-toolchain.yml | 6 ++ config/pkg/target/php.yml | 44 +++++++++++ config/pkg/target/upx.yml | 7 ++ spc.registry.json | 8 +- src/Package/Artifact/php_src.php | 75 +++++++++++++++++++ src/Package/Extension/glfw.php | 59 +++++++++++++++ src/Package/Library/glfw.php | 100 +++++++++++++++++++++++++ src/Package/Target/php/unix.php | 42 +++++++++-- src/StaticPHP/Doctor/Item/ZigCheck.php | 6 +- 16 files changed, 365 insertions(+), 102 deletions(-) create mode 100644 config/artifact/glfw.yml create mode 100644 config/artifact/php-src.yml create mode 100644 config/pkg/ext/ext-glfw.yml create mode 100644 config/pkg/lib/glfw.yml create mode 100644 config/pkg/target/go-xcaddy.yml create mode 100644 config/pkg/target/musl-toolchain.yml create mode 100644 config/pkg/target/php.yml create mode 100644 config/pkg/target/upx.yml create mode 100644 src/Package/Artifact/php_src.php create mode 100644 src/Package/Extension/glfw.php create mode 100644 src/Package/Library/glfw.php diff --git a/config/artifact/glfw.yml b/config/artifact/glfw.yml new file mode 100644 index 00000000..05e9f18d --- /dev/null +++ b/config/artifact/glfw.yml @@ -0,0 +1,9 @@ +glfw: + metadata: + license-files: + - LICENSE + license: MIT + source: + type: git + url: 'https://github.com/mario-deluna/php-glfw' + rev: master diff --git a/config/artifact/php-src.yml b/config/artifact/php-src.yml new file mode 100644 index 00000000..32bcb6cf --- /dev/null +++ b/config/artifact/php-src.yml @@ -0,0 +1,7 @@ +php-src: + metadata: + license-files: + - LICENSE + license: PHP-3.01 + source: + type: php-release diff --git a/config/pkg.ext.json b/config/pkg.ext.json index d1ca0b3f..cbcf5ad5 100644 --- a/config/pkg.ext.json +++ b/config/pkg.ext.json @@ -244,27 +244,6 @@ "arg-type": "with-path" } }, - "ext-glfw": { - "type": "php-extension", - "artifact": "ext-glfw", - "depends": [ - "glfw" - ], - "depends@windows": [], - "license": { - "type": "file", - "path": "LICENSE" - }, - "php-extension": { - "support": { - "Windows": "wip", - "BSD": "no", - "Linux": "no" - }, - "arg-type": "custom", - "notes": true - } - }, "ext-gmp": { "type": "php-extension", "depends": [ diff --git a/config/pkg.target.json b/config/pkg.target.json index a5c20b78..59c6c65a 100644 --- a/config/pkg.target.json +++ b/config/pkg.target.json @@ -1,70 +1,8 @@ { - "frankenphp": { - "type": "virtual-target", - "artifact": "frankenphp", - "depends": [ - "php-embed", - "go-xcaddy" - ], - "depends@macos": [ - "php-embed", - "go-xcaddy", - "libxml2" - ] - }, - "go-xcaddy": { - "type": "target", - "artifact": "go-xcaddy", - "static-bins": [ - "xcaddy" - ] - }, - "musl-toolchain": { - "type": "target", - "artifact": "musl-toolchain" - }, "nasm": { "type": "target", "artifact": "nasm" }, - "php": { - "type": "target", - "artifact": "php-src", - "depends@macos": [ - "libxml2" - ] - }, - "php-cgi": { - "type": "virtual-target", - "depends": [ - "php" - ] - }, - "php-cli": { - "type": "virtual-target", - "depends": [ - "php" - ] - }, - "php-embed": { - "type": "virtual-target", - "depends": [ - "php" - ] - }, - "php-fpm": { - "type": "virtual-target", - "depends": [ - "php" - ] - }, - "php-micro": { - "type": "virtual-target", - "artifact": "micro", - "depends": [ - "php" - ] - }, "php-sdk-binary-tools": { "type": "target", "artifact": "php-sdk-binary-tools" @@ -73,10 +11,6 @@ "type": "target", "artifact": "strawberry-perl" }, - "upx": { - "type": "target", - "artifact": "upx" - }, "vswhere": { "type": "target", "artifact": "vswhere", diff --git a/config/pkg/ext/ext-glfw.yml b/config/pkg/ext/ext-glfw.yml new file mode 100644 index 00000000..dc8844a8 --- /dev/null +++ b/config/pkg/ext/ext-glfw.yml @@ -0,0 +1,5 @@ +ext-glfw: + type: php-extension + artifact: glfw + depends: + - glfw diff --git a/config/pkg/lib/glfw.yml b/config/pkg/lib/glfw.yml new file mode 100644 index 00000000..13fba596 --- /dev/null +++ b/config/pkg/lib/glfw.yml @@ -0,0 +1,6 @@ +glfw: + type: library + artifact: glfw + lang: cpp + static-libs@unix: + - libglfw3.a diff --git a/config/pkg/target/go-xcaddy.yml b/config/pkg/target/go-xcaddy.yml new file mode 100644 index 00000000..89cb4cd0 --- /dev/null +++ b/config/pkg/target/go-xcaddy.yml @@ -0,0 +1,6 @@ +go-xcaddy: + type: target + artifact: + binary: custom + static-bins: + - xcaddy diff --git a/config/pkg/target/musl-toolchain.yml b/config/pkg/target/musl-toolchain.yml new file mode 100644 index 00000000..038059e2 --- /dev/null +++ b/config/pkg/target/musl-toolchain.yml @@ -0,0 +1,6 @@ +musl-toolchain: + type: target + artifact: + binary: + linux-x86_64: { type: url, url: 'https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/x86_64-musl-toolchain.tgz', extract: '{pkg_root_path}/musl-toolchain' } + linux-aarch64: { type: url, url: 'https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/aarch64-musl-toolchain.tgz', extract: '{pkg_root_path}/musl-toolchain' } diff --git a/config/pkg/target/php.yml b/config/pkg/target/php.yml new file mode 100644 index 00000000..8f88cb58 --- /dev/null +++ b/config/pkg/target/php.yml @@ -0,0 +1,44 @@ +frankenphp: + type: virtual-target + artifact: + source: + type: ghtar + repo: php/frankenphp + prefer-stable: true + metadata: + license-files: [LICENSE] + license: MIT + depends: + - php-embed + - go-xcaddy +php: + type: target + artifact: php-src + depends@macos: + - libxml2 +php-cgi: + type: virtual-target + depends: + - php +php-cli: + type: virtual-target + depends: + - php +php-embed: + type: virtual-target + depends: + - php +php-fpm: + type: virtual-target + depends: + - php +php-micro: + type: virtual-target + artifact: + source: + type: git + extract: php-src/sapi/micro + rev: master + url: 'https://github.com/static-php/phpmicro' + depends: + - php diff --git a/config/pkg/target/upx.yml b/config/pkg/target/upx.yml new file mode 100644 index 00000000..29506c39 --- /dev/null +++ b/config/pkg/target/upx.yml @@ -0,0 +1,7 @@ +upx: + type: target + artifact: + binary: + linux-x86_64: { type: ghrel, repo: upx/upx, match: upx.+-amd64_linux\.tar\.xz, extract: { upx: '{pkg_root_path}/bin/upx' } } + linux-aarch64: { type: ghrel, repo: upx/upx, match: upx.+-arm64_linux\.tar\.xz, extract: { upx: '{pkg_root_path}/bin/upx' } } + windows-x86_64: { type: ghrel, repo: upx/upx, match: upx.+-win64\.zip, extract: { upx.exe: '{pkg_root_path}/bin/upx.exe' } } diff --git a/spc.registry.json b/spc.registry.json index b3d34939..b731249b 100644 --- a/spc.registry.json +++ b/spc.registry.json @@ -12,12 +12,16 @@ }, "config": [ "config/pkg.ext.json", - "config/pkg/lib", - "config/pkg/target", + "config/pkg/lib/", + "config/pkg/target/", + "config/pkg/ext/", "config/pkg.target.json" ] }, "artifact": { + "config": [ + "config/artifact/" + ], "psr-4": { "Package\\Artifact": "src/Package/Artifact" } diff --git a/src/Package/Artifact/php_src.php b/src/Package/Artifact/php_src.php new file mode 100644 index 00000000..498abc66 --- /dev/null +++ b/src/Package/Artifact/php_src.php @@ -0,0 +1,75 @@ += 80100 ? file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_81.w32') : file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_80.w32'); + file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32.bak', file_get_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32')); + file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32', $origin); + } + } + + #[AfterSourceExtract('php-src')] + #[PatchDescription('Patch FFI extension on CentOS 7 with -O3 optimization (strncmp issue)')] + public function patchFfiCentos7FixO3strncmp(): void + { + spc_skip_if(!($ver = SystemTarget::getLibcVersion()) || version_compare($ver, '2.17', '>')); + spc_skip_if(!file_exists(SOURCE_PATH . '/php-src/main/php_version.h')); + $file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h'); + spc_skip_if(preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0 && intval($match[1]) < 80316); + SourcePatcher::patchFile('ffi_centos7_fix_O3_strncmp.patch', SOURCE_PATH . '/php-src'); + } + + #[AfterSourceExtract('php-src')] + #[PatchDescription('Add LICENSE file to IMAP extension if missing')] + public function patchImapLicense(): void + { + if (!file_exists(SOURCE_PATH . '/php-src/ext/imap/LICENSE') && is_dir(SOURCE_PATH . '/php-src/ext/imap')) { + file_put_contents(SOURCE_PATH . '/php-src/ext/imap/LICENSE', file_get_contents(ROOT_DIR . '/src/globals/extra/Apache_LICENSE')); + } + } +} diff --git a/src/Package/Extension/glfw.php b/src/Package/Extension/glfw.php new file mode 100644 index 00000000..61d722e1 --- /dev/null +++ b/src/Package/Extension/glfw.php @@ -0,0 +1,59 @@ +getSourceDir(), SOURCE_PATH . '/php-src/ext/glfw'); + } + } + + #[BeforeStage('php', [php::class, 'configureForUnix'], 'ext-glfw')] + #[PatchDescription('Patch glfw extension before configure')] + public function patchBeforeConfigure(): void + { + FileSystem::replaceFileStr( + SOURCE_PATH . '/php-src/configure', + '-lglfw ', + '-lglfw3 ' + ); + + // add X11 shared libs for linux + if (SystemTarget::getTargetOS() === 'Linux') { + $extra_libs = getenv('SPC_EXTRA_LIBS') ?: ''; + $extra_libs .= ' -lX11 -lXrandr -lXinerama -lXcursor -lXi'; + putenv('SPC_EXTRA_LIBS=' . trim($extra_libs)); + $extra_cflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') ?: ''; + + $extra_cflags .= ' -idirafter /usr/include'; + putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . trim($extra_cflags)); + $extra_ldflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS') ?: ''; + $extra_ldflags .= ' -L/usr/lib/' . SystemTarget::getTargetArch() . '-linux-gnu '; + putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS=' . $extra_ldflags); + } + } + + #[CustomPhpConfigureArg('Darwin')] + #[CustomPhpConfigureArg('Linux')] + public function getUnixConfigureArg(bool $shared = false): string + { + return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH; + } +} diff --git a/src/Package/Library/glfw.php b/src/Package/Library/glfw.php new file mode 100644 index 00000000..9348489c --- /dev/null +++ b/src/Package/Library/glfw.php @@ -0,0 +1,100 @@ +isStatic()) { + throw new ValidationException('glfw library does not support full-static linking on Linux, please build with dynamic target specified.'); + } + // detect X11 dev packages + $required_headers = [ + '/usr/include/X11', + '/usr/include/X11/extensions/Xrandr.h', + '/usr/include/X11/extensions/Xinerama.h', + '/usr/include/X11/Xcursor/Xcursor.h', + ]; + foreach ($required_headers as $header) { + if (!file_exists($header)) { + throw new ValidationException("glfw requires X11 development headers. Missing: {$header}. Please confirm that your system has the necessary X11 packages installed."); + } + } + } + } + + #[BuildFor('Linux')] + public function buildForLinux(LibraryPackage $lib): void + { + $x11_lib_find = [ + '/usr/lib/' . SystemTarget::getTargetArch() . '-linux-gnu/libX11.so', + '/usr/lib64/libX11.so', + '/usr/lib/libX11.so', + ]; + $found = false; + foreach ($x11_lib_find as $path) { + if (file_exists($path)) { + $found = $path; + break; + } + } + if (!$found) { + throw new BuildFailureException('Cannot find X11 library files in standard locations. Please ensure that the X11 development libraries are installed.'); + } + $base_path = pathinfo($found, PATHINFO_DIRNAME); + UnixCMakeExecutor::create($lib) + ->setBuildDir("{$lib->getSourceDir()}/vendor/glfw") + ->setReset(false) + ->addConfigureArgs( + '-DGLFW_BUILD_EXAMPLES=OFF', + '-DGLFW_BUILD_TESTS=OFF', + '-DGLFW_BUILD_DOCS=OFF', + '-DX11_X11_INCLUDE_PATH=/usr/include', + '-DX11_Xrandr_INCLUDE_PATH=/usr/include/X11/extensions', + '-DX11_Xinerama_INCLUDE_PATH=/usr/include/X11/extensions', + '-DX11_Xkb_INCLUDE_PATH=/usr/include/X11', + '-DX11_Xcursor_INCLUDE_PATH=/usr/include/X11/Xcursor', + '-DX11_Xi_INCLUDE_PATH=/usr/include/X11/extensions', + "-DX11_X11_LIB={$base_path}/libX11.so", + "-DX11_Xrandr_LIB={$base_path}/libXrandr.so", + "-DX11_Xinerama_LIB={$base_path}/libXinerama.so", + "-DX11_Xcursor_LIB={$base_path}/libXcursor.so", + "-DX11_Xi_LIB={$base_path}/libXi.so" + ) + ->build('.'); + // patch pkgconf + $lib->patchPkgconfPrefix(['glfw3.pc']); + } + + #[BuildFor('Darwin')] + public function buildForMac(LibraryPackage $lib): void + { + UnixCMakeExecutor::create($lib) + ->setBuildDir("{$lib->getSourceDir()}/vendor/glfw") + ->setReset(false) + ->addConfigureArgs( + '-DGLFW_BUILD_EXAMPLES=OFF', + '-DGLFW_BUILD_TESTS=OFF', + '-DGLFW_BUILD_DOCS=OFF', + ) + ->build('.'); + // patch pkgconf + $lib->patchPkgconfPrefix(['glfw3.pc']); + } +} diff --git a/src/Package/Target/php/unix.php b/src/Package/Target/php/unix.php index 1ce2ff95..edbc6dd2 100644 --- a/src/Package/Target/php/unix.php +++ b/src/Package/Target/php/unix.php @@ -134,9 +134,11 @@ trait unix { InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('make cli')); $concurrency = $builder->concurrency; + $vars = $this->makeVars($installer); + $makeArgs = $this->makeVarsToArgs($vars); shell()->cd($package->getSourceDir()) - ->setEnv($this->makeVars($installer)) - ->exec("make -j{$concurrency} cli"); + ->setEnv($vars) + ->exec("make -j{$concurrency} {$makeArgs} cli"); $builder->deployBinary("{$package->getSourceDir()}/sapi/cli/php", BUILD_BIN_PATH . '/php'); $package->setOutput('Binary path for cli SAPI', BUILD_BIN_PATH . '/php'); @@ -147,9 +149,11 @@ trait unix { InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('make cgi')); $concurrency = $builder->concurrency; + $vars = $this->makeVars($installer); + $makeArgs = $this->makeVarsToArgs($vars); shell()->cd($package->getSourceDir()) - ->setEnv($this->makeVars($installer)) - ->exec("make -j{$concurrency} cgi"); + ->setEnv($vars) + ->exec("make -j{$concurrency} {$makeArgs} cgi"); $builder->deployBinary("{$package->getSourceDir()}/sapi/cgi/php-cgi", BUILD_BIN_PATH . '/php-cgi'); $package->setOutput('Binary path for cgi SAPI', BUILD_BIN_PATH . '/php-cgi'); @@ -160,9 +164,11 @@ trait unix { InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('make fpm')); $concurrency = $builder->concurrency; + $vars = $this->makeVars($installer); + $makeArgs = $this->makeVarsToArgs($vars); shell()->cd($package->getSourceDir()) - ->setEnv($this->makeVars($installer)) - ->exec("make -j{$concurrency} fpm"); + ->setEnv($vars) + ->exec("make -j{$concurrency} {$makeArgs} fpm"); $builder->deployBinary("{$package->getSourceDir()}/sapi/fpm/php-fpm", BUILD_BIN_PATH . '/php-fpm'); $package->setOutput('Binary path for fpm SAPI', BUILD_BIN_PATH . '/php-fpm'); @@ -182,10 +188,11 @@ trait unix // apply --with-micro-fake-cli option $vars = $this->makeVars($installer); $vars['EXTRA_CFLAGS'] .= $package->getBuildOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : ''; + $makeArgs = $this->makeVarsToArgs($vars); // build shell()->cd($package->getSourceDir()) ->setEnv($vars) - ->exec("make -j{$builder->concurrency} micro"); + ->exec("make -j{$builder->concurrency} {$makeArgs} micro"); $builder->deployBinary($package->getSourceDir() . '/sapi/micro/micro.sfx', BUILD_BIN_PATH . '/micro.sfx'); $package->setOutput('Binary path for micro SAPI', BUILD_BIN_PATH . '/micro.sfx'); @@ -440,11 +447,30 @@ trait unix $static = ApplicationContext::get(ToolchainInterface::class)->isStatic() ? '-all-static' : ''; $pie = SystemTarget::getTargetOS() === 'Linux' ? '-pie' : ''; + // Append SPC_EXTRA_LIBS to libs for dynamic linking support (e.g., X11) + $extra_libs = getenv('SPC_EXTRA_LIBS') ?: ''; + $libs = trim($config['libs'] . ' ' . $extra_libs); + return array_filter([ 'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'), 'EXTRA_LDFLAGS_PROGRAM' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS') . "{$config['ldflags']} {$static} {$pie}", 'EXTRA_LDFLAGS' => $config['ldflags'], - 'EXTRA_LIBS' => $config['libs'], + 'EXTRA_LIBS' => $libs, ]); } + + /** + * Convert make variables array to command line argument string. + * This is needed because make command line arguments have higher priority than environment variables. + */ + private function makeVarsToArgs(array $vars): string + { + $args = []; + foreach ($vars as $key => $value) { + if (trim($value) !== '') { + $args[] = $key . '=' . escapeshellarg($value); + } + } + return implode(' ', $args); + } } diff --git a/src/StaticPHP/Doctor/Item/ZigCheck.php b/src/StaticPHP/Doctor/Item/ZigCheck.php index 4157e9d6..c3a6aa9f 100644 --- a/src/StaticPHP/Doctor/Item/ZigCheck.php +++ b/src/StaticPHP/Doctor/Item/ZigCheck.php @@ -25,11 +25,7 @@ class ZigCheck #[CheckItem('if zig is installed', level: 800)] public function checkZig(): CheckResult { - $installer = new PackageInstaller(); - $package = 'zig'; - $installer->addInstallPackage($package); - $installed = $installer->isPackageInstalled($package); - if ($installed) { + if (new PackageInstaller()->addInstallPackage('zig')->isPackageInstalled('zig')) { return CheckResult::ok(); } return CheckResult::fail('zig is not installed', 'install-zig');