Add go-xcaddy,musl-toolchain,php,upx, and also glfw linux support

This commit is contained in:
crazywhalecc 2026-02-04 15:28:10 +08:00
parent 0afa1dd80c
commit e9c27dee1f
No known key found for this signature in database
GPG Key ID: 1F4BDD59391F2680
16 changed files with 365 additions and 102 deletions

9
config/artifact/glfw.yml Normal file
View File

@ -0,0 +1,9 @@
glfw:
metadata:
license-files:
- LICENSE
license: MIT
source:
type: git
url: 'https://github.com/mario-deluna/php-glfw'
rev: master

View File

@ -0,0 +1,7 @@
php-src:
metadata:
license-files:
- LICENSE
license: PHP-3.01
source:
type: php-release

View File

@ -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": [

View File

@ -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",

View File

@ -0,0 +1,5 @@
ext-glfw:
type: php-extension
artifact: glfw
depends:
- glfw

6
config/pkg/lib/glfw.yml Normal file
View File

@ -0,0 +1,6 @@
glfw:
type: library
artifact: glfw
lang: cpp
static-libs@unix:
- libglfw3.a

View File

@ -0,0 +1,6 @@
go-xcaddy:
type: target
artifact:
binary: custom
static-bins:
- xcaddy

View File

@ -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' }

44
config/pkg/target/php.yml Normal file
View File

@ -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

View File

@ -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' } }

View File

@ -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"
}

View File

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace Package\Artifact;
use StaticPHP\Attribute\Artifact\AfterSourceExtract;
use StaticPHP\Attribute\PatchDescription;
use StaticPHP\Runtime\SystemTarget;
use StaticPHP\Util\FileSystem;
use StaticPHP\Util\SourcePatcher;
class php_src
{
#[AfterSourceExtract('php-src')]
#[PatchDescription('Patch PHP source for libxml2 2.12 compatibility on Alpine Linux')]
public function patchPhpLibxml212(): void
{
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
$ver_id = intval($match[1]);
if ($ver_id < 80000) {
SourcePatcher::patchFile('spc_fix_alpine_build_php80.patch', SOURCE_PATH . '/php-src');
return;
}
if ($ver_id < 80100) {
SourcePatcher::patchFile('spc_fix_libxml2_12_php80.patch', SOURCE_PATH . '/php-src');
SourcePatcher::patchFile('spc_fix_alpine_build_php80.patch', SOURCE_PATH . '/php-src');
return;
}
if ($ver_id < 80200) {
// self::patchFile('spc_fix_libxml2_12_php81.patch', SOURCE_PATH . '/php-src');
SourcePatcher::patchFile('spc_fix_alpine_build_php80.patch', SOURCE_PATH . '/php-src');
}
}
}
#[AfterSourceExtract('php-src')]
#[PatchDescription('Patch GD extension for Windows builds')]
public function patchGDWin32(): void
{
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
$ver_id = intval($match[1]);
if ($ver_id < 80200) {
// see: https://github.com/php/php-src/commit/243966177e39eb71822935042c3f13fa6c5b9eed
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/gd/libgd/gdft.c', '#ifndef MSWIN32', '#ifndef _WIN32');
}
// custom config.w32, because official config.w32 is hard-coded many things
$origin = $ver_id >= 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'));
}
}
}

View File

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace Package\Extension;
use Package\Target\php;
use StaticPHP\Attribute\Package\BeforeStage;
use StaticPHP\Attribute\Package\CustomPhpConfigureArg;
use StaticPHP\Attribute\Package\Extension;
use StaticPHP\Attribute\PatchDescription;
use StaticPHP\Package\PhpExtensionPackage;
use StaticPHP\Runtime\SystemTarget;
use StaticPHP\Util\FileSystem;
#[Extension('glfw')]
class glfw extends PhpExtensionPackage
{
#[BeforeStage('php', [php::class, 'buildconfForUnix'], 'ext-glfw')]
#[PatchDescription('Patch glfw extension before buildconf')]
public function patchBeforeBuildconf(): void
{
if (!file_exists(SOURCE_PATH . '/php-src/ext/glfw')) {
FileSystem::copyDir($this->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;
}
}

View File

@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace Package\Library;
use StaticPHP\Attribute\Package\BuildFor;
use StaticPHP\Attribute\Package\Library;
use StaticPHP\Attribute\Package\Validate;
use StaticPHP\Exception\BuildFailureException;
use StaticPHP\Exception\ValidationException;
use StaticPHP\Package\LibraryPackage;
use StaticPHP\Runtime\Executor\UnixCMakeExecutor;
use StaticPHP\Runtime\SystemTarget;
use StaticPHP\Toolchain\Interface\ToolchainInterface;
#[Library('glfw')]
class glfw
{
#[Validate]
public function validate(ToolchainInterface $toolchain): void
{
if (SystemTarget::getTargetOS() === 'Linux') {
if ($toolchain->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']);
}
}

View File

@ -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);
}
}

View File

@ -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');