From 223dd10ac6bbe97934e0e4fa7648b655d6b71ca9 Mon Sep 17 00:00:00 2001 From: henderkes Date: Sat, 24 Jan 2026 20:26:16 +0100 Subject: [PATCH 01/28] fix spx shared libadd --- src/SPC/builder/Extension.php | 2 +- src/SPC/builder/extension/excimer.php | 19 ------------------- src/SPC/builder/extension/spx.php | 7 +++++++ 3 files changed, 8 insertions(+), 20 deletions(-) delete mode 100644 src/SPC/builder/extension/excimer.php diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 925a4c8e..f5a5d956 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -542,7 +542,7 @@ class Extension */ protected function getSharedExtensionEnv(): array { - $config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this); + $config = (new SPCConfigUtil($this->builder, ['no_php' => true]))->getExtensionConfig($this); [$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']); $preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group '; $postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group '; diff --git a/src/SPC/builder/extension/excimer.php b/src/SPC/builder/extension/excimer.php deleted file mode 100644 index 03dd8f22..00000000 --- a/src/SPC/builder/extension/excimer.php +++ /dev/null @@ -1,19 +0,0 @@ -source_dir . '/src/php_spx.h', $this->source_dir . '/php_spx.h'); return true; } + + public function getSharedExtensionEnv(): array + { + $env = parent::getSharedExtensionEnv(); + $env['SPX_SHARED_LIBADD'] = $env['LIBS']; + return $env; + } } From 4531c9fe57d54062c499c007687c412df13e8451 Mon Sep 17 00:00:00 2001 From: henderkes Date: Tue, 27 Jan 2026 00:57:58 +0100 Subject: [PATCH 02/28] add option to allow linking musl dynamically on alpine --- config/env.ini | 4 +++- src/SPC/util/SPCTarget.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/env.ini b/config/env.ini index c1d4dbc4..a16bc160 100644 --- a/config/env.ini +++ b/config/env.ini @@ -75,8 +75,10 @@ SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime ; - musl-native: used for alpine linux, can build `musl` and `musl -dynamic` target. ; - gnu-native: used for general linux distros, can build gnu target for the installed glibc version only. -; LEGACY option to specify the target +; option to specify the target, superceded by SPC_TARGET if set SPC_LIBC=musl +; uncomment to link libc dynamically on musl +; SPC_MUSL_DYNAMIC=true ; Recommended: specify your target here. Zig toolchain will be used. ; examples: diff --git a/src/SPC/util/SPCTarget.php b/src/SPC/util/SPCTarget.php index b8f5367a..037c6d8c 100644 --- a/src/SPC/util/SPCTarget.php +++ b/src/SPC/util/SPCTarget.php @@ -27,10 +27,10 @@ class SPCTarget return true; } if (ToolchainManager::getToolchainClass() === GccNativeToolchain::class) { - return PHP_OS_FAMILY === 'Linux' && SystemUtil::isMuslDist(); + return PHP_OS_FAMILY === 'Linux' && SystemUtil::isMuslDist() && !getenv('SPC_MUSL_DYNAMIC'); } if (ToolchainManager::getToolchainClass() === ClangNativeToolchain::class) { - return PHP_OS_FAMILY === 'Linux' && SystemUtil::isMuslDist(); + return PHP_OS_FAMILY === 'Linux' && SystemUtil::isMuslDist() && !getenv('SPC_MUSL_DYNAMIC'); } // if SPC_LIBC is set, it means the target is static, remove it when 3.0 is released if ($target = getenv('SPC_TARGET')) { From c5882c1f8e2d95643c50e29740209c1ea9e8dae8 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 30 Jan 2026 19:41:39 +0100 Subject: [PATCH 03/28] fix gettext v1.0 release --- src/SPC/builder/unix/library/gettext.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SPC/builder/unix/library/gettext.php b/src/SPC/builder/unix/library/gettext.php index 332e25c9..d383faf7 100644 --- a/src/SPC/builder/unix/library/gettext.php +++ b/src/SPC/builder/unix/library/gettext.php @@ -16,7 +16,11 @@ trait gettext ->addConfigureArgs( '--disable-java', '--disable-c++', - '--with-included-gettext', + '--disable-d', + '--disable-rpath', + '--disable-modula2', + '--disable-libasprintf', + '--with-included-libintl', "--with-iconv-prefix={$this->getBuildRootPath()}", ); From a414c65f372f376f8d716fded13de53f2165a940 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 09:59:10 +0800 Subject: [PATCH 04/28] Forward-port #1022 spc target env var --- src/StaticPHP/Toolchain/ClangNativeToolchain.php | 2 +- src/StaticPHP/Toolchain/GccNativeToolchain.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StaticPHP/Toolchain/ClangNativeToolchain.php b/src/StaticPHP/Toolchain/ClangNativeToolchain.php index c34e619c..2513dd71 100644 --- a/src/StaticPHP/Toolchain/ClangNativeToolchain.php +++ b/src/StaticPHP/Toolchain/ClangNativeToolchain.php @@ -52,6 +52,6 @@ class ClangNativeToolchain implements UnixToolchainInterface public function isStatic(): bool { - return PHP_OS_FAMILY === 'Linux' && LinuxUtil::isMuslDist(); + return PHP_OS_FAMILY === 'Linux' && LinuxUtil::isMuslDist() && !getenv('SPC_MUSL_DYNAMIC'); } } diff --git a/src/StaticPHP/Toolchain/GccNativeToolchain.php b/src/StaticPHP/Toolchain/GccNativeToolchain.php index 92b82892..dbf9925e 100644 --- a/src/StaticPHP/Toolchain/GccNativeToolchain.php +++ b/src/StaticPHP/Toolchain/GccNativeToolchain.php @@ -49,6 +49,6 @@ class GccNativeToolchain implements UnixToolchainInterface public function isStatic(): bool { - return PHP_OS_FAMILY === 'Linux' && LinuxUtil::isMuslDist(); + return PHP_OS_FAMILY === 'Linux' && LinuxUtil::isMuslDist() && !getenv('SPC_MUSL_DYNAMIC'); } } From 455d42d1628f63280be3206d3a48211a83715899 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 13:32:35 +0800 Subject: [PATCH 05/28] Separate package config --- README-en.md | 3 - config/artifact.yaml | 67 -------------------- config/pkg.lib.yaml | 48 -------------- config/pkg/lib/attr.yml | 14 ++++ config/pkg/lib/brotli.yml | 17 +++++ config/pkg/lib/bzip2.yml | 18 ++++++ config/pkg/lib/fastlz.yml | 14 ++++ config/pkg/lib/gmp.yml | 19 ++++++ config/pkg/lib/openssl.yml | 22 +++++++ config/pkg/lib/zlib.yml | 16 +++++ spc.registry.json | 7 +- src/Package/Artifact/openssl.php | 4 +- src/Package/Library/gmp.php | 25 ++++++++ src/StaticPHP/Config/ArtifactConfig.php | 15 +++++ src/StaticPHP/Config/ConfigValidator.php | 42 +++++++++++- src/StaticPHP/Config/PackageConfig.php | 31 ++++++++- src/StaticPHP/Doctor/Item/LinuxToolCheck.php | 5 +- src/StaticPHP/Package/Package.php | 17 ++++- src/StaticPHP/Registry/Registry.php | 48 ++++++++------ src/StaticPHP/Util/LicenseDumper.php | 18 ++++-- src/globals/licenses/gmp.txt | 1 + 21 files changed, 294 insertions(+), 157 deletions(-) delete mode 100755 README-en.md delete mode 100644 config/artifact.yaml delete mode 100644 config/pkg.lib.yaml create mode 100644 config/pkg/lib/attr.yml create mode 100644 config/pkg/lib/brotli.yml create mode 100644 config/pkg/lib/bzip2.yml create mode 100644 config/pkg/lib/fastlz.yml create mode 100644 config/pkg/lib/gmp.yml create mode 100644 config/pkg/lib/openssl.yml create mode 100644 config/pkg/lib/zlib.yml create mode 100644 src/Package/Library/gmp.php create mode 100644 src/globals/licenses/gmp.txt diff --git a/README-en.md b/README-en.md deleted file mode 100755 index 505fd70a..00000000 --- a/README-en.md +++ /dev/null @@ -1,3 +0,0 @@ -# static-php-cli - -English README has been moved to [README.md](README.md). diff --git a/config/artifact.yaml b/config/artifact.yaml deleted file mode 100644 index d01d6267..00000000 --- a/config/artifact.yaml +++ /dev/null @@ -1,67 +0,0 @@ -attr: - source: - type: url - url: 'https://download.savannah.nongnu.org/releases/attr/attr-2.5.2.tar.gz' - source-mirror: - type: url - url: 'https://mirror.souseiseki.middlendian.com/nongnu/attr/attr-2.5.2.tar.gz' - metadata: - license-files: ['doc/COPYING.LGPL'] - license: LGPL-2.1-or-later - -brotli: - source: - type: ghtagtar - repo: google/brotli - match: 'v1\.\d.*' - binary: hosted # 等价于v2的provide-pre-built: true - metadata: - license-files: ['LICENSE'] - license: MIT - -bzip2: - source: - type: url - url: 'https://dl.static-php.dev/static-php-cli/deps/bzip2/bzip2-1.0.8.tar.gz' - source-mirror: - type: filelist - url: 'https://sourceware.org/pub/bzip2/' - regex: '/href="(?bzip2-(?[^"]+)\.tar\.gz)"/' - binary: hosted - metadata: - license-files: ['{registry_root}/src/globals/licenses/bzip2.txt'] - license: bzip2-1.0.6 - -fastlz: - source: - type: git - url: 'https://github.com/ariya/FastLZ.git' - rev: master - metadata: - license-files: ['LICENSE.MIT'] - license: MIT - -openssl: - source: - type: ghrel - repo: openssl/openssl - match: 'openssl.+\.tar\.gz' - prefer-stable: true - source-mirror: - type: filelist - url: 'https://www.openssl.org/source/' - regex: '/href="(?openssl-(?[^"]+)\.tar\.gz)"/' - binary: hosted - metadata: - license-files: ['LICENSE.txt'] - license: OpenSSL - -zlib: - source: - type: ghrel - repo: madler/zlib - match: 'zlib.+\.tar\.gz' - binary: hosted - metadata: - license-files: ['{registry_root}/src/globals/licenses/zlib.txt'] - license: Zlib-Custom diff --git a/config/pkg.lib.yaml b/config/pkg.lib.yaml deleted file mode 100644 index 7c4df000..00000000 --- a/config/pkg.lib.yaml +++ /dev/null @@ -1,48 +0,0 @@ -attr: - type: library - static-libs@unix: - - libattr.a - artifact: attr -brotli: - type: library - pkg-configs: - - libbrotlicommon - - libbrotlidec - - libbrotlienc - headers: - - brotli - artifact: brotli -bzip2: - type: library - static-libs@unix: - - libbz2.a - headers: - - bzlib.h - artifact: bzip2 - -fastlz: - type: library - static-libs@unix: - - libfastlz.a - headers: - - fastlz.h - artifact: fastlz - -openssl: - type: library - static-libs@unix: - - libssl.a - - libcrypto.a - headers: ['openssl'] - depends: - - zlib - artifact: openssl - -zlib: - type: library - static-libs@unix: - - libz.a - headers: - - zlib.h - - zconf.h - artifact: zlib diff --git a/config/pkg/lib/attr.yml b/config/pkg/lib/attr.yml new file mode 100644 index 00000000..4e785851 --- /dev/null +++ b/config/pkg/lib/attr.yml @@ -0,0 +1,14 @@ +attr: + type: library + static-libs@unix: + - libattr.a + artifact: + source: + type: url + url: 'https://download.savannah.nongnu.org/releases/attr/attr-2.5.2.tar.gz' + source-mirror: + type: url + url: 'https://mirror.souseiseki.middlendian.com/nongnu/attr/attr-2.5.2.tar.gz' + metadata: + license-files: ['doc/COPYING.LGPL'] + license: LGPL-2.1-or-later diff --git a/config/pkg/lib/brotli.yml b/config/pkg/lib/brotli.yml new file mode 100644 index 00000000..342359aa --- /dev/null +++ b/config/pkg/lib/brotli.yml @@ -0,0 +1,17 @@ +brotli: + type: library + pkg-configs: + - libbrotlicommon + - libbrotlidec + - libbrotlienc + headers: + - brotli + artifact: + source: + type: ghtagtar + repo: google/brotli + match: 'v1\.\d.*' + binary: hosted + metadata: + license-files: ['LICENSE'] + license: MIT diff --git a/config/pkg/lib/bzip2.yml b/config/pkg/lib/bzip2.yml new file mode 100644 index 00000000..6f7b483b --- /dev/null +++ b/config/pkg/lib/bzip2.yml @@ -0,0 +1,18 @@ +bzip2: + type: library + static-libs@unix: + - libbz2.a + headers: + - bzlib.h + artifact: + source: + type: url + url: 'https://dl.static-php.dev/static-php-cli/deps/bzip2/bzip2-1.0.8.tar.gz' + source-mirror: + type: filelist + url: 'https://sourceware.org/pub/bzip2/' + regex: '/href="(?bzip2-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: ['{registry_root}/src/globals/licenses/bzip2.txt'] + license: bzip2-1.0.6 \ No newline at end of file diff --git a/config/pkg/lib/fastlz.yml b/config/pkg/lib/fastlz.yml new file mode 100644 index 00000000..32f26d8a --- /dev/null +++ b/config/pkg/lib/fastlz.yml @@ -0,0 +1,14 @@ +fastlz: + type: library + static-libs@unix: + - libfastlz.a + headers: + - fastlz.h + artifact: + source: + type: git + url: 'https://github.com/ariya/FastLZ.git' + rev: master + metadata: + license-files: ['LICENSE.MIT'] + license: MIT \ No newline at end of file diff --git a/config/pkg/lib/gmp.yml b/config/pkg/lib/gmp.yml new file mode 100644 index 00000000..8a28069b --- /dev/null +++ b/config/pkg/lib/gmp.yml @@ -0,0 +1,19 @@ +gmp: + type: library + static-libs@unix: + - libgmp.a + headers: + - gmp.h + pkg-configs: + - gmp + artifact: + source: + type: filelist + url: 'https://gmplib.org/download/gmp/' + regex: '/href="(?gmp-(?[^"]+)\.tar\.xz)"/' + source-mirror: + type: url + url: 'https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz' + metadata: + license-files: ['@/gmp.txt'] + license: Custom diff --git a/config/pkg/lib/openssl.yml b/config/pkg/lib/openssl.yml new file mode 100644 index 00000000..ce83a4d4 --- /dev/null +++ b/config/pkg/lib/openssl.yml @@ -0,0 +1,22 @@ +openssl: + type: library + static-libs@unix: + - libssl.a + - libcrypto.a + headers: ['openssl'] + depends: + - zlib + artifact: + source: + type: ghrel + repo: openssl/openssl + match: 'openssl.+\.tar\.gz' + prefer-stable: true + source-mirror: + type: filelist + url: 'https://www.openssl.org/source/' + regex: '/href="(?openssl-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: ['LICENSE.txt'] + license: OpenSSL diff --git a/config/pkg/lib/zlib.yml b/config/pkg/lib/zlib.yml new file mode 100644 index 00000000..0a7eec71 --- /dev/null +++ b/config/pkg/lib/zlib.yml @@ -0,0 +1,16 @@ +zlib: + type: library + static-libs@unix: + - libz.a + headers: + - zlib.h + - zconf.h + artifact: + source: + type: ghrel + repo: madler/zlib + match: 'zlib.+\.tar\.gz' + binary: hosted + metadata: + license-files: ['{registry_root}/src/globals/licenses/zlib.txt'] + license: Zlib-Custom \ No newline at end of file diff --git a/spc.registry.json b/spc.registry.json index 3ced5656..e8be4b5d 100644 --- a/spc.registry.json +++ b/spc.registry.json @@ -1,5 +1,5 @@ { - "name": "internal", + "name": "core", "autoload": "vendor/autoload.php", "doctor": { "psr-4": { @@ -12,14 +12,11 @@ }, "config": [ "config/pkg.ext.json", - "config/pkg.lib.yaml", + "config/pkg/lib", "config/pkg.target.json" ] }, "artifact": { - "config": [ - "config/artifact.yaml" - ], "psr-4": { "Package\\Artifact": "src/Package/Artifact" } diff --git a/src/Package/Artifact/openssl.php b/src/Package/Artifact/openssl.php index 8809d9ce..325e6a09 100644 --- a/src/Package/Artifact/openssl.php +++ b/src/Package/Artifact/openssl.php @@ -27,9 +27,9 @@ class openssl spc_skip_if(!file_exists("{$target_path}/openssl/test/v3ext.c"), 'v3ext.c not found, skipping patch.'); FileSystem::replaceFileStr( - SOURCE_PATH . '/openssl/test/v3ext.c', + "{$target_path}/openssl/test/v3ext.c", '#include ', - '#include ' . PHP_EOL . '#include ' + "#include \n#include " ); } } diff --git a/src/Package/Library/gmp.php b/src/Package/Library/gmp.php new file mode 100644 index 00000000..f8eb5f8e --- /dev/null +++ b/src/Package/Library/gmp.php @@ -0,0 +1,25 @@ +appendEnv(['CFLAGS' => '-std=c17']) + ->configure('--enable-fat') + ->make(); + $lib->patchPkgconfPrefix(['gmp.pc']); + } +} diff --git a/src/StaticPHP/Config/ArtifactConfig.php b/src/StaticPHP/Config/ArtifactConfig.php index 0ae9e284..49bfec23 100644 --- a/src/StaticPHP/Config/ArtifactConfig.php +++ b/src/StaticPHP/Config/ArtifactConfig.php @@ -77,4 +77,19 @@ class ArtifactConfig { return self::$artifact_configs[$artifact_name] ?? null; } + + /** + * Register an inline artifact configuration. + * Used when artifact is defined inline within a package configuration. + * + * @param string $artifact_name Artifact name (usually same as package name) + * @param array $config Artifact configuration + * @param string $registry_name Registry name + * @param string $source_info Source info for debugging + */ + public static function registerInlineArtifact(string $artifact_name, array $config, string $registry_name, string $source_info = 'inline'): void + { + self::$artifact_configs[$artifact_name] = $config; + Registry::_bindArtifactConfigFile($artifact_name, $registry_name, $source_info); + } } diff --git a/src/StaticPHP/Config/ConfigValidator.php b/src/StaticPHP/Config/ConfigValidator.php index b32f4106..1f3d5b9d 100644 --- a/src/StaticPHP/Config/ConfigValidator.php +++ b/src/StaticPHP/Config/ConfigValidator.php @@ -18,7 +18,7 @@ class ConfigValidator 'type' => ConfigType::STRING, 'depends' => ConfigType::LIST_ARRAY, // @ 'suggests' => ConfigType::LIST_ARRAY, // @ - 'artifact' => ConfigType::STRING, + 'artifact' => [self::class, 'validateArtifactField'], // STRING or OBJECT 'license' => [ConfigType::class, 'validateLicenseField'], 'lang' => ConfigType::STRING, 'frameworks' => ConfigType::LIST_ARRAY, // @ @@ -102,7 +102,14 @@ class ConfigValidator if (!is_array($data)) { throw new ValidationException("{$config_file_name} is broken"); } + + // Define allowed artifact fields + $allowed_artifact_fields = ['source', 'source-mirror', 'binary', 'binary-mirror', 'metadata']; + foreach ($data as $name => $artifact) { + // First pass: validate unknown fields + self::validateNoInvalidFields('artifact', $name, $artifact, $allowed_artifact_fields); + foreach ($artifact as $k => $v) { // check source field if ($k === 'source' || $k === 'source-mirror') { @@ -202,6 +209,11 @@ class ConfigValidator throw new ValidationException("Package [{$name}] in {$config_file_name} of type '{$pkg['type']}' must have an 'artifact' field"); } + // validate and lint inline artifact object if present + if (isset($pkg['artifact']) && is_array($pkg['artifact'])) { + self::validateAndLintInlineArtifact($name, $data[$name]['artifact']); + } + // check if "php-extension" package has php-extension specific fields and validate inside if ($pkg['type'] === 'php-extension') { self::validatePhpExtensionFields($name, $pkg); @@ -234,6 +246,19 @@ class ConfigValidator } } + /** + * Validate artifact field - can be string (reference) or object (inline). + * + * @param mixed $value Field value + */ + public static function validateArtifactField(mixed $value): bool + { + if (!is_string($value) && !is_assoc_array($value)) { + return false; + } + return true; + } + /** * Validate an artifact download object field. * @@ -373,4 +398,19 @@ class ConfigValidator } } } + + /** + * Validate and lint inline artifact object structure. + * + * @param string $pkg_name Package name + * @param array $artifact Inline artifact configuration (passed by reference to apply linting) + */ + private static function validateAndLintInlineArtifact(string $pkg_name, array &$artifact): void + { + // Validate and lint as if it's a standalone artifact + $temp_data = [$pkg_name => $artifact]; + self::validateAndLintArtifacts("inline artifact in package '{$pkg_name}'", $temp_data); + // Write back the linted artifact configuration + $artifact = $temp_data[$pkg_name]; + } } diff --git a/src/StaticPHP/Config/PackageConfig.php b/src/StaticPHP/Config/PackageConfig.php index 92c01f70..bd9786c3 100644 --- a/src/StaticPHP/Config/PackageConfig.php +++ b/src/StaticPHP/Config/PackageConfig.php @@ -23,7 +23,7 @@ class PackageConfig throw new WrongUsageException("Directory {$dir} does not exist, cannot load pkg.json config."); } $loaded = []; - $files = glob("{$dir}/pkg.*.json"); + $files = glob("{$dir}/*"); if (is_array($files)) { foreach ($files as $file) { self::loadFromFile($file, $registry_name); @@ -58,10 +58,39 @@ class PackageConfig foreach ($data as $pkg_name => $config) { self::$package_configs[$pkg_name] = $config; Registry::_bindPackageConfigFile($pkg_name, $registry_name, $file); + + // Register inline artifact if present + if (isset($config['artifact']) && is_array($config['artifact'])) { + ArtifactConfig::registerInlineArtifact( + $pkg_name, + $config['artifact'], + $registry_name, + "inline in {$file}" + ); + } } return $file; } + public static function loadFromArray(array $data, string $registry_name): void + { + ConfigValidator::validateAndLintPackages('array_input', $data); + foreach ($data as $pkg_name => $config) { + self::$package_configs[$pkg_name] = $config; + Registry::_bindPackageConfigFile($pkg_name, $registry_name, 'array_input'); + + // Register inline artifact if present + if (isset($config['artifact']) && is_array($config['artifact'])) { + ArtifactConfig::registerInlineArtifact( + $pkg_name, + $config['artifact'], + $registry_name, + 'inline in array_input' + ); + } + } + } + /** * Check if a package configuration exists. */ diff --git a/src/StaticPHP/Doctor/Item/LinuxToolCheck.php b/src/StaticPHP/Doctor/Item/LinuxToolCheck.php index 09161c74..f4cdc311 100644 --- a/src/StaticPHP/Doctor/Item/LinuxToolCheck.php +++ b/src/StaticPHP/Doctor/Item/LinuxToolCheck.php @@ -19,7 +19,6 @@ class LinuxToolCheck 'bzip2', 'cmake', 'gcc', 'g++', 'patch', 'binutils-gold', 'libtoolize', 'which', - 'patchelf', ]; public const TOOLS_DEBIAN = [ @@ -28,7 +27,6 @@ class LinuxToolCheck 'tar', 'unzip', 'gzip', 'gcc', 'g++', 'bzip2', 'cmake', 'patch', 'xz', 'libtoolize', 'which', - 'patchelf', ]; public const TOOLS_RHEL = [ @@ -36,8 +34,7 @@ class LinuxToolCheck 'git', 'autoconf', 'automake', 'tar', 'unzip', 'gzip', 'gcc', 'g++', 'bzip2', 'cmake', 'patch', 'which', - 'xz', 'libtool', 'gettext-devel', - 'patchelf', 'file', + 'xz', 'libtool', 'gettext-devel', 'file', ]; public const TOOLS_ARCH = [ diff --git a/src/StaticPHP/Package/Package.php b/src/StaticPHP/Package/Package.php index 943d03b0..a0f415d1 100644 --- a/src/StaticPHP/Package/Package.php +++ b/src/StaticPHP/Package/Package.php @@ -175,8 +175,21 @@ abstract class Package public function getArtifact(): ?Artifact { // find config - $artifact_name = PackageConfig::get($this->name, 'artifact'); - return $artifact_name !== null ? ArtifactLoader::getArtifactInstance($artifact_name) : null; + $artifact_field = PackageConfig::get($this->name, 'artifact'); + + if ($artifact_field === null) { + return null; + } + + if (is_string($artifact_field)) { + return ArtifactLoader::getArtifactInstance($artifact_field); + } + + if (is_array($artifact_field)) { + return ArtifactLoader::getArtifactInstance($this->name); + } + + return null; } /** diff --git a/src/StaticPHP/Registry/Registry.php b/src/StaticPHP/Registry/Registry.php index e464ed47..68aa766d 100644 --- a/src/StaticPHP/Registry/Registry.php +++ b/src/StaticPHP/Registry/Registry.php @@ -13,6 +13,8 @@ use Symfony\Component\Yaml\Yaml; class Registry { + private static ?string $current_registry_name = null; + /** @var string[] List of loaded registries */ private static array $loaded_registries = []; @@ -35,7 +37,7 @@ class Registry public static function getRegistryConfig(?string $registry_name = null): array { if ($registry_name === null && spc_mode(SPC_MODE_SOURCE)) { - return self::$registry_configs['internal']; + return self::$registry_configs['core']; } if ($registry_name !== null && isset(self::$registry_configs[$registry_name])) { return self::$registry_configs[$registry_name]; @@ -83,6 +85,8 @@ class Registry logger()->debug("Loading registry '{$registry_name}' from file: {$registry_file}"); + self::$current_registry_name = $registry_name; + // Load composer autoload if specified (for external registries with their own dependencies) if (isset($data['autoload']) && is_string($data['autoload'])) { $autoload_path = FileSystem::fullpath($data['autoload'], dirname($registry_file)); @@ -94,24 +98,6 @@ class Registry } } - // load doctor items from PSR-4 directories - if (isset($data['doctor']['psr-4']) && is_assoc_array($data['doctor']['psr-4'])) { - foreach ($data['doctor']['psr-4'] as $namespace => $path) { - $path = FileSystem::fullpath($path, dirname($registry_file)); - DoctorLoader::loadFromPsr4Dir($path, $namespace, $auto_require); - } - } - - // load doctor items from specific classes - // Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"} - if (isset($data['doctor']['classes']) && is_array($data['doctor']['classes'])) { - foreach ($data['doctor']['classes'] as $key => $value) { - [$class, $file] = self::parseClassEntry($key, $value); - self::requireClassFile($class, $file, dirname($registry_file), $auto_require); - DoctorLoader::loadFromClass($class); - } - } - // load package configs if (isset($data['package']['config']) && is_array($data['package']['config'])) { foreach ($data['package']['config'] as $path) { @@ -136,6 +122,24 @@ class Registry } } + // load doctor items from PSR-4 directories + if (isset($data['doctor']['psr-4']) && is_assoc_array($data['doctor']['psr-4'])) { + foreach ($data['doctor']['psr-4'] as $namespace => $path) { + $path = FileSystem::fullpath($path, dirname($registry_file)); + DoctorLoader::loadFromPsr4Dir($path, $namespace, $auto_require); + } + } + + // load doctor items from specific classes + // Supports both array format ["ClassName"] and map format {"ClassName": "path/to/file.php"} + if (isset($data['doctor']['classes']) && is_array($data['doctor']['classes'])) { + foreach ($data['doctor']['classes'] as $key => $value) { + [$class, $file] = self::parseClassEntry($key, $value); + self::requireClassFile($class, $file, dirname($registry_file), $auto_require); + DoctorLoader::loadFromClass($class); + } + } + // load packages from PSR-4 directories if (isset($data['package']['psr-4']) && is_assoc_array($data['package']['psr-4'])) { foreach ($data['package']['psr-4'] as $namespace => $path) { @@ -193,6 +197,7 @@ class Registry } ConsoleApplication::_addAdditionalCommands($instances); } + self::$current_registry_name = null; } /** @@ -300,6 +305,11 @@ class Registry return self::$loaded_artifact_configs; } + public static function getCurrentRegistryName(): ?string + { + return self::$current_registry_name; + } + /** * Parse a class entry from the classes array. * Supports two formats: diff --git a/src/StaticPHP/Util/LicenseDumper.php b/src/StaticPHP/Util/LicenseDumper.php index 57fc3aec..54c6266b 100644 --- a/src/StaticPHP/Util/LicenseDumper.php +++ b/src/StaticPHP/Util/LicenseDumper.php @@ -163,18 +163,26 @@ class LicenseDumper { $artifact_name = $artifact->getName(); - // Try source directory first (if extracted) - if ($artifact->isSourceExtracted()) { - $source_dir = $artifact->getSourceDir(); - $full_path = "{$source_dir}/{$license_file_path}"; + // replace + if (str_starts_with($license_file_path, '@/')) { + $license_file_path = str_replace('@/', ROOT_DIR . '/src/globals/licenses/', $license_file_path); + } + $source_dir = $artifact->getSourceDir(); + if (FileSystem::isRelativePath($license_file_path)) { + $full_path = "{$source_dir}/{$license_file_path}"; + } else { + $full_path = $license_file_path; + } + // Try source directory first (if extracted) + if ($artifact->isSourceExtracted() || file_exists($full_path)) { logger()->debug("Checking license file: {$full_path}"); if (file_exists($full_path)) { logger()->info("Reading license from source: {$full_path}"); return file_get_contents($full_path); } } else { - logger()->debug("Artifact source not extracted: {$artifact_name}"); + logger()->warning("Artifact source not extracted: {$artifact_name}"); } // Fallback: try SOURCE_PATH directly diff --git a/src/globals/licenses/gmp.txt b/src/globals/licenses/gmp.txt new file mode 100644 index 00000000..488f3b90 --- /dev/null +++ b/src/globals/licenses/gmp.txt @@ -0,0 +1 @@ +Since version 6, GMP is distributed under the dual licenses, GNU LGPL v3 and GNU GPL v2. These licenses make the library free to use, share, and improve, and allow you to pass on the result. The GNU licenses give freedoms, but also set firm restrictions on the use with non-free programs. From f4a29c4830b0eacfe33313a83d6a360c54a97bfb Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 14:13:05 +0800 Subject: [PATCH 06/28] Add dev:lint-config to replace sort-config command --- config/pkg/lib/attr.yml | 6 +++--- config/pkg/lib/brotli.yml | 14 +++++++------- config/pkg/lib/bzip2.yml | 10 +++++----- config/pkg/lib/fastlz.yml | 12 ++++++------ config/pkg/lib/gmp.yml | 12 ++++++------ config/pkg/lib/openssl.yml | 17 +++++++++-------- config/pkg/lib/zlib.yml | 14 +++++++------- src/StaticPHP/ConsoleApplication.php | 4 ++-- 8 files changed, 45 insertions(+), 44 deletions(-) diff --git a/config/pkg/lib/attr.yml b/config/pkg/lib/attr.yml index 4e785851..289bcd67 100644 --- a/config/pkg/lib/attr.yml +++ b/config/pkg/lib/attr.yml @@ -1,7 +1,5 @@ attr: type: library - static-libs@unix: - - libattr.a artifact: source: type: url @@ -10,5 +8,7 @@ attr: type: url url: 'https://mirror.souseiseki.middlendian.com/nongnu/attr/attr-2.5.2.tar.gz' metadata: - license-files: ['doc/COPYING.LGPL'] + license-files: [doc/COPYING.LGPL] license: LGPL-2.1-or-later + static-libs@unix: + - libattr.a diff --git a/config/pkg/lib/brotli.yml b/config/pkg/lib/brotli.yml index 342359aa..524f9ddc 100644 --- a/config/pkg/lib/brotli.yml +++ b/config/pkg/lib/brotli.yml @@ -1,11 +1,5 @@ brotli: type: library - pkg-configs: - - libbrotlicommon - - libbrotlidec - - libbrotlienc - headers: - - brotli artifact: source: type: ghtagtar @@ -13,5 +7,11 @@ brotli: match: 'v1\.\d.*' binary: hosted metadata: - license-files: ['LICENSE'] + license-files: [LICENSE] license: MIT + headers: + - brotli + pkg-configs: + - libbrotlicommon + - libbrotlidec + - libbrotlienc diff --git a/config/pkg/lib/bzip2.yml b/config/pkg/lib/bzip2.yml index 6f7b483b..132a24ff 100644 --- a/config/pkg/lib/bzip2.yml +++ b/config/pkg/lib/bzip2.yml @@ -1,9 +1,5 @@ bzip2: type: library - static-libs@unix: - - libbz2.a - headers: - - bzlib.h artifact: source: type: url @@ -15,4 +11,8 @@ bzip2: binary: hosted metadata: license-files: ['{registry_root}/src/globals/licenses/bzip2.txt'] - license: bzip2-1.0.6 \ No newline at end of file + license: bzip2-1.0.6 + headers: + - bzlib.h + static-libs@unix: + - libbz2.a diff --git a/config/pkg/lib/fastlz.yml b/config/pkg/lib/fastlz.yml index 32f26d8a..e3296831 100644 --- a/config/pkg/lib/fastlz.yml +++ b/config/pkg/lib/fastlz.yml @@ -1,14 +1,14 @@ fastlz: type: library - static-libs@unix: - - libfastlz.a - headers: - - fastlz.h artifact: source: type: git url: 'https://github.com/ariya/FastLZ.git' rev: master metadata: - license-files: ['LICENSE.MIT'] - license: MIT \ No newline at end of file + license-files: [LICENSE.MIT] + license: MIT + headers: + - fastlz.h + static-libs@unix: + - libfastlz.a diff --git a/config/pkg/lib/gmp.yml b/config/pkg/lib/gmp.yml index 8a28069b..bdc13b55 100644 --- a/config/pkg/lib/gmp.yml +++ b/config/pkg/lib/gmp.yml @@ -1,11 +1,5 @@ gmp: type: library - static-libs@unix: - - libgmp.a - headers: - - gmp.h - pkg-configs: - - gmp artifact: source: type: filelist @@ -17,3 +11,9 @@ gmp: metadata: license-files: ['@/gmp.txt'] license: Custom + headers: + - gmp.h + pkg-configs: + - gmp + static-libs@unix: + - libgmp.a diff --git a/config/pkg/lib/openssl.yml b/config/pkg/lib/openssl.yml index ce83a4d4..22d06508 100644 --- a/config/pkg/lib/openssl.yml +++ b/config/pkg/lib/openssl.yml @@ -1,16 +1,10 @@ openssl: type: library - static-libs@unix: - - libssl.a - - libcrypto.a - headers: ['openssl'] - depends: - - zlib artifact: source: type: ghrel repo: openssl/openssl - match: 'openssl.+\.tar\.gz' + match: openssl.+\.tar\.gz prefer-stable: true source-mirror: type: filelist @@ -18,5 +12,12 @@ openssl: regex: '/href="(?openssl-(?[^"]+)\.tar\.gz)"/' binary: hosted metadata: - license-files: ['LICENSE.txt'] + license-files: [LICENSE.txt] license: OpenSSL + depends: + - zlib + headers: + - openssl + static-libs@unix: + - libssl.a + - libcrypto.a diff --git a/config/pkg/lib/zlib.yml b/config/pkg/lib/zlib.yml index 0a7eec71..9ca70f42 100644 --- a/config/pkg/lib/zlib.yml +++ b/config/pkg/lib/zlib.yml @@ -1,16 +1,16 @@ zlib: type: library - static-libs@unix: - - libz.a - headers: - - zlib.h - - zconf.h artifact: source: type: ghrel repo: madler/zlib - match: 'zlib.+\.tar\.gz' + match: zlib.+\.tar\.gz binary: hosted metadata: license-files: ['{registry_root}/src/globals/licenses/zlib.txt'] - license: Zlib-Custom \ No newline at end of file + license: Zlib-Custom + headers: + - zlib.h + - zconf.h + static-libs@unix: + - libz.a diff --git a/src/StaticPHP/ConsoleApplication.php b/src/StaticPHP/ConsoleApplication.php index bd2e4eb1..e6561705 100644 --- a/src/StaticPHP/ConsoleApplication.php +++ b/src/StaticPHP/ConsoleApplication.php @@ -8,8 +8,8 @@ use StaticPHP\Command\BuildLibsCommand; use StaticPHP\Command\BuildTargetCommand; use StaticPHP\Command\Dev\EnvCommand; use StaticPHP\Command\Dev\IsInstalledCommand; +use StaticPHP\Command\Dev\LintConfigCommand; use StaticPHP\Command\Dev\ShellCommand; -use StaticPHP\Command\Dev\SortConfigCommand; use StaticPHP\Command\DoctorCommand; use StaticPHP\Command\DownloadCommand; use StaticPHP\Command\DumpLicenseCommand; @@ -62,7 +62,7 @@ class ConsoleApplication extends Application new ShellCommand(), new IsInstalledCommand(), new EnvCommand(), - new SortConfigCommand(), + new LintConfigCommand(), ]); // add additional commands from registries From f437efebb7a93ce8a28ae90ab8d3228965775238 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 14:14:01 +0800 Subject: [PATCH 07/28] Add dev:lint-config to replace sort-config command --- .../Command/Dev/LintConfigCommand.php | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/StaticPHP/Command/Dev/LintConfigCommand.php diff --git a/src/StaticPHP/Command/Dev/LintConfigCommand.php b/src/StaticPHP/Command/Dev/LintConfigCommand.php new file mode 100644 index 00000000..1b08bb85 --- /dev/null +++ b/src/StaticPHP/Command/Dev/LintConfigCommand.php @@ -0,0 +1,121 @@ +sortConfigFile($file, 'artifact'); + } + $loaded_pkg_configs = Registry::getLoadedPackageConfigs(); + foreach ($loaded_pkg_configs as $file) { + $this->sortConfigFile($file, 'package'); + } + return static::SUCCESS; + } + + public function artifactSortKey(string $a, string $b): int + { + // sort by predefined order, other not matching keys go to the end alphabetically + $order = ['source', 'source-mirror', 'binary', 'binary-mirror', 'metadata']; + + $pos_a = array_search($a, $order, true); + $pos_b = array_search($b, $order, true); + + // Both in order list + if ($pos_a !== false && $pos_b !== false) { + return $pos_a <=> $pos_b; + } + + // Only $a in order list + if ($pos_a !== false) { + return -1; + } + + // Only $b in order list + if ($pos_b !== false) { + return 1; + } + + // Neither in order list, sort alphabetically + return $a <=> $b; + } + + public function packageSortKey(string $a, string $b): int + { + // sort by predefined order, other not matching keys go to the end alphabetically + $order = ['type', 'artifact']; + + // Handle suffix patterns (e.g., 'depends@unix', 'static-libs@windows') + $base_a = preg_replace('/@(unix|windows|macos|linux|freebsd|bsd)$/', '', $a); + $base_b = preg_replace('/@(unix|windows|macos|linux|freebsd|bsd)$/', '', $b); + + $pos_a = array_search($base_a, $order, true); + $pos_b = array_search($base_b, $order, true); + + // Both in order list + if ($pos_a !== false && $pos_b !== false) { + if ($pos_a === $pos_b) { + // Same base field, sort by suffix + return $a <=> $b; + } + return $pos_a <=> $pos_b; + } + + // Only $a in order list + if ($pos_a !== false) { + return -1; + } + + // Only $b in order list + if ($pos_b !== false) { + return 1; + } + + // Neither in order list, sort alphabetically + return $a <=> $b; + } + + private function sortConfigFile(mixed $file, string $config_type): void + { + // read file content with different extensions + $content = file_get_contents($file); + if ($content === false) { + $this->output->writeln("Failed to read artifact config file: {$file}"); + return; + } + $data = match (pathinfo($file, PATHINFO_EXTENSION)) { + 'json' => json_decode($content, true), + 'yml', 'yaml' => Yaml::parse($content), // skip yaml files for now + default => null, + }; + if (!is_array($data)) { + $this->output->writeln("Invalid JSON format in artifact config file: {$file}"); + return; + } + ksort($data); + foreach ($data as $artifact_name => &$config) { + uksort($config, $config_type === 'artifact' ? [$this, 'artifactSortKey'] : [$this, 'packageSortKey']); + } + unset($config); + $new_content = match (pathinfo($file, PATHINFO_EXTENSION)) { + 'json' => json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n", + 'yml', 'yaml' => Yaml::dump($data, 4, 2), + default => null, + }; + file_put_contents($file, $new_content); + $this->output->writeln("Sorted artifact config file: {$file}"); + } +} From 5a8341203ba190020fe21c46c6cfddbf0df76671 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 14:14:19 +0800 Subject: [PATCH 08/28] Remove sort config command --- .../Command/Dev/SortConfigCommand.php | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 src/StaticPHP/Command/Dev/SortConfigCommand.php diff --git a/src/StaticPHP/Command/Dev/SortConfigCommand.php b/src/StaticPHP/Command/Dev/SortConfigCommand.php deleted file mode 100644 index aa3a9ecd..00000000 --- a/src/StaticPHP/Command/Dev/SortConfigCommand.php +++ /dev/null @@ -1,49 +0,0 @@ -sortConfigFile($file); - } - $loaded_pkg_configs = Registry::getLoadedPackageConfigs(); - foreach ($loaded_pkg_configs as $file) { - $this->sortConfigFile($file); - } - return static::SUCCESS; - } - - private function sortConfigFile(mixed $file): void - { - $content = file_get_contents($file); - if ($content === false) { - $this->output->writeln("Failed to read artifact config file: {$file}"); - return; - } - $data = json_decode($content, true); - if (!is_array($data)) { - $this->output->writeln("Invalid JSON format in artifact config file: {$file}"); - return; - } - ksort($data); - foreach ($data as $artifact_name => &$config) { - ksort($config); - } - unset($config); - $new_content = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; - file_put_contents($file, $new_content); - $this->output->writeln("Sorted artifact config file: {$file}"); - } -} From 23db10d3cdfd95c5ab2262df20f94c291d4af70c Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 15:35:59 +0800 Subject: [PATCH 09/28] Add libiconv,libssh2,libxml2,xz --- config/pkg/lib/libiconv.yml | 18 +++++++ config/pkg/lib/libssh2.yml | 22 ++++++++ config/pkg/lib/libxml2.yml | 19 +++++++ config/pkg/lib/xz.yml | 20 +++++++ src/Package/Library/libiconv.php | 9 ++-- src/Package/Library/libssh2.php | 29 ++++++++++ src/Package/Library/libxml2.php | 63 ++++++++++++++-------- src/Package/Library/xz.php | 30 +++++++++++ src/StaticPHP/Command/BuildLibsCommand.php | 4 +- 9 files changed, 187 insertions(+), 27 deletions(-) create mode 100644 config/pkg/lib/libiconv.yml create mode 100644 config/pkg/lib/libssh2.yml create mode 100644 config/pkg/lib/libxml2.yml create mode 100644 config/pkg/lib/xz.yml create mode 100644 src/Package/Library/libssh2.php create mode 100644 src/Package/Library/xz.php diff --git a/config/pkg/lib/libiconv.yml b/config/pkg/lib/libiconv.yml new file mode 100644 index 00000000..7fc3bdda --- /dev/null +++ b/config/pkg/lib/libiconv.yml @@ -0,0 +1,18 @@ +libiconv: + type: library + artifact: + source: + type: filelist + url: 'https://ftp.gnu.org/gnu/libiconv/' + regex: '/href="(?libiconv-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: [COPYING.LIB] + license: LGPL-2.0-or-later + headers: + - iconv.h + - libcharset.h + - localcharset.h + static-libs@unix: + - libiconv.a + - libcharset.a diff --git a/config/pkg/lib/libssh2.yml b/config/pkg/lib/libssh2.yml new file mode 100644 index 00000000..4b66ed2b --- /dev/null +++ b/config/pkg/lib/libssh2.yml @@ -0,0 +1,22 @@ +libssh2: + type: library + artifact: + source: + type: ghrel + repo: libssh2/libssh2 + match: libssh2.+\.tar\.gz + prefer-stable: true + binary: hosted + metadata: + license-files: [COPYING] + license: BSD-3-Clause + depends: + - openssl + headers: + - libssh2.h + - libssh2_publickey.h + - libssh2_sftp.h + static-libs@unix: + - libssh2.a + pkg-configs: + - libssh2 diff --git a/config/pkg/lib/libxml2.yml b/config/pkg/lib/libxml2.yml new file mode 100644 index 00000000..4d628ffb --- /dev/null +++ b/config/pkg/lib/libxml2.yml @@ -0,0 +1,19 @@ +libxml2: + type: library + artifact: + source: + type: ghtagtar + repo: GNOME/libxml2 + match: 'v2\.\d+\.\d+$' + metadata: + license-files: [Copyright] + license: MIT + depends@unix: + - libiconv + suggests@unix: + - xz + - zlib + headers: + - libxml2 + pkg-configs: + - libxml-2.0 diff --git a/config/pkg/lib/xz.yml b/config/pkg/lib/xz.yml new file mode 100644 index 00000000..a64cf2e9 --- /dev/null +++ b/config/pkg/lib/xz.yml @@ -0,0 +1,20 @@ +xz: + type: library + artifact: + source: + type: ghrel + repo: tukaani-project/xz + match: xz.+\.tar\.xz + prefer-stable: true + binary: hosted + metadata: + license-files: [COPYING] + license: 0BSD + depends@unix: + - libiconv + headers@unix: + - lzma + static-libs@unix: + - liblzma.a + pkg-configs: + - liblzma diff --git a/src/Package/Library/libiconv.php b/src/Package/Library/libiconv.php index ac91d188..d2ac4d26 100644 --- a/src/Package/Library/libiconv.php +++ b/src/Package/Library/libiconv.php @@ -12,16 +12,17 @@ use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; #[Library('libiconv')] class libiconv { + #[BuildFor('Linux')] #[BuildFor('Darwin')] - public function build(LibraryPackage $package): void + public function build(LibraryPackage $lib): void { - UnixAutoconfExecutor::create($package) + UnixAutoconfExecutor::create($lib) ->configure( '--enable-extra-encodings', '--enable-year2038', ) ->make('install-lib', with_install: false) - ->make('install-lib', with_install: false, dir: "{$package->getSourceDir()}/libcharset"); - $package->patchLaDependencyPrefix(); + ->make('install-lib', with_install: false, dir: $lib->getSourceDir() . '/libcharset'); + $lib->patchLaDependencyPrefix(); } } diff --git a/src/Package/Library/libssh2.php b/src/Package/Library/libssh2.php new file mode 100644 index 00000000..f71d508a --- /dev/null +++ b/src/Package/Library/libssh2.php @@ -0,0 +1,29 @@ +optionalPackage('zlib', ...cmake_boolean_args('ENABLE_ZLIB_COMPRESSION')) + ->addConfigureArgs( + '-DBUILD_EXAMPLES=OFF', + '-DBUILD_TESTING=OFF' + ) + ->build(); + + $lib->patchPkgconfPrefix(['libssh2.pc']); + } +} diff --git a/src/Package/Library/libxml2.php b/src/Package/Library/libxml2.php index 4767efcb..7c35d685 100644 --- a/src/Package/Library/libxml2.php +++ b/src/Package/Library/libxml2.php @@ -8,47 +8,68 @@ use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; -use StaticPHP\Runtime\SystemTarget; use StaticPHP\Util\FileSystem; #[Library('libxml2')] class libxml2 { - #[BuildFor('Darwin')] - public function build(LibraryPackage $package): void + #[BuildFor('Linux')] + public function buildForLinux(LibraryPackage $lib): void { - $cmake = UnixCMakeExecutor::create($package) + UnixCMakeExecutor::create($lib) ->optionalPackage( 'zlib', '-DLIBXML2_WITH_ZLIB=ON ' . - "-DZLIB_LIBRARY={$package->getLibDir()}/libz.a " . - "-DZLIB_INCLUDE_DIR={$package->getIncludeDir()}", + "-DZLIB_LIBRARY={$lib->getLibDir()}/libz.a " . + "-DZLIB_INCLUDE_DIR={$lib->getIncludeDir()}", '-DLIBXML2_WITH_ZLIB=OFF', ) ->optionalPackage('xz', ...cmake_boolean_args('LIBXML2_WITH_LZMA')) ->addConfigureArgs( '-DLIBXML2_WITH_ICONV=ON', + '-DIconv_IS_BUILT_IN=OFF', '-DLIBXML2_WITH_ICU=OFF', // optional, but discouraged: https://gitlab.gnome.org/GNOME/libxml2/-/blob/master/README.md '-DLIBXML2_WITH_PYTHON=OFF', '-DLIBXML2_WITH_PROGRAMS=OFF', '-DLIBXML2_WITH_TESTS=OFF', - ); + ) + ->build(); - if (SystemTarget::getTargetOS() === 'Linux') { - $cmake->addConfigureArgs('-DIconv_IS_BUILT_IN=OFF'); - } + $this->patchPkgConfig($lib); + } - $cmake->build(); + #[BuildFor('Darwin')] + public function buildForDarwin(LibraryPackage $lib): void + { + UnixCMakeExecutor::create($lib) + ->optionalPackage( + 'zlib', + '-DLIBXML2_WITH_ZLIB=ON ' . + "-DZLIB_LIBRARY={$lib->getLibDir()}/libz.a " . + "-DZLIB_INCLUDE_DIR={$lib->getIncludeDir()}", + '-DLIBXML2_WITH_ZLIB=OFF', + ) + ->optionalPackage('xz', ...cmake_boolean_args('LIBXML2_WITH_LZMA')) + ->addConfigureArgs( + '-DLIBXML2_WITH_ICONV=ON', + '-DLIBXML2_WITH_ICU=OFF', + '-DLIBXML2_WITH_PYTHON=OFF', + '-DLIBXML2_WITH_PROGRAMS=OFF', + '-DLIBXML2_WITH_TESTS=OFF', + ) + ->build(); - FileSystem::replaceFileStr( - BUILD_LIB_PATH . '/pkgconfig/libxml-2.0.pc', - '-lxml2 -liconv', - '-lxml2' - ); - FileSystem::replaceFileStr( - BUILD_LIB_PATH . '/pkgconfig/libxml-2.0.pc', - '-lxml2', - '-lxml2 -liconv' - ); + $this->patchPkgConfig($lib); + } + + private function patchPkgConfig(LibraryPackage $lib): void + { + $pcFile = "{$lib->getLibDir()}/pkgconfig/libxml-2.0.pc"; + + // Remove -liconv from original + FileSystem::replaceFileStr($pcFile, '-lxml2 -liconv', '-lxml2'); + + // Add -liconv after -lxml2 + FileSystem::replaceFileStr($pcFile, '-lxml2', '-lxml2 -liconv'); } } diff --git a/src/Package/Library/xz.php b/src/Package/Library/xz.php new file mode 100644 index 00000000..3486d4c1 --- /dev/null +++ b/src/Package/Library/xz.php @@ -0,0 +1,30 @@ +configure( + '--disable-scripts', + '--disable-doc', + '--with-libiconv', + '--bindir=/tmp/xz', // xz binary will corrupt `tar` command, that's really strange. + ) + ->make(); + $lib->patchPkgconfPrefix(['liblzma.pc']); + $lib->patchLaDependencyPrefix(); + } +} diff --git a/src/StaticPHP/Command/BuildLibsCommand.php b/src/StaticPHP/Command/BuildLibsCommand.php index 2ff36b49..309867c0 100644 --- a/src/StaticPHP/Command/BuildLibsCommand.php +++ b/src/StaticPHP/Command/BuildLibsCommand.php @@ -7,10 +7,10 @@ namespace StaticPHP\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; -#[AsCommand('build:libs')] +#[AsCommand('build:libs', 'Build specified library packages')] class BuildLibsCommand extends BaseCommand { - public function configure() + public function configure(): void { $this->addArgument('libraries', InputArgument::REQUIRED, 'The library packages will be compiled, comma separated'); } From 1586825b5bd00c0e12176599851931c715a8c7b8 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 15:55:41 +0800 Subject: [PATCH 10/28] Add builder options for build:libs command --- src/StaticPHP/Command/BuildLibsCommand.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/StaticPHP/Command/BuildLibsCommand.php b/src/StaticPHP/Command/BuildLibsCommand.php index 309867c0..a415ca3e 100644 --- a/src/StaticPHP/Command/BuildLibsCommand.php +++ b/src/StaticPHP/Command/BuildLibsCommand.php @@ -4,8 +4,11 @@ declare(strict_types=1); namespace StaticPHP\Command; +use StaticPHP\Package\PackageInstaller; +use StaticPHP\Util\V2CompatLayer; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; #[AsCommand('build:libs', 'Build specified library packages')] class BuildLibsCommand extends BaseCommand @@ -13,13 +16,20 @@ class BuildLibsCommand extends BaseCommand public function configure(): void { $this->addArgument('libraries', InputArgument::REQUIRED, 'The library packages will be compiled, comma separated'); + // Builder options + $this->getDefinition()->addOptions([ + new InputOption('with-suggests', ['L', 'E'], null, 'Resolve and install suggested packages as well'), + new InputOption('with-packages', null, InputOption::VALUE_REQUIRED, 'add additional packages to install/build, comma separated', ''), + new InputOption('no-download', null, null, 'Skip downloading artifacts (use existing cached files)'), + ...V2CompatLayer::getLegacyBuildOptions(), + ]); } public function handle(): int { $libs = parse_comma_list($this->input->getArgument('libraries')); - $installer = new \StaticPHP\Package\PackageInstaller($this->input->getOptions()); + $installer = new PackageInstaller($this->input->getOptions()); foreach ($libs as $lib) { $installer->addBuildPackage($lib); } From 82ab14165e966303565d5fa9f2a47fe658fe4b68 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 15:56:12 +0800 Subject: [PATCH 11/28] Add nghttp2, nghttp3, ngtcp2 --- config/pkg/lib/nghttp2.yml | 24 +++++++++++++++ config/pkg/lib/nghttp3.yml | 19 ++++++++++++ config/pkg/lib/ngtcp2.yml | 24 +++++++++++++++ src/Package/Library/nghttp2.php | 41 ++++++++++++++++++++++++++ src/Package/Library/nghttp3.php | 25 ++++++++++++++++ src/Package/Library/ngtcp2.php | 52 +++++++++++++++++++++++++++++++++ 6 files changed, 185 insertions(+) create mode 100644 config/pkg/lib/nghttp2.yml create mode 100644 config/pkg/lib/nghttp3.yml create mode 100644 config/pkg/lib/ngtcp2.yml create mode 100644 src/Package/Library/nghttp2.php create mode 100644 src/Package/Library/nghttp3.php create mode 100644 src/Package/Library/ngtcp2.php diff --git a/config/pkg/lib/nghttp2.yml b/config/pkg/lib/nghttp2.yml new file mode 100644 index 00000000..9678d16b --- /dev/null +++ b/config/pkg/lib/nghttp2.yml @@ -0,0 +1,24 @@ +nghttp2: + type: library + artifact: + source: + type: ghrel + repo: nghttp2/nghttp2 + match: nghttp2.+\.tar\.xz + prefer-stable: true + metadata: + license-files: [COPYING] + depends: + - zlib + - openssl + suggests: + - libxml2 + - nghttp3 + - ngtcp2 + - brotli + headers: + - nghttp2 + static-libs@unix: + - libnghttp2.a + pkg-configs: + - libnghttp2 diff --git a/config/pkg/lib/nghttp3.yml b/config/pkg/lib/nghttp3.yml new file mode 100644 index 00000000..7d15c602 --- /dev/null +++ b/config/pkg/lib/nghttp3.yml @@ -0,0 +1,19 @@ +nghttp3: + type: library + artifact: + source: + type: ghrel + repo: ngtcp2/nghttp3 + match: nghttp3.+\.tar\.xz + prefer-stable: true + metadata: + license-files: [COPYING] + license: MIT + depends: + - openssl + headers: + - nghttp3 + static-libs@unix: + - libnghttp3.a + pkg-configs: + - libnghttp3 diff --git a/config/pkg/lib/ngtcp2.yml b/config/pkg/lib/ngtcp2.yml new file mode 100644 index 00000000..44b0aaae --- /dev/null +++ b/config/pkg/lib/ngtcp2.yml @@ -0,0 +1,24 @@ +ngtcp2: + type: library + artifact: + source: + type: ghrel + repo: ngtcp2/ngtcp2 + match: ngtcp2.+\.tar\.xz + prefer-stable: true + metadata: + license-files: [COPYING] + license: MIT + depends: + - openssl + suggests: + - nghttp3 + - brotli + headers: + - ngtcp2 + static-libs@unix: + - libngtcp2.a + - libngtcp2_crypto_ossl.a + pkg-configs: + - libngtcp2 + - libngtcp2_crypto_ossl diff --git a/src/Package/Library/nghttp2.php b/src/Package/Library/nghttp2.php new file mode 100644 index 00000000..3a85ada4 --- /dev/null +++ b/src/Package/Library/nghttp2.php @@ -0,0 +1,41 @@ +optionalPackage('zlib', ...ac_with_args('zlib', true)) + ->optionalPackage('openssl', ...ac_with_args('openssl', true)) + ->optionalPackage('libxml2', ...ac_with_args('libxml2', true)) + ->optionalPackage('ngtcp2', ...ac_with_args('libngtcp2', true)) + ->optionalPackage('nghttp3', ...ac_with_args('libnghttp3', true)) + ->optionalPackage( + 'brotli', + fn (LibraryPackage $brotli) => implode(' ', [ + '--with-brotlidec=yes', + "LIBBROTLIDEC_CFLAGS=\"-I{$brotli->getIncludeDir()}\"", + "LIBBROTLIDEC_LIBS=\"{$brotli->getStaticLibFiles()}\"", + '--with-libbrotlienc=yes', + "LIBBROTLIENC_CFLAGS=\"-I{$brotli->getIncludeDir()}\"", + "LIBBROTLIENC_LIBS=\"{$brotli->getStaticLibFiles()}\"", + ]) + ) + ->configure('--enable-lib-only') + ->make(); + + $lib->patchPkgconfPrefix(['libnghttp2.pc'], PKGCONF_PATCH_PREFIX); + } +} diff --git a/src/Package/Library/nghttp3.php b/src/Package/Library/nghttp3.php new file mode 100644 index 00000000..1f686b7b --- /dev/null +++ b/src/Package/Library/nghttp3.php @@ -0,0 +1,25 @@ +configure('--enable-lib-only') + ->make(); + + $lib->patchPkgconfPrefix(['libnghttp3.pc'], PKGCONF_PATCH_PREFIX); + } +} diff --git a/src/Package/Library/ngtcp2.php b/src/Package/Library/ngtcp2.php new file mode 100644 index 00000000..15821225 --- /dev/null +++ b/src/Package/Library/ngtcp2.php @@ -0,0 +1,52 @@ +optionalPackage( + 'openssl', + fn (LibraryPackage $openssl) => implode(' ', [ + '--with-openssl=yes', + "OPENSSL_LIBS=\"{$openssl->getStaticLibFiles()}\"", + "OPENSSL_CFLAGS=\"-I{$openssl->getIncludeDir()}\"", + ]), + '--with-openssl=no' + ) + ->optionalPackage('nghttp3', ...ac_with_args('libnghttp3', true)) + ->optionalPackage( + 'brotli', + fn (LibraryPackage $brotli) => implode(' ', [ + '--with-brotlidec=yes', + "LIBBROTLIDEC_CFLAGS=\"-I{$brotli->getIncludeDir()}\"", + "LIBBROTLIDEC_LIBS=\"{$brotli->getStaticLibFiles()}\"", + '--with-libbrotlienc=yes', + "LIBBROTLIENC_CFLAGS=\"-I{$brotli->getIncludeDir()}\"", + "LIBBROTLIENC_LIBS=\"{$brotli->getStaticLibFiles()}\"", + ]) + ) + ->appendEnv(['PKG_CONFIG' => '$PKG_CONFIG --static']) + ->configure('--enable-lib-only') + ->make(); + + $lib->patchPkgconfPrefix(['libngtcp2.pc', 'libngtcp2_crypto_ossl.pc'], PKGCONF_PATCH_PREFIX); + + // On macOS, the static library may contain other static libraries + // ld: archive member 'libssl.a' not a mach-o file in libngtcp2_crypto_ossl.a + $AR = getenv('AR') ?: 'ar'; + shell()->cd($lib->getLibDir())->exec("{$AR} -t libngtcp2_crypto_ossl.a | grep '\\.a\$' | xargs -n1 {$AR} d libngtcp2_crypto_ossl.a"); + } +} From 3d102363c42761aaa9667553dc5a1385e623f2a8 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 16:15:25 +0800 Subject: [PATCH 12/28] Add PatchBeforeBuild attribute --- .../Attribute/Package/PatchBeforeBuild.php | 8 +++++++ .../Package/PackageCallbacksTrait.php | 22 ++++++++++--------- src/StaticPHP/Registry/PackageLoader.php | 8 +++++++ 3 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 src/StaticPHP/Attribute/Package/PatchBeforeBuild.php diff --git a/src/StaticPHP/Attribute/Package/PatchBeforeBuild.php b/src/StaticPHP/Attribute/Package/PatchBeforeBuild.php new file mode 100644 index 00000000..254e1a6b --- /dev/null +++ b/src/StaticPHP/Attribute/Package/PatchBeforeBuild.php @@ -0,0 +1,8 @@ +validate_callback = $callback; } - public function setPatchBeforeBuildCallback(callable $callback): void + public function addPatchBeforeBuildCallback(callable $callback): void { - $this->patch_before_build_callback = $callback; + $this->patch_before_build_callbacks[] = $callback; } public function patchBeforeBuild(): void @@ -58,16 +58,18 @@ trait PackageCallbacksTrait if (file_exists("{$this->getSourceDir()}/.spc-patched")) { return; } - if ($this->patch_before_build_callback === null) { + if ($this->patch_before_build_callbacks === null) { return; } // Use CallbackInvoker with current package as context - $ret = ApplicationContext::invoke($this->patch_before_build_callback, [ - Package::class => $this, - static::class => $this, - ]); - if ($ret === true) { - FileSystem::writeFile("{$this->getSourceDir()}/.spc-patched", 'PATCHED!!!'); + foreach ($this->patch_before_build_callbacks as $callback) { + $ret = ApplicationContext::invoke($callback, [ + Package::class => $this, + static::class => $this, + ]); + if ($ret === true) { + FileSystem::writeFile("{$this->getSourceDir()}/.spc-patched", 'PATCHED!!!'); + } } } diff --git a/src/StaticPHP/Registry/PackageLoader.php b/src/StaticPHP/Registry/PackageLoader.php index 29ce0a96..e9502127 100644 --- a/src/StaticPHP/Registry/PackageLoader.php +++ b/src/StaticPHP/Registry/PackageLoader.php @@ -12,6 +12,7 @@ use StaticPHP\Attribute\Package\Extension; use StaticPHP\Attribute\Package\Info; use StaticPHP\Attribute\Package\InitPackage; use StaticPHP\Attribute\Package\Library; +use StaticPHP\Attribute\Package\PatchBeforeBuild; use StaticPHP\Attribute\Package\ResolveBuild; use StaticPHP\Attribute\Package\Stage; use StaticPHP\Attribute\Package\Target; @@ -196,6 +197,8 @@ class PackageLoader match ($method_attribute->getName()) { // #[BuildFor(PHP_OS_FAMILY)] BuildFor::class => self::addBuildFunction($pkg, $method_instance, [$instance_class, $method->getName()]), + // #[BeforeBuild] + PatchBeforeBuild::class => self::addPatchBeforeBuildFunction($pkg, [$instance_class, $method->getName()]), // #[CustomPhpConfigureArg(PHP_OS_FAMILY)] CustomPhpConfigureArg::class => self::bindCustomPhpConfigureArg($pkg, $method_attribute->newInstance(), [$instance_class, $method->getName()]), // #[Stage('stage_name')] @@ -332,6 +335,11 @@ class PackageLoader $pkg->addBuildFunction($attr->os, $fn); } + private static function addPatchBeforeBuildFunction(Package $pkg, callable $fn): void + { + $pkg->addPatchBeforeBuildCallback($fn); + } + private static function addStage(\ReflectionMethod $method, Package $pkg, object $instance_class, object $method_instance): void { $name = $method_instance->function; From 6ee8dc799497485977ef6a3023b42850b24bb342 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 16:15:36 +0800 Subject: [PATCH 13/28] Add zstd,libcares --- config/pkg/lib/libcares.yml | 23 +++++++++++++++++++ config/pkg/lib/zstd.yml | 19 ++++++++++++++++ src/Package/Library/libcares.php | 38 ++++++++++++++++++++++++++++++++ src/Package/Library/zstd.php | 29 ++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 config/pkg/lib/libcares.yml create mode 100644 config/pkg/lib/zstd.yml create mode 100644 src/Package/Library/libcares.php create mode 100644 src/Package/Library/zstd.php diff --git a/config/pkg/lib/libcares.yml b/config/pkg/lib/libcares.yml new file mode 100644 index 00000000..da0d1ad6 --- /dev/null +++ b/config/pkg/lib/libcares.yml @@ -0,0 +1,23 @@ +libcares: + type: library + artifact: + source: + type: ghrel + repo: c-ares/c-ares + match: c-ares-.+\.tar\.gz + prefer-stable: true + source-mirror: + type: filelist + url: 'https://c-ares.org/download/' + regex: '/href="\/download\/(?c-ares-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: [LICENSE.md] + headers@unix: + - ares.h + - ares_dns.h + - ares_nameser.h + static-libs@unix: + - libcares.a + pkg-configs: + - libcares diff --git a/config/pkg/lib/zstd.yml b/config/pkg/lib/zstd.yml new file mode 100644 index 00000000..60d33519 --- /dev/null +++ b/config/pkg/lib/zstd.yml @@ -0,0 +1,19 @@ +zstd: + type: library + artifact: + source: + type: ghrel + repo: facebook/zstd + match: zstd.+\.tar\.gz + prefer-stable: true + metadata: + license-files: [LICENSE] + license: BSD-3-Clause + headers@unix: + - zdict.h + - zstd.h + - zstd_errors.h + static-libs@unix: + - libzstd.a + pkg-configs: + - libzstd diff --git a/src/Package/Library/libcares.php b/src/Package/Library/libcares.php new file mode 100644 index 00000000..fbfb5830 --- /dev/null +++ b/src/Package/Library/libcares.php @@ -0,0 +1,38 @@ +getSourceDir()}/src/lib/thirdparty/apple/dnsinfo.h")) { + FileSystem::createDir("{$lib->getSourceDir()}/src/lib/thirdparty/apple"); + copy(ROOT_DIR . '/src/globals/extra/libcares_dnsinfo.h', "{$lib->getSourceDir()}/src/lib/thirdparty/apple/dnsinfo.h"); + return true; + } + return false; + } + + #[BuildFor('Linux')] + #[BuildFor('Darwin')] + public function build(LibraryPackage $lib): void + { + UnixAutoconfExecutor::create($lib)->configure('--disable-tests')->make(); + + $lib->patchPkgconfPrefix(['libcares.pc'], PKGCONF_PATCH_PREFIX); + } +} diff --git a/src/Package/Library/zstd.php b/src/Package/Library/zstd.php new file mode 100644 index 00000000..ab538358 --- /dev/null +++ b/src/Package/Library/zstd.php @@ -0,0 +1,29 @@ +setBuildDir("{$lib->getSourceDir()}/build/cmake/build") + ->addConfigureArgs( + '-DZSTD_BUILD_STATIC=ON', + '-DZSTD_BUILD_SHARED=OFF', + ) + ->build(); + + $lib->patchPkgconfPrefix(['libzstd.pc'], PKGCONF_PATCH_PREFIX); + } +} From 19e11caa830b00b6525fb69a4e2144dc5258cfc0 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 16:53:04 +0800 Subject: [PATCH 14/28] Add ldap,libcares,libsodium,libunistring, lint all configs --- config/pkg/lib/ldap.yml | 17 ++++++++ config/pkg/lib/libcares.yml | 4 +- config/pkg/lib/libsodium.yml | 15 +++++++ config/pkg/lib/libssh2.yml | 4 +- config/pkg/lib/libunistring.yml | 16 ++++++++ config/pkg/lib/libxml2.yml | 8 ++-- config/pkg/lib/nghttp2.yml | 12 +++--- config/pkg/lib/nghttp3.yml | 4 +- config/pkg/lib/ngtcp2.yml | 12 +++--- config/pkg/lib/xz.yml | 4 +- config/pkg/lib/zstd.yml | 4 +- src/Package/Library/ldap.php | 59 ++++++++++++++++++++++++++++ src/Package/Library/libsodium.php | 24 +++++++++++ src/Package/Library/libunistring.php | 25 ++++++++++++ 14 files changed, 182 insertions(+), 26 deletions(-) create mode 100644 config/pkg/lib/ldap.yml create mode 100644 config/pkg/lib/libsodium.yml create mode 100644 config/pkg/lib/libunistring.yml create mode 100644 src/Package/Library/ldap.php create mode 100644 src/Package/Library/libsodium.php create mode 100644 src/Package/Library/libunistring.php diff --git a/config/pkg/lib/ldap.yml b/config/pkg/lib/ldap.yml new file mode 100644 index 00000000..d1e7db2a --- /dev/null +++ b/config/pkg/lib/ldap.yml @@ -0,0 +1,17 @@ +ldap: + type: library + artifact: + source: + type: filelist + url: 'https://www.openldap.org/software/download/OpenLDAP/openldap-release/' + regex: '/href="(?openldap-(?[^"]+)\.tgz)"/' + metadata: + license-files: [LICENSE] + depends: + - openssl + - zlib + - gmp + - libsodium + pkg-configs: + - ldap + - lber diff --git a/config/pkg/lib/libcares.yml b/config/pkg/lib/libcares.yml index da0d1ad6..5d3f8c9d 100644 --- a/config/pkg/lib/libcares.yml +++ b/config/pkg/lib/libcares.yml @@ -17,7 +17,7 @@ libcares: - ares.h - ares_dns.h - ares_nameser.h - static-libs@unix: - - libcares.a pkg-configs: - libcares + static-libs@unix: + - libcares.a diff --git a/config/pkg/lib/libsodium.yml b/config/pkg/lib/libsodium.yml new file mode 100644 index 00000000..f5a551b9 --- /dev/null +++ b/config/pkg/lib/libsodium.yml @@ -0,0 +1,15 @@ +libsodium: + type: library + artifact: + source: + type: ghrel + repo: jedisct1/libsodium + match: 'libsodium-(?!1\.0\.21)\d+(\.\d+)*\.tar\.gz' + prefer-stable: true + binary: hosted + metadata: + license-files: [LICENSE] + pkg-configs: + - libsodium + static-libs@unix: + - libsodium.a diff --git a/config/pkg/lib/libssh2.yml b/config/pkg/lib/libssh2.yml index 4b66ed2b..8e1d8275 100644 --- a/config/pkg/lib/libssh2.yml +++ b/config/pkg/lib/libssh2.yml @@ -16,7 +16,7 @@ libssh2: - libssh2.h - libssh2_publickey.h - libssh2_sftp.h - static-libs@unix: - - libssh2.a pkg-configs: - libssh2 + static-libs@unix: + - libssh2.a diff --git a/config/pkg/lib/libunistring.yml b/config/pkg/lib/libunistring.yml new file mode 100644 index 00000000..2b2ffd33 --- /dev/null +++ b/config/pkg/lib/libunistring.yml @@ -0,0 +1,16 @@ +libunistring: + type: library + artifact: + source: + type: filelist + url: 'https://ftp.gnu.org/gnu/libunistring/' + regex: '/href="(?libunistring-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: [COPYING.LIB] + license: LGPL-3.0-or-later + headers: + - unistr.h + - unistring/ + static-libs@unix: + - libunistring.a diff --git a/config/pkg/lib/libxml2.yml b/config/pkg/lib/libxml2.yml index 4d628ffb..8ba0f8e1 100644 --- a/config/pkg/lib/libxml2.yml +++ b/config/pkg/lib/libxml2.yml @@ -4,16 +4,16 @@ libxml2: source: type: ghtagtar repo: GNOME/libxml2 - match: 'v2\.\d+\.\d+$' + match: v2\.\d+\.\d+$ metadata: license-files: [Copyright] license: MIT depends@unix: - libiconv - suggests@unix: - - xz - - zlib headers: - libxml2 pkg-configs: - libxml-2.0 + suggests@unix: + - xz + - zlib diff --git a/config/pkg/lib/nghttp2.yml b/config/pkg/lib/nghttp2.yml index 9678d16b..20a1840d 100644 --- a/config/pkg/lib/nghttp2.yml +++ b/config/pkg/lib/nghttp2.yml @@ -11,14 +11,14 @@ nghttp2: depends: - zlib - openssl + headers: + - nghttp2 + pkg-configs: + - libnghttp2 + static-libs@unix: + - libnghttp2.a suggests: - libxml2 - nghttp3 - ngtcp2 - brotli - headers: - - nghttp2 - static-libs@unix: - - libnghttp2.a - pkg-configs: - - libnghttp2 diff --git a/config/pkg/lib/nghttp3.yml b/config/pkg/lib/nghttp3.yml index 7d15c602..f9adc05b 100644 --- a/config/pkg/lib/nghttp3.yml +++ b/config/pkg/lib/nghttp3.yml @@ -13,7 +13,7 @@ nghttp3: - openssl headers: - nghttp3 - static-libs@unix: - - libnghttp3.a pkg-configs: - libnghttp3 + static-libs@unix: + - libnghttp3.a diff --git a/config/pkg/lib/ngtcp2.yml b/config/pkg/lib/ngtcp2.yml index 44b0aaae..a609d3ca 100644 --- a/config/pkg/lib/ngtcp2.yml +++ b/config/pkg/lib/ngtcp2.yml @@ -11,14 +11,14 @@ ngtcp2: license: MIT depends: - openssl - suggests: - - nghttp3 - - brotli headers: - ngtcp2 - static-libs@unix: - - libngtcp2.a - - libngtcp2_crypto_ossl.a pkg-configs: - libngtcp2 - libngtcp2_crypto_ossl + static-libs@unix: + - libngtcp2.a + - libngtcp2_crypto_ossl.a + suggests: + - nghttp3 + - brotli diff --git a/config/pkg/lib/xz.yml b/config/pkg/lib/xz.yml index a64cf2e9..7d0af682 100644 --- a/config/pkg/lib/xz.yml +++ b/config/pkg/lib/xz.yml @@ -14,7 +14,7 @@ xz: - libiconv headers@unix: - lzma - static-libs@unix: - - liblzma.a pkg-configs: - liblzma + static-libs@unix: + - liblzma.a diff --git a/config/pkg/lib/zstd.yml b/config/pkg/lib/zstd.yml index 60d33519..3d76e270 100644 --- a/config/pkg/lib/zstd.yml +++ b/config/pkg/lib/zstd.yml @@ -13,7 +13,7 @@ zstd: - zdict.h - zstd.h - zstd_errors.h - static-libs@unix: - - libzstd.a pkg-configs: - libzstd + static-libs@unix: + - libzstd.a diff --git a/src/Package/Library/ldap.php b/src/Package/Library/ldap.php new file mode 100644 index 00000000..21e7f8c0 --- /dev/null +++ b/src/Package/Library/ldap.php @@ -0,0 +1,59 @@ +getSourceDir() . '/configure', '"-lssl -lcrypto', '"-lssl -lcrypto -lz ' . $extra); + return true; + } + + #[BuildFor('Linux')] + #[BuildFor('Darwin')] + public function build(LibraryPackage $lib): void + { + UnixAutoconfExecutor::create($lib) + ->optionalPackage('openssl', '--with-tls=openssl') + ->optionalPackage('gmp', '--with-mp=gmp') + ->optionalPackage('libsodium', '--with-argon2=libsodium', '--enable-argon2=no') + ->addConfigureArgs( + '--disable-slapd', + '--without-systemd', + '--without-cyrus-sasl', + 'ac_cv_func_pthread_kill_other_threads_np=no' + ) + ->appendEnv([ + 'CFLAGS' => '-Wno-date-time', + 'LDFLAGS' => "-L{$lib->getLibDir()}", + 'CPPFLAGS' => "-I{$lib->getIncludeDir()}", + ]) + ->configure() + ->exec('sed -i -e "s/SUBDIRS= include libraries clients servers tests doc/SUBDIRS= include libraries clients servers/g" Makefile') + ->make(); + + FileSystem::replaceFileLineContainsString( + $lib->getLibDir() . '/pkgconfig/ldap.pc', + 'Libs: -L${libdir} -lldap', + 'Libs: -L${libdir} -lldap -llber' + ); + $lib->patchPkgconfPrefix(['ldap.pc', 'lber.pc']); + $lib->patchLaDependencyPrefix(); + } +} diff --git a/src/Package/Library/libsodium.php b/src/Package/Library/libsodium.php new file mode 100644 index 00000000..50d706ba --- /dev/null +++ b/src/Package/Library/libsodium.php @@ -0,0 +1,24 @@ +configure()->make(); + + // Patch pkg-config file + $lib->patchPkgconfPrefix(['libsodium.pc'], PKGCONF_PATCH_PREFIX); + } +} diff --git a/src/Package/Library/libunistring.php b/src/Package/Library/libunistring.php new file mode 100644 index 00000000..5f5575dc --- /dev/null +++ b/src/Package/Library/libunistring.php @@ -0,0 +1,25 @@ +configure('--disable-nls') + ->make(); + + $lib->patchLaDependencyPrefix(); + } +} From a6c79e30a8d9b53e2a56d6e19695066cd96b05f8 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Mon, 2 Feb 2026 16:53:28 +0800 Subject: [PATCH 15/28] Add dump license files after installing --- src/StaticPHP/Package/PackageInstaller.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/StaticPHP/Package/PackageInstaller.php b/src/StaticPHP/Package/PackageInstaller.php index c4262d9a..9ceb2107 100644 --- a/src/StaticPHP/Package/PackageInstaller.php +++ b/src/StaticPHP/Package/PackageInstaller.php @@ -17,6 +17,7 @@ use StaticPHP\Util\DependencyResolver; use StaticPHP\Util\FileSystem; use StaticPHP\Util\GlobalEnvManager; use StaticPHP\Util\InteractiveTerm; +use StaticPHP\Util\LicenseDumper; use StaticPHP\Util\V2CompatLayer; use ZM\Logger\ConsoleColor; @@ -208,6 +209,11 @@ class PackageInstaller } } } + + $this->dumpLicenseFiles($this->packages); + if ($interactive) { + InteractiveTerm::success('Exported package licenses', true); + } } public function isBuildPackage(Package|string $package): bool @@ -460,6 +466,21 @@ class PackageInstaller return null; } + /** + * @param Package[] $packages + */ + private function dumpLicenseFiles(array $packages): void + { + $dumper = new LicenseDumper(); + foreach ($packages as $package) { + $artifact = $package->getArtifact(); + if ($artifact !== null) { + $dumper->addArtifacts([$artifact->getName()]); + } + } + $dumper->dump(BUILD_ROOT_PATH . '/license'); + } + /** * Validate that a package has required artifacts. */ From 3492992b562eac4c9dcf5703496c0defa2be873e Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 09:42:53 +0800 Subject: [PATCH 16/28] Add ncurses --- config/pkg/lib/ncurses.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 config/pkg/lib/ncurses.yml diff --git a/config/pkg/lib/ncurses.yml b/config/pkg/lib/ncurses.yml new file mode 100644 index 00000000..be50a6c7 --- /dev/null +++ b/config/pkg/lib/ncurses.yml @@ -0,0 +1,12 @@ +ncurses: + type: library + artifact: + source: + type: filelist + url: 'https://ftp.gnu.org/pub/gnu/ncurses/' + regex: '/href="(?ncurses-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: ['COPYING'] + static-libs@unix: + - libncurses.a From fddcdb87962c7787e4ae2415cf89022fac1247ab Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 10:05:11 +0800 Subject: [PATCH 17/28] Add filelist downloader debug message --- src/StaticPHP/Artifact/Downloader/Type/FileList.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/StaticPHP/Artifact/Downloader/Type/FileList.php b/src/StaticPHP/Artifact/Downloader/Type/FileList.php index 8290a1cc..314f0c33 100644 --- a/src/StaticPHP/Artifact/Downloader/Type/FileList.php +++ b/src/StaticPHP/Artifact/Downloader/Type/FileList.php @@ -20,6 +20,7 @@ class FileList implements DownloadTypeInterface throw new DownloaderException("Failed to get {$name} file list from {$config['url']}"); } $versions = []; + logger()->debug('Matched ' . count($matches['version']) . " versions for {$name}"); foreach ($matches['version'] as $i => $version) { $lower = strtolower($version); foreach (['alpha', 'beta', 'rc', 'pre', 'nightly', 'snapshot', 'dev'] as $beta) { From e732543bd731dce1afa62a1d1c8184846246d2f6 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 10:05:28 +0800 Subject: [PATCH 18/28] Fix wrong debug message show --- src/StaticPHP/Artifact/ArtifactDownloader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StaticPHP/Artifact/ArtifactDownloader.php b/src/StaticPHP/Artifact/ArtifactDownloader.php index b53ddd8a..b4d79b76 100644 --- a/src/StaticPHP/Artifact/ArtifactDownloader.php +++ b/src/StaticPHP/Artifact/ArtifactDownloader.php @@ -438,7 +438,7 @@ class ArtifactDownloader break; } } - $vvv = ApplicationContext::isDebug() ? "\nIf the problem persists, consider using `-vvv` to enable verbose mode, and disable parallel downloading for more details." : ''; + $vvv = !ApplicationContext::isDebug() ? "\nIf the problem persists, consider using `-vvv` to enable verbose mode, or disable parallel downloading for more details." : ''; throw new DownloaderException("Download artifact '{$artifact->getName()}' failed. Please check your internet connection and try again.{$vvv}"); } From e4d6723b01f2b33f19282f35a8bc2b114d55a634 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 10:05:39 +0800 Subject: [PATCH 19/28] Add gettext --- config/pkg/lib/gettext.yml | 19 +++++++++++++ src/Package/Library/gettext.php | 48 +++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 config/pkg/lib/gettext.yml create mode 100644 src/Package/Library/gettext.php diff --git a/config/pkg/lib/gettext.yml b/config/pkg/lib/gettext.yml new file mode 100644 index 00000000..4be2e7d7 --- /dev/null +++ b/config/pkg/lib/gettext.yml @@ -0,0 +1,19 @@ +gettext: + type: library + artifact: + source: + type: filelist + url: 'https://ftp.gnu.org/pub/gnu/gettext/' + regex: '/href="(?gettext-(?[^"]+)\.tar\.xz)"/' + metadata: + license-files: [gettext-runtime/intl/COPYING.LIB] + license: LGPL-2.1-or-later + static-libs@unix: + - libintl.a + depends: + - libiconv + suggests: + - ncurses + - libxml2 + frameworks: + - CoreFoundation diff --git a/src/Package/Library/gettext.php b/src/Package/Library/gettext.php new file mode 100644 index 00000000..7af69905 --- /dev/null +++ b/src/Package/Library/gettext.php @@ -0,0 +1,48 @@ +optionalPackage('ncurses', "--with-libncurses-prefix={$pkg->getBuildRootPath()}") + ->optionalPackage('libxml2', "--with-libxml2-prefix={$pkg->getBuildRootPath()}") + ->addConfigureArgs( + '--disable-java', + '--disable-c++', + '--disable-d', + '--disable-rpath', + '--disable-modula2', + '--disable-libasprintf', + '--with-included-libintl', + "--with-iconv-prefix={$pkg->getBuildRootPath()}", + ); + + // zts + if ($builder->getOption('enable-zts')) { + $autoconf->addConfigureArgs('--enable-threads=isoc+posix') + ->appendEnv([ + 'CFLAGS' => '-lpthread -D_REENTRANT', + 'LDFLGAS' => '-lpthread', + ]); + } else { + $autoconf->addConfigureArgs('--disable-threads'); + } + + $autoconf->configure()->make(dir: "{$pkg->getSourceDir()}/gettext-runtime/intl"); + $pkg->patchLaDependencyPrefix(); + } +} From 2e8f6bbb310989088fc69a79cc92f5587e35758f Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 10:10:10 +0800 Subject: [PATCH 20/28] Add idn2 --- config/pkg/lib/idn2.yml | 21 +++++++++++++++++++++ src/Package/Library/idn2.php | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 config/pkg/lib/idn2.yml create mode 100644 src/Package/Library/idn2.php diff --git a/config/pkg/lib/idn2.yml b/config/pkg/lib/idn2.yml new file mode 100644 index 00000000..c2970d3e --- /dev/null +++ b/config/pkg/lib/idn2.yml @@ -0,0 +1,21 @@ +idn2: + type: library + artifact: + source: + type: filelist + url: 'https://ftp.gnu.org/gnu/libidn/' + regex: '/href="(?libidn2-(?[^"]+)\.tar\.gz)"/' + metadata: + license-files: ['COPYING.LESSERv3'] + license: LGPL-3.0-or-later + pkg-configs: + - libidn2 + headers: + - idn2.h + suggests@unix: + - libiconv + - gettext + - libunistring + depends@macos: + - libiconv + - gettext diff --git a/src/Package/Library/idn2.php b/src/Package/Library/idn2.php new file mode 100644 index 00000000..3cffd9be --- /dev/null +++ b/src/Package/Library/idn2.php @@ -0,0 +1,33 @@ +configure( + '--disable-nls', + '--disable-doc', + '--enable-year2038', + '--disable-rpath' + ) + ->optionalPackage('libiconv', '--with-libiconv-prefix=' . BUILD_ROOT_PATH) + ->optionalPackage('libunistring', '--with-libunistring-prefix=' . BUILD_ROOT_PATH) + ->optionalPackage('gettext', '--with-libnintl-prefix=' . BUILD_ROOT_PATH) + ->make(); + $lib->patchPkgconfPrefix(['libidn2.pc']); + $lib->patchLaDependencyPrefix(); + } +} From 668881960520109d636f851c91140e8586951d15 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 10:17:13 +0800 Subject: [PATCH 21/28] Add libedit --- config/pkg/lib/libedit.yml | 15 +++++++++++++++ src/Package/Library/libedit.php | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 config/pkg/lib/libedit.yml diff --git a/config/pkg/lib/libedit.yml b/config/pkg/lib/libedit.yml new file mode 100644 index 00000000..c782238b --- /dev/null +++ b/config/pkg/lib/libedit.yml @@ -0,0 +1,15 @@ +libedit: + type: library + artifact: + source: + type: filelist + url: 'https://thrysoee.dk/editline/' + regex: '/href="(?libedit-(?[^"]+)\.tar\.gz)"/' + binary: hosted + metadata: + license-files: ['COPYING'] + license: BSD-3-Clause + static-libs@unix: + - libedit.a + depends: + - ncurses diff --git a/src/Package/Library/libedit.php b/src/Package/Library/libedit.php index 08a435da..c06dbae3 100644 --- a/src/Package/Library/libedit.php +++ b/src/Package/Library/libedit.php @@ -4,9 +4,9 @@ declare(strict_types=1); namespace Package\Library; -use StaticPHP\Attribute\Package\BeforeStage; use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\Library; +use StaticPHP\Attribute\Package\PatchBeforeBuild; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; use StaticPHP\Util\FileSystem; @@ -14,7 +14,7 @@ use StaticPHP\Util\FileSystem; #[Library('libedit')] class libedit extends LibraryPackage { - #[BeforeStage(stage: 'build')] + #[PatchBeforeBuild] public function patchBeforeBuild(): void { FileSystem::replaceFileRegex( From a2409d9c0fba0c45dedd5c27f9be7e531dd90a99 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 10:59:16 +0800 Subject: [PATCH 22/28] Add getSourceRoot for artifacts --- src/Package/Target/php/unix.php | 2 +- src/StaticPHP/Artifact/Artifact.php | 13 +++++++++++++ src/StaticPHP/Package/Package.php | 13 +++++++++++++ .../Runtime/Executor/UnixAutoconfExecutor.php | 8 ++++---- .../Runtime/Executor/UnixCMakeExecutor.php | 4 ++-- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/Package/Target/php/unix.php b/src/Package/Target/php/unix.php index 23d465df..1ce2ff95 100644 --- a/src/Package/Target/php/unix.php +++ b/src/Package/Target/php/unix.php @@ -436,7 +436,7 @@ trait unix */ private function makeVars(PackageInstaller $installer): array { - $config = (new SPCConfigUtil(['libs_only_deps' => true]))->config(array_map(fn ($x) => $x->getName(), $installer->getResolvedPackages())); + $config = new SPCConfigUtil(['libs_only_deps' => true])->config(array_map(fn ($x) => $x->getName(), $installer->getResolvedPackages())); $static = ApplicationContext::get(ToolchainInterface::class)->isStatic() ? '-all-static' : ''; $pie = SystemTarget::getTargetOS() === 'Linux' ? '-pie' : ''; diff --git a/src/StaticPHP/Artifact/Artifact.php b/src/StaticPHP/Artifact/Artifact.php index b5cf74c0..67876d90 100644 --- a/src/StaticPHP/Artifact/Artifact.php +++ b/src/StaticPHP/Artifact/Artifact.php @@ -268,6 +268,19 @@ class Artifact return FileSystem::convertPath(SOURCE_PATH . '/' . $path); } + /** + * Get source build root directory. + * It's only worked when 'source-root' is defined in artifact config. + * Normally it's equal to source dir. + */ + public function getSourceRoot(): string + { + if (isset($this->config['metadata']['source-root'])) { + return $this->getSourceDir() . '/' . ltrim($this->config['metadata']['source-root'], '/'); + } + return $this->getSourceDir(); + } + /** * Get binary extraction directory and mode. * diff --git a/src/StaticPHP/Package/Package.php b/src/StaticPHP/Package/Package.php index a0f415d1..cd4f3840 100644 --- a/src/StaticPHP/Package/Package.php +++ b/src/StaticPHP/Package/Package.php @@ -212,6 +212,19 @@ abstract class Package throw new SPCInternalException("Source directory for package {$this->name} is not available because the source artifact is missing."); } + /** + * Get source build root directory. + * It's only worked when 'source-root' is defined in artifact config. + * Normally it's equal to source dir. + */ + public function getSourceRoot(): string + { + if (($artifact = $this->getArtifact()) && $artifact->hasSource()) { + return $artifact->getSourceRoot(); + } + throw new SPCInternalException("Source root for package {$this->name} is not available because the source artifact is missing."); + } + /** * Check if the package has a binary available for current OS and architecture. */ diff --git a/src/StaticPHP/Runtime/Executor/UnixAutoconfExecutor.php b/src/StaticPHP/Runtime/Executor/UnixAutoconfExecutor.php index e75a7ed0..41bc6e78 100644 --- a/src/StaticPHP/Runtime/Executor/UnixAutoconfExecutor.php +++ b/src/StaticPHP/Runtime/Executor/UnixAutoconfExecutor.php @@ -169,7 +169,7 @@ class UnixAutoconfExecutor extends Executor */ private function initShell(): void { - $this->shell = shell()->cd($this->package->getSourceDir())->initializeEnv($this->package)->appendEnv([ + $this->shell = shell()->cd($this->package->getSourceRoot())->initializeEnv($this->package)->appendEnv([ 'CFLAGS' => "-I{$this->package->getIncludeDir()}", 'CXXFLAGS' => "-I{$this->package->getIncludeDir()}", 'LDFLAGS' => "-L{$this->package->getLibDir()}", @@ -185,12 +185,12 @@ class UnixAutoconfExecutor extends Executor $callable(); return $this; } catch (SPCException $e) { - if (file_exists("{$this->package->getSourceDir()}/config.log")) { - logger()->debug("Config log file found: {$this->package->getSourceDir()}/config.log"); + if (file_exists("{$this->package->getSourceRoot()}/config.log")) { + logger()->debug("Config log file found: {$this->package->getSourceRoot()}/config.log"); $log_file = "lib.{$this->package->getName()}.console.log"; logger()->debug('Saved config log file to: ' . SPC_LOGS_DIR . "/{$log_file}"); $e->addExtraLogFile("{$this->package->getName()} library config.log", $log_file); - copy("{$this->package->getSourceDir()}/config.log", SPC_LOGS_DIR . "/{$log_file}"); + copy("{$this->package->getSourceRoot()}/config.log", SPC_LOGS_DIR . "/{$log_file}"); } throw $e; } diff --git a/src/StaticPHP/Runtime/Executor/UnixCMakeExecutor.php b/src/StaticPHP/Runtime/Executor/UnixCMakeExecutor.php index 107aac11..3d628b89 100644 --- a/src/StaticPHP/Runtime/Executor/UnixCMakeExecutor.php +++ b/src/StaticPHP/Runtime/Executor/UnixCMakeExecutor.php @@ -233,7 +233,7 @@ class UnixCMakeExecutor extends Executor private function initBuildDir(): void { if ($this->build_dir === null) { - $this->build_dir = "{$this->package->getSourceDir()}/build"; + $this->build_dir = "{$this->package->getSourceRoot()}/build"; } } @@ -295,7 +295,7 @@ CMAKE; */ private function initShell(): void { - $this->shell = shell()->cd($this->package->getSourceDir())->initializeEnv($this->package)->appendEnv([ + $this->shell = shell()->cd($this->package->getSourceRoot())->initializeEnv($this->package)->appendEnv([ 'CFLAGS' => "-I{$this->package->getIncludeDir()}", 'CXXFLAGS' => "-I{$this->package->getIncludeDir()}", 'LDFLAGS' => "-L{$this->package->getLibDir()}", From 09ddd2fdd8401db5b4f4b64d6175c2b5f3c3a414 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 10:59:37 +0800 Subject: [PATCH 23/28] Add methods to retrieve package sub-dependencies and configuration --- src/StaticPHP/Util/DependencyResolver.php | 85 +++++++++++++++++ src/StaticPHP/Util/SPCConfigUtil.php | 111 ++++++++++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/src/StaticPHP/Util/DependencyResolver.php b/src/StaticPHP/Util/DependencyResolver.php index defb00ba..b03f8089 100644 --- a/src/StaticPHP/Util/DependencyResolver.php +++ b/src/StaticPHP/Util/DependencyResolver.php @@ -55,6 +55,58 @@ class DependencyResolver return $resolved; } + /** + * Get all dependencies of a specific package within a resolved package set. + * This is useful when you need to get build flags for a specific library and its deps. + * + * The method will only include dependencies that exist in the resolved set, + * which properly handles optional dependencies (suggests) - only those that + * were actually resolved will be included. + * + * @param string $package_name The package to get dependencies for + * @param string[] $resolved_packages The resolved package list (from resolve()) + * @param bool $include_suggests Whether to include suggests that are in resolved set + * @return string[] Dependencies of the package (NOT including itself), ordered for building + */ + public static function getSubDependencies(string $package_name, array $resolved_packages, bool $include_suggests = false): array + { + // Create a lookup set for O(1) membership check + $resolved_set = array_flip($resolved_packages); + + // Verify the target package is in the resolved set + if (!isset($resolved_set[$package_name])) { + return []; + } + + // Build dependency map from config + $dep_map = []; + foreach ($resolved_packages as $pkg) { + $dep_map[$pkg] = [ + 'depends' => PackageConfig::get($pkg, 'depends', []), + 'suggests' => PackageConfig::get($pkg, 'suggests', []), + ]; + } + + // Collect all sub-dependencies recursively (excluding the package itself) + $visited = []; + $sorted = []; + + // Get dependencies to process for the target package + $deps = $dep_map[$package_name]['depends'] ?? []; + if ($include_suggests) { + $deps = array_merge($deps, $dep_map[$package_name]['suggests'] ?? []); + } + + // Only visit dependencies that are in the resolved set + foreach ($deps as $dep) { + if (isset($resolved_set[$dep])) { + self::visitSubDeps($dep, $dep_map, $resolved_set, $include_suggests, $visited, $sorted); + } + } + + return $sorted; + } + /** * Build a reverse dependency map for the resolved packages. * For each package that is depended upon, list which packages depend on it. @@ -89,6 +141,39 @@ class DependencyResolver return $why; } + /** + * Recursive helper for getSubDependencies. + * Visits dependencies in topological order (dependencies first). + */ + private static function visitSubDeps( + string $pkg_name, + array $dep_map, + array $resolved_set, + bool $include_suggests, + array &$visited, + array &$sorted + ): void { + if (isset($visited[$pkg_name])) { + return; + } + $visited[$pkg_name] = true; + + // Get dependencies to process + $deps = $dep_map[$pkg_name]['depends'] ?? []; + if ($include_suggests) { + $deps = array_merge($deps, $dep_map[$pkg_name]['suggests'] ?? []); + } + + // Only visit dependencies that are in the resolved set + foreach ($deps as $dep) { + if (isset($resolved_set[$dep])) { + self::visitSubDeps($dep, $dep_map, $resolved_set, $include_suggests, $visited, $sorted); + } + } + + $sorted[] = $pkg_name; + } + /** * Visitor pattern implementation for dependency resolution. * diff --git a/src/StaticPHP/Util/SPCConfigUtil.php b/src/StaticPHP/Util/SPCConfigUtil.php index 3a20e56f..a31b771f 100644 --- a/src/StaticPHP/Util/SPCConfigUtil.php +++ b/src/StaticPHP/Util/SPCConfigUtil.php @@ -149,6 +149,117 @@ class SPCConfigUtil return $ret; } + /** + * Get build configuration for a package and its sub-dependencies within a resolved set. + * + * This is useful when you need to statically link something against a specific + * library and all its transitive dependencies. It properly handles optional + * dependencies by only including those that were actually resolved. + * + * @param string $package_name The package to get config for + * @param string[] $resolved_packages The full resolved package list + * @param bool $include_suggests Whether to include resolved suggests + * @return array{ + * cflags: string, + * ldflags: string, + * libs: string + * } + */ + public function getPackageDepsConfig(string $package_name, array $resolved_packages, bool $include_suggests = false): array + { + // Get sub-dependencies within the resolved set + $sub_deps = DependencyResolver::getSubDependencies($package_name, $resolved_packages, $include_suggests); + + if (empty($sub_deps)) { + return [ + 'cflags' => '', + 'ldflags' => '', + 'libs' => '', + ]; + } + + // Use libs_only_deps mode and no_php for library linking + $save_no_php = $this->no_php; + $save_libs_only_deps = $this->libs_only_deps; + $this->no_php = true; + $this->libs_only_deps = true; + + $ret = $this->configWithResolvedPackages($sub_deps); + + $this->no_php = $save_no_php; + $this->libs_only_deps = $save_libs_only_deps; + + return $ret; + } + + /** + * Get configuration using already-resolved packages (skip dependency resolution). + * + * @param string[] $resolved_packages Already resolved package names in build order + * @return array{ + * cflags: string, + * ldflags: string, + * libs: string + * } + */ + public function configWithResolvedPackages(array $resolved_packages): array + { + $ldflags = $this->getLdflagsString(); + $cflags = $this->getIncludesString($resolved_packages); + $libs = $this->getLibsString($resolved_packages, !$this->absolute_libs); + + // additional OS-specific libraries (e.g. macOS -lresolv) + if ($extra_libs = SystemTarget::getRuntimeLibs()) { + $libs .= " {$extra_libs}"; + } + + $extra_env = getenv('SPC_EXTRA_LIBS'); + if (is_string($extra_env) && !empty($extra_env)) { + $libs .= " {$extra_env}"; + } + + // package frameworks + if (SystemTarget::getTargetOS() === 'Darwin') { + $libs .= " {$this->getFrameworksString($resolved_packages)}"; + } + + // C++ + if ($this->hasCpp($resolved_packages)) { + $libcpp = SystemTarget::getTargetOS() === 'Darwin' ? '-lc++' : '-lstdc++'; + $libs = str_replace($libcpp, '', $libs) . " {$libcpp}"; + } + + if ($this->libs_only_deps) { + // mimalloc must come first + if (in_array('mimalloc', $resolved_packages) && file_exists(BUILD_LIB_PATH . '/libmimalloc.a')) { + $libs = BUILD_LIB_PATH . '/libmimalloc.a ' . str_replace([BUILD_LIB_PATH . '/libmimalloc.a', '-lmimalloc'], ['', ''], $libs); + } + return [ + 'cflags' => clean_spaces(getenv('CFLAGS') . ' ' . $cflags), + 'ldflags' => clean_spaces(getenv('LDFLAGS') . ' ' . $ldflags), + 'libs' => clean_spaces(getenv('LIBS') . ' ' . $libs), + ]; + } + + // embed + if (!$this->no_php) { + $libs = "-lphp {$libs} -lc"; + } + + $allLibs = getenv('LIBS') . ' ' . $libs; + + // mimalloc must come first + if (in_array('mimalloc', $resolved_packages) && file_exists(BUILD_LIB_PATH . '/libmimalloc.a')) { + $allLibs = BUILD_LIB_PATH . '/libmimalloc.a ' . str_replace([BUILD_LIB_PATH . '/libmimalloc.a', '-lmimalloc'], ['', ''], $allLibs); + } + + return [ + 'cflags' => clean_spaces(getenv('CFLAGS') . ' ' . $cflags), + 'ldflags' => clean_spaces(getenv('LDFLAGS') . ' ' . $ldflags), + 'libs' => clean_spaces($allLibs), + ]; + } + private function hasCpp(array $packages): bool { foreach ($packages as $package) { From c536fedff7f2e447cc2200fb0234b5077640a9e7 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 10:59:56 +0800 Subject: [PATCH 24/28] Add krb5 and lint configs --- config/pkg/lib/gettext.yml | 8 ++--- config/pkg/lib/idn2.yml | 12 +++---- config/pkg/lib/krb5.yml | 23 +++++++++++++ config/pkg/lib/libedit.yml | 6 ++-- config/pkg/lib/ncurses.yml | 2 +- config/pkg/lib/zlib.yml | 2 +- src/Package/Library/krb5.php | 63 ++++++++++++++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 config/pkg/lib/krb5.yml create mode 100644 src/Package/Library/krb5.php diff --git a/config/pkg/lib/gettext.yml b/config/pkg/lib/gettext.yml index 4be2e7d7..5b1f57a6 100644 --- a/config/pkg/lib/gettext.yml +++ b/config/pkg/lib/gettext.yml @@ -8,12 +8,12 @@ gettext: metadata: license-files: [gettext-runtime/intl/COPYING.LIB] license: LGPL-2.1-or-later - static-libs@unix: - - libintl.a depends: - libiconv + frameworks: + - CoreFoundation + static-libs@unix: + - libintl.a suggests: - ncurses - libxml2 - frameworks: - - CoreFoundation diff --git a/config/pkg/lib/idn2.yml b/config/pkg/lib/idn2.yml index c2970d3e..5d2e2043 100644 --- a/config/pkg/lib/idn2.yml +++ b/config/pkg/lib/idn2.yml @@ -6,16 +6,16 @@ idn2: url: 'https://ftp.gnu.org/gnu/libidn/' regex: '/href="(?libidn2-(?[^"]+)\.tar\.gz)"/' metadata: - license-files: ['COPYING.LESSERv3'] + license-files: [COPYING.LESSERv3] license: LGPL-3.0-or-later - pkg-configs: - - libidn2 + depends@macos: + - libiconv + - gettext headers: - idn2.h + pkg-configs: + - libidn2 suggests@unix: - libiconv - gettext - libunistring - depends@macos: - - libiconv - - gettext diff --git a/config/pkg/lib/krb5.yml b/config/pkg/lib/krb5.yml new file mode 100644 index 00000000..305a95a1 --- /dev/null +++ b/config/pkg/lib/krb5.yml @@ -0,0 +1,23 @@ +krb5: + type: library + artifact: + source: + type: ghtagtar + repo: krb5/krb5 + match: krb5.+-final + metadata: + license-files: [NOTICE] + license: BSD-3-Clause + source-root: src + depends: + - openssl + frameworks: + - Kerberos + headers: + - krb5.h + - gssapi/gssapi.h + pkg-configs: + - krb5-gssapi + suggests: + - ldap + - libedit diff --git a/config/pkg/lib/libedit.yml b/config/pkg/lib/libedit.yml index c782238b..02d6dd81 100644 --- a/config/pkg/lib/libedit.yml +++ b/config/pkg/lib/libedit.yml @@ -7,9 +7,9 @@ libedit: regex: '/href="(?libedit-(?[^"]+)\.tar\.gz)"/' binary: hosted metadata: - license-files: ['COPYING'] + license-files: [COPYING] license: BSD-3-Clause - static-libs@unix: - - libedit.a depends: - ncurses + static-libs@unix: + - libedit.a diff --git a/config/pkg/lib/ncurses.yml b/config/pkg/lib/ncurses.yml index be50a6c7..cbc1ba67 100644 --- a/config/pkg/lib/ncurses.yml +++ b/config/pkg/lib/ncurses.yml @@ -7,6 +7,6 @@ ncurses: regex: '/href="(?ncurses-(?[^"]+)\.tar\.gz)"/' binary: hosted metadata: - license-files: ['COPYING'] + license-files: [COPYING] static-libs@unix: - libncurses.a diff --git a/config/pkg/lib/zlib.yml b/config/pkg/lib/zlib.yml index 9ca70f42..cf7f11ba 100644 --- a/config/pkg/lib/zlib.yml +++ b/config/pkg/lib/zlib.yml @@ -7,7 +7,7 @@ zlib: match: zlib.+\.tar\.gz binary: hosted metadata: - license-files: ['{registry_root}/src/globals/licenses/zlib.txt'] + license-files: ['@/zlib.txt'] license: Zlib-Custom headers: - zlib.h diff --git a/src/Package/Library/krb5.php b/src/Package/Library/krb5.php new file mode 100644 index 00000000..303c3b63 --- /dev/null +++ b/src/Package/Library/krb5.php @@ -0,0 +1,63 @@ +cd($lib->getSourceRoot())->exec('autoreconf -if'); + + $resolved = array_keys($installer->getResolvedPackages()); + $spc = new SPCConfigUtil(['no_php' => true, 'libs_only_deps' => true]); + $config = $spc->getPackageDepsConfig($lib->getName(), $resolved, include_suggests: true); + $extraEnv = [ + 'CFLAGS' => '-fcommon', + 'LIBS' => $config['libs'], + ]; + if (getenv('SPC_LD_LIBRARY_PATH') && getenv('SPC_LIBRARY_PATH')) { + $extraEnv = [...$extraEnv, ...[ + 'LD_LIBRARY_PATH' => getenv('SPC_LD_LIBRARY_PATH'), + 'LIBRARY_PATH' => getenv('SPC_LIBRARY_PATH'), + ]]; + } + $args = [ + '--disable-nls', + '--disable-rpath', + '--without-system-verto', + ]; + if (SystemTarget::getTargetOS() === 'Darwin') { + $extraEnv['LDFLAGS'] = '-framework Kerberos'; + $args[] = 'ac_cv_func_secure_getenv=no'; + } + UnixAutoconfExecutor::create($lib) + ->appendEnv($extraEnv) + ->optionalPackage('ldap', '--with-ldap', '--without-ldap') + ->optionalPackage('libedit', '--with-libedit', '--without-libedit') + ->configure(...$args) + ->make(); + $lib->patchPkgconfPrefix([ + 'krb5-gssapi.pc', + 'krb5.pc', + 'kadm-server.pc', + 'kadm-client.pc', + 'kdb.pc', + 'mit-krb5-gssapi.pc', + 'mit-krb5.pc', + 'gssrpc.pc', + ]); + } +} From 103b5b35853f69813399b5446f5ff450e7fe2d2c Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 11:22:32 +0800 Subject: [PATCH 25/28] Upgrade phpstan to v2 --- composer.json | 2 +- composer.lock | 299 +++++++++--------- phpstan.neon | 6 +- src/Package/Target/php.php | 1 - src/StaticPHP/Artifact/ArtifactDownloader.php | 2 +- src/StaticPHP/Artifact/ArtifactExtractor.php | 1 + src/StaticPHP/Registry/PackageLoader.php | 6 +- src/StaticPHP/Util/LicenseDumper.php | 2 +- src/StaticPHP/Util/System/UnixUtil.php | 2 +- 9 files changed, 162 insertions(+), 159 deletions(-) diff --git a/composer.json b/composer.json index fb17f9a0..fbdbc94b 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "captainhook/hook-installer": "^1.0", "friendsofphp/php-cs-fixer": "^3.60", "humbug/box": "^4.5.0 || ^4.6.0", - "phpstan/phpstan": "^1.10", + "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^10.3 || ^9.5" }, "autoload": { diff --git a/composer.lock b/composer.lock index a0538ce8..40489a06 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "edb3243ddaa8b05d8f6545266a146e93", + "content-hash": "f30595c9c60e55083112410cd1ffb203", "packages": [ { "name": "laravel/prompts", - "version": "v0.3.8", + "version": "v0.3.11", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "096748cdfb81988f60090bbb839ce3205ace0d35" + "reference": "dd2a2ed95acacbcccd32fd98dee4c946ae7a7217" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/096748cdfb81988f60090bbb839ce3205ace0d35", - "reference": "096748cdfb81988f60090bbb839ce3205ace0d35", + "url": "https://api.github.com/repos/laravel/prompts/zipball/dd2a2ed95acacbcccd32fd98dee4c946ae7a7217", + "reference": "dd2a2ed95acacbcccd32fd98dee4c946ae7a7217", "shasum": "" }, "require": { @@ -61,22 +61,22 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.3.8" + "source": "https://github.com/laravel/prompts/tree/v0.3.11" }, - "time": "2025-11-21T20:52:52+00:00" + "time": "2026-01-27T02:55:06+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.7", + "version": "v2.0.8", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "cb291e4c998ac50637c7eeb58189c14f5de5b9dd" + "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/cb291e4c998ac50637c7eeb58189c14f5de5b9dd", - "reference": "cb291e4c998ac50637c7eeb58189c14f5de5b9dd", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b", + "reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b", "shasum": "" }, "require": { @@ -124,7 +124,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2025-11-21T20:52:36+00:00" + "time": "2026-01-08T16:22:46+00:00" }, { "name": "nette/php-generator", @@ -200,16 +200,16 @@ }, { "name": "nette/utils", - "version": "v4.1.0", + "version": "v4.1.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0" + "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", - "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", + "url": "https://api.github.com/repos/nette/utils/zipball/c99059c0315591f1a0db7ad6002000288ab8dc72", + "reference": "c99059c0315591f1a0db7ad6002000288ab8dc72", "shasum": "" }, "require": { @@ -283,9 +283,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.1.0" + "source": "https://github.com/nette/utils/tree/v4.1.1" }, - "time": "2025-12-01T17:49:23+00:00" + "time": "2025-12-22T12:14:32+00:00" }, { "name": "php-di/invoker", @@ -520,16 +520,16 @@ }, { "name": "symfony/console", - "version": "v7.4.0", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8" + "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", - "reference": "0bc0f45254b99c58d45a8fbf9fb955d46cbd1bb8", + "url": "https://api.github.com/repos/symfony/console/zipball/41e38717ac1dd7a46b6bda7d6a82af2d98a78894", + "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894", "shasum": "" }, "require": { @@ -594,7 +594,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.0" + "source": "https://github.com/symfony/console/tree/v7.4.4" }, "funding": [ { @@ -614,7 +614,7 @@ "type": "tidelift" } ], - "time": "2025-11-27T13:27:24+00:00" + "time": "2026-01-13T11:36:38+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1020,16 +1020,16 @@ }, { "name": "symfony/process", - "version": "v7.4.0", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8" + "reference": "608476f4604102976d687c483ac63a79ba18cc97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", - "reference": "7ca8dc2d0dcf4882658313aba8be5d9fd01026c8", + "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", + "reference": "608476f4604102976d687c483ac63a79ba18cc97", "shasum": "" }, "require": { @@ -1061,7 +1061,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.4.0" + "source": "https://github.com/symfony/process/tree/v7.4.5" }, "funding": [ { @@ -1081,7 +1081,7 @@ "type": "tidelift" } ], - "time": "2025-10-16T11:21:06+00:00" + "time": "2026-01-26T15:07:59+00:00" }, { "name": "symfony/service-contracts", @@ -1172,16 +1172,16 @@ }, { "name": "symfony/string", - "version": "v8.0.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f929eccf09531078c243df72398560e32fa4cf4f" + "reference": "758b372d6882506821ed666032e43020c4f57194" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f929eccf09531078c243df72398560e32fa4cf4f", - "reference": "f929eccf09531078c243df72398560e32fa4cf4f", + "url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194", + "reference": "758b372d6882506821ed666032e43020c4f57194", "shasum": "" }, "require": { @@ -1238,7 +1238,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v8.0.0" + "source": "https://github.com/symfony/string/tree/v8.0.4" }, "funding": [ { @@ -1258,20 +1258,20 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:37:55+00:00" + "time": "2026-01-12T12:37:40+00:00" }, { "name": "symfony/yaml", - "version": "v7.4.0", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "6c84a4b55aee4cd02034d1c528e83f69ddf63810" + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/6c84a4b55aee4cd02034d1c528e83f69ddf63810", - "reference": "6c84a4b55aee4cd02034d1c528e83f69ddf63810", + "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", "shasum": "" }, "require": { @@ -1314,7 +1314,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.4.0" + "source": "https://github.com/symfony/yaml/tree/v7.4.1" }, "funding": [ { @@ -1334,7 +1334,7 @@ "type": "tidelift" } ], - "time": "2025-11-16T10:14:42+00:00" + "time": "2025-12-04T18:11:45+00:00" }, { "name": "zhamao/logger", @@ -1719,16 +1719,16 @@ }, { "name": "amphp/parallel", - "version": "v2.3.2", + "version": "v2.3.3", "source": { "type": "git", "url": "https://github.com/amphp/parallel.git", - "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce" + "reference": "296b521137a54d3a02425b464e5aee4c93db2c60" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parallel/zipball/321b45ae771d9c33a068186b24117e3cd1c48dce", - "reference": "321b45ae771d9c33a068186b24117e3cd1c48dce", + "url": "https://api.github.com/repos/amphp/parallel/zipball/296b521137a54d3a02425b464e5aee4c93db2c60", + "reference": "296b521137a54d3a02425b464e5aee4c93db2c60", "shasum": "" }, "require": { @@ -1791,7 +1791,7 @@ ], "support": { "issues": "https://github.com/amphp/parallel/issues", - "source": "https://github.com/amphp/parallel/tree/v2.3.2" + "source": "https://github.com/amphp/parallel/tree/v2.3.3" }, "funding": [ { @@ -1799,7 +1799,7 @@ "type": "github" } ], - "time": "2025-08-27T21:55:40+00:00" + "time": "2025-11-15T06:23:42+00:00" }, { "name": "amphp/parser", @@ -2217,7 +2217,7 @@ }, { "name": "captainhook/captainhook-phar", - "version": "5.27.3", + "version": "5.27.5", "source": { "type": "git", "url": "https://github.com/captainhook-git/captainhook-phar.git", @@ -2271,7 +2271,7 @@ ], "support": { "issues": "https://github.com/captainhook-git/captainhook/issues", - "source": "https://github.com/captainhook-git/captainhook-phar/tree/5.27.3" + "source": "https://github.com/captainhook-git/captainhook-phar/tree/5.27.5" }, "funding": [ { @@ -2968,16 +2968,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.91.0", + "version": "v3.93.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "c4a25f20390337789c26b693ae46faa125040352" + "reference": "b3546ab487c0762c39f308dc1ec0ea2c461fc21a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/c4a25f20390337789c26b693ae46faa125040352", - "reference": "c4a25f20390337789c26b693ae46faa125040352", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/b3546ab487c0762c39f308dc1ec0ea2c461fc21a", + "reference": "b3546ab487c0762c39f308dc1ec0ea2c461fc21a", "shasum": "" }, "require": { @@ -3009,16 +3009,17 @@ }, "require-dev": { "facile-it/paraunit": "^1.3.1 || ^2.7", - "infection/infection": "^0.31.0", - "justinrainbow/json-schema": "^6.5", - "keradus/cli-executor": "^2.2", + "infection/infection": "^0.32", + "justinrainbow/json-schema": "^6.6", + "keradus/cli-executor": "^2.3", "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.9", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", - "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34", - "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2 || ^8.0", - "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2 || ^8.0" + "phpunit/phpunit": "^9.6.31 || ^10.5.60 || ^11.5.48", + "symfony/polyfill-php85": "^1.33", + "symfony/var-dumper": "^5.4.48 || ^6.4.26 || ^7.4.0 || ^8.0", + "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -3033,7 +3034,7 @@ "PhpCsFixer\\": "src/" }, "exclude-from-classmap": [ - "src/Fixer/Internal/*" + "src/**/Internal/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3059,7 +3060,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.91.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.93.1" }, "funding": [ { @@ -3067,7 +3068,7 @@ "type": "github" } ], - "time": "2025-11-28T22:07:42+00:00" + "time": "2026-01-28T23:50:50+00:00" }, { "name": "humbug/box", @@ -3316,21 +3317,21 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.6.2", + "version": "6.6.4", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "3c25fe750c1599716ef26aa997f7c026cee8c4b7" + "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/3c25fe750c1599716ef26aa997f7c026cee8c4b7", - "reference": "3c25fe750c1599716ef26aa997f7c026cee8c4b7", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/2eeb75d21cf73211335888e7f5e6fd7440723ec7", + "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7", "shasum": "" }, "require": { "ext-json": "*", - "marc-mabe/php-enum": "^4.0", + "marc-mabe/php-enum": "^4.4", "php": "^7.2 || ^8.0" }, "require-dev": { @@ -3385,9 +3386,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.2" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.4" }, - "time": "2025-11-28T15:24:03+00:00" + "time": "2025-12-19T15:01:32+00:00" }, { "name": "kelunik/certificate", @@ -3449,20 +3450,20 @@ }, { "name": "league/uri", - "version": "7.6.0", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "f625804987a0a9112d954f9209d91fec52182344" + "reference": "4436c6ec8d458e4244448b069cc572d088230b76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/f625804987a0a9112d954f9209d91fec52182344", - "reference": "f625804987a0a9112d954f9209d91fec52182344", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.6", + "league/uri-interfaces": "^7.8", "php": "^8.1", "psr/http-factory": "^1" }, @@ -3476,11 +3477,11 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "ext-uri": "to use the PHP native URI class", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", - "league/uri-polyfill": "Needed to backport the PHP URI extension for older versions of PHP", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", "php-64bit": "to improve IPV4 host parsing", - "rowbot/url": "to handle WHATWG URL", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3535,7 +3536,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.6.0" + "source": "https://github.com/thephpleague/uri/tree/7.8.0" }, "funding": [ { @@ -3543,20 +3544,20 @@ "type": "github" } ], - "time": "2025-11-18T12:17:23+00:00" + "time": "2026-01-14T17:24:56+00:00" }, { "name": "league/uri-interfaces", - "version": "7.6.0", + "version": "7.8.0", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "ccbfb51c0445298e7e0b7f4481b942f589665368" + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/ccbfb51c0445298e7e0b7f4481b942f589665368", - "reference": "ccbfb51c0445298e7e0b7f4481b942f589665368", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", "shasum": "" }, "require": { @@ -3569,7 +3570,7 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "php-64bit": "to improve IPV4 host parsing", - "rowbot/url": "to handle WHATWG URL", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -3619,7 +3620,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.6.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0" }, "funding": [ { @@ -3627,7 +3628,7 @@ "type": "github" } ], - "time": "2025-11-18T12:17:23+00:00" + "time": "2026-01-15T06:54:53+00:00" }, { "name": "marc-mabe/php-enum", @@ -3816,16 +3817,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.2", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -3868,9 +3869,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-10-21T19:32:17+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "phar-io/composer-distributor", @@ -4259,16 +4260,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.5", + "version": "5.6.6", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "90614c73d3800e187615e2dd236ad0e2a01bf761" + "reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/90614c73d3800e187615e2dd236ad0e2a01bf761", - "reference": "90614c73d3800e187615e2dd236ad0e2a01bf761", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/5cee1d3dfc2d2aa6599834520911d246f656bcb8", + "reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8", "shasum": "" }, "require": { @@ -4278,7 +4279,7 @@ "phpdocumentor/reflection-common": "^2.2", "phpdocumentor/type-resolver": "^1.7", "phpstan/phpdoc-parser": "^1.7|^2.0", - "webmozart/assert": "^1.9.1" + "webmozart/assert": "^1.9.1 || ^2" }, "require-dev": { "mockery/mockery": "~1.3.5 || ~1.6.0", @@ -4317,9 +4318,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.5" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.6" }, - "time": "2025-11-27T19:50:05+00:00" + "time": "2025-12-22T21:13:58+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -4381,16 +4382,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.0", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", "shasum": "" }, "require": { @@ -4422,21 +4423,21 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" }, - "time": "2025-08-30T15:50:23+00:00" + "time": "2026-01-25T14:56:51+00:00" }, { "name": "phpstan/phpstan", - "version": "1.12.32", + "version": "2.1.38", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8", - "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dfaf1f530e1663aa167bc3e52197adb221582629", + "reference": "dfaf1f530e1663aa167bc3e52197adb221582629", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -4477,7 +4478,7 @@ "type": "github" } ], - "time": "2025-09-30T10:16:31+00:00" + "time": "2026-01-30T17:12:46+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4802,16 +4803,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.58", + "version": "10.5.63", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca" + "reference": "33198268dad71e926626b618f3ec3966661e4d90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e24fb46da450d8e6a5788670513c1af1424f16ca", - "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33198268dad71e926626b618f3ec3966661e4d90", + "reference": "33198268dad71e926626b618f3ec3966661e4d90", "shasum": "" }, "require": { @@ -4832,7 +4833,7 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.4", + "sebastian/comparator": "^5.0.5", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.4", @@ -4883,7 +4884,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.58" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.63" }, "funding": [ { @@ -4907,7 +4908,7 @@ "type": "tidelift" } ], - "time": "2025-09-28T12:04:46+00:00" + "time": "2026-01-27T05:48:37+00:00" }, { "name": "psr/event-dispatcher", @@ -5141,16 +5142,16 @@ }, { "name": "react/child-process", - "version": "v0.6.6", + "version": "v0.6.7", "source": { "type": "git", "url": "https://github.com/reactphp/child-process.git", - "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159" + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159", - "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/970f0e71945556422ee4570ccbabaedc3cf04ad3", + "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3", "shasum": "" }, "require": { @@ -5204,7 +5205,7 @@ ], "support": { "issues": "https://github.com/reactphp/child-process/issues", - "source": "https://github.com/reactphp/child-process/tree/v0.6.6" + "source": "https://github.com/reactphp/child-process/tree/v0.6.7" }, "funding": [ { @@ -5212,7 +5213,7 @@ "type": "open_collective" } ], - "time": "2025-01-01T16:37:48+00:00" + "time": "2025-12-23T15:25:20+00:00" }, { "name": "react/dns", @@ -5835,16 +5836,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.4", + "version": "5.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e" + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e8e53097718d2b53cfb2aa859b06a41abf58c62e", - "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d", + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d", "shasum": "" }, "require": { @@ -5900,7 +5901,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.4" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5" }, "funding": [ { @@ -5920,7 +5921,7 @@ "type": "tidelift" } ], - "time": "2025-09-07T05:25:07+00:00" + "time": "2026-01-24T09:25:16+00:00" }, { "name": "sebastian/complexity", @@ -6732,16 +6733,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v8.0.0", + "version": "v8.0.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "573f95783a2ec6e38752979db139f09fec033f03" + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/573f95783a2ec6e38752979db139f09fec033f03", - "reference": "573f95783a2ec6e38752979db139f09fec033f03", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99301401da182b6cfaa4700dbe9987bb75474b47", + "reference": "99301401da182b6cfaa4700dbe9987bb75474b47", "shasum": "" }, "require": { @@ -6793,7 +6794,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.0" + "source": "https://github.com/symfony/event-dispatcher/tree/v8.0.4" }, "funding": [ { @@ -6813,7 +6814,7 @@ "type": "tidelift" } ], - "time": "2025-10-30T14:17:19+00:00" + "time": "2026-01-05T11:45:55+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -6963,16 +6964,16 @@ }, { "name": "symfony/finder", - "version": "v7.4.0", + "version": "v7.4.5", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd" + "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd", - "reference": "340b9ed7320570f319028a2cbec46d40535e94bd", + "url": "https://api.github.com/repos/symfony/finder/zipball/ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", + "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", "shasum": "" }, "require": { @@ -7007,7 +7008,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.0" + "source": "https://github.com/symfony/finder/tree/v7.4.5" }, "funding": [ { @@ -7027,7 +7028,7 @@ "type": "tidelift" } ], - "time": "2025-11-05T05:42:40+00:00" + "time": "2026-01-26T15:07:59+00:00" }, { "name": "symfony/options-resolver", @@ -7332,16 +7333,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.4.0", + "version": "v7.4.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece" + "reference": "0e4769b46a0c3c62390d124635ce59f66874b282" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/41fd6c4ae28c38b294b42af6db61446594a0dece", - "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e4769b46a0c3c62390d124635ce59f66874b282", + "reference": "0e4769b46a0c3c62390d124635ce59f66874b282", "shasum": "" }, "require": { @@ -7395,7 +7396,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.0" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.4" }, "funding": [ { @@ -7415,7 +7416,7 @@ "type": "tidelift" } ], - "time": "2025-10-27T20:36:44+00:00" + "time": "2026-01-01T22:13:48+00:00" }, { "name": "thecodingmachine/safe", diff --git a/phpstan.neon b/phpstan.neon index 45e512ba..ce7cdb2d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -11,11 +11,13 @@ parameters: - '#Function Swoole\\Coroutine\\run not found.#' - '#Static call to instance method ZM\\Logger\\ConsoleColor#' - '#Constant GNU_ARCH not found#' + - + identifiers: + - 'if.alwaysFalse' dynamicConstantNames: - PHP_OS_FAMILY excludePaths: analyseAndScan: - - ./src/globals/ext-tests/swoole.php - - ./src/globals/ext-tests/swoole.phpt + - ./src/globals/ext-tests/ - ./src/globals/test-extensions.php - ./src/SPC/ diff --git a/src/Package/Target/php.php b/src/Package/Target/php.php index 8cd6e940..32e8a13b 100644 --- a/src/Package/Target/php.php +++ b/src/Package/Target/php.php @@ -241,7 +241,6 @@ class php extends TargetPackage { $arg = []; foreach ($installer->getResolvedPackages() as $package) { - /** @var PhpExtensionPackage $package */ if ($package->getType() !== 'php-extension' || !$package instanceof PhpExtensionPackage) { continue; } diff --git a/src/StaticPHP/Artifact/ArtifactDownloader.php b/src/StaticPHP/Artifact/ArtifactDownloader.php index b4d79b76..b07c5661 100644 --- a/src/StaticPHP/Artifact/ArtifactDownloader.php +++ b/src/StaticPHP/Artifact/ArtifactDownloader.php @@ -312,7 +312,7 @@ class ArtifactDownloader FileSystem::createDir(DOWNLOAD_PATH); } logger()->info('Downloading' . implode(', ', array_map(fn ($x) => " '{$x->getName()}'", $this->artifacts)) . " with concurrency {$this->parallel} ..."); - // Download artifacts parallely + // Download artifacts parallelly if ($this->parallel > 1) { $this->downloadWithConcurrency(); } else { diff --git a/src/StaticPHP/Artifact/ArtifactExtractor.php b/src/StaticPHP/Artifact/ArtifactExtractor.php index 93b36382..217a6f54 100644 --- a/src/StaticPHP/Artifact/ArtifactExtractor.php +++ b/src/StaticPHP/Artifact/ArtifactExtractor.php @@ -247,6 +247,7 @@ class ArtifactExtractor $artifact->emitAfterBinaryExtract($target_path, $platform); logger()->debug("Emitted after-binary-extract hooks for [{$name}]"); + /* @phpstan-ignore-next-line */ if ($hash !== null && $cache_info['cache_type'] !== 'file') { FileSystem::writeFile("{$target_path}/.spc-hash", $hash); } diff --git a/src/StaticPHP/Registry/PackageLoader.php b/src/StaticPHP/Registry/PackageLoader.php index e9502127..424363eb 100644 --- a/src/StaticPHP/Registry/PackageLoader.php +++ b/src/StaticPHP/Registry/PackageLoader.php @@ -169,7 +169,7 @@ class PackageLoader } } - $pkg = self::$packages[$attribute_instance->name]; + $pkg = self::$packages[$attribute_instance->name] ?? null; // Use the package instance if it's a Package subclass, otherwise create a new instance $instance_class = is_a($class_name, Package::class, true) ? $pkg : $refClass->newInstance(); @@ -184,7 +184,7 @@ class PackageLoader if (!in_array($package_type, $pkg_type_attr, true)) { throw new RegistryException("Package [{$attribute_instance->name}] type mismatch: config type is [{$package_type}], but attribute type is [" . implode('|', $pkg_type_attr) . '].'); } - if ($pkg !== null && !PackageConfig::isPackageExists($pkg->getName())) { + if ($pkg instanceof Package && !PackageConfig::isPackageExists($pkg->getName())) { throw new RegistryException("Package [{$pkg->getName()}] config not found for class {$class}"); } @@ -355,7 +355,7 @@ class PackageLoader $stage = $method_instance->stage; $stage = match (true) { is_string($stage) => $stage, - is_array($stage) && count($stage) === 2 => $stage[1], + count($stage) === 2 => $stage[1], default => throw new RegistryException('Invalid stage definition in BeforeStage attribute.'), }; if ($method_instance->package_name === '' && $pkg === null) { diff --git a/src/StaticPHP/Util/LicenseDumper.php b/src/StaticPHP/Util/LicenseDumper.php index 54c6266b..f439ec52 100644 --- a/src/StaticPHP/Util/LicenseDumper.php +++ b/src/StaticPHP/Util/LicenseDumper.php @@ -75,7 +75,7 @@ class LicenseDumper * * @param Artifact $artifact Artifact instance * @param string $target_dir Target directory - * @param array &$license_summary Summary data to populate + * @param array &$license_summary Summary data to populate * @return bool True if dumped * @throws SPCInternalException */ diff --git a/src/StaticPHP/Util/System/UnixUtil.php b/src/StaticPHP/Util/System/UnixUtil.php index 8dd60618..aca50d9e 100644 --- a/src/StaticPHP/Util/System/UnixUtil.php +++ b/src/StaticPHP/Util/System/UnixUtil.php @@ -44,7 +44,7 @@ abstract class UnixUtil continue; } $name = preg_replace('/@.*$/', '', $name); - if ($name !== '' && $name !== false) { + if (!empty($name)) { $defined[] = $name; } } From 7041e060f2fb028f028a6b0c85d0025cd5aa21c6 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 13:02:43 +0800 Subject: [PATCH 26/28] Add curl --- config/pkg/lib/curl.yml | 33 ++++++++++++++++++ src/Package/Library/curl.php | 61 +++++++++++++++++++++++++++++++++ src/StaticPHP/Doctor/Doctor.php | 3 +- 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 config/pkg/lib/curl.yml create mode 100644 src/Package/Library/curl.php diff --git a/config/pkg/lib/curl.yml b/config/pkg/lib/curl.yml new file mode 100644 index 00000000..38d632ce --- /dev/null +++ b/config/pkg/lib/curl.yml @@ -0,0 +1,33 @@ +curl: + type: library + artifact: + source: + type: ghrel + repo: curl/curl + match: 'curl.+\.tar\.xz' + prefer-stable: true + metadata: + license-files: [COPYING] + license: curl + static-libs@unix: + - libcurl.a + headers: + - curl + depends@unix: + - openssl + - zlib + suggests@unix: + - libssh2 + - brotli + - nghttp2 + - nghttp3 + - ngtcp2 + - zstd + - libcares + - ldap + - idn2 + - krb5 + frameworks: + - CoreFoundation + - CoreServices + - SystemConfiguration diff --git a/src/Package/Library/curl.php b/src/Package/Library/curl.php new file mode 100644 index 00000000..a2856ad4 --- /dev/null +++ b/src/Package/Library/curl.php @@ -0,0 +1,61 @@ +cd($lib->getSourceDir())->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ./CMakeLists.txt'); + if (SystemTarget::getTargetOS() === 'Darwin') { + FileSystem::replaceFileRegex("{$lib->getSourceDir()}/curl/CMakeLists.txt", '/NOT COREFOUNDATION_FRAMEWORK/m', 'FALSE'); + FileSystem::replaceFileRegex("{$lib->getSourceDir()}/curl/CMakeLists.txt", '/NOT SYSTEMCONFIGURATION_FRAMEWORK/m', 'FALSE'); + FileSystem::replaceFileRegex("{$lib->getSourceDir()}/curl/CMakeLists.txt", '/NOT CORESERVICES_FRAMEWORK/m', 'FALSE'); + } + return true; + } + + #[BuildFor('Linux')] + #[BuildFor('Darwin')] + public function build(LibraryPackage $lib): void + { + UnixCMakeExecutor::create($lib) + ->optionalPackage('openssl', '-DCURL_USE_OPENSSL=ON -DCURL_CA_BUNDLE=OFF -DCURL_CA_PATH=OFF -DCURL_CA_FALLBACK=ON', '-DCURL_USE_OPENSSL=OFF -DCURL_ENABLE_SSL=OFF') + ->optionalPackage('brotli', ...cmake_boolean_args('CURL_BROTLI')) + ->optionalPackage('libssh2', ...cmake_boolean_args('CURL_USE_LIBSSH2')) + ->optionalPackage('nghttp2', ...cmake_boolean_args('USE_NGHTTP2')) + ->optionalPackage('nghttp3', ...cmake_boolean_args('USE_NGHTTP3')) + ->optionalPackage('ngtcp2', ...cmake_boolean_args('USE_NGTCP2')) + ->optionalPackage('ldap', ...cmake_boolean_args('CURL_DISABLE_LDAP', true)) + ->optionalPackage('zstd', ...cmake_boolean_args('CURL_ZSTD')) + ->optionalPackage('idn2', ...cmake_boolean_args('USE_LIBIDN2')) + ->optionalPackage('psl', ...cmake_boolean_args('CURL_USE_LIBPSL')) + ->optionalPackage('krb5', ...cmake_boolean_args('CURL_USE_GSSAPI')) + ->optionalPackage('idn2', ...cmake_boolean_args('CURL_USE_IDN2')) + ->optionalPackage('libcares', '-DENABLE_ARES=ON') + ->addConfigureArgs( + '-DBUILD_CURL_EXE=OFF', + '-DBUILD_LIBCURL_DOCS=OFF', + ) + ->build(); + + // patch pkgconf + $lib->patchPkgconfPrefix(['libcurl.pc']); + shell()->cd("{$lib->getLibDir()}/cmake/CURL/") + ->exec("sed -ie 's|\"/lib/libcurl.a\"|\"{$lib->getLibDir()}/libcurl.a\"|g' CURLTargets-release.cmake"); + } +} diff --git a/src/StaticPHP/Doctor/Doctor.php b/src/StaticPHP/Doctor/Doctor.php index d86e42ac..36db37ae 100644 --- a/src/StaticPHP/Doctor/Doctor.php +++ b/src/StaticPHP/Doctor/Doctor.php @@ -146,7 +146,8 @@ readonly class Doctor foreach (DoctorLoader::getDoctorItems() as [$item, $optional]) { /* @var CheckItem $item */ // optional check - if ($optional !== null && !call_user_func($optional)) { + /* @phpstan-ignore-next-line */ + if (is_callable($optional) && !call_user_func($optional)) { continue; // skip this when the optional check is false } // limit_os check From 6fdbf629dc7dac1ba9501ca8020ecd467fc63efc Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 14:00:21 +0800 Subject: [PATCH 27/28] Fix selective artifact installation detect --- src/StaticPHP/Artifact/Artifact.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/StaticPHP/Artifact/Artifact.php b/src/StaticPHP/Artifact/Artifact.php index 67876d90..b3e27371 100644 --- a/src/StaticPHP/Artifact/Artifact.php +++ b/src/StaticPHP/Artifact/Artifact.php @@ -164,7 +164,14 @@ class Artifact // For selective mode, cannot reliably check extraction status if ($mode === 'selective') { - return false; + // check files existence + foreach ($extract_config['files'] as $target_file) { + $target_file = FileSystem::replacePathVariable($target_file); + if (!file_exists($target_file)) { + return false; + } + } + return true; } // For standalone mode, check directory or file and hash From 38f742156d614ad427bb4d9c099d2d90e675b6c8 Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Tue, 3 Feb 2026 14:01:41 +0800 Subject: [PATCH 28/28] Use zig toolchain by default, lint files --- config/env.ini | 24 +- config/pkg.ext.json | 534 +++++++++--------- config/pkg.target.json | 67 +-- config/pkg/lib/curl.yml | 10 +- config/pkg/lib/gettext.yml | 6 +- config/pkg/lib/idn2.yml | 8 +- config/pkg/lib/krb5.yml | 6 +- config/pkg/lib/libxml2.yml | 6 +- config/pkg/lib/nghttp2.yml | 10 +- config/pkg/lib/ngtcp2.yml | 6 +- config/pkg/target/pkg-config.yml | 9 + config/pkg/target/zig.yml | 4 + spc.registry.json | 1 + .../Command/Dev/LintConfigCommand.php | 2 +- src/StaticPHP/Doctor/Item/LinuxMuslCheck.php | 10 +- src/StaticPHP/Package/PackageInstaller.php | 2 +- .../Toolchain/ClangNativeToolchain.php | 8 +- .../Toolchain/GccNativeToolchain.php | 8 +- src/StaticPHP/Toolchain/MuslToolchain.php | 10 +- src/StaticPHP/Util/PkgConfigUtil.php | 7 +- 20 files changed, 373 insertions(+), 365 deletions(-) create mode 100644 config/pkg/target/pkg-config.yml create mode 100644 config/pkg/target/zig.yml diff --git a/config/env.ini b/config/env.ini index 718e556f..c77f6bcd 100644 --- a/config/env.ini +++ b/config/env.ini @@ -83,7 +83,7 @@ SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime ; - gnu-native: used for general linux distros, can build gnu target for the installed glibc version only. ; option to specify the target, superceded by SPC_TARGET if set -SPC_LIBC=musl +; SPC_LIBC=musl ; uncomment to link libc dynamically on musl ; SPC_MUSL_DYNAMIC=true @@ -94,13 +94,13 @@ SPC_LIBC=musl ; `native-native` - links against system libc dynamically ; `native-native-musl` - links against musl libc statically ; `native-native-musl -dynamic` - links against musl libc dynamically -; SPC_TARGET= +SPC_TARGET=native-native-musl -; compiler environments -CC=${SPC_LINUX_DEFAULT_CC} -CXX=${SPC_LINUX_DEFAULT_CXX} -AR=${SPC_LINUX_DEFAULT_AR} -LD=${SPC_LINUX_DEFAULT_LD} +; compiler environments (default value is defined by selected toolchain) +CC=${SPC_DEFAULT_CC} +CXX=${SPC_DEFAULT_CXX} +AR=${SPC_DEFAULT_AR} +LD=${SPC_DEFAULT_LD} ; default compiler flags, used in CMake toolchain file, openssl and pkg-config build SPC_DEFAULT_C_FLAGS="-fPIC -Os" SPC_DEFAULT_CXX_FLAGS="-fPIC -Os" @@ -132,11 +132,11 @@ OPENSSLDIR="" ; build target: macho or macho (possibly we could support macho-universal in the future) ; Currently we do not support universal and cross-compilation for macOS. SPC_TARGET=native-macos -; compiler environments -CC=clang -CXX=clang++ -AR=ar -LD=ld +; compiler environments (default value is defined by selected toolchain) +CC=${SPC_DEFAULT_CC} +CXX=${SPC_DEFAULT_CXX} +AR=${SPC_DEFAULT_AR} +LD=${SPC_DEFAULT_LD} ; default compiler flags, used in CMake toolchain file, openssl and pkg-config build SPC_DEFAULT_C_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os" SPC_DEFAULT_CXX_FLAGS="--target=${MAC_ARCH}-apple-darwin -Os" diff --git a/config/pkg.ext.json b/config/pkg.ext.json index b1e819eb..d1ca0b3f 100644 --- a/config/pkg.ext.json +++ b/config/pkg.ext.json @@ -1,5 +1,6 @@ { "ext-amqp": { + "type": "php-extension", "artifact": "amqp", "depends": [ "librabbitmq" @@ -16,29 +17,29 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "type": "php-extension" + } }, "ext-apcu": { + "type": "php-extension", "artifact": "apcu", "license": { "type": "file", "path": "LICENSE" - }, - "type": "php-extension" + } }, "ext-ast": { + "type": "php-extension", "artifact": "ast", "license": { "type": "file", "path": "LICENSE" - }, - "type": "php-extension" + } }, "ext-bcmath": { "type": "php-extension" }, "ext-brotli": { + "type": "php-extension", "artifact": "ext-brotli", "depends": [ "brotli" @@ -49,18 +50,17 @@ }, "php-extension": { "arg-type": "enable" - }, - "type": "php-extension" + } }, "ext-bz2": { + "type": "php-extension", "depends": [ "bzip2" ], "php-extension": { "arg-type@windows": "with", "arg-type": "with-path" - }, - "type": "php-extension" + } }, "ext-calendar": { "type": "php-extension" @@ -69,6 +69,7 @@ "type": "php-extension" }, "ext-curl": { + "type": "php-extension", "depends": [ "curl" ], @@ -79,19 +80,19 @@ "php-extension": { "arg-type": "with", "notes": true - }, - "type": "php-extension" + } }, "ext-dba": { - "php-extension": { - "arg-type": "custom" - }, + "type": "php-extension", "suggests": [ "qdbm" ], - "type": "php-extension" + "php-extension": { + "arg-type": "custom" + } }, "ext-dio": { + "type": "php-extension", "artifact": "dio", "license": { "type": "file", @@ -101,10 +102,10 @@ "support": { "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-dom": { + "type": "php-extension", "depends": [ "libxml2", "zlib" @@ -118,18 +119,18 @@ }, "arg-type": "custom", "arg-type@windows": "with" - }, - "type": "php-extension" + } }, "ext-ds": { + "type": "php-extension", "artifact": "ext-ds", "license": { "type": "file", "path": "LICENSE" - }, - "type": "php-extension" + } }, "ext-enchant": { + "type": "php-extension", "php-extension": { "support": { "Windows": "wip", @@ -137,10 +138,10 @@ "Darwin": "wip", "Linux": "wip" } - }, - "type": "php-extension" + } }, "ext-ev": { + "type": "php-extension", "artifact": "ev", "depends": [ "ext-sockets" @@ -151,15 +152,18 @@ }, "php-extension": { "arg-type@windows": "with" - }, - "type": "php-extension" + } }, "ext-event": { + "type": "php-extension", "artifact": "ext-event", "depends": [ "libevent", "ext-openssl" ], + "suggests": [ + "ext-sockets" + ], "license": { "type": "file", "path": "LICENSE" @@ -171,16 +175,13 @@ }, "arg-type": "custom", "notes": true - }, - "suggests": [ - "ext-sockets" - ], - "type": "php-extension" + } }, "ext-exif": { "type": "php-extension" }, "ext-ffi": { + "type": "php-extension", "depends": [ "libffi" ], @@ -194,8 +195,7 @@ }, "arg-type": "custom", "notes": true - }, - "type": "php-extension" + } }, "ext-fileinfo": { "type": "php-extension" @@ -204,17 +204,24 @@ "type": "php-extension" }, "ext-ftp": { + "type": "php-extension", "suggests": [ "openssl" - ], - "type": "php-extension" + ] }, "ext-gd": { + "type": "php-extension", "depends": [ "zlib", "libpng", "ext-zlib" ], + "suggests": [ + "libavif", + "libwebp", + "libjpeg", + "freetype" + ], "php-extension": { "support": { "BSD": "wip" @@ -222,16 +229,10 @@ "arg-type": "custom", "arg-type@windows": "with", "notes": true - }, - "suggests": [ - "libavif", - "libwebp", - "libjpeg", - "freetype" - ], - "type": "php-extension" + } }, "ext-gettext": { + "type": "php-extension", "depends": [ "gettext" ], @@ -241,10 +242,10 @@ "BSD": "wip" }, "arg-type": "with-path" - }, - "type": "php-extension" + } }, "ext-glfw": { + "type": "php-extension", "artifact": "ext-glfw", "depends": [ "glfw" @@ -262,10 +263,10 @@ }, "arg-type": "custom", "notes": true - }, - "type": "php-extension" + } }, "ext-gmp": { + "type": "php-extension", "depends": [ "gmp" ], @@ -275,10 +276,10 @@ "BSD": "wip" }, "arg-type": "with-path" - }, - "type": "php-extension" + } }, "ext-gmssl": { + "type": "php-extension", "artifact": "ext-gmssl", "depends": [ "gmssl" @@ -291,10 +292,10 @@ "support": { "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-grpc": { + "type": "php-extension", "artifact": "grpc", "depends": [ "grpc" @@ -310,10 +311,10 @@ "BSD": "wip" }, "arg-type": "enable-path" - }, - "type": "php-extension" + } }, "ext-iconv": { + "type": "php-extension", "depends": [ "libiconv" ], @@ -326,11 +327,15 @@ }, "arg-type": "with-path", "arg-type@windows": "with" - }, - "type": "php-extension" + } }, "ext-igbinary": { + "type": "php-extension", "artifact": "igbinary", + "suggests": [ + "ext-session", + "ext-apcu" + ], "license": { "type": "file", "path": "COPYING" @@ -339,14 +344,10 @@ "support": { "BSD": "wip" } - }, - "suggests": [ - "ext-session", - "ext-apcu" - ], - "type": "php-extension" + } }, "ext-imagick": { + "type": "php-extension", "artifact": "ext-imagick", "depends": [ "imagemagick" @@ -362,14 +363,17 @@ }, "arg-type": "custom", "notes": true - }, - "type": "php-extension" + } }, "ext-imap": { + "type": "php-extension", "artifact": "ext-imap", "depends": [ "imap" ], + "suggests": [ + "ext-openssl" + ], "license": { "type": "file", "path": [ @@ -383,13 +387,10 @@ }, "arg-type": "custom", "notes": true - }, - "suggests": [ - "ext-openssl" - ], - "type": "php-extension" + } }, "ext-inotify": { + "type": "php-extension", "artifact": "inotify", "license": { "type": "file", @@ -401,10 +402,10 @@ "BSD": "wip", "Darwin": "no" } - }, - "type": "php-extension" + } }, "ext-intl": { + "type": "php-extension", "depends": [ "icu" ], @@ -415,28 +416,28 @@ "support": { "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-ldap": { + "type": "php-extension", "depends": [ "ldap" ], + "suggests": [ + "gmp", + "libsodium", + "ext-openssl" + ], "php-extension": { "support": { "Windows": "wip", "BSD": "wip" }, "arg-type": "with-path" - }, - "suggests": [ - "gmp", - "libsodium", - "ext-openssl" - ], - "type": "php-extension" + } }, "ext-libxml": { + "type": "php-extension", "depends": [ "ext-xml" ], @@ -448,10 +449,10 @@ "build-shared": false, "build-static": true, "build-with-php": true - }, - "type": "php-extension" + } }, "ext-lz4": { + "type": "php-extension", "artifact": "ext-lz4", "depends": [ "liblz4" @@ -468,10 +469,10 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "type": "php-extension" + } }, "ext-mbregex": { + "type": "php-extension", "depends": [ "onig", "ext-mbstring" @@ -480,16 +481,16 @@ "arg-type": "custom", "build-shared": false, "build-static": true - }, - "type": "php-extension" + } }, "ext-mbstring": { + "type": "php-extension", "php-extension": { "arg-type": "custom" - }, - "type": "php-extension" + } }, "ext-mcrypt": { + "type": "php-extension", "php-extension": { "support": { "Windows": "no", @@ -498,10 +499,10 @@ "Linux": "no" }, "notes": true - }, - "type": "php-extension" + } }, "ext-memcache": { + "type": "php-extension", "artifact": "ext-memcache", "depends": [ "ext-zlib", @@ -518,10 +519,10 @@ }, "arg-type": "custom", "build-with-php": true - }, - "type": "php-extension" + } }, "ext-memcached": { + "type": "php-extension", "artifact": "memcached", "depends": [ "libmemcached", @@ -529,6 +530,12 @@ "ext-session", "ext-zlib" ], + "suggests": [ + "zstd", + "ext-igbinary", + "ext-msgpack", + "ext-session" + ], "lang": "cpp", "license": { "type": "file", @@ -540,17 +547,17 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "suggests": [ - "zstd", - "ext-igbinary", - "ext-msgpack", - "ext-session" - ], - "type": "php-extension" + } }, "ext-mongodb": { + "type": "php-extension", "artifact": "mongodb", + "suggests": [ + "icu", + "openssl", + "zstd", + "zlib" + ], "frameworks": [ "CoreFoundation", "Security" @@ -565,16 +572,10 @@ "Windows": "wip" }, "arg-type": "custom" - }, - "suggests": [ - "icu", - "openssl", - "zstd", - "zlib" - ], - "type": "php-extension" + } }, "ext-msgpack": { + "type": "php-extension", "artifact": "msgpack", "depends": [ "ext-session" @@ -589,30 +590,30 @@ }, "arg-type@windows": "enable", "arg-type": "with" - }, - "type": "php-extension" + } }, "ext-mysqli": { + "type": "php-extension", "depends": [ "ext-mysqlnd" ], "php-extension": { "arg-type": "with", "build-with-php": true - }, - "type": "php-extension" + } }, "ext-mysqlnd": { + "type": "php-extension", "depends": [ "zlib" ], "php-extension": { "arg-type@windows": "with", "build-with-php": true - }, - "type": "php-extension" + } }, "ext-oci8": { + "type": "php-extension", "php-extension": { "support": { "Windows": "wip", @@ -621,10 +622,10 @@ "Linux": "no" }, "notes": true - }, - "type": "php-extension" + } }, "ext-odbc": { + "type": "php-extension", "depends": [ "unixodbc" ], @@ -634,18 +635,18 @@ "Windows": "wip" }, "arg-type": "custom" - }, - "type": "php-extension" + } }, "ext-opcache": { + "type": "php-extension", "php-extension": { "arg-type@windows": "enable", "arg-type": "custom", "zend-extension": true - }, - "type": "php-extension" + } }, "ext-openssl": { + "type": "php-extension", "depends": [ "openssl", "zlib", @@ -656,10 +657,10 @@ "arg-type@windows": "with", "build-with-php": true, "notes": true - }, - "type": "php-extension" + } }, "ext-opentelemetry": { + "type": "php-extension", "artifact": "opentelemetry", "license": { "type": "file", @@ -669,10 +670,10 @@ "support": { "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-parallel": { + "type": "php-extension", "artifact": "parallel", "depends@windows": [ "pthreads4w" @@ -687,10 +688,10 @@ }, "arg-type@windows": "with", "notes": true - }, - "type": "php-extension" + } }, "ext-password-argon2": { + "type": "php-extension", "depends": [ "libargon2", "openssl" @@ -702,31 +703,31 @@ }, "arg-type": "custom", "notes": true - }, - "type": "php-extension" + } }, "ext-pcntl": { + "type": "php-extension", "php-extension": { "support": { "Windows": "no" } - }, - "type": "php-extension" + } }, "ext-pdo": { "type": "php-extension" }, "ext-pdo_mysql": { + "type": "php-extension", "depends": [ "ext-pdo", "ext-mysqlnd" ], "php-extension": { "arg-type": "with" - }, - "type": "php-extension" + } }, "ext-pdo_odbc": { + "type": "php-extension", "depends": [ "unixodbc", "ext-pdo", @@ -737,10 +738,10 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "type": "php-extension" + } }, "ext-pdo_pgsql": { + "type": "php-extension", "depends": [ "postgresql", "ext-pdo", @@ -755,10 +756,10 @@ }, "arg-type": "with-path", "arg-type@windows": "custom" - }, - "type": "php-extension" + } }, "ext-pdo_sqlite": { + "type": "php-extension", "depends": [ "sqlite", "ext-pdo", @@ -769,10 +770,10 @@ "BSD": "wip" }, "arg-type": "with" - }, - "type": "php-extension" + } }, "ext-pdo_sqlsrv": { + "type": "php-extension", "artifact": "pdo_sqlsrv", "depends": [ "ext-pdo", @@ -787,10 +788,10 @@ "BSD": "wip" }, "arg-type": "with" - }, - "type": "php-extension" + } }, "ext-pgsql": { + "type": "php-extension", "depends": [ "postgresql" ], @@ -803,24 +804,24 @@ }, "arg-type": "custom", "notes": true - }, - "type": "php-extension" + } }, "ext-phar": { + "type": "php-extension", "depends": [ "ext-zlib" - ], - "type": "php-extension" + ] }, "ext-posix": { + "type": "php-extension", "php-extension": { "support": { "Windows": "no" } - }, - "type": "php-extension" + } }, "ext-protobuf": { + "type": "php-extension", "artifact": "protobuf", "license": { "type": "file", @@ -831,10 +832,10 @@ "Windows": "wip", "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-rar": { + "type": "php-extension", "artifact": "rar", "lang": "cpp", "license": { @@ -847,10 +848,10 @@ "Darwin": "partial" }, "notes": true - }, - "type": "php-extension" + } }, "ext-rdkafka": { + "type": "php-extension", "artifact": "ext-rdkafka", "depends": [ "librdkafka" @@ -866,10 +867,10 @@ "Windows": "wip" }, "arg-type": "custom" - }, - "type": "php-extension" + } }, "ext-readline": { + "type": "php-extension", "depends": [ "libedit" ], @@ -881,11 +882,18 @@ "arg-type": "with-path", "build-shared": false, "build-static": true - }, - "type": "php-extension" + } }, "ext-redis": { + "type": "php-extension", "artifact": "redis", + "suggests": [ + "zstd", + "liblz4", + "ext-session", + "ext-igbinary", + "ext-msgpack" + ], "license": { "type": "file", "path": [ @@ -898,38 +906,31 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "suggests": [ - "zstd", - "liblz4", - "ext-session", - "ext-igbinary", - "ext-msgpack" - ], - "type": "php-extension" + } }, "ext-session": { + "type": "php-extension", "php-extension": { "build-with-php": true - }, - "type": "php-extension" + } }, "ext-shmop": { + "type": "php-extension", "php-extension": { "build-with-php": true - }, - "type": "php-extension" + } }, "ext-simdjson": { + "type": "php-extension", "artifact": "ext-simdjson", "lang": "cpp", "license": { "type": "file", "path": "LICENSE" - }, - "type": "php-extension" + } }, "ext-simplexml": { + "type": "php-extension", "depends": [ "libxml2" ], @@ -942,14 +943,17 @@ }, "arg-type": "custom", "build-with-php": true - }, - "type": "php-extension" + } }, "ext-snappy": { + "type": "php-extension", "artifact": "ext-snappy", "depends": [ "snappy" ], + "suggests": [ + "ext-apcu" + ], "lang": "cpp", "license": { "type": "file", @@ -961,13 +965,10 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "suggests": [ - "ext-apcu" - ], - "type": "php-extension" + } }, "ext-snmp": { + "type": "php-extension", "depends": [ "net-snmp" ], @@ -978,10 +979,10 @@ }, "arg-type@windows": "with", "arg-type": "with" - }, - "type": "php-extension" + } }, "ext-soap": { + "type": "php-extension", "depends": [ "ext-libxml", "ext-session" @@ -991,13 +992,13 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "type": "php-extension" + } }, "ext-sockets": { "type": "php-extension" }, "ext-sodium": { + "type": "php-extension", "depends": [ "libsodium" ], @@ -1006,10 +1007,10 @@ "BSD": "wip" }, "arg-type": "with" - }, - "type": "php-extension" + } }, "ext-spx": { + "type": "php-extension", "artifact": "spx", "depends": [ "zlib" @@ -1025,10 +1026,10 @@ }, "arg-type": "custom", "notes": true - }, - "type": "php-extension" + } }, "ext-sqlite3": { + "type": "php-extension", "depends": [ "sqlite" ], @@ -1039,10 +1040,10 @@ "arg-type": "with-path", "arg-type@windows": "with", "build-with-php": true - }, - "type": "php-extension" + } }, "ext-sqlsrv": { + "type": "php-extension", "artifact": "sqlsrv", "depends": [ "unixodbc" @@ -1059,10 +1060,10 @@ "support": { "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-ssh2": { + "type": "php-extension", "artifact": "ext-ssh2", "depends": [ "libssh2", @@ -1079,10 +1080,10 @@ }, "arg-type": "with-path", "arg-type@windows": "with" - }, - "type": "php-extension" + } }, "ext-swoole": { + "type": "php-extension", "artifact": "swoole", "depends": [ "libcares", @@ -1092,6 +1093,18 @@ "ext-openssl", "ext-curl" ], + "suggests": [ + "zstd", + "ext-sockets", + "ext-swoole-hook-pgsql", + "ext-swoole-hook-mysql", + "ext-swoole-hook-sqlite", + "ext-swoole-hook-odbc" + ], + "suggests@linux": [ + "zstd", + "liburing" + ], "lang": "cpp", "license": { "type": "file", @@ -1104,28 +1117,19 @@ }, "arg-type": "custom", "notes": true - }, - "suggests": [ - "zstd", - "ext-sockets", - "ext-swoole-hook-pgsql", - "ext-swoole-hook-mysql", - "ext-swoole-hook-sqlite", - "ext-swoole-hook-odbc" - ], - "suggests@linux": [ - "zstd", - "liburing" - ], - "type": "php-extension" + } }, "ext-swoole-hook-mysql": { + "type": "php-extension", "depends": [ "ext-mysqlnd", "ext-pdo", "ext-pdo_mysql", "ext-swoole" ], + "suggests": [ + "ext-mysqli" + ], "php-extension": { "support": { "Windows": "no", @@ -1133,13 +1137,10 @@ }, "arg-type": "none", "notes": true - }, - "suggests": [ - "ext-mysqli" - ], - "type": "php-extension" + } }, "ext-swoole-hook-odbc": { + "type": "php-extension", "depends": [ "unixodbc", "ext-pdo", @@ -1152,10 +1153,10 @@ }, "arg-type": "none", "notes": true - }, - "type": "php-extension" + } }, "ext-swoole-hook-pgsql": { + "type": "php-extension", "depends": [ "ext-pgsql", "ext-pdo", @@ -1169,10 +1170,10 @@ }, "arg-type": "none", "notes": true - }, - "type": "php-extension" + } }, "ext-swoole-hook-sqlite": { + "type": "php-extension", "depends": [ "ext-sqlite3", "ext-pdo", @@ -1185,11 +1186,17 @@ }, "arg-type": "none", "notes": true - }, - "type": "php-extension" + } }, "ext-swow": { + "type": "php-extension", "artifact": "swow", + "suggests": [ + "openssl", + "curl", + "ext-openssl", + "ext-curl" + ], "license": { "type": "file", "path": "LICENSE" @@ -1200,42 +1207,36 @@ }, "arg-type": "custom", "notes": true - }, - "suggests": [ - "openssl", - "curl", - "ext-openssl", - "ext-curl" - ], - "type": "php-extension" + } }, "ext-sysvmsg": { + "type": "php-extension", "php-extension": { "support": { "Windows": "no", "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-sysvsem": { + "type": "php-extension", "php-extension": { "support": { "Windows": "no", "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-sysvshm": { + "type": "php-extension", "php-extension": { "support": { "BSD": "wip" } - }, - "type": "php-extension" + } }, "ext-tidy": { + "type": "php-extension", "depends": [ "tidy" ], @@ -1245,16 +1246,16 @@ "BSD": "wip" }, "arg-type": "with-path" - }, - "type": "php-extension" + } }, "ext-tokenizer": { + "type": "php-extension", "php-extension": { "build-with-php": true - }, - "type": "php-extension" + } }, "ext-trader": { + "type": "php-extension", "artifact": "ext-trader", "license": { "type": "file", @@ -1265,10 +1266,10 @@ "BSD": "wip", "Windows": "wip" } - }, - "type": "php-extension" + } }, "ext-uuid": { + "type": "php-extension", "artifact": "ext-uuid", "depends": [ "libuuid" @@ -1283,10 +1284,10 @@ "BSD": "wip" }, "arg-type": "with-path" - }, - "type": "php-extension" + } }, "ext-uv": { + "type": "php-extension", "artifact": "ext-uv", "depends": [ "libuv", @@ -1302,10 +1303,10 @@ "BSD": "wip" }, "arg-type": "with-path" - }, - "type": "php-extension" + } }, "ext-xdebug": { + "type": "php-extension", "artifact": "xdebug", "license": { "type": "file", @@ -1322,10 +1323,10 @@ "build-static": false, "notes": true, "zend-extension": true - }, - "type": "php-extension" + } }, "ext-xhprof": { + "type": "php-extension", "artifact": "xhprof", "depends": [ "ext-ctype" @@ -1341,15 +1342,18 @@ }, "build-with-php": true, "notes": true - }, - "type": "php-extension" + } }, "ext-xlswriter": { + "type": "php-extension", "artifact": "xlswriter", "depends": [ "ext-zlib", "ext-zip" ], + "suggests": [ + "openssl" + ], "license": { "type": "file", "path": "LICENSE" @@ -1359,13 +1363,10 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "suggests": [ - "openssl" - ], - "type": "php-extension" + } }, "ext-xml": { + "type": "php-extension", "depends": [ "libxml2" ], @@ -1380,10 +1381,10 @@ "arg-type@windows": "with", "build-with-php": true, "notes": true - }, - "type": "php-extension" + } }, "ext-xmlreader": { + "type": "php-extension", "depends": [ "libxml2" ], @@ -1397,10 +1398,10 @@ }, "arg-type": "custom", "build-with-php": true - }, - "type": "php-extension" + } }, "ext-xmlwriter": { + "type": "php-extension", "depends": [ "libxml2" ], @@ -1413,10 +1414,10 @@ }, "arg-type": "custom", "build-with-php": true - }, - "type": "php-extension" + } }, "ext-xsl": { + "type": "php-extension", "depends": [ "libxslt", "ext-xml", @@ -1428,10 +1429,10 @@ "BSD": "wip" }, "arg-type": "with-path" - }, - "type": "php-extension" + } }, "ext-xz": { + "type": "php-extension", "artifact": "ext-xz", "depends": [ "xz" @@ -1442,10 +1443,10 @@ }, "php-extension": { "arg-type": "with" - }, - "type": "php-extension" + } }, "ext-yac": { + "type": "php-extension", "artifact": "yac", "depends": [ "fastlz", @@ -1460,10 +1461,10 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "type": "php-extension" + } }, "ext-yaml": { + "type": "php-extension", "artifact": "yaml", "depends": [ "libyaml" @@ -1478,10 +1479,10 @@ }, "arg-type@windows": "with", "arg-type": "with-path" - }, - "type": "php-extension" + } }, "ext-zip": { + "type": "php-extension", "artifact": "ext-zip", "depends": [ "libzip" @@ -1504,10 +1505,10 @@ }, "arg-type": "custom", "arg-type@windows": "enable" - }, - "type": "php-extension" + } }, "ext-zlib": { + "type": "php-extension", "depends": [ "zlib" ], @@ -1517,10 +1518,10 @@ "build-shared": false, "build-static": true, "build-with-php": true - }, - "type": "php-extension" + } }, "ext-zstd": { + "type": "php-extension", "artifact": "ext-zstd", "depends": [ "zstd" @@ -1535,7 +1536,6 @@ "BSD": "wip" }, "arg-type": "custom" - }, - "type": "php-extension" + } } } diff --git a/config/pkg.target.json b/config/pkg.target.json index 8e04df90..a5c20b78 100644 --- a/config/pkg.target.json +++ b/config/pkg.target.json @@ -1,5 +1,6 @@ { "frankenphp": { + "type": "virtual-target", "artifact": "frankenphp", "depends": [ "php-embed", @@ -9,90 +10,78 @@ "php-embed", "go-xcaddy", "libxml2" - ], - "type": "virtual-target" + ] }, "go-xcaddy": { + "type": "target", "artifact": "go-xcaddy", "static-bins": [ "xcaddy" - ], - "type": "target" + ] }, "musl-toolchain": { - "artifact": "musl-toolchain", - "type": "target" + "type": "target", + "artifact": "musl-toolchain" }, "nasm": { - "artifact": "nasm", - "type": "target" + "type": "target", + "artifact": "nasm" }, "php": { + "type": "target", "artifact": "php-src", "depends@macos": [ "libxml2" - ], - "type": "target" + ] }, "php-cgi": { + "type": "virtual-target", "depends": [ "php" - ], - "type": "virtual-target" + ] }, "php-cli": { + "type": "virtual-target", "depends": [ "php" - ], - "type": "virtual-target" + ] }, "php-embed": { + "type": "virtual-target", "depends": [ "php" - ], - "type": "virtual-target" + ] }, "php-fpm": { + "type": "virtual-target", "depends": [ "php" - ], - "type": "virtual-target" + ] }, "php-micro": { + "type": "virtual-target", "artifact": "micro", "depends": [ "php" - ], - "type": "virtual-target" + ] }, "php-sdk-binary-tools": { - "artifact": "php-sdk-binary-tools", - "type": "target" - }, - "pkg-config": { - "artifact": "pkg-config", - "static-bins": [ - "pkg-config" - ], - "type": "target" + "type": "target", + "artifact": "php-sdk-binary-tools" }, "strawberry-perl": { - "artifact": "strawberry-perl", - "type": "target" + "type": "target", + "artifact": "strawberry-perl" }, "upx": { - "artifact": "upx", - "type": "target" + "type": "target", + "artifact": "upx" }, "vswhere": { + "type": "target", "artifact": "vswhere", "static-bins@windows": [ "vswhere.exe" - ], - "type": "target" - }, - "zig": { - "artifact": "zig", - "type": "target" + ] } } diff --git a/config/pkg/lib/curl.yml b/config/pkg/lib/curl.yml index 38d632ce..f183b21e 100644 --- a/config/pkg/lib/curl.yml +++ b/config/pkg/lib/curl.yml @@ -4,15 +4,11 @@ curl: source: type: ghrel repo: curl/curl - match: 'curl.+\.tar\.xz' + match: curl.+\.tar\.xz prefer-stable: true metadata: license-files: [COPYING] license: curl - static-libs@unix: - - libcurl.a - headers: - - curl depends@unix: - openssl - zlib @@ -31,3 +27,7 @@ curl: - CoreFoundation - CoreServices - SystemConfiguration + headers: + - curl + static-libs@unix: + - libcurl.a diff --git a/config/pkg/lib/gettext.yml b/config/pkg/lib/gettext.yml index 5b1f57a6..58f541f8 100644 --- a/config/pkg/lib/gettext.yml +++ b/config/pkg/lib/gettext.yml @@ -10,10 +10,10 @@ gettext: license: LGPL-2.1-or-later depends: - libiconv + suggests: + - ncurses + - libxml2 frameworks: - CoreFoundation static-libs@unix: - libintl.a - suggests: - - ncurses - - libxml2 diff --git a/config/pkg/lib/idn2.yml b/config/pkg/lib/idn2.yml index 5d2e2043..cef2a149 100644 --- a/config/pkg/lib/idn2.yml +++ b/config/pkg/lib/idn2.yml @@ -11,11 +11,11 @@ idn2: depends@macos: - libiconv - gettext - headers: - - idn2.h - pkg-configs: - - libidn2 suggests@unix: - libiconv - gettext - libunistring + headers: + - idn2.h + pkg-configs: + - libidn2 diff --git a/config/pkg/lib/krb5.yml b/config/pkg/lib/krb5.yml index 305a95a1..07fa3327 100644 --- a/config/pkg/lib/krb5.yml +++ b/config/pkg/lib/krb5.yml @@ -11,6 +11,9 @@ krb5: source-root: src depends: - openssl + suggests: + - ldap + - libedit frameworks: - Kerberos headers: @@ -18,6 +21,3 @@ krb5: - gssapi/gssapi.h pkg-configs: - krb5-gssapi - suggests: - - ldap - - libedit diff --git a/config/pkg/lib/libxml2.yml b/config/pkg/lib/libxml2.yml index 8ba0f8e1..db88e8b1 100644 --- a/config/pkg/lib/libxml2.yml +++ b/config/pkg/lib/libxml2.yml @@ -10,10 +10,10 @@ libxml2: license: MIT depends@unix: - libiconv + suggests@unix: + - xz + - zlib headers: - libxml2 pkg-configs: - libxml-2.0 - suggests@unix: - - xz - - zlib diff --git a/config/pkg/lib/nghttp2.yml b/config/pkg/lib/nghttp2.yml index 20a1840d..166c33ac 100644 --- a/config/pkg/lib/nghttp2.yml +++ b/config/pkg/lib/nghttp2.yml @@ -11,14 +11,14 @@ nghttp2: depends: - zlib - openssl + suggests: + - libxml2 + - nghttp3 + - ngtcp2 + - brotli headers: - nghttp2 pkg-configs: - libnghttp2 static-libs@unix: - libnghttp2.a - suggests: - - libxml2 - - nghttp3 - - ngtcp2 - - brotli diff --git a/config/pkg/lib/ngtcp2.yml b/config/pkg/lib/ngtcp2.yml index a609d3ca..c864739a 100644 --- a/config/pkg/lib/ngtcp2.yml +++ b/config/pkg/lib/ngtcp2.yml @@ -11,6 +11,9 @@ ngtcp2: license: MIT depends: - openssl + suggests: + - nghttp3 + - brotli headers: - ngtcp2 pkg-configs: @@ -19,6 +22,3 @@ ngtcp2: static-libs@unix: - libngtcp2.a - libngtcp2_crypto_ossl.a - suggests: - - nghttp3 - - brotli diff --git a/config/pkg/target/pkg-config.yml b/config/pkg/target/pkg-config.yml new file mode 100644 index 00000000..9b6d1603 --- /dev/null +++ b/config/pkg/target/pkg-config.yml @@ -0,0 +1,9 @@ +pkg-config: + type: target + artifact: + source: 'https://dl.static-php.dev/static-php-cli/deps/pkg-config/pkg-config-0.29.2.tar.gz' + binary: + linux-x86_64: { type: ghrel, repo: static-php/static-php-cli-hosted, match: pkg-config-x86_64-linux-musl-1.2.5.txz, extract: { bin/pkg-config: '{pkg_root_path}/bin/pkg-config' } } + linux-aarch64: { type: ghrel, repo: static-php/static-php-cli-hosted, match: pkg-config-aarch64-linux-musl-1.2.5.txz, extract: { bin/pkg-config: '{pkg_root_path}/bin/pkg-config' } } + macos-x86_64: { type: ghrel, repo: static-php/static-php-cli-hosted, match: pkg-config-x86_64-darwin.txz, extract: { bin/pkg-config: '{pkg_root_path}/bin/pkg-config' } } + macos-aarch64: { type: ghrel, repo: static-php/static-php-cli-hosted, match: pkg-config-aarch64-darwin.txz, extract: { bin/pkg-config: '{pkg_root_path}/bin/pkg-config' } } diff --git a/config/pkg/target/zig.yml b/config/pkg/target/zig.yml new file mode 100644 index 00000000..dda72b55 --- /dev/null +++ b/config/pkg/target/zig.yml @@ -0,0 +1,4 @@ +zig: + type: target + artifact: + binary: custom diff --git a/spc.registry.json b/spc.registry.json index e8be4b5d..b3d34939 100644 --- a/spc.registry.json +++ b/spc.registry.json @@ -13,6 +13,7 @@ "config": [ "config/pkg.ext.json", "config/pkg/lib", + "config/pkg/target", "config/pkg.target.json" ] }, diff --git a/src/StaticPHP/Command/Dev/LintConfigCommand.php b/src/StaticPHP/Command/Dev/LintConfigCommand.php index 1b08bb85..8149af14 100644 --- a/src/StaticPHP/Command/Dev/LintConfigCommand.php +++ b/src/StaticPHP/Command/Dev/LintConfigCommand.php @@ -56,7 +56,7 @@ class LintConfigCommand extends BaseCommand public function packageSortKey(string $a, string $b): int { // sort by predefined order, other not matching keys go to the end alphabetically - $order = ['type', 'artifact']; + $order = ['type', 'artifact', 'depends', 'suggests', 'frameworks']; // Handle suffix patterns (e.g., 'depends@unix', 'static-libs@windows') $base_a = preg_replace('/@(unix|windows|macos|linux|freebsd|bsd)$/', '', $a); diff --git a/src/StaticPHP/Doctor/Item/LinuxMuslCheck.php b/src/StaticPHP/Doctor/Item/LinuxMuslCheck.php index 4d7a86be..b64df85b 100644 --- a/src/StaticPHP/Doctor/Item/LinuxMuslCheck.php +++ b/src/StaticPHP/Doctor/Item/LinuxMuslCheck.php @@ -27,25 +27,25 @@ class LinuxMuslCheck public static function optionalCheck(): bool { $toolchain = ApplicationContext::get(ToolchainInterface::class); - return $toolchain instanceof MuslToolchain || $toolchain instanceof ZigToolchain && !LinuxUtil::isMuslDist(); + return $toolchain instanceof MuslToolchain || $toolchain instanceof ZigToolchain && !LinuxUtil::isMuslDist() && !str_contains(getenv('SPC_TARGET') ?: '', 'gnu'); } /** @noinspection PhpUnused */ #[CheckItem('if musl-wrapper is installed', limit_os: 'Linux', level: 800)] - public function checkMusl(): CheckResult + public function checkMusl(): ?CheckResult { $musl_wrapper_lib = sprintf('/lib/ld-musl-%s.so.1', php_uname('m')); if (file_exists($musl_wrapper_lib) && (file_exists('/usr/local/musl/lib/libc.a') || getenv('SPC_TOOLCHAIN') === ZigToolchain::class)) { - return CheckResult::ok(); + return null; } return CheckResult::fail('musl-wrapper is not installed on your system', 'fix-musl-wrapper'); } #[CheckItem('if musl-cross-make is installed', limit_os: 'Linux', level: 799)] - public function checkMuslCrossMake(): CheckResult + public function checkMuslCrossMake(): ?CheckResult { if (getenv('SPC_TOOLCHAIN') === ZigToolchain::class && !LinuxUtil::isMuslDist()) { - return CheckResult::ok(); + return null; } $arch = arch2gnu(php_uname('m')); $cross_compile_lib = "/usr/local/musl/{$arch}-linux-musl/lib/libc.a"; diff --git a/src/StaticPHP/Package/PackageInstaller.php b/src/StaticPHP/Package/PackageInstaller.php index 9ceb2107..2469159a 100644 --- a/src/StaticPHP/Package/PackageInstaller.php +++ b/src/StaticPHP/Package/PackageInstaller.php @@ -259,7 +259,7 @@ class PackageInstaller if ($this->isBuildPackage($package)) { return $package->isInstalled(); } - if ($package instanceof LibraryPackage && $package->getArtifact()->shouldUseBinary()) { + if ($package->getArtifact() !== null && $package->getArtifact()->shouldUseBinary()) { $artifact = $package->getArtifact(); return $artifact->isBinaryExtracted(); } diff --git a/src/StaticPHP/Toolchain/ClangNativeToolchain.php b/src/StaticPHP/Toolchain/ClangNativeToolchain.php index 2513dd71..27ae2b65 100644 --- a/src/StaticPHP/Toolchain/ClangNativeToolchain.php +++ b/src/StaticPHP/Toolchain/ClangNativeToolchain.php @@ -18,10 +18,10 @@ class ClangNativeToolchain implements UnixToolchainInterface { public function initEnv(): void { - GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CC=clang'); - GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=clang++'); - GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar'); - GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld'); + GlobalEnvManager::putenv('SPC_DEFAULT_CC=clang'); + GlobalEnvManager::putenv('SPC_DEFAULT_CXX=clang++'); + GlobalEnvManager::putenv('SPC_DEFAULT_AR=ar'); + GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld'); } public function afterInit(): void diff --git a/src/StaticPHP/Toolchain/GccNativeToolchain.php b/src/StaticPHP/Toolchain/GccNativeToolchain.php index dbf9925e..7c339e69 100644 --- a/src/StaticPHP/Toolchain/GccNativeToolchain.php +++ b/src/StaticPHP/Toolchain/GccNativeToolchain.php @@ -15,10 +15,10 @@ class GccNativeToolchain implements UnixToolchainInterface { public function initEnv(): void { - GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CC=gcc'); - GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=g++'); - GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar'); - GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld'); + GlobalEnvManager::putenv('SPC_DEFAULT_CC=gcc'); + GlobalEnvManager::putenv('SPC_DEFAULT_CXX=g++'); + GlobalEnvManager::putenv('SPC_DEFAULT_AR=ar'); + GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld'); } public function afterInit(): void diff --git a/src/StaticPHP/Toolchain/MuslToolchain.php b/src/StaticPHP/Toolchain/MuslToolchain.php index c7b39dbf..6963a364 100644 --- a/src/StaticPHP/Toolchain/MuslToolchain.php +++ b/src/StaticPHP/Toolchain/MuslToolchain.php @@ -14,10 +14,10 @@ class MuslToolchain implements UnixToolchainInterface { $arch = getenv('GNU_ARCH'); // Set environment variables for musl toolchain - GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CC={$arch}-linux-musl-gcc"); - GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CXX={$arch}-linux-musl-g++"); - GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_AR={$arch}-linux-musl-ar"); - GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_LD={$arch}-linux-musl-ld"); + GlobalEnvManager::putenv("SPC_DEFAULT_CC={$arch}-linux-musl-gcc"); + GlobalEnvManager::putenv("SPC_DEFAULT_CXX={$arch}-linux-musl-g++"); + GlobalEnvManager::putenv("SPC_DEFAULT_AR={$arch}-linux-musl-ar"); + GlobalEnvManager::putenv("SPC_DEFAULT_LD={$arch}-linux-musl-ld"); GlobalEnvManager::addPathIfNotExists('/usr/local/musl/bin'); GlobalEnvManager::addPathIfNotExists("/usr/local/musl/{$arch}-linux-musl/bin"); @@ -40,7 +40,7 @@ class MuslToolchain implements UnixToolchainInterface public function getCompilerInfo(): ?string { - $compiler = getenv('CC') ?: getenv('SPC_LINUX_DEFAULT_CC'); + $compiler = getenv('CC') ?: getenv('SPC_DEFAULT_CC'); $version = shell(false)->execWithResult("{$compiler} --version", false); $head = pathinfo($compiler, PATHINFO_BASENAME); if ($version[0] === 0 && preg_match('/linux-musl-cc.*(\d+.\d+.\d+)/', $version[1][0], $match)) { diff --git a/src/StaticPHP/Util/PkgConfigUtil.php b/src/StaticPHP/Util/PkgConfigUtil.php index 5efd33de..d5b03757 100644 --- a/src/StaticPHP/Util/PkgConfigUtil.php +++ b/src/StaticPHP/Util/PkgConfigUtil.php @@ -28,7 +28,12 @@ class PkgConfigUtil ]; $found = null; foreach ($find_list as $file) { - if (file_exists($file) && is_executable($file)) { + $exists = file_exists($file); + $executable = is_executable($file); + if (!$exists) { + continue; + } + if (!$executable && chmod($file, 0755) || $executable) { $found = $file; break; }