Compare commits

..

51 Commits

Author SHA1 Message Date
crazywhalecc
331da67049 Fix gen-ext-test-matrix AND bug (should be OR) 2026-07-07 15:48:35 +08:00
crazywhalecc
cc448d463b simdjson test 2026-07-07 15:42:34 +08:00
crazywhalecc
dc55881b78 libde265 fix build 2026-07-07 15:21:19 +08:00
crazywhalecc
a59473e4ab ext-test-matrix generation fix 2026-07-07 15:03:31 +08:00
crazywhalecc
c6a227f4de libde265 test 2026-07-07 14:50:32 +08:00
Jerry Ma
392733b7c3 feat(v3): Tool package refactor (#1200) 2026-07-06 21:59:44 +08:00
Jerry Ma
3870269330 feat(docs): add agent guide, build class patterns, log triage, and AI instructions (#1202) 2026-07-06 21:59:26 +08:00
crazywhalecc
03f1313eec chore 2026-07-06 21:20:38 +08:00
crazywhalecc
b9def51f86 Simplify redundant github instruction 2026-07-06 21:20:20 +08:00
crazywhalecc
8533702cf6 oops 2026-07-06 21:19:55 +08:00
crazywhalecc
fe3cd15f81 feat(docs): add agent guide, build class patterns, log triage, and AI instructions 2026-07-06 20:39:44 +08:00
crazywhalecc
dc33b55fd0 Use binary 2026-07-06 20:12:10 +08:00
crazywhalecc
c9401a0b7a Use redirect instead 2026-07-06 19:35:48 +08:00
crazywhalecc
fa040bc346 Fix mingw patch paths 2026-07-06 19:10:10 +08:00
crazywhalecc
ab37b34fb5 fix: improve Windows patching logic and update file paths for xlsxwriter 2026-07-06 16:46:29 +08:00
crazywhalecc
0b02f62b7e feat: add pkg-config tool package config 2026-07-06 15:36:36 +08:00
crazywhalecc
924fac137c docs: fix hosted repo URL in READMEs
- Update static-php-cli-hosted → static-php/hosted in both README.md and README-zh.md
2026-07-06 15:11:07 +08:00
crazywhalecc
d9c41a73da feat: add --installed flag to check-update, improve CLI and InteractiveTerm
- Add --installed option to check-update command to compare against on-disk version (tool packages)
- Support use_installed parameter in ArtifactDownloader::checkUpdate/checkUpdates
- Add -y shorthand for --auto-fix in doctor command
- Hook InteractiveTerm::init() in ConsoleApplication::doRun() to properly inject Symfony input/output
2026-07-06 15:10:52 +08:00
crazywhalecc
dd1e70a394 feat: declare tool dependencies in package configs via tools field
- Add 'tools' field to ConfigValidator for build-time tool declarations
- Move jom and strawberry-perl from depends@windows to tools@windows in openssl.yml
- Move go-xcaddy/go-win from depends to tools in frankenphp.yml
- Register config/pkg/tool/ path in spc.registry.yml
- Use addInstallPackage for upx tool in php.php (ToolPackage instead of library dep)
- Include 'tool' type in DumpCapabilitiesCommand and InstallPackageCommand package lists
2026-07-06 15:10:22 +08:00
crazywhalecc
1bdbdfc08c refactor: move getLibExtra* to Package base, add ToolPackage support to executors and builders
- Move getLibExtraCFlags/getLibExtraCxxFlags/getLibExtraLdFlags/getLibExtraLibs from LibraryPackage to Package base class so ToolPackage can also use them
- Full ToolPackage implementation: getBuildRootPath, getIncludeDir, getLibDir, getBinDir, getToolField with platform suffix support
- Update PackageBuilder to support building ToolPackage (not just LibraryPackage)
- Update PackageInstaller: support ToolPackage in download/extract/install pipeline, auto-install build-time tools, record installed versions
- Allow LibraryPackage|ToolPackage union type in all Executor classes and UnixShell::initializeEnv
2026-07-06 15:10:08 +08:00
crazywhalecc
90846ab149 refactor: restructure tool target configs into tool package system
- Move tool configs from config/pkg/target/ to config/pkg/tool/
- Add ToolVersionRegistry for tracking installed tool versions
- Delete old Target/pkgconfig.php, move to tool config
- Rename: 7za-win, go-win, go-xcaddy, jom, nasm, protoc, strawberry-perl, upx, vswhere, zig, pkg-config
2026-07-06 15:08:43 +08:00
Jerry Ma
8dd7882869 CRLF to LF (#1199) 2026-07-06 14:14:57 +08:00
crazywhalecc
7f6be12bf1 CRLF to LF 2026-07-06 14:02:38 +08:00
Jerry Ma
45b97581d8 feat(zip): add additional dependencies for Windows zip build (#1198) 2026-07-04 15:42:31 +08:00
crazywhalecc
12a5217f17 feat(zip): add additional dependencies for Windows zip build 2026-07-04 14:10:59 +08:00
Jerry Ma
5913cb07fd [v3] implement tool package support with validation and config (#1196) 2026-06-27 20:17:53 +08:00
crazywhalecc
dd69155539 feat(tool): remove deprecated tool package directory from registry configuration 2026-06-27 15:47:46 +08:00
crazywhalecc
a81dd6d5c9 feat(tool): implement tool package support with validation and configuration 2026-06-27 15:39:30 +08:00
Jerry Ma
b4ed673261 feat(windows): replace php-sdk-binary-tools with MSYS2 + 7za-win (#1193) 2026-06-23 14:36:28 +08:00
crazywhalecc
db2d9a909f feat(gmssl): add patch for pbkdf2_hmac_sm3_genkey rename and update build process 2026-06-22 16:44:44 +08:00
crazywhalecc
38e01a9b88 feat(tests): enhance label information for triggering extension build tests 2026-06-22 13:33:25 +08:00
crazywhalecc
2b210f9403 feat(logging): synchronize logger level and debug mode with output verbosity 2026-06-22 13:33:02 +08:00
crazywhalecc
be329c1d56 feat(build): add patch to Makefile for include order to resolve zip.h conflict 2026-06-22 11:14:14 +08:00
Jerry Ma
227b8f0b0a fix(test): fix redundant terminal output during phpunit (#1194) 2026-06-22 08:08:47 +08:00
crazywhalecc
c88041b7e0 feat(build): add UPX as an optional package for compression 2026-06-21 20:08:27 +08:00
crazywhalecc
3bb84f3b94 feat(build): add zlib as a dependency for Windows 2026-06-21 19:35:07 +08:00
crazywhalecc
c31bf73685 feat(build): add bison and re2c to required packages; bypass phpsdk_version check for MSVC + msys2 2026-06-21 19:28:15 +08:00
crazywhalecc
c4d7ca819b fix(openssl): update perl path for Windows compatibility 2026-06-21 19:27:47 +08:00
crazywhalecc
fd8ab71d80 feat(build): use WinCNG as crypto backend for libssh2 windows 2026-06-21 19:27:32 +08:00
crazywhalecc
2a7966aa4b Fix curl zstd build bug 2026-06-21 19:26:55 +08:00
crazywhalecc
ef83ff074e fix(source): use ftp.gnu.org as primary, ftpmirror.gnu.org as fallback
All GNU packages now use ftp.gnu.org (stable canonical server) as the
primary filelist source, with ftpmirror.gnu.org configured as
source-mirror fallback. ftpmirror uses DNS round-robin across many
mirrors of varying reliability; this setup eliminates random CI failures
caused by unreachable mirror nodes while preserving a fallback path.
2026-06-21 17:33:48 +08:00
crazywhalecc
06864fc3f6 feat(windows): replace php-sdk-binary-tools with MSYS2 + 7za-win
- Add msys2-build-essentials target: downloads the MSYS2 nightly sfx,
  extracts it, disables PGP keyring (CI-safe), runs two-pass pacman
  update, and installs autotools build essentials (make, autoconf,
  automake, libtool, pkgconf, perl).
- Add 7za-win target: downloads 7za.exe to PKG_ROOT_PATH\bin.
- Remove php-sdk-binary-tools target and all PHP_SDK_PATH references;
  replace with SPC_MSYS2_PATH throughout Artifact, ArtifactExtractor,
  FileSystem, DefaultShell and MSVCToolchain.
- Replace {php_sdk_path} path placeholder with {spc_msys2_path}.
- WindowsToolCheck: replace checkSDK/installSDK with checkMsys2,
  installMsys2 and check7zaWin/install7zaWin fix items.
- nasm.yml: extract nasm.exe/ndisasm.exe to {pkg_root_path}/bin.
- env.ini: rename PHP_SDK_PATH to SPC_MSYS2_PATH.
- Docs: update Windows migration guide and package-model placeholder docs.
2026-06-21 16:56:40 +08:00
Marc
408d8f755c Remove laravel/prompts from box.json (#1190) 2026-06-16 19:05:39 +07:00
Marc
1f291a9036 Add Visual Studio 2026 support (#1191) 2026-06-16 19:05:09 +07:00
crazywhalecc
127fb1989f Add vs 18 support 2026-06-16 19:21:18 +08:00
Jerry Ma
af771cf2b5 feat: enhance type hints and improve verbosity handling in commands (#1186) 2026-06-16 18:50:18 +08:00
crazywhalecc
5df65d926c Remove laravel/prompts from box.json 2026-06-16 18:49:22 +08:00
Jerry Ma
bdc7bbe1f1 v3: Fix gmssl build (#1188) 2026-06-16 18:45:43 +08:00
Jerry Ma
89dca1f0fb refactor: remove unused symfony/process and unnecessary laravel/prompts (#1187) 2026-06-16 18:15:03 +08:00
crazywhalecc
064a1f05ae Fix phpstan 2026-06-16 15:17:51 +08:00
crazywhalecc
88cb6749b8 Remove laravel/prompts and symfony/process 2026-06-16 15:11:48 +08:00
160 changed files with 3973 additions and 1571 deletions

24
.gitattributes vendored Normal file
View File

@@ -0,0 +1,24 @@
# Force LF line endings for all text files.
# Prevents git from auto-converting LF -> CRLF on Windows checkouts.
* text=auto eol=lf
# Explicit binary files — git won't touch line endings for these
*.phar binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.zip binary
*.gz binary
*.tgz binary
*.txz binary
*.xz binary
*.bz2 binary
*.7z binary
*.exe binary
*.dll binary
*.sfx binary
*.so binary
*.a binary
*.o binary

23
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,23 @@
# StaticPHP v3 Copilot Instructions
> The canonical agent instructions live in [AGENTS.md](./AGENTS.md). This file provides the essential summary for GitHub Copilot; read `AGENTS.md` for the complete project map, working rules, and validation steps.
StaticPHP is a PHP CLI application for building static PHP binaries, PHP SAPIs, extensions, libraries, and helper tools. Prefer the v3 architecture under `src/StaticPHP`, `src/Package`, `config/pkg`, and `config/artifact`.
## Skills
Use the repository skills when the task matches them:
- `.github/skills/staticphp-package-maintenance`: add, modify, review, or validate package, artifact, extension, library, target, or tool definitions.
- `.github/skills/staticphp-build-troubleshooting`: diagnose build, download, doctor, shell, terminal, CI, smoke-test, or log failures.
## Quick Reference
- **Entrypoint**: `php bin/spc`
- **Config lint**: `php bin/spc dev:lint-config`
- **CS fix**: `composer cs-fix`
- **Tests**: `composer test`
- **Static analysis**: `composer analyse`
- **Extension packages**: `config/pkg/ext/ext-*.yml`, prefix with `ext-` in dependencies
- **Platform suffixes**: `@unix`, `@linux`, `@macos`, `@windows` — prefer these over runtime conditionals
- **Do NOT edit generated dirs**: `buildroot/`, `source/`, `downloads/`, `pkgroot/`

View File

@@ -0,0 +1,56 @@
---
name: staticphp-build-troubleshooting
description: Diagnose StaticPHP v3 failures. Use when investigating build, compile, linker, download, doctor, environment, CI, smoke-test, terminal output, spc.output.log, spc.shell.log, config.log, CMake logs, or user-provided error snippets from StaticPHP commands.
---
# StaticPHP Build Troubleshooting
## Overview
Use this skill to triage StaticPHP failures from the outside in: command and environment first, SPC module/stage metadata next, shell/config logs last. The goal is to isolate the failing package, stage, command, and root cause before editing code.
## First Pass
1. Capture the exact command, OS, architecture, PHP version, extensions/libs/targets, and whether the run used `-v`, `-vv`, or `-vvv`.
2. Read the final terminal error first. StaticPHP prints module error info, failed package, failed stage, failed command, log paths, and extra log files when available.
3. If log files exist, inspect them in this order:
- `log/spc.output.log`: user-facing SPC messages and exception summary.
- `log/spc.shell.log`: executed commands, working directories, env, stdout/stderr.
- Extra logs named in the exception output: `php-src.config.log`, `lib.<pkg>.console.log`, `lib.<pkg>.cmake-error.log`, `lib.<pkg>.cmake-configure.log`, `lib.<pkg>.cmake-output.log`.
4. Read `references/log-triage.md` for pattern matching, likely causes, and next checks.
## Diagnosis Rules
- Do not start by changing shared core code. Most failures are package metadata, environment, upstream source, dependency order, or platform flags.
- Prefer evidence from the last failing command over earlier warnings.
- When logs are long, search backward for `Command exited`, `error:`, `undefined reference`, `not found`, `No package`, `CMake Error`, `configure: error`, `fatal error`, `Failed module`, and `Failed stage`.
- Use `config.log` and CMake logs for configure detection failures; use `spc.shell.log` for the actual command and env.
- Be careful with rebuild suggestions. `spc reset --with-download --yes` is destructive to caches; ask before clearing caches unless the user explicitly asked.
## Repro Commands
Use focused commands when reproducing:
```bash
php bin/spc doctor -vvv
php bin/spc download --for-extensions="curl,openssl" --with-php=8.5 --parallel=4 --retry=3 -vvv
php bin/spc build:libs "openssl" -vvv
php bin/spc build:php "bcmath,openssl,curl" --build-cli -vvv
php bin/spc dev:lint-config
```
Choose the smallest command that still reaches the failing package.
## Fix Direction
After finding the failing package/stage:
- Package YAML issue: use `$staticphp-package-maintenance`, then edit `config/pkg/*` or `config/artifact/*`.
- Build command or patch issue: inspect the package class under `src/Package/*`.
- Environment issue: check `doctor`, toolchain classes, and `config/pkg/tool/*`.
- Upstream download issue: check artifact type, regex, GitHub rate limiting, mirror behavior, and `GITHUB_TOKEN`.
- Core exception/logging issue: inspect `src/StaticPHP/Exception`, `src/StaticPHP/Runtime/Shell`, or executor classes only after package-level causes are ruled out.
## Resources
- `references/log-triage.md`: log files, failure categories, search patterns, and likely fixes.

View File

@@ -0,0 +1,4 @@
interface:
display_name: "StaticPHP Build Troubleshooting"
short_description: "Diagnose StaticPHP build and log failures."
default_prompt: "Use $staticphp-build-troubleshooting to investigate a StaticPHP build, download, doctor, or log failure."

View File

@@ -0,0 +1,209 @@
# StaticPHP Log Triage
## Contents
- Log files
- Terminal summary
- Search strategy
- Failure categories
- Rebuild hygiene
- Reporting checklist
## Log Files
Default log directory is `log/`, controlled by `SPC_LOGS_DIR`. The important files are:
- `spc.output.log`: StaticPHP console/logger output and exception summaries.
- `spc.shell.log`: command execution log with command, caller, inline env, working directory, stdout, stderr, and exit code.
- `php-src.config.log`: copied when PHP source configure fails.
- `lib.<pkg>.console.log`: copied Autoconf `config.log` for a library when available.
- `lib.<pkg>.cmake-configure.log`: copied CMake 3.26+ configure log.
- `lib.<pkg>.cmake-error.log`: copied CMake error log.
- `lib.<pkg>.cmake-output.log`: copied CMake output log.
Logs are created when `SPC_ENABLE_LOG_FILE` is true. Old `*.log` files are cleaned unless `SPC_PRESERVE_LOG` is set to a truthy value. The code in `src/bootstrap.php` reads `SPC_PRESERVE_LOG` (no trailing S).
## Terminal Summary
StaticPHP exceptions often print:
- Exception category: build, download, environment, execution, file system, patch, validation, wrong usage, registry, internal.
- Failed module: package name, type, and sometimes class/file/line.
- Failed stage: call chain such as `build` or `build -> configure`.
- Failed command: the command that returned non-zero.
- Command working directory and inline env.
- Paths to `spc.output.log`, `spc.shell.log`, and extra logs.
Use this summary to choose the first files to read. If a package and stage are present, start with that package's YAML and class after reading the relevant log tail.
## Search Strategy
For long logs, search from the end first.
Useful patterns:
```text
Failed module:
Failed stage:
Failed command:
Command exited with non-zero code
configure: error
CMake Error
undefined reference
cannot find -l
fatal error:
No package
Package .* not found
Could NOT find
is not a valid
permission denied
curl: (
HTTP/2 403
rate limit
```
In `spc.shell.log`, each command block begins with `>>>>>>>>>>>>>>>>>>>>>>>>>>`, then prints the command, caller, env, and working dir. The last failed block is usually the highest-value evidence.
## Failure Categories
### Download Failure
Signs:
- `Download failed`
- `curl: (56)`, `curl: (22)`, HTTP 403/404/429
- GitHub API calls in verbose logs
- Asset regex did not match a release asset
Likely checks:
- If GitHub rate limited, ask user to set `GITHUB_TOKEN`.
- Verify artifact source type and regex in `config/pkg/*` or `config/artifact/*`.
- Use `--dl-retry`, `--dl-parallel`, `--ignore-cache`, `--no-alt`, or custom source options only as repro aids.
- Prefer fixing stale URLs/regexes over adding workarounds.
### Doctor or Environment Failure
Signs:
- `Environment check failed`
- missing `make`, `cmake`, `autoconf`, `pkg-config`, compiler, Perl, Visual Studio, MSYS2, Zig, etc.
- `Some check items can not be fixed`
Likely checks:
- Run `php bin/spc doctor -vvv`.
- Inspect `src/StaticPHP/Doctor/Item/*` for the check and fix behavior.
- Inspect `config/pkg/tool/*` for installable helper tools.
- On Windows, some dependencies cannot be auto-installed.
### Configure Failure
Signs:
- `configure: error`
- Autoconf failure before compilation
- extra `config.log` listed
Likely checks:
- Read copied `php-src.config.log` or `lib.<pkg>.console.log`.
- Look for the first compiler/linker probe that failed.
- Check `headers`, `static-libs`, `pkg-configs`, dependency order, and `initializeEnv($pkg)` behavior.
- For extensions, check `php-extension.arg-type` and `#[CustomPhpConfigureArg]`.
### CMake Failure
Signs:
- `CMake Error`
- `Could NOT find`
- missing target, package config, or static library
Likely checks:
- Read `lib.<pkg>.cmake-error.log` and `lib.<pkg>.cmake-configure.log`.
- Inspect `UnixCMakeExecutor`/`WindowsCMakeExecutor` usage in the package class.
- Check CMake options, toolchain root path, `pkg-configs`, and transitive dependency libraries.
### Compile Failure
Signs:
- compiler `fatal error: header.h: No such file or directory`
- syntax/type errors from upstream source
- incompatible PHP API or platform macros
Likely checks:
- Identify the source file and include path from `spc.shell.log`.
- Verify dependency headers are installed in `buildroot/include`.
- Check PHP version compatibility and existing patches in `src/globals/patch`.
- Prefer targeted patches or compile flags in the package class over broad toolchain changes.
### Link Failure
Signs:
- `undefined reference`
- `cannot find -lfoo`
- duplicate symbols
- Windows unresolved external symbol or missing `.lib`
Likely checks:
- Verify `static-libs`, dependency order, and `getStaticLibFiles()` usage.
- Inspect `SPC_EXTRA_LIBS`, `Libs.private` in `.pc` files, and package-specific pkg-config patching.
- On Windows, confirm `.lib` names and required system libraries.
- For OpenSSL/curl-like packages, search existing linker flag hooks before adding a new one.
### Smoke Test or Validation Failure
Signs:
- `Validation failed`
- `php --ri` failure
- extension not loaded after build
- micro/embed runtime smoke test fails
Likely checks:
- Check extension `display-name`; empty string skips `php --ri`.
- Confirm static vs shared build settings.
- Confirm the extension is included in the final SAPI target and not only built as a dependency.
- Inspect `src/globals/ext-tests/*` and common tests for expected runtime behavior.
### Registry or Config Failure
Signs:
- `Registry error`
- unknown package, invalid field, invalid platform suffix, type mismatch
- package referenced by attribute but missing config
Likely checks:
- Run `php bin/spc dev:lint-config`.
- Inspect `ConfigValidator` tests for accepted fields and error expectations.
- Confirm attribute type matches YAML `type`.
- Confirm hooks reference existing package names and stages for the current platform.
## Rebuild Hygiene
Use the smallest cleanup that can invalidate the suspected stale state:
- Redownload one artifact: `--ignore-cache="artifact-name"`.
- Skip downloads to test local source/build logic: `--no-download`.
- Prefer source when debugging build logic: `--dl-prefer-source`.
- Clear build products only when necessary. `spc reset --with-download --yes` removes caches and should not be suggested casually.
## Reporting Checklist
When preparing an issue or PR explanation, include:
- Exact `php bin/spc ...` command.
- OS, architecture, PHP version option, and relevant env vars.
- Failed package and stage.
- Last failed command and exit code.
- Tail of `spc.output.log`, relevant command block from `spc.shell.log`, and any extra config/CMake log.
- Whether the failure reproduces after a focused clean or cache refresh.

View File

@@ -0,0 +1,55 @@
---
name: staticphp-package-maintenance
description: Maintain StaticPHP v3 packages and artifacts. Use when adding, modifying, reviewing, or validating config under config/pkg or config/artifact; package classes under src/Package; extension/library/target/tool dependencies; PHP configure args; build hooks; package metadata; or related tests and docs.
---
# StaticPHP Package Maintenance
## Overview
Use this skill to make focused package changes without re-reading the entire repository. StaticPHP v3 separates declarative package/artifact YAML from package-specific PHP build logic; prefer config-only edits unless current patterns require a class.
## Quick Workflow
1. Identify the package kind and exact name.
- Extension: `config/pkg/ext/ext-name.yml`, class `src/Package/Extension/name.php`.
- Library: `config/pkg/lib/name.yml`, class `src/Package/Library/name.php`.
- Target or virtual target: `config/pkg/target/name.yml`, class `src/Package/Target/name.php`.
- Tool: `config/pkg/tool/name.yml`, class `src/Package/Tool/name.php`.
- Shared/custom artifact: `config/artifact/name.yml`, class `src/Package/Artifact/name.php`.
2. Search for the closest existing package before designing anything new.
- Similar build system: `rg "#\\[BuildFor|UnixCMakeExecutor|UnixAutoconfExecutor|WindowsCMakeExecutor" src/Package`.
- Similar config fields: `rg "static-libs|pkg-configs|arg-type|depends@" config/pkg`.
- Similar download type: `rg "type: ghrel|type: pecl|type: pie|type: git|binary: hosted" config`.
3. Read `references/package-reference.md` when changing YAML fields, artifact definitions, package naming, dependencies, platform suffixes, or validation expectations.
4. Read `references/build-class-patterns.md` when PHP build logic, attributes, lifecycle hooks, custom configure args, source patching, or executor usage is needed.
5. Validate narrowly, then broadly if risk warrants it.
- Config lint: `php bin/spc dev:lint-config`
- Focused tests: `vendor/bin/phpunit tests/StaticPHP/Config tests/StaticPHP/Registry tests/StaticPHP/Util/DependencyResolverTest.php --no-coverage`
- Full project checks: `composer test`, `composer analyse`
## Editing Rules
- Treat `config/pkg/*` and `config/artifact/*` as the source of package truth; package classes augment behavior.
- Use platform suffix fields for declarative OS differences: `@unix`, `@linux`, `@macos`, `@windows`.
- Add a PHP class only for custom build stages, validation, hook behavior, patches, or custom configure arguments.
- Keep extension dependencies prefixed with `ext-`; libraries, tools, and targets use their package names.
- Prefer existing helpers such as `UnixAutoconfExecutor`, `UnixCMakeExecutor`, `WindowsCMakeExecutor`, `shell()`, `cmd()`, and `FileSystem`.
- Do not modify build outputs (`buildroot/`, `source/`, `downloads/`, `pkgroot/`) to fix package definitions.
- If upstream metadata changes, update license metadata and smoke-test/display names when relevant.
## Common Task Paths
- Add a new PECL extension: define `config/pkg/ext/ext-name.yml` with `type: php-extension`, `artifact.source.type: pecl`, dependencies, and `php-extension.arg-type`; add a class only if configure args, patches, or hooks are non-standard.
- Add a library: define `config/pkg/lib/name.yml` with artifact, dependencies, and install verification fields (`headers`, `static-libs`, `pkg-configs`, `static-bins`); add build class methods by OS.
- Fix an existing package build: start from the failing package config/class, then inspect dependencies and hooks targeting that package before changing shared core code.
- Update a version source: prefer artifact fields that support update checking (`ghrel`, `ghtar`, `ghtagtar`, `git` with regex, `filelist`, `pecl`, `pie`) over hard-coded URLs when upstream supports it.
## Resources
- `references/package-reference.md`: YAML package/artifact model, naming, fields, validation, and commands.
- `references/build-class-patterns.md`: PHP package attributes, stages, hooks, executors, and class patterns.

View File

@@ -0,0 +1,4 @@
interface:
display_name: "StaticPHP Package Maintenance"
short_description: "Add, update, and validate StaticPHP v3 package definitions."
default_prompt: "Use $staticphp-package-maintenance to add, modify, or review StaticPHP package and artifact definitions."

View File

@@ -0,0 +1,143 @@
# StaticPHP Build Class Patterns
## Contents
- When a class is needed
- Package attributes
- Stage and hook behavior
- Executor choices
- Common patterns
- Failure-safe edits
## When a Class Is Needed
Do not add a PHP package class for simple metadata. Use YAML alone when StaticPHP can infer the configure args, dependencies, and verification.
Add or update a class when the package needs:
- OS-specific build commands.
- Custom validation before building.
- Custom PHP configure arguments.
- Patches or file edits before build.
- Hooks into another package's stage.
- Custom source/binary download or extraction logic.
- Package info shown by dev tooling.
Package classes live in `src/Package/*` and are discovered through PSR-4 plus attributes. Config must exist first; `PackageLoader` throws if an attribute references an undefined package.
## Package Attributes
Class-level package attributes:
- `#[Extension('curl')]` maps to package `ext-curl` if the prefix is omitted.
- `#[Library('openssl')]`
- `#[Target('php')]`
- `#[Tool('zig')]`
Method-level attributes:
- `#[BuildFor('Linux'|'Darwin'|'Windows')]`: registers the `build` stage for that OS.
- `#[Stage('name')]`: registers a named stage; defaults to the method name when omitted.
- `#[BeforeStage('package', 'stage', 'only-when-package-resolved')]`: hook before a target package stage.
- `#[AfterStage('package', 'stage', 'only-when-package-resolved')]`: hook after a target package stage.
- `#[PatchBeforeBuild]`: runs once before package build unless `.spc-patched` exists; return `true` to write that marker.
- `#[CustomPhpConfigureArg('Linux')]`: supplies custom extension configure args.
- `#[Validate]`: validates environment/source assumptions.
- `#[Info]`: returns package information for tooling.
- `#[InitPackage]`: runs while loading a package class.
- `#[ResolveBuild]`: target package callback for resolving build dependencies.
- `#[ConditionalOn(SomeClass::class)]`: conditionally enables before/after hooks only when DI has the class.
## Stage and Hook Behavior
`PackageBuilder::buildPackage()` does:
1. Ensure build directories exist.
2. Skip if already installed unless forced.
3. Ensure source exists for non-virtual packages.
4. Emit `PatchBeforeBuild` callbacks.
5. Run the `build` stage.
6. Install license data.
7. Record tool package versions where relevant.
`Package::runStage()` wraps a stage with:
1. `BeforeStage` callbacks.
2. The stage method itself.
3. `AfterStage` callbacks.
SPC exceptions bind package and stage metadata. Preserve that behavior by throwing existing `SPCException` subclasses instead of raw exceptions when adding new failure paths.
## Executor Choices
Use existing executors where possible:
- `UnixAutoconfExecutor`: for Unix packages using `./configure && make && make install`. It injects default static flags and copies `config.log` into SPC logs on failure.
- `UnixCMakeExecutor`: for Unix CMake packages. It writes toolchain settings and copies CMake configure/error/output logs on failure.
- `WindowsCMakeExecutor`: for Windows CMake packages.
- `shell()->cd(...)->initializeEnv($pkg)`: for custom Unix command chains.
- `cmd()->cd(...)`: for Windows command chains.
Prefer `FileSystem` helpers for file edits and copies so behavior stays consistent.
## Common Patterns
Minimal library class:
```php
#[Library('example')]
class example
{
#[BuildFor('Linux')]
public function build(LibraryPackage $pkg): void
{
(new UnixAutoconfExecutor($pkg))
->configure()
->make();
}
}
```
Extension hook into PHP build:
```php
#[Extension('curl')]
class curl
{
#[BeforeStage('php', [php::class, 'makeForWindows'], 'ext-curl')]
public function patchBeforePhpBuild(): void
{
// Adjust env, generated build files, or linker flags.
}
}
```
Validation:
```php
#[Validate]
public function validate(): void
{
if (SystemTarget::getTargetOS() === 'Windows' && WindowsUtil::findCommand('perl.exe') === null) {
throw new EnvironmentException('You need to install perl first!');
}
}
```
Custom configure args should be used when YAML `arg-type` is `custom` or when args need package/install context:
```php
#[CustomPhpConfigureArg('Linux')]
public function configureArg(PhpExtensionPackage $ext): string
{
return '--with-example=' . $ext->getBuildRootPath();
}
```
## Failure-Safe Edits
- Make hooks conditional with the third `BeforeStage`/`AfterStage` argument when a dependency must be resolved before the hook should run.
- Keep platform-specific code under matching `#[BuildFor]` methods rather than branching heavily inside one method.
- If a patch changes upstream source, place patch files in `src/globals/patch/` and describe them with `#[PatchDescription]` where appropriate.
- If a class only mutates environment variables for another package, search for existing hooks first to avoid duplicate linker flags.
- After adding attributes, run registry/config tests because invalid stages and unknown packages are caught during loading.

View File

@@ -0,0 +1,157 @@
# StaticPHP Package Reference
## Contents
- Package locations
- Package types
- Artifact model
- Common YAML fields
- PHP extension fields
- Platform suffixes
- Validation and tests
## Package Locations
StaticPHP v3 keeps package metadata in YAML and behavior in PHP classes.
| Kind | YAML | PHP class namespace | Typical attribute |
|---|---|---|---|
| PHP extension | `config/pkg/ext/ext-name.yml` | `Package\Extension` | `#[Extension('name')]` |
| Library | `config/pkg/lib/name.yml` | `Package\Library` | `#[Library('name')]` |
| Target | `config/pkg/target/name.yml` | `Package\Target` | `#[Target('name')]` |
| Virtual target | `config/pkg/target/name.yml` | `Package\Target` | `#[Target('name')]` |
| Tool | `config/pkg/tool/name.yml` | `Package\Tool` | `#[Tool('name')]` |
| Custom artifact | `config/artifact/name.yml` | `Package\Artifact` | artifact attributes |
Prefer one package per YAML file unless an existing file groups related definitions. Match nearby naming and ordering.
## Package Types
`php-extension` packages describe PHP extensions. Config package names must use the `ext-` prefix. Dependencies on extensions also use `ext-`.
`library` packages describe buildable dependency libraries. They usually define source artifacts plus verification fields such as headers, static libraries, pkg-config files, or binaries.
`target` packages represent final build outputs and inherit the library-style fields. StaticPHP automatically exposes build commands for targets.
`virtual-target` packages are abstract dependency/build scheduling nodes. They may omit `artifact`.
`tool` packages are helper programs or toolchains installed into `pkgroot/` or used by builds.
## Artifact Model
Artifacts define downloadable source archives or prebuilt binaries. Use inline artifacts for simple one-package sources and `config/artifact/*.yml` for shared, complex, or custom artifacts.
Top-level artifact sections:
- `source`: source archive, git checkout, PECL/PIE package, local directory, or custom source.
- `binary`: prebuilt binary by platform, or aliases such as `hosted`/`custom`.
- `metadata`: `license`, `license-files`, and `source-root`.
Common source types:
- `url`: fixed URL; supports `filename`, `version`, and `extract`.
- `git`: repository source; use `rev` for a fixed branch/tag/commit or `regex` with named `version` capture for update checks.
- `ghrel`: GitHub release asset by regex filename match.
- `ghtar`: generated GitHub release tarball.
- `ghtagtar`: generated GitHub tag tarball.
- `filelist`: scrape a download index and extract version/filename with regex.
- `pecl`: PECL extension by name.
- `pie`: Packagist PIE extension by `vendor/package`.
- `php-release`: official PHP source selected by build PHP version.
- `local`: local source directory for development/offline use.
- `custom`: PHP artifact class handles source or binary logic.
Use `metadata.source-root` when the actual build directory is inside an extracted subdirectory.
Use `metadata.license-files` for source licenses. `@/file.txt` points to bundled license files in `src/globals/licenses/`.
## Common YAML Fields
Shared fields:
- `type`: required package type.
- `description`: optional human-readable package description.
- `license`: package-level license annotation where applicable.
- `lang`: implementation language such as `c` or `c++`.
- `frameworks`: macOS framework tags.
- `artifact`: string reference or inline artifact object. Required for `library` and `target`; optional for built-in extensions and virtual targets.
- `depends`: hard dependencies.
- `suggests`: optional dependencies.
Library, target, and tool verification/installation fields:
- `headers`: expected files/directories under `buildroot/include`.
- `static-libs`: expected static libraries under `buildroot/lib`.
- `pkg-configs`: expected `.pc` files under `buildroot/lib/pkgconfig`.
- `static-bins`: expected executables under `buildroot/bin`.
- `path`: directories appended to PATH after install.
- `env`: environment variables set after install.
- `append-env`: values appended to existing environment variables.
Path placeholders in `path`, `env`, and `append-env`:
- `{build_root_path}`: `buildroot/`
- `{pkg_root_path}`: `pkgroot/`
- `{working_dir}`: repository or working directory
- `{download_path}`: `downloads/`
- `{source_path}`: `source/`
- `{spc_msys2_path}`: MSYS2 root on Windows
## PHP Extension Fields
Extension-specific fields live under `php-extension`.
- `arg-type`: configure argument behavior. Built-ins include `enable`, `enable-path`, `with`, `with-path`, `custom`, and `none`. Full strings are allowed.
- `zend-extension`: true for Zend extensions such as opcache/xdebug.
- `build-shared`: whether shared builds are allowed.
- `build-static`: whether static builds are allowed.
- `build-with-php`: true when built inside the PHP source tree.
- `display-name`: value used for `php --ri` smoke tests and license display; empty string skips the `--ri` check.
- `os`: allowed OS families: `Linux`, `Darwin`, `Windows`.
Configure string placeholders:
- `@build_root_path@`: absolute buildroot path.
- `@shared_suffix@`: `=shared` in shared builds, empty in static builds.
- `@shared_path_suffix@`: `=shared,{buildroot}` in shared builds, `={buildroot}` in static builds.
## Platform Suffixes
Many fields support platform suffixes:
- `@unix`: Linux and macOS.
- `@linux`: Linux only.
- `@macos`: macOS only.
- `@windows`: Windows only.
For Linux, specific fields override generic fields in this order: `field@linux`, then `field@unix`, then `field`.
Use suffixes for declarative differences in dependencies, headers, libraries, pkg-configs, extension args, and suggestions.
## Validation and Tests
Run config validation for most package edits:
```bash
php bin/spc dev:lint-config
```
Run focused tests after config or registry changes:
```bash
vendor/bin/phpunit tests/StaticPHP/Config tests/StaticPHP/Registry tests/StaticPHP/Util/DependencyResolverTest.php --no-coverage
```
Run broader checks for framework or class changes:
```bash
composer test
composer analyse
```
Build commands are expensive. Use them for user-provided repros, package-specific fixes, or when validation cannot prove the behavior:
```bash
php bin/spc build:libs "openssl,curl" -vvv
php bin/spc build:php "bcmath,openssl,curl" --build-cli -vvv
```

59
AGENTS.md Normal file
View File

@@ -0,0 +1,59 @@
# StaticPHP v3 Agent Guide
StaticPHP is a PHP CLI application for building static PHP binaries, PHP SAPIs, extensions, libraries, helper tools, and project bundles. Prefer the v3 architecture under `src/StaticPHP`, `src/Package`, `config/pkg`, and `config/artifact`.
This file is the shared entry point for coding agents such as Codex, OpenCode, Claude-compatible agents, and GitHub Copilot agents. GitHub Copilot also has `.github/copilot-instructions.md`.
## Skills
Detailed task workflows live in `.github/skills`. Use them when the task matches:
- `.github/skills/staticphp-package-maintenance`: add, modify, review, or validate package, artifact, extension, library, target, or tool definitions.
- `.github/skills/staticphp-build-troubleshooting`: diagnose build, download, doctor, shell, terminal, CI, smoke-test, or log failures.
If your agent does not automatically discover skills from `.github/skills`, read the matching `SKILL.md` manually before working on that task.
## Project Map
- `bin/spc`: primary CLI entrypoint.
- `composer.json`: PHP 8.4+, Symfony Console, DI, YAML, logger; useful scripts are `composer test`, `composer analyse`, `composer lint-config`, and `composer cs-fix`.
- `spc.registry.yml`: built-in `core` registry.
- `config/pkg/ext`: PHP extension package YAML, usually named `ext-*.yml`.
- `config/pkg/lib`: library package YAML.
- `config/pkg/target`: final build target and virtual target YAML.
- `config/pkg/tool`: helper tool package YAML.
- `config/artifact`: standalone artifact YAML for shared or complex sources/binaries.
- `log/`: build and shell execution logs (`spc.output.log`, `spc.shell.log`, and per-package CMake/config logs); controlled by `SPC_LOGS_DIR` and `SPC_ENABLE_LOG_FILE`.
- `src/StaticPHP`: framework core: registry loading, config validation, dependency resolution, package install/build pipeline, doctor, toolchains, runtime shell/executors, exceptions.
- `src/Package`: package-specific build logic registered by PHP attributes.
- `src/globals`: constants, helper functions, patches, smoke tests, bundled license text.
- `tests`: PHPUnit tests for config, registry, artifacts, dependency resolver, DI, commands, and utilities.
- `docs/en/develop` and `docs/zh/develop`: developer documentation. Some pages may be TODO; verify against source when behavior matters.
## Working Rules
- Keep changes scoped to the requested package, artifact, command, docs, or tests.
- Prefer existing package patterns over new abstractions. Search for a similar package first.
- Use structured YAML config; do not encode dependency logic in PHP when config fields are enough.
- Match package names exactly: extension packages use `ext-` in config and dependencies; `#[Extension('curl')]` expands to `ext-curl`.
- Use platform suffixes such as `@unix`, `@linux`, `@macos`, and `@windows` instead of runtime conditionals when the difference is declarative.
- Add or update PHP package classes only when build commands, validation, custom configure args, hooks, or source patching are required.
- Do not edit generated build directories (`buildroot/`, `source/`, `downloads/`, `pkgroot/`) as a fix.
## Validation
For config or package changes, run CS checks first:
```bash
bin/spc dev:lint-config
composer cs-fix
```
For broader PHP code changes, also run:
```bash
composer test
composer analyse
```
Use build commands only when needed for the task or when the user provided a repro, because full static builds can be slow and platform-sensitive.

View File

@@ -104,7 +104,7 @@ echo '<?php echo "Hello world!\n";' > a.php
## 直接下载 ## 直接下载
如果你暂时不想构建,或只想先测试,可以从 [Actions](https://github.com/static-php/static-php-cli-hosted/actions/workflows/build-php-bulk.yml) 下载示例预编译产物,或从自托管服务器下载。 如果你暂时不想构建,或只想先测试,可以从 [Actions](https://github.com/static-php/hosted/actions/workflows/build-php-bulk.yml) 下载示例预编译产物,或从自托管服务器下载。
我们为每个 PHP 版本提供 2 种扩展集合: 我们为每个 PHP 版本提供 2 种扩展集合:

View File

@@ -104,7 +104,7 @@ see <https://static-php.dev>.
## Direct Download ## Direct Download
If you do not want to build yet or just want to test first, you can download example pre-compiled artifacts from [Actions](https://github.com/static-php/static-php-cli-hosted/actions/workflows/build-php-bulk.yml) or from a self-hosted server. If you do not want to build yet or just want to test first, you can download example pre-compiled artifacts from [Actions](https://github.com/static-php/hosted/actions/workflows/build-php-bulk.yml) or from a self-hosted server.
We offer 2 types of extension sets for each PHP version: We offer 2 types of extension sets for each PHP version:

View File

@@ -10,7 +10,6 @@
"config", "config",
"src", "src",
"vendor/psr", "vendor/psr",
"vendor/laravel/prompts",
"vendor/symfony", "vendor/symfony",
"vendor/php-di", "vendor/php-di",
"vendor/zhamao" "vendor/zhamao"

View File

@@ -12,10 +12,8 @@
"php": ">=8.4", "php": ">=8.4",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-zlib": "*", "ext-zlib": "*",
"laravel/prompts": "~0.1",
"php-di/php-di": "^7.1", "php-di/php-di": "^7.1",
"symfony/console": "^5.4 || ^6 || ^7", "symfony/console": "^5.4 || ^6 || ^7",
"symfony/process": "^7.2",
"symfony/yaml": "^7.2", "symfony/yaml": "^7.2",
"zhamao/logger": "^1.1.4" "zhamao/logger": "^1.1.4"
}, },

568
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,10 @@ ncurses:
license-files: license-files:
- COPYING - COPYING
source: source:
type: filelist
url: 'https://ftp.gnu.org/gnu/ncurses/'
regex: '/href="(?<file>ncurses-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist type: filelist
url: 'https://ftpmirror.gnu.org/gnu/ncurses/' url: 'https://ftpmirror.gnu.org/gnu/ncurses/'
regex: '/href="(?<file>ncurses-(?<version>[^"]+)\.tar\.gz)"/' regex: '/href="(?<file>ncurses-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -53,8 +53,8 @@ PHP_BUILD_PROVIDER="StaticPHP ${SPC_VERSION}"
SPC_ENABLE_LOG_FILE="yes" SPC_ENABLE_LOG_FILE="yes"
; The LOG DIR for spc logs ; The LOG DIR for spc logs
SPC_LOGS_DIR="${WORKING_DIR}/log" SPC_LOGS_DIR="${WORKING_DIR}/log"
; Preserve old logs when running new builds ; Preserve old logs when running new builds (code checks SPC_PRESERVE_LOG, not SPC_PRESERVE_LOGS)
SPC_PRESERVE_LOGS="no" SPC_PRESERVE_LOG="no"
; EXTENSION_DIR where the built php will look for extension when a .ini instructs to load them ; EXTENSION_DIR where the built php will look for extension when a .ini instructs to load them
; only useful for builds targeting not pure-static linking ; only useful for builds targeting not pure-static linking
@@ -68,8 +68,8 @@ SPC_PRESERVE_LOGS="no"
[windows] [windows]
; build target: win7-static ; build target: win7-static
SPC_TARGET=native-windows SPC_TARGET=native-windows
; php-sdk-binary-tools path ; MSYS2 root directory (msys64 subfolder), used by the Windows toolchain
PHP_SDK_PATH="${WORKING_DIR}\php-sdk-binary-tools" SPC_MSYS2_PATH="${PKG_ROOT_PATH}\msys2-build-essentials\msys64"
; upx executable path ; upx executable path
UPX_EXEC="${PKG_ROOT_PATH}\bin\upx.exe" UPX_EXEC="${PKG_ROOT_PATH}\bin\upx.exe"
; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches ; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches

View File

@@ -10,3 +10,5 @@ ext-gmssl:
license: PHP-3.01 license: PHP-3.01
depends: depends:
- gmssl - gmssl
php-extension:
arg-type: with-path

View File

@@ -10,6 +10,11 @@ ext-zip:
license: PHP-3.01 license: PHP-3.01
depends: depends:
- libzip - libzip
depends@windows:
- libzip
- zlib
- xz
- bzip2
php-extension: php-extension:
arg-type: custom arg-type: custom
arg-type@windows: enable arg-type@windows: enable

View File

@@ -2,6 +2,10 @@ gettext:
type: library type: library
artifact: artifact:
source: source:
type: filelist
url: 'https://ftp.gnu.org/gnu/gettext/'
regex: '/href="(?<file>gettext-(?<version>[^"]+)\.tar\.xz)"/'
source-mirror:
type: filelist type: filelist
url: 'https://ftpmirror.gnu.org/gnu/gettext/' url: 'https://ftpmirror.gnu.org/gnu/gettext/'
regex: '/href="(?<file>gettext-(?<version>[^"]+)\.tar\.xz)"/' regex: '/href="(?<file>gettext-(?<version>[^"]+)\.tar\.xz)"/'

View File

@@ -3,11 +3,12 @@ gmp:
artifact: artifact:
source: source:
type: filelist type: filelist
url: 'https://ftpmirror.gnu.org/gnu/gmp/' url: 'https://ftp.gnu.org/gnu/gmp/'
regex: '/href="(?<file>gmp-(?<version>[^"]+)\.tar\.xz)"/' regex: '/href="(?<file>gmp-(?<version>[^"]+)\.tar\.xz)"/'
source-mirror: source-mirror:
type: url type: filelist
url: 'https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz' url: 'https://ftpmirror.gnu.org/gnu/gmp/'
regex: '/href="(?<file>gmp-(?<version>[^"]+)\.tar\.xz)"/'
metadata: metadata:
license-files: ['@/gmp.txt'] license-files: ['@/gmp.txt']
license: Custom license: Custom

View File

@@ -2,6 +2,10 @@ idn2:
type: library type: library
artifact: artifact:
source: source:
type: filelist
url: 'https://ftp.gnu.org/gnu/libidn/'
regex: '/href="(?<file>libidn2-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist type: filelist
url: 'https://ftpmirror.gnu.org/gnu/libidn/' url: 'https://ftpmirror.gnu.org/gnu/libidn/'
regex: '/href="(?<file>libidn2-(?<version>[^"]+)\.tar\.gz)"/' regex: '/href="(?<file>libidn2-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -2,6 +2,10 @@ libiconv:
type: library type: library
artifact: artifact:
source: source:
type: filelist
url: 'https://ftp.gnu.org/gnu/libiconv/'
regex: '/href="(?<file>libiconv-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist type: filelist
url: 'https://ftpmirror.gnu.org/gnu/libiconv/' url: 'https://ftpmirror.gnu.org/gnu/libiconv/'
regex: '/href="(?<file>libiconv-(?<version>[^"]+)\.tar\.gz)"/' regex: '/href="(?<file>libiconv-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -9,8 +9,10 @@ libssh2:
metadata: metadata:
license-files: [COPYING] license-files: [COPYING]
license: BSD-3-Clause license: BSD-3-Clause
depends: depends@unix:
- openssl - openssl
depends@windows:
- zlib
headers: headers:
- libssh2.h - libssh2.h
- libssh2_publickey.h - libssh2_publickey.h

View File

@@ -2,6 +2,10 @@ libunistring:
type: library type: library
artifact: artifact:
source: source:
type: filelist
url: 'https://ftp.gnu.org/gnu/libunistring/'
regex: '/href="(?<file>libunistring-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist type: filelist
url: 'https://ftpmirror.gnu.org/gnu/libunistring/' url: 'https://ftpmirror.gnu.org/gnu/libunistring/'
regex: '/href="(?<file>libunistring-(?<version>[^"]+)\.tar\.gz)"/' regex: '/href="(?<file>libunistring-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -17,7 +17,6 @@ openssl:
- zlib - zlib
depends@windows: depends@windows:
- zlib - zlib
- jom
headers: headers:
- openssl - openssl
static-libs@unix: static-libs@unix:
@@ -26,3 +25,6 @@ openssl:
static-libs@windows: static-libs@windows:
- libssl.lib - libssl.lib
- libcrypto.lib - libcrypto.lib
tools@windows:
- jom
- strawberry-perl

View File

@@ -2,6 +2,10 @@ readline:
type: library type: library
artifact: artifact:
source: source:
type: filelist
url: 'https://ftp.gnu.org/gnu/readline/'
regex: '/href="(?<file>readline-(?<version>[^"]+)\.tar\.gz)"/'
source-mirror:
type: filelist type: filelist
url: 'https://ftpmirror.gnu.org/gnu/readline/' url: 'https://ftpmirror.gnu.org/gnu/readline/'
regex: '/href="(?<file>readline-(?<version>[^"]+)\.tar\.gz)"/' regex: '/href="(?<file>readline-(?<version>[^"]+)\.tar\.gz)"/'

View File

@@ -10,10 +10,8 @@ frankenphp:
license: MIT license: MIT
depends: depends:
- php-embed - php-embed
- go-xcaddy
depends@windows: depends@windows:
- php-embed - php-embed
- go-win
- pthreads4w - pthreads4w
suggests@unix: suggests@unix:
- brotli - brotli
@@ -24,3 +22,7 @@ frankenphp:
- frankenphp - frankenphp
static-bins@windows: static-bins@windows:
- frankenphp.exe - frankenphp.exe
tools:
- go-xcaddy
tools@windows:
- go-win

View File

@@ -0,0 +1,8 @@
msys2-build-essentials:
type: target
artifact:
binary: custom
env:
SPC_MSYS2_PATH: '{pkg_root_path}/msys2-build-essentials/msys64'
path@windows:
- '{pkg_root_path}/msys2-build-essentials/msys64/usr/bin'

View File

@@ -1,5 +0,0 @@
nasm:
type: target
artifact:
binary:
windows-x86_64: { type: url, url: 'https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip', extract: { nasm.exe: '{php_sdk_path}/bin/nasm.exe', ndisasm.exe: '{php_sdk_path}/bin/ndisasm.exe' } }

View File

@@ -1,5 +0,0 @@
php-sdk-binary-tools:
type: target
artifact:
binary:
windows-x86_64: { type: git, rev: master, url: 'https://github.com/php/php-sdk-binary-tools.git', extract: '{php_sdk_path}' }

View File

@@ -1,9 +0,0 @@
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' } }

View File

@@ -1,4 +0,0 @@
zig:
type: target
artifact:
binary: custom

View File

@@ -0,0 +1,9 @@
7za-win:
type: tool
artifact:
binary:
windows-x86_64: { type: url, url: 'https://dl.static-php.dev/v3/tools/7zip/7za.exe', extract: '{pkg_root_path}/bin/7za.exe' }
tool:
provides:
- 7za.exe
binary-subdir: bin

View File

@@ -1,5 +1,5 @@
go-win: go-win:
type: target type: tool
artifact: artifact:
binary: custom binary: custom
env: env:
@@ -8,3 +8,8 @@ go-win:
GOPATH: '{pkg_root_path}/go-win/go' GOPATH: '{pkg_root_path}/go-win/go'
path@windows: path@windows:
- '{pkg_root_path}/go-win/bin' - '{pkg_root_path}/go-win/bin'
tool:
provides:
- go.exe
- gofmt.exe
binary-subdir: go-win/bin

View File

@@ -1,5 +1,5 @@
go-xcaddy: go-xcaddy:
type: target type: tool
artifact: artifact:
binary: custom binary: custom
env: env:
@@ -8,5 +8,8 @@ go-xcaddy:
GOPATH: '{pkg_root_path}/go-xcaddy/go' GOPATH: '{pkg_root_path}/go-xcaddy/go'
path@unix: path@unix:
- '{pkg_root_path}/go-xcaddy/bin' - '{pkg_root_path}/go-xcaddy/bin'
static-bins: tool:
- xcaddy provides:
- go
- gofmt
binary-subdir: go-xcaddy/bin

View File

@@ -1,7 +1,11 @@
jom: jom:
type: target type: tool
artifact: artifact:
binary: binary:
windows-x86_64: { type: url, url: 'https://download.qt.io/official_releases/jom/jom.zip', extract: '{pkg_root_path}/jom' } windows-x86_64: { type: url, url: 'https://download.qt.io/official_releases/jom/jom.zip', extract: '{pkg_root_path}/jom' }
path@windows: path@windows:
- '{pkg_root_path}\jom' - '{pkg_root_path}\jom'
tool:
provides:
- jom.exe
binary-subdir: jom

10
config/pkg/tool/nasm.yml Normal file
View File

@@ -0,0 +1,10 @@
nasm:
type: tool
artifact:
binary:
windows-x86_64: { type: url, url: 'https://dl.static-php.dev/static-php-cli/deps/nasm/nasm-2.16.01-win64.zip', extract: { nasm.exe: '{pkg_root_path}/bin/nasm.exe', ndisasm.exe: '{pkg_root_path}/bin/ndisasm.exe' } }
tool:
provides:
- nasm.exe
- ndisasm.exe
binary-subdir: bin

View File

@@ -0,0 +1,13 @@
pkg-config:
type: tool
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/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/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/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/hosted, match: pkg-config-aarch64-darwin.txz, extract: { bin/pkg-config: '{pkg_root_path}/bin/pkg-config' } }
tool:
provides:
- pkg-config
binary-subdir: bin

View File

@@ -1,8 +1,12 @@
protoc: protoc:
type: target type: tool
artifact: artifact:
binary: binary:
linux-x86_64: { type: ghrel, repo: protocolbuffers/protobuf, match: 'protoc-([0-9.]+)-linux-x86_64\.zip', extract: '{pkg_root_path}/protoc' } linux-x86_64: { type: ghrel, repo: protocolbuffers/protobuf, match: 'protoc-([0-9.]+)-linux-x86_64\.zip', extract: '{pkg_root_path}/protoc' }
linux-aarch64: { type: ghrel, repo: protocolbuffers/protobuf, match: 'protoc-([0-9.]+)-linux-aarch_64\.zip', extract: '{pkg_root_path}/protoc' } linux-aarch64: { type: ghrel, repo: protocolbuffers/protobuf, match: 'protoc-([0-9.]+)-linux-aarch_64\.zip', extract: '{pkg_root_path}/protoc' }
path: path:
- '{pkg_root_path}/protoc/bin' - '{pkg_root_path}/protoc/bin'
tool:
provides:
- protoc
binary-subdir: protoc/bin

View File

@@ -1,5 +1,9 @@
strawberry-perl: strawberry-perl:
type: target type: tool
artifact: artifact:
binary: binary:
windows-x86_64: { type: url, url: 'https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_5380_5361/strawberry-perl-5.38.0.1-64bit-portable.zip', extract: '{pkg_root_path}/strawberry-perl' } windows-x86_64: { type: url, url: 'https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_5380_5361/strawberry-perl-5.38.0.1-64bit-portable.zip', extract: '{pkg_root_path}/strawberry-perl' }
tool:
provides:
- perl.exe
binary-subdir: strawberry-perl/perl/bin

View File

@@ -1,7 +1,13 @@
upx: upx:
type: target type: tool
artifact: artifact:
binary: binary:
linux-x86_64: { type: ghrel, repo: upx/upx, match: upx.+-amd64_linux\.tar\.xz, extract: { upx: '{pkg_root_path}/bin/upx' } } linux-x86_64: { type: ghrel, repo: upx/upx, match: upx.+-amd64_linux\.tar\.xz, extract: { upx: '{pkg_root_path}/bin/upx' } }
linux-aarch64: { type: ghrel, repo: upx/upx, match: upx.+-arm64_linux\.tar\.xz, extract: { upx: '{pkg_root_path}/bin/upx' } } linux-aarch64: { type: ghrel, repo: upx/upx, match: upx.+-arm64_linux\.tar\.xz, extract: { upx: '{pkg_root_path}/bin/upx' } }
windows-x86_64: { type: ghrel, repo: upx/upx, match: upx.+-win64\.zip, extract: { upx.exe: '{pkg_root_path}/bin/upx.exe' } } windows-x86_64: { type: ghrel, repo: upx/upx, match: upx.+-win64\.zip, extract: { upx.exe: '{pkg_root_path}/bin/upx.exe' } }
tool:
provides:
- upx
provides@windows:
- upx.exe
binary-subdir: bin

View File

@@ -1,5 +1,9 @@
vswhere: vswhere:
type: target type: tool
artifact: artifact:
binary: binary:
windows-x86_64: { type: url, url: 'https://github.com/microsoft/vswhere/releases/download/3.1.7/vswhere.exe', extract: '{pkg_root_path}/bin/vswhere.exe' } windows-x86_64: { type: url, url: 'https://github.com/microsoft/vswhere/releases/download/3.1.7/vswhere.exe', extract: '{pkg_root_path}/bin/vswhere.exe' }
tool:
provides:
- vswhere.exe
binary-subdir: bin

14
config/pkg/tool/zig.yml Normal file
View File

@@ -0,0 +1,14 @@
zig:
type: tool
artifact:
binary: custom
tool:
provides:
- zig
- zig-cc
- zig-c++
- zig-ar
- zig-ld.lld
- zig-ranlib
- zig-objcopy
binary-subdir: zig

View File

@@ -229,7 +229,7 @@ The following path placeholders are supported in string values of the `path`, `e
| `{working_dir}` | Working directory (project root) | | `{working_dir}` | Working directory (project root) |
| `{download_path}` | Download cache directory (`downloads/`) | | `{download_path}` | Download cache directory (`downloads/`) |
| `{source_path}` | Extracted source directory (`source/`) | | `{source_path}` | Extracted source directory (`source/`) |
| `{php_sdk_path}` | Windows PHP SDK directory | | `{spc_msys2_path}` | MSYS2 root directory (`msys64/`) — Windows only |
## target Package Type ## target Package Type

View File

@@ -58,7 +58,13 @@ A single-file hook API for lightweight patches may be provided in a future relea
### Windows-only: `--with-sdk-binary-dir` and `--vs-ver` ### Windows-only: `--with-sdk-binary-dir` and `--vs-ver`
These options are no longer accepted on the command line. Instead, set the `PHP_SDK_PATH` environment variable to point to your PHP SDK binary tools directory. The Visual Studio version is now managed by the toolchain configuration. These options are no longer accepted on the command line. In v3, the `php-sdk-binary-tools` dependency has been completely removed. v3 now manages its own **MSYS2** environment to support autotools-based library builds on Windows. Run `spc doctor --install` to download and configure MSYS2 automatically.
If you need to point to a custom MSYS2 installation, set the `SPC_MSYS2_PATH` environment variable to the `msys64` directory (e.g. `C:\msys64`). Visual Studio is now auto-detected by the toolchain — no manual version flag needed.
::: warning Migrating from v2
v2 relied on `php-sdk-binary-tools` and required `--with-sdk-binary-dir` and `--vs-ver` on every build invocation. In v3 these options are gone. Remove them from all CI scripts and run `spc doctor --install` once to set up the Windows build environment.
:::
## Renamed / Deprecated Options ## Renamed / Deprecated Options

View File

@@ -223,7 +223,7 @@ openssl:
| `{working_dir}` | 工作目录(项目根目录) | | `{working_dir}` | 工作目录(项目根目录) |
| `{download_path}` | 下载缓存目录(`downloads/` | | `{download_path}` | 下载缓存目录(`downloads/` |
| `{source_path}` | 解压源码目录(`source/` | | `{source_path}` | 解压源码目录(`source/` |
| `{php_sdk_path}` | Windows PHP SDK 目录 | | `{spc_msys2_path}` | MSYS2 根目录(`msys64/`)——仅 Windows |
## target 包类型 ## target 包类型

View File

@@ -58,7 +58,13 @@ curl -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-linux-x86_64
### Windows 专有:`--with-sdk-binary-dir` 和 `--vs-ver` ### Windows 专有:`--with-sdk-binary-dir` 和 `--vs-ver`
这两个选项已不再被命令行接受。请改为设置 `PHP_SDK_PATH` 环境变量,指向你的 PHP SDK binary tools 目录。Visual Studio 版本现在由工具链配置统一管理 这两个选项已不再被命令行接受。在 v3 中,`php-sdk-binary-tools` 依赖已被完全移除。v3 现在通过管理自己的 **MSYS2** 环境来支持 Windows 上基于 autotools 的库构建。运行 `spc doctor --install` 即可自动下载并配置 MSYS2
如需指向自定义 MSYS2 安装目录,请设置 `SPC_MSYS2_PATH` 环境变量,值为 `msys64` 目录路径(例如 `C:\msys64`。Visual Studio 版本现在由工具链自动检测,无需手动指定版本号。
::: warning 从 v2 迁移
v2 依赖 `php-sdk-binary-tools`,并在每次构建时需要传入 `--with-sdk-binary-dir``--vs-ver` 参数。在 v3 中这些选项已被移除。请从所有 CI 脚本中删除这些参数,并使用 `spc doctor --install` 一次性完成 Windows 构建环境的配置。
:::
## 已重命名 / 已弃用的选项 ## 已重命名 / 已弃用的选项

View File

@@ -1,6 +1,6 @@
parameters: parameters:
reportUnmatchedIgnoredErrors: false reportUnmatchedIgnoredErrors: false
level: 4 level: 5
phpVersion: 80400 phpVersion: 80400
paths: paths:
- ./src/ - ./src/

View File

@@ -10,6 +10,7 @@ package:
- config/pkg/lib/ - config/pkg/lib/
- config/pkg/target/ - config/pkg/target/
- config/pkg/ext/ - config/pkg/ext/
- config/pkg/tool/
artifact: artifact:
config: config:
- config/artifact/ - config/artifact/

View File

@@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace Package\Artifact;
use StaticPHP\Artifact\ArtifactDownloader;
use StaticPHP\Artifact\Downloader\DownloadResult;
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
use StaticPHP\Attribute\Artifact\BinaryExtract;
use StaticPHP\Attribute\Artifact\CustomBinary;
use StaticPHP\Exception\DownloaderException;
use StaticPHP\Util\FileSystem;
use StaticPHP\Util\GlobalEnvManager;
class msys2_build_essentials
{
// MSYS subsystem packages required for autotools-based builds.
private const REQUIRED_PACKAGES = ['make', 'autoconf', 'automake', 'libtool', 'pkgconf', 'perl', 'bison', 're2c'];
#[CustomBinary('msys2-build-essentials', ['windows-x86_64'])]
public function downBinary(ArtifactDownloader $downloader): DownloadResult
{
// MSYS2 nightly self-extracting archive; running it with `-y -oTARGET` extracts to TARGET\msys64\.
$url = 'https://github.com/msys2/msys2-installer/releases/download/nightly-x86_64/msys2-base-x86_64-latest.sfx.exe';
$filename = 'msys2-base-x86_64-latest.sfx.exe';
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . $filename;
default_shell()->executeCurlDownload($url, $path, retries: $downloader->getRetry());
return DownloadResult::file(
$filename,
['url' => $url, 'version' => 'nightly'],
version: 'nightly',
extract: '{pkg_root_path}/msys2-build-essentials',
);
}
#[BinaryExtract('msys2-build-essentials', ['windows-x86_64'])]
public function extractBinary(string $source_file, string $target_path): void
{
$target_path = FileSystem::convertPath($target_path);
$source_file = FileSystem::convertPath($source_file);
// Guard: skip re-extraction if already initialized (marker written at end of this method).
$marker = "{$target_path}\\.spc-msys2-initialized";
if (file_exists($marker)) {
return;
}
if (!is_dir($target_path)) {
FileSystem::createDir($target_path);
}
cmd()->exec("\"{$source_file}\" -y -o\"{$target_path}\"");
$msys2_bin = "{$target_path}\\msys64\\usr\\bin";
if (!file_exists("{$msys2_bin}\\bash.exe")) {
throw new DownloaderException("MSYS2 extraction failed: bash.exe not found at {$msys2_bin}\\bash.exe");
}
// Add MSYS2 usr\bin to PATH so pacman.exe can load msys-2.0.dll.
GlobalEnvManager::addPathIfNotExists($msys2_bin);
GlobalEnvManager::putenv('CHERE_INVOKING=yes');
GlobalEnvManager::putenv('MSYSTEM=MSYS');
// Disable PGP signature checking: pacman-key --init requires a pseudo-TTY which is unavailable
// from PHP. Patching pacman.conf is the standard approach for CI pipelines.
$pacman_conf = "{$target_path}\\msys64\\etc\\pacman.conf";
FileSystem::replaceFileRegex($pacman_conf, '/^SigLevel\s*=.*$/m', 'SigLevel = Never');
$pacman = "{$target_path}\\msys64\\usr\\bin\\pacman.exe";
// Two-pass update as recommended by MSYS2 CI docs.
cmd()->exec("\"{$pacman}\" --noconfirm -Syuu");
cmd()->exec("\"{$pacman}\" --noconfirm -Syuu");
$pkgs = implode(' ', self::REQUIRED_PACKAGES);
cmd()->exec("\"{$pacman}\" --noconfirm -S --needed {$pkgs}");
FileSystem::writeFile($marker, date('Y-m-d H:i:s'));
}
#[AfterBinaryExtract('msys2-build-essentials', ['windows-x86_64'])]
public function afterExtract(string $target_path): void
{
$target_path = FileSystem::convertPath($target_path);
$msys2_root = "{$target_path}\\msys64";
GlobalEnvManager::putenv("SPC_MSYS2_PATH={$msys2_root}");
GlobalEnvManager::addPathIfNotExists("{$msys2_root}\\usr\\bin");
}
}

View File

@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Package\Extension;
use Package\Target\php;
use StaticPHP\Attribute\Package\BeforeStage;
use StaticPHP\Attribute\Package\Extension;
use StaticPHP\Attribute\PatchDescription;
use StaticPHP\Package\PhpExtensionPackage;
use StaticPHP\Util\FileSystem;
#[Extension('gmssl')]
class gmssl extends PhpExtensionPackage
{
#[BeforeStage('php', [php::class, 'buildconfForUnix'], 'ext-gmssl')]
#[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-gmssl')]
#[PatchDescription('Fix ext-gmssl v1.1.1 compatibility with GmSSL >= 3.1.0 where SM2_VERIFY_CTX was removed (unified into SM2_SIGN_CTX)')]
public function patchSm2VerifyCtx(): void
{
// See: https://github.com/crazywhalecc/static-php-cli/issues/1182
FileSystem::replaceFileStr(
"{$this->getSourceDir()}/gmssl.c",
'SM2_VERIFY_CTX',
'SM2_SIGN_CTX'
);
}
#[BeforeStage('php', [php::class, 'buildconfForUnix'], 'ext-gmssl')]
#[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-gmssl')]
#[PatchDescription('Fix ext-gmssl v1.1.1: pbkdf2_hmac_sm3_genkey was renamed to sm3_pbkdf2 in GmSSL >= 3.2.0')]
public function patchPbkdf2Rename(): void
{
FileSystem::replaceFileStr(
"{$this->getSourceDir()}/gmssl.c",
'pbkdf2_hmac_sm3_genkey',
'sm3_pbkdf2'
);
}
#[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-gmssl')]
#[PatchDescription('Add CHECK_LIB to config.w32 for static Windows builds')]
public function patchBeforeBuildconfWin(): bool
{
$configW32 = "{$this->getSourceDir()}/config.w32";
if (str_contains(FileSystem::readFile($configW32), 'CHECK_LIB(')) {
return false;
}
FileSystem::replaceFileStr(
$configW32,
'AC_DEFINE(',
'CHECK_LIB("gmssl.lib", "gmssl", PHP_GMSSL);' . PHP_EOL . 'AC_DEFINE('
);
return true;
}
}

View File

@@ -50,6 +50,7 @@ class simdjson extends PhpExtensionPackage
if (!str_contains((string) $extra, '-lstdc++')) { if (!str_contains((string) $extra, '-lstdc++')) {
f_putenv('SPC_COMPILER_EXTRA=' . clean_spaces($extra . ' -lstdc++')); f_putenv('SPC_COMPILER_EXTRA=' . clean_spaces($extra . ' -lstdc++'));
} }
$env['CFLAGS'] .= ' -Xclang -target-feature -Xclang +evex512'; $env['CFLAGS'] .= ' -Xclang -target-feature -Xclang +evex512';
$env['CXXFLAGS'] .= ' -Xclang -target-feature -Xclang +evex512'; $env['CXXFLAGS'] .= ' -Xclang -target-feature -Xclang +evex512';
} }

View File

@@ -32,12 +32,15 @@ class xlswriter extends PhpExtensionPackage
#[PatchDescription('Fix Windows build: apply win32 patch and add UTF-8 BOM to theme.c')] #[PatchDescription('Fix Windows build: apply win32 patch and add UTF-8 BOM to theme.c')]
public function patchBeforeMakeForWindows(): void public function patchBeforeMakeForWindows(): void
{ {
$source_dir = $this->getSourceDir();
$theme_file = "{$source_dir}/library/libxlsx/src/theme.c";
// fix windows build with openssl extension duplicate symbol bug // fix windows build with openssl extension duplicate symbol bug
SourcePatcher::patchFile('spc_fix_xlswriter_win32.patch', $this->getSourceDir()); SourcePatcher::patchFile('spc_fix_xlswriter_win32.patch', $source_dir);
$content = file_get_contents($this->getSourceDir() . '/library/libxlsxwriter/src/theme.c'); $content = file_get_contents($theme_file);
$bom = pack('CCC', 0xEF, 0xBB, 0xBF); $bom = pack('CCC', 0xEF, 0xBB, 0xBF);
if (!str_starts_with($content, $bom)) { if (!str_starts_with($content, $bom)) {
file_put_contents($this->getSourceDir() . '/library/libxlsxwriter/src/theme.c', $bom . $content); file_put_contents($theme_file, $bom . $content);
} }
} }
} }

View File

@@ -27,10 +27,7 @@ class brotli
{ {
UnixCMakeExecutor::create($lib) UnixCMakeExecutor::create($lib)
->setBuildDir($lib->getSourceDir() . '/build-dir') ->setBuildDir($lib->getSourceDir() . '/build-dir')
->addConfigureArgs( ->addConfigureArgs("-DSHARE_INSTALL_PREFIX={$lib->getBuildRootPath()}")
"-DSHARE_INSTALL_PREFIX={$lib->getBuildRootPath()}",
'-DBROTLI_DISABLE_TESTS=ON',
)
->build(); ->build();
// Patch pkg-config files // Patch pkg-config files

View File

@@ -17,9 +17,7 @@ class bzip2
#[PatchBeforeBuild] #[PatchBeforeBuild]
public function patchBeforeBuild(LibraryPackage $lib): void public function patchBeforeBuild(LibraryPackage $lib): void
{ {
// Makefile pins -O2 -fPIC; inject SPC_DEFAULT_CFLAGS FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS=-Wall', 'CFLAGS=-fPIC -Wall');
$extra = deduplicate_flags(trim((string) getenv('SPC_DEFAULT_CFLAGS')) . ' -fPIC -Wall');
FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS=-Wall', "CFLAGS={$extra}");
} }
#[BuildFor('Windows')] #[BuildFor('Windows')]

View File

@@ -18,11 +18,9 @@ class fastlz
{ {
$cc = getenv('CC') ?: 'cc'; $cc = getenv('CC') ?: 'cc';
$ar = getenv('AR') ?: 'ar'; $ar = getenv('AR') ?: 'ar';
$extra = trim((string) getenv('SPC_DEFAULT_CFLAGS'));
$extra = $extra !== '' ? $extra . ' -fPIC' : '-O3 -fPIC';
shell()->cd($lib->getSourceDir())->initializeEnv($lib) shell()->cd($lib->getSourceDir())->initializeEnv($lib)
->exec("{$cc} -c {$extra} fastlz.c -o fastlz.o") ->exec("{$cc} -c -O3 -fPIC fastlz.c -o fastlz.o")
->exec("{$ar} rcs libfastlz.a fastlz.o"); ->exec("{$ar} rcs libfastlz.a fastlz.o");
// Copy header file // Copy header file

View File

@@ -22,6 +22,7 @@ class gettext_win
{ {
$ver = WindowsUtil::findVisualStudio(); $ver = WindowsUtil::findVisualStudio();
$vs_ver_dir = match ($ver['major_version']) { $vs_ver_dir = match ($ver['major_version']) {
'18', // VS 2026 reuses the VS2022 (MSVC17) solution, which msbuild builds via forward compatibility.
'17' => '\MSVC17', '17' => '\MSVC17',
'16' => '\MSVC16', '16' => '\MSVC16',
default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"), default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"),
@@ -44,7 +45,9 @@ class gettext_win
{ {
$vs_ver_dir = ApplicationContext::get('gettext_win_vs_ver_dir'); $vs_ver_dir = ApplicationContext::get('gettext_win_vs_ver_dir');
cmd()->cd("{$lib->getSourceDir()}{$vs_ver_dir}\\libintl_static") cmd()->cd("{$lib->getSourceDir()}{$vs_ver_dir}\\libintl_static")
->exec('msbuild libintl_static.vcxproj /t:Rebuild /p:Configuration=Release /p:Platform=x64 /p:WindowsTargetPlatformVersion=10.0'); // WholeProgramOptimization (/GL) emits LTCG objects that frankenphp's lld-link cannot
// read ("is not a native COFF file"); disable it so the .lib stays plain COFF.
->exec('msbuild libintl_static.vcxproj /t:Rebuild /p:Configuration=Release /p:Platform=x64 /p:WindowsTargetPlatformVersion=10.0 /p:WholeProgramOptimization=false');
FileSystem::createDir($lib->getLibDir()); FileSystem::createDir($lib->getLibDir());
FileSystem::createDir($lib->getIncludeDir()); FileSystem::createDir($lib->getIncludeDir());
// libintl_a.lib is the static library output; copy as libintl.lib for linker compatibility // libintl_a.lib is the static library output; copy as libintl.lib for linker compatibility

View File

@@ -8,7 +8,6 @@ use StaticPHP\Attribute\Package\BuildFor;
use StaticPHP\Attribute\Package\Library; use StaticPHP\Attribute\Package\Library;
use StaticPHP\Package\LibraryPackage; use StaticPHP\Package\LibraryPackage;
use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor;
use StaticPHP\Runtime\SystemTarget;
#[Library('gmp')] #[Library('gmp')]
class gmp class gmp
@@ -17,12 +16,10 @@ class gmp
#[BuildFor('Darwin')] #[BuildFor('Darwin')]
public function build(LibraryPackage $lib): void public function build(LibraryPackage $lib): void
{ {
$make = UnixAutoconfExecutor::create($lib)->appendEnv(['CFLAGS' => '-std=c17']); UnixAutoconfExecutor::create($lib)
if (SystemTarget::getTargetArch() === 'x86_64' && SystemTarget::getTargetOS() === 'Linux') { ->appendEnv(['CFLAGS' => '-std=c17'])
$libc = SystemTarget::getLibc() === 'glibc' ? 'gnu' : 'musl'; ->configure('--enable-fat')
$make->addConfigureArgs(["--host=x86_64-pc-linux-{$libc}"]); ->make();
}
$make->configure('--enable-fat')->make();
$lib->patchPkgconfPrefix(['gmp.pc']); $lib->patchPkgconfPrefix(['gmp.pc']);
} }
} }

View File

@@ -18,7 +18,9 @@ class gmssl
#[BuildFor('Darwin')] #[BuildFor('Darwin')]
public function build(LibraryPackage $lib): void public function build(LibraryPackage $lib): void
{ {
UnixCMakeExecutor::create($lib)->build(); UnixCMakeExecutor::create($lib)
->addConfigureArgs('-DENABLE_SM2_PRIVATE_KEY_EXPORT=ON')
->build();
} }
#[BuildFor('Windows')] #[BuildFor('Windows')]
@@ -33,6 +35,7 @@ class gmssl
'-G "NMake Makefiles"', '-G "NMake Makefiles"',
'-DWIN32=ON', '-DWIN32=ON',
'-DBUILD_SHARED_LIBS=OFF', '-DBUILD_SHARED_LIBS=OFF',
'-DENABLE_SM2_PRIVATE_KEY_EXPORT=ON',
'-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_BUILD_TYPE=Release',
'-DCMAKE_C_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"', '-DCMAKE_C_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"',
'-DCMAKE_CXX_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"', '-DCMAKE_CXX_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"',
@@ -42,13 +45,13 @@ class gmssl
->toStep(1) ->toStep(1)
->build(); ->build();
// fix cmake_install.cmake install prefix (GmSSL overrides it internally) cmd()->cd($buildDir)->exec('nmake gmssl XCFLAGS=/MT');
$installCmake = "{$buildDir}\\cmake_install.cmake";
FileSystem::writeFile(
$installCmake,
'set(CMAKE_INSTALL_PREFIX "' . str_replace('\\', '/', $lib->getBuildRootPath()) . '")' . PHP_EOL . FileSystem::readFile($installCmake)
);
cmd()->cd($buildDir)->exec('nmake install XCFLAGS=/MT'); $libPath = "{$lib->getBuildRootPath()}/lib";
$incPath = "{$lib->getBuildRootPath()}/include/gmssl";
FileSystem::createDir($libPath);
FileSystem::createDir($incPath);
FileSystem::copy("{$buildDir}\\bin\\gmssl.lib", "{$libPath}/gmssl.lib");
FileSystem::copyDir("{$lib->getSourceDir()}\\include\\gmssl", $incPath);
} }
} }

View File

@@ -24,12 +24,9 @@ class icu
#[BuildFor('Linux')] #[BuildFor('Linux')]
public function buildLinux(LibraryPackage $lib, ToolchainInterface $toolchain, PackageBuilder $builder): void public function buildLinux(LibraryPackage $lib, ToolchainInterface $toolchain, PackageBuilder $builder): void
{ {
// runConfigureICU bakes CXXFLAGS/LDFLAGS, apply user flags too
$userCxxFlags = trim((string) getenv('SPC_DEFAULT_CXXFLAGS'));
$userLdFlags = trim((string) getenv('SPC_DEFAULT_LDFLAGS'));
$cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -DPIC -fPIC"'; $cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -DPIC -fPIC"';
$cxxflags = "CXXFLAGS=\"-std=c++17 -DPIC -fPIC -fno-ident {$userCxxFlags}\""; $cxxflags = 'CXXFLAGS="-std=c++17 -DPIC -fPIC -fno-ident"';
$ldflags = $toolchain->isStatic() ? "LDFLAGS=\"-static {$userLdFlags}\"" : "LDFLAGS=\"{$userLdFlags}\""; $ldflags = $toolchain->isStatic() ? 'LDFLAGS="-static"' : '';
shell()->cd($lib->getSourceDir() . '/source')->initializeEnv($lib) shell()->cd($lib->getSourceDir() . '/source')->initializeEnv($lib)
->exec( ->exec(
"{$cppflags} {$cxxflags} {$ldflags} " . "{$cppflags} {$cxxflags} {$ldflags} " .

View File

@@ -45,9 +45,6 @@ class imagemagick
// implicit --with-gcc-arch // implicit --with-gcc-arch
// bleeds host cpu features into built binaries // bleeds host cpu features into built binaries
'--without-gcc-arch', '--without-gcc-arch',
'--disable-docs',
'--without-utilities',
'--disable-dpc',
); );
// special: linux-static target needs `-static` // special: linux-static target needs `-static`

View File

@@ -17,9 +17,7 @@ class jbig
#[PatchBeforeBuild] #[PatchBeforeBuild]
public function patchBeforeBuild(LibraryPackage $lib): void public function patchBeforeBuild(LibraryPackage $lib): void
{ {
$extra = trim((string) getenv('SPC_DEFAULT_CFLAGS')); FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS = -O2 -W -Wno-unused-result', 'CFLAGS = -O2 -W -Wno-unused-result -fPIC');
$cflags = ($extra !== '' ? $extra : '-O2') . ' -W -Wno-unused-result -fPIC';
FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS = -O2 -W -Wno-unused-result', "CFLAGS = {$cflags}");
} }
#[BuildFor('Darwin')] #[BuildFor('Darwin')]

View File

@@ -35,7 +35,6 @@ class ldap
->optionalPackage('libsodium', '--with-argon2=libsodium', '--enable-argon2=no') ->optionalPackage('libsodium', '--with-argon2=libsodium', '--enable-argon2=no')
->addConfigureArgs( ->addConfigureArgs(
'--disable-slapd', '--disable-slapd',
'--disable-debug',
'--without-systemd', '--without-systemd',
'--without-cyrus-sasl', '--without-cyrus-sasl',
'ac_cv_func_pthread_kill_other_threads_np=no' 'ac_cv_func_pthread_kill_other_threads_np=no'

View File

@@ -9,10 +9,8 @@ use StaticPHP\Attribute\Package\Library;
use StaticPHP\Package\LibraryPackage; use StaticPHP\Package\LibraryPackage;
use StaticPHP\Runtime\Executor\UnixCMakeExecutor; use StaticPHP\Runtime\Executor\UnixCMakeExecutor;
use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; use StaticPHP\Runtime\Executor\WindowsCMakeExecutor;
use StaticPHP\Runtime\SystemTarget;
use StaticPHP\Toolchain\Interface\ToolchainInterface; use StaticPHP\Toolchain\Interface\ToolchainInterface;
use StaticPHP\Toolchain\ZigToolchain; use StaticPHP\Toolchain\ZigToolchain;
use StaticPHP\Util\System\UnixUtil;
#[Library('libaom')] #[Library('libaom')]
class libaom extends LibraryPackage class libaom extends LibraryPackage
@@ -41,23 +39,9 @@ class libaom extends LibraryPackage
$new = trim($extra . ' -D_GNU_SOURCE'); $new = trim($extra . ' -D_GNU_SOURCE');
f_putenv("SPC_COMPILER_EXTRA={$new}"); f_putenv("SPC_COMPILER_EXTRA={$new}");
} }
$targetCpu = SystemTarget::getTargetArch();
if (str_starts_with($targetCpu, 'aarch')) {
$targetCpu = str_replace('aarch', 'arm', $targetCpu);
}
if (!UnixUtil::findCommand('nasm') && !UnixUtil::findCommand('yasm')) {
$targetCpu = 'generic';
}
UnixCMakeExecutor::create($this) UnixCMakeExecutor::create($this)
->setBuildDir("{$this->getSourceDir()}/builddir") ->setBuildDir("{$this->getSourceDir()}/builddir")
->addConfigureArgs( ->addConfigureArgs('-DAOM_TARGET_CPU=generic')
"-DAOM_TARGET_CPU={$targetCpu}",
'-DCONFIG_RUNTIME_CPU_DETECT=1',
'-DENABLE_EXAMPLES=OFF',
'-DENABLE_TESTS=OFF',
'-DENABLE_TOOLS=OFF',
'-DENABLE_DOCS=OFF',
)
->build(); ->build();
f_putenv("SPC_COMPILER_EXTRA={$extra}"); f_putenv("SPC_COMPILER_EXTRA={$extra}");
$this->patchPkgconfPrefix(['aom.pc']); $this->patchPkgconfPrefix(['aom.pc']);

View File

@@ -35,12 +35,7 @@ class libavif
->optionalPackage('libjpeg', '-DAVIF_JPEG=SYSTEM', '-DAVIF_JPEG=OFF') ->optionalPackage('libjpeg', '-DAVIF_JPEG=SYSTEM', '-DAVIF_JPEG=OFF')
->optionalPackage('libxml2', '-DAVIF_LIBXML2=SYSTEM', '-DAVIF_LIBXML2=OFF') ->optionalPackage('libxml2', '-DAVIF_LIBXML2=SYSTEM', '-DAVIF_LIBXML2=OFF')
->optionalPackage('libpng', '-DAVIF_LIBPNG=SYSTEM', '-DAVIF_LIBPNG=OFF') ->optionalPackage('libpng', '-DAVIF_LIBPNG=SYSTEM', '-DAVIF_LIBPNG=OFF')
->addConfigureArgs( ->addConfigureArgs('-DAVIF_LIBYUV=OFF')
'-DAVIF_LIBYUV=OFF',
'-DAVIF_BUILD_APPS=OFF',
'-DAVIF_BUILD_TESTS=OFF',
'-DAVIF_GTEST=OFF',
)
->build(); ->build();
// patch pkgconfig // patch pkgconfig
$lib->patchPkgconfPrefix(['libavif.pc']); $lib->patchPkgconfPrefix(['libavif.pc']);
@@ -54,7 +49,7 @@ class libavif
'-DAVIF_BUILD_APPS=OFF', '-DAVIF_BUILD_APPS=OFF',
'-DAVIF_BUILD_TESTS=OFF', '-DAVIF_BUILD_TESTS=OFF',
'-DAVIF_LIBYUV=OFF', '-DAVIF_LIBYUV=OFF',
'-DAVIF_GTEST=OFF', '-DAVIF_ENABLE_GTEST=OFF',
) )
->build(); ->build();
} }

View File

@@ -20,6 +20,7 @@ class libde265 extends LibraryPackage
->addConfigureArgs( ->addConfigureArgs(
'-DENABLE_SDL=OFF', '-DENABLE_SDL=OFF',
'-DENABLE_DECODER=OFF', '-DENABLE_DECODER=OFF',
'-DENABLE_SIMD=OFF',
'-DHAVE_NEON=OFF', '-DHAVE_NEON=OFF',
) )
->build(); ->build();

View File

@@ -16,7 +16,7 @@ class libffi extends LibraryPackage
public function buildLinux(): void public function buildLinux(): void
{ {
UnixAutoconfExecutor::create($this) UnixAutoconfExecutor::create($this)
->configure('--disable-docs')->make(); ->configure()->make();
if (is_file("{$this->getBuildRootPath()}/lib64/libffi.a")) { if (is_file("{$this->getBuildRootPath()}/lib64/libffi.a")) {
copy("{$this->getBuildRootPath()}/lib64/libffi.a", "{$this->getBuildRootPath()}/lib/libffi.a"); copy("{$this->getBuildRootPath()}/lib64/libffi.a", "{$this->getBuildRootPath()}/lib/libffi.a");
@@ -33,7 +33,6 @@ class libffi extends LibraryPackage
->configure( ->configure(
"--host={$arch}-apple-darwin", "--host={$arch}-apple-darwin",
"--target={$arch}-apple-darwin", "--target={$arch}-apple-darwin",
'--disable-docs',
) )
->make(); ->make();
$this->patchPkgconfPrefix(['libffi.pc']); $this->patchPkgconfPrefix(['libffi.pc']);

View File

@@ -21,6 +21,7 @@ class libffi_win
{ {
$ver = WindowsUtil::findVisualStudio(); $ver = WindowsUtil::findVisualStudio();
$vs_ver_dir = match ($ver['major_version']) { $vs_ver_dir = match ($ver['major_version']) {
'18', // VS 2026 reuses the vs17 solution, which msbuild builds via forward compatibility.
'17' => '\win32\vs17_x64', '17' => '\win32\vs17_x64',
'16' => '\win32\vs16_x64', '16' => '\win32\vs16_x64',
default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported!"), default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported!"),
@@ -33,7 +34,9 @@ class libffi_win
{ {
$vs_ver_dir = ApplicationContext::get('libffi_win_vs_ver_dir'); $vs_ver_dir = ApplicationContext::get('libffi_win_vs_ver_dir');
cmd()->cd("{$lib->getSourceDir()}{$vs_ver_dir}") cmd()->cd("{$lib->getSourceDir()}{$vs_ver_dir}")
->exec('msbuild libffi-msvc.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64'); // WholeProgramOptimization (/GL) emits LTCG objects that frankenphp's lld-link cannot
// read ("is not a native COFF file"); disable it so the .lib stays plain COFF.
->exec('msbuild libffi-msvc.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64 /p:WholeProgramOptimization=false');
FileSystem::createDir($lib->getLibDir()); FileSystem::createDir($lib->getLibDir());
FileSystem::createDir($lib->getIncludeDir()); FileSystem::createDir($lib->getIncludeDir());

View File

@@ -24,17 +24,6 @@ class libheif
'list(APPEND REQUIRES_PRIVATE "libbrotlidec")' . "\n" . ' list(APPEND REQUIRES_PRIVATE "libbrotlienc")' 'list(APPEND REQUIRES_PRIVATE "libbrotlidec")' . "\n" . ' list(APPEND REQUIRES_PRIVATE "libbrotlienc")'
); );
} }
// libheif 1.22+ ships a C-incompatible header: `struct heif_bad_pixel`
$heif_properties = $lib->getSourceDir() . '/libheif/api/libheif/heif_properties.h';
if (file_exists($heif_properties)
&& str_contains(file_get_contents($heif_properties), 'struct heif_bad_pixel { uint32_t row; uint32_t column; };')
) {
FileSystem::replaceFileStr(
$heif_properties,
'struct heif_bad_pixel { uint32_t row; uint32_t column; };',
'typedef struct heif_bad_pixel { uint32_t row; uint32_t column; } heif_bad_pixel;'
);
}
} }
#[BuildFor('Darwin')] #[BuildFor('Darwin')]
@@ -47,7 +36,6 @@ class libheif
'-DWITH_EXAMPLES=OFF', '-DWITH_EXAMPLES=OFF',
'-DWITH_GDK_PIXBUF=OFF', '-DWITH_GDK_PIXBUF=OFF',
'-DBUILD_TESTING=OFF', '-DBUILD_TESTING=OFF',
'-DBUILD_DOCUMENTATION=OFF',
'-DWITH_LIBSHARPYUV=ON', // optional: libwebp '-DWITH_LIBSHARPYUV=ON', // optional: libwebp
'-DENABLE_PLUGIN_LOADING=OFF', '-DENABLE_PLUGIN_LOADING=OFF',
) )

View File

@@ -21,6 +21,7 @@ class libiconv_win
{ {
$ver = WindowsUtil::findVisualStudio(); $ver = WindowsUtil::findVisualStudio();
$vs_ver_dir = match ($ver['major_version']) { $vs_ver_dir = match ($ver['major_version']) {
'18', // VS 2026 reuses the VS2022 (MSVC17) solution, which msbuild builds via forward compatibility.
'17' => '\MSVC17', '17' => '\MSVC17',
'16' => '\MSVC16', '16' => '\MSVC16',
default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"), default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"),
@@ -33,7 +34,9 @@ class libiconv_win
{ {
$vs_ver_dir = ApplicationContext::get('vs_ver_dir'); $vs_ver_dir = ApplicationContext::get('vs_ver_dir');
cmd()->cd("{$lib->getSourceDir()}{$vs_ver_dir}") cmd()->cd("{$lib->getSourceDir()}{$vs_ver_dir}")
->exec('msbuild libiconv.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64'); // WholeProgramOptimization (/GL) emits LTCG objects that frankenphp's lld-link cannot
// read ("is not a native COFF file"); disable it so the .lib stays plain COFF.
->exec('msbuild libiconv.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64 /p:WholeProgramOptimization=false');
FileSystem::createDir($lib->getLibDir()); FileSystem::createDir($lib->getLibDir());
FileSystem::createDir($lib->getIncludeDir()); FileSystem::createDir($lib->getIncludeDir());
FileSystem::copy("{$lib->getSourceDir()}{$vs_ver_dir}\\x64\\lib\\libiconv.lib", "{$lib->getLibDir()}\\libiconv.lib"); FileSystem::copy("{$lib->getSourceDir()}{$vs_ver_dir}\\x64\\lib\\libiconv.lib", "{$lib->getLibDir()}\\libiconv.lib");

View File

@@ -25,7 +25,6 @@ class libjxl extends LibraryPackage
'-DJPEGXL_ENABLE_MANPAGES=OFF', '-DJPEGXL_ENABLE_MANPAGES=OFF',
'-DJPEGXL_ENABLE_BENCHMARK=OFF', '-DJPEGXL_ENABLE_BENCHMARK=OFF',
'-DJPEGXL_ENABLE_PLUGINS=OFF', '-DJPEGXL_ENABLE_PLUGINS=OFF',
'-DJPEGXL_ENABLE_DOXYGEN=OFF',
'-DJPEGXL_ENABLE_SJPEG=ON', '-DJPEGXL_ENABLE_SJPEG=ON',
'-DJPEGXL_ENABLE_JNI=OFF', '-DJPEGXL_ENABLE_JNI=OFF',
'-DJPEGXL_ENABLE_TRANSCODE_JPEG=ON', '-DJPEGXL_ENABLE_TRANSCODE_JPEG=ON',

View File

@@ -12,25 +12,17 @@ use StaticPHP\Runtime\Executor\UnixCMakeExecutor;
#[Library('libmemcached')] #[Library('libmemcached')]
class libmemcached extends LibraryPackage class libmemcached extends LibraryPackage
{ {
private const array DISABLE_ARGS = [
'-DBUILD_TESTING=OFF',
'-DBUILD_DOCS=OFF',
'-DENABLE_MEMASLAP=OFF',
];
#[BuildFor('Linux')] #[BuildFor('Linux')]
public function buildLinux(): void public function buildLinux(): void
{ {
UnixCMakeExecutor::create($this) UnixCMakeExecutor::create($this)
->addConfigureArgs('-DCMAKE_INSTALL_RPATH=""', ...self::DISABLE_ARGS) ->addConfigureArgs('-DCMAKE_INSTALL_RPATH=""')
->build(); ->build();
} }
#[BuildFor('Darwin')] #[BuildFor('Darwin')]
public function buildDarwin(): void public function buildDarwin(): void
{ {
UnixCMakeExecutor::create($this) UnixCMakeExecutor::create($this)->build();
->addConfigureArgs(...self::DISABLE_ARGS)
->build();
} }
} }

View File

@@ -20,8 +20,6 @@ class libpng
{ {
$args = [ $args = [
'--enable-hardware-optimizations', '--enable-hardware-optimizations',
'--disable-tests',
'--disable-tools',
"--with-zlib-prefix={$lib->getBuildRootPath()}", "--with-zlib-prefix={$lib->getBuildRootPath()}",
]; ];

View File

@@ -13,29 +13,17 @@ use StaticPHP\Runtime\Executor\WindowsCMakeExecutor;
#[Library('librabbitmq')] #[Library('librabbitmq')]
class librabbitmq extends LibraryPackage class librabbitmq extends LibraryPackage
{ {
private const array DISABLE_ARGS = [
'-DBUILD_EXAMPLES=OFF',
'-DBUILD_TESTING=OFF',
'-DBUILD_TOOLS=OFF',
'-DBUILD_TOOLS_DOCS=OFF',
'-DBUILD_API_DOCS=OFF',
];
#[BuildFor('Darwin')] #[BuildFor('Darwin')]
#[BuildFor('Linux')] #[BuildFor('Linux')]
public function buildUnix(): void public function buildUnix(): void
{ {
UnixCMakeExecutor::create($this) UnixCMakeExecutor::create($this)->addConfigureArgs('-DBUILD_STATIC_LIBS=ON')->build();
->addConfigureArgs('-DBUILD_STATIC_LIBS=ON', ...self::DISABLE_ARGS)
->build();
} }
#[BuildFor('Windows')] #[BuildFor('Windows')]
public function buildWin(): void public function buildWin(): void
{ {
WindowsCMakeExecutor::create($this) WindowsCMakeExecutor::create($this)->build();
->addConfigureArgs(...self::DISABLE_ARGS)
->build();
rename("{$this->getLibDir()}\\librabbitmq.4.lib", "{$this->getLibDir()}\\rabbitmq.4.lib"); rename("{$this->getLibDir()}\\librabbitmq.4.lib", "{$this->getLibDir()}\\rabbitmq.4.lib");
} }
} }

View File

@@ -42,13 +42,16 @@ class libsodium
{ {
$ver = WindowsUtil::findVisualStudio(); $ver = WindowsUtil::findVisualStudio();
$vs_ver_dir = match ($ver['major_version']) { $vs_ver_dir = match ($ver['major_version']) {
'18', // VS 2026 reuses the vs2022 solution, which msbuild builds via forward compatibility.
'17' => '\vs2022', '17' => '\vs2022',
'16' => '\vs2019', '16' => '\vs2019',
default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"), default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"),
}; };
cmd()->cd("{$lib->getSourceDir()}\\builds\\msvc{$vs_ver_dir}") cmd()->cd("{$lib->getSourceDir()}\\builds\\msvc{$vs_ver_dir}")
->exec('msbuild libsodium.sln /t:Rebuild /p:Configuration=StaticRelease /p:Platform=x64 /p:PreprocessorDefinitions="SODIUM_STATIC=1"'); // WholeProgramOptimization (/GL) emits LTCG objects that frankenphp's lld-link cannot
// read ("is not a native COFF file"); disable it so the .lib stays plain COFF.
->exec('msbuild libsodium.sln /t:Rebuild /p:Configuration=StaticRelease /p:Platform=x64 /p:WholeProgramOptimization=false /p:PreprocessorDefinitions="SODIUM_STATIC=1"');
FileSystem::createDir($lib->getLibDir()); FileSystem::createDir($lib->getLibDir());
FileSystem::createDir($lib->getIncludeDir()); FileSystem::createDir($lib->getIncludeDir());

View File

@@ -18,6 +18,7 @@ class libssh2
{ {
WindowsCMakeExecutor::create($lib) WindowsCMakeExecutor::create($lib)
->addConfigureArgs( ->addConfigureArgs(
'-DCRYPTO_BACKEND=WinCNG',
'-DENABLE_ZLIB_COMPRESSION=ON', '-DENABLE_ZLIB_COMPRESSION=ON',
'-DBUILD_TESTING=OFF' '-DBUILD_TESTING=OFF'
) )

View File

@@ -41,9 +41,6 @@ class libtiff
'--disable-libdeflate', '--disable-libdeflate',
'--disable-tools', '--disable-tools',
'--disable-contrib', '--disable-contrib',
'--disable-tests',
'--disable-docs',
'--disable-sphinx',
'--disable-cxx', '--disable-cxx',
'--without-x', '--without-x',
) )

View File

@@ -13,18 +13,12 @@ use StaticPHP\Runtime\Executor\WindowsCMakeExecutor;
#[Library('libuv')] #[Library('libuv')]
class libuv class libuv
{ {
private const array DISABLE_ARGS = [
'-DLIBUV_BUILD_SHARED=OFF',
'-DLIBUV_BUILD_TESTS=OFF',
'-DLIBUV_BUILD_BENCH=OFF',
];
#[BuildFor('Darwin')] #[BuildFor('Darwin')]
#[BuildFor('Linux')] #[BuildFor('Linux')]
public function buildUnix(LibraryPackage $lib): void public function buildUnix(LibraryPackage $lib): void
{ {
UnixCMakeExecutor::create($lib) UnixCMakeExecutor::create($lib)
->addConfigureArgs(...self::DISABLE_ARGS) ->addConfigureArgs('-DLIBUV_BUILD_SHARED=OFF')
->build(); ->build();
// patch pkgconfig // patch pkgconfig
$lib->patchPkgconfPrefix(['libuv-static.pc']); $lib->patchPkgconfPrefix(['libuv-static.pc']);
@@ -34,7 +28,7 @@ class libuv
public function buildWindows(LibraryPackage $lib): void public function buildWindows(LibraryPackage $lib): void
{ {
WindowsCMakeExecutor::create($lib) WindowsCMakeExecutor::create($lib)
->addConfigureArgs(...self::DISABLE_ARGS) ->addConfigureArgs('-DLIBUV_BUILD_SHARED=OFF')
->build(); ->build();
} }
} }

View File

@@ -34,7 +34,6 @@ class libxslt
'--without-crypto', '--without-crypto',
'--without-debug', '--without-debug',
'--without-debugger', '--without-debugger',
'--without-profiler',
"--with-libxml-prefix={$lib->getBuildRootPath()}", "--with-libxml-prefix={$lib->getBuildRootPath()}",
); );
if (getenv('SPC_LD_LIBRARY_PATH') && getenv('SPC_LIBRARY_PATH')) { if (getenv('SPC_LD_LIBRARY_PATH') && getenv('SPC_LIBRARY_PATH')) {

View File

@@ -21,7 +21,6 @@ class mimalloc
->addConfigureArgs( ->addConfigureArgs(
'-DMI_BUILD_SHARED=OFF', '-DMI_BUILD_SHARED=OFF',
'-DMI_BUILD_OBJECT=OFF', '-DMI_BUILD_OBJECT=OFF',
'-DMI_BUILD_TESTS=OFF',
'-DMI_INSTALL_TOPLEVEL=ON', '-DMI_INSTALL_TOPLEVEL=ON',
); );
if (SystemTarget::getLibc() === 'musl') { if (SystemTarget::getLibc() === 'musl') {

View File

@@ -21,6 +21,7 @@ class mpir
{ {
$ver = WindowsUtil::findVisualStudio(); $ver = WindowsUtil::findVisualStudio();
$vs_ver_dir = match ($ver['major_version']) { $vs_ver_dir = match ($ver['major_version']) {
'18', // VS 2026 reuses the build.vc17 solution, which msbuild builds via forward compatibility.
'17' => '\build.vc17', '17' => '\build.vc17',
'16' => '\build.vc16', '16' => '\build.vc16',
default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"), default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"),

View File

@@ -6,8 +6,6 @@ namespace Package\Library;
use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\BuildFor;
use StaticPHP\Attribute\Package\Library; use StaticPHP\Attribute\Package\Library;
use StaticPHP\Attribute\Package\PatchBeforeBuild;
use StaticPHP\Attribute\PatchDescription;
use StaticPHP\Package\LibraryPackage; use StaticPHP\Package\LibraryPackage;
use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor;
use StaticPHP\Toolchain\Interface\ToolchainInterface; use StaticPHP\Toolchain\Interface\ToolchainInterface;
@@ -18,24 +16,6 @@ use StaticPHP\Util\FileSystem;
#[Library('ncursesw')] #[Library('ncursesw')]
class ncurses class ncurses
{ {
#[PatchBeforeBuild]
#[PatchDescription('Filter clang/zig "N warning(s) generated." line out of MKlib_gen.sh preprocessor pipe')]
public function patchBeforeBuild(LibraryPackage $lib): void
{
// MKlib_gen.sh feeds the C preprocessor's stdout through a sed/awk
// pipeline into lib_gen.c. zig-cc/clang emits "N warning(s) generated."
// on stdout (not stderr), and that line ends up as invalid C in the
// generated source. Filter it out of the pipe before sed sees it.
$mklibGen = $lib->getSourceDir() . '/ncurses/base/MKlib_gen.sh';
if (is_file($mklibGen) && !str_contains((string) file_get_contents($mklibGen), "| grep -v ' generated")) {
FileSystem::replaceFileStr(
$mklibGen,
'$preprocessor $TMP 2>/dev/null \\',
"\$preprocessor \$TMP 2>/dev/null \\\n| grep -v ' generated\\.\$' \\",
);
}
}
#[BuildFor('Darwin')] #[BuildFor('Darwin')]
#[BuildFor('Linux')] #[BuildFor('Linux')]
public function build(LibraryPackage $package, ToolchainInterface $toolchain): void public function build(LibraryPackage $package, ToolchainInterface $toolchain): void

View File

@@ -24,7 +24,6 @@ class nghttp3
'-DBUILD_SHARED_LIBS=OFF', '-DBUILD_SHARED_LIBS=OFF',
'-DENABLE_STATIC_CRT=ON', '-DENABLE_STATIC_CRT=ON',
'-DENABLE_LIB_ONLY=ON', '-DENABLE_LIB_ONLY=ON',
'-DBUILD_TESTING=OFF',
) )
->build(); ->build();
} }

View File

@@ -25,7 +25,6 @@ class ngtcp2
'-DENABLE_STATIC_CRT=ON', '-DENABLE_STATIC_CRT=ON',
'-DENABLE_LIB_ONLY=ON', '-DENABLE_LIB_ONLY=ON',
'-DENABLE_OPENSSL=OFF', '-DENABLE_OPENSSL=OFF',
'-DBUILD_TESTING=OFF',
) )
->build(); ->build();
} }

View File

@@ -24,7 +24,7 @@ class openssl
{ {
if (SystemTarget::getTargetOS() === 'Windows') { if (SystemTarget::getTargetOS() === 'Windows') {
global $argv; global $argv;
$perl_path_native = PKG_ROOT_PATH . '\strawberry-perl-' . arch2gnu(php_uname('m')) . '-win\perl\bin\perl.exe'; $perl_path_native = PKG_ROOT_PATH . '\strawberry-perl\perl\bin\perl.exe';
$perl = file_exists($perl_path_native) ? ($perl_path_native) : WindowsUtil::findCommand('perl.exe'); $perl = file_exists($perl_path_native) ? ($perl_path_native) : WindowsUtil::findCommand('perl.exe');
if ($perl === null) { if ($perl === null) {
throw new EnvironmentException( throw new EnvironmentException(
@@ -111,12 +111,6 @@ class openssl
$openssl_dir ??= LinuxUtil::getOSRelease()['dist'] === 'redhat' ? '/etc/pki/tls' : '/etc/ssl'; $openssl_dir ??= LinuxUtil::getOSRelease()['dist'] === 'redhat' ? '/etc/pki/tls' : '/etc/ssl';
$ex_lib = trim($ex_lib); $ex_lib = trim($ex_lib);
// anything we want included (PGO -fprofile-*, LTO, custom hardening)
// has to be appended on the command line *after* the target name.
$userCFlags = trim((string) getenv('SPC_DEFAULT_CFLAGS'));
$userLdFlags = trim((string) getenv('SPC_DEFAULT_LDFLAGS'));
$userExtra = trim($userCFlags . ' ' . $userLdFlags);
shell()->cd($lib->getSourceDir())->initializeEnv($lib) shell()->cd($lib->getSourceDir())->initializeEnv($lib)
->exec( ->exec(
"{$env} ./Configure no-shared zlib " . "{$env} ./Configure no-shared zlib " .
@@ -127,8 +121,7 @@ class openssl
'enable-pie ' . 'enable-pie ' .
'no-legacy ' . 'no-legacy ' .
'no-tests ' . 'no-tests ' .
"linux-{$arch} " . "linux-{$arch}"
$userExtra
) )
->exec('make clean') ->exec('make clean')
->exec("make -j{$lib->getBuilder()->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"") ->exec("make -j{$lib->getBuilder()->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")

View File

@@ -20,11 +20,6 @@ class qdbm
{ {
$ac = UnixAutoconfExecutor::create($lib)->configure(); $ac = UnixAutoconfExecutor::create($lib)->configure();
FileSystem::replaceFileRegex($lib->getSourceDir() . '/Makefile', '/MYLIBS = libqdbm.a.*/m', 'MYLIBS = libqdbm.a'); FileSystem::replaceFileRegex($lib->getSourceDir() . '/Makefile', '/MYLIBS = libqdbm.a.*/m', 'MYLIBS = libqdbm.a');
// Makefile pins -O3, replace with SPC_DEFAULT_CFLAGS
$extra = trim((string) getenv('SPC_DEFAULT_CFLAGS'));
if ($extra !== '') {
FileSystem::replaceFileRegex($lib->getSourceDir() . '/Makefile', '/^CFLAGS = .*$/m', "CFLAGS = -Wall {$extra}");
}
$ac->make(SystemTarget::getTargetOS() === 'Darwin' ? 'mac' : ''); $ac->make(SystemTarget::getTargetOS() === 'Darwin' ? 'mac' : '');
$lib->patchPkgconfPrefix(['qdbm.pc']); $lib->patchPkgconfPrefix(['qdbm.pc']);
} }

View File

@@ -20,7 +20,6 @@ class readline
->configure( ->configure(
'--with-curses', '--with-curses',
'--enable-multibyte=yes', '--enable-multibyte=yes',
'--disable-install-examples',
) )
->make(); ->make();
$lib->patchPkgconfPrefix(['readline.pc']); $lib->patchPkgconfPrefix(['readline.pc']);

View File

@@ -22,8 +22,7 @@ class tidy
->setBuildDir("{$lib->getSourceDir()}/build-dir") ->setBuildDir("{$lib->getSourceDir()}/build-dir")
->addConfigureArgs( ->addConfigureArgs(
'-DSUPPORT_CONSOLE_APP=OFF', '-DSUPPORT_CONSOLE_APP=OFF',
'-DBUILD_SHARED_LIB=OFF', '-DBUILD_SHARED_LIB=OFF'
'-DSUPPORT_LOCALIZATIONS=OFF',
); );
if (version_compare(get_cmake_version(), '4.0.0', '>=')) { if (version_compare(get_cmake_version(), '4.0.0', '>=')) {
$cmake->addConfigureArgs('-DCMAKE_POLICY_VERSION_MINIMUM=3.5'); $cmake->addConfigureArgs('-DCMAKE_POLICY_VERSION_MINIMUM=3.5');
@@ -39,8 +38,7 @@ class tidy
->setBuildDir("{$lib->getSourceDir()}/build-dir") ->setBuildDir("{$lib->getSourceDir()}/build-dir")
->addConfigureArgs( ->addConfigureArgs(
'-DSUPPORT_CONSOLE_APP=OFF', '-DSUPPORT_CONSOLE_APP=OFF',
'-DBUILD_SHARED_LIB=OFF', '-DBUILD_SHARED_LIB=OFF'
'-DSUPPORT_LOCALIZATIONS=OFF',
)->build(); )->build();
// rename tidy_static.lib to tidy_a.lib // rename tidy_static.lib to tidy_a.lib

View File

@@ -35,7 +35,6 @@ class unixodbc extends LibraryPackage
'--with-included-ltdl', '--with-included-ltdl',
"--sysconfdir={$sysconf_selector}", "--sysconfdir={$sysconf_selector}",
'--enable-gui=no', '--enable-gui=no',
'--enable-readline=no',
) )
->make(); ->make();
$this->patchPkgconfPrefix(['odbc.pc', 'odbccr.pc', 'odbcinst.pc']); $this->patchPkgconfPrefix(['odbc.pc', 'odbccr.pc', 'odbcinst.pc']);

View File

@@ -22,11 +22,6 @@ class xz
->configure( ->configure(
'--disable-scripts', '--disable-scripts',
'--disable-doc', '--disable-doc',
'--disable-xz',
'--disable-xzdec',
'--disable-lzmadec',
'--disable-lzmainfo',
'--disable-lzma-links',
'--with-libiconv', '--with-libiconv',
'--bindir=/tmp/xz', // xz binary will corrupt `tar` command, that's really strange. '--bindir=/tmp/xz', // xz binary will corrupt `tar` command, that's really strange.
) )

View File

@@ -14,20 +14,16 @@ use StaticPHP\Util\FileSystem;
#[Library('zstd')] #[Library('zstd')]
class zstd class zstd
{ {
private const array DISABLE_ARGS = [
'-DZSTD_BUILD_STATIC=ON',
'-DZSTD_BUILD_SHARED=OFF',
'-DZSTD_BUILD_PROGRAMS=OFF',
'-DZSTD_BUILD_TESTS=OFF',
];
#[BuildFor('Windows')] #[BuildFor('Windows')]
public function buildWin(LibraryPackage $package): void public function buildWin(LibraryPackage $package): void
{ {
WindowsCMakeExecutor::create($package) WindowsCMakeExecutor::create($package)
->setWorkingDir("{$package->getSourceDir()}/build/cmake") ->setWorkingDir("{$package->getSourceDir()}/build/cmake")
->setBuildDir("{$package->getSourceDir()}/build/cmake/build") ->setBuildDir("{$package->getSourceDir()}/build/cmake/build")
->addConfigureArgs(...self::DISABLE_ARGS) ->addConfigureArgs(
'-DZSTD_BUILD_STATIC=ON',
'-DZSTD_BUILD_SHARED=OFF',
)
->build(); ->build();
FileSystem::copy($package->getLibDir() . '\zstd_static.lib', $package->getLibDir() . '/zstd.lib'); FileSystem::copy($package->getLibDir() . '\zstd_static.lib', $package->getLibDir() . '/zstd.lib');
FileSystem::copy($package->getLibDir() . '\zstd_static.lib', $package->getLibDir() . '/libzstd.lib'); FileSystem::copy($package->getLibDir() . '\zstd_static.lib', $package->getLibDir() . '/libzstd.lib');
@@ -39,7 +35,10 @@ class zstd
{ {
UnixCMakeExecutor::create($lib) UnixCMakeExecutor::create($lib)
->setBuildDir("{$lib->getSourceDir()}/build/cmake/build") ->setBuildDir("{$lib->getSourceDir()}/build/cmake/build")
->addConfigureArgs(...self::DISABLE_ARGS) ->addConfigureArgs(
'-DZSTD_BUILD_STATIC=ON',
'-DZSTD_BUILD_SHARED=OFF',
)
->build(); ->build();
$lib->patchPkgconfPrefix(['libzstd.pc'], PKGCONF_PATCH_PREFIX); $lib->patchPkgconfPrefix(['libzstd.pc'], PKGCONF_PATCH_PREFIX);

View File

@@ -40,11 +40,9 @@ class curl
->optionalPackage('brotli', ...cmake_boolean_args('CURL_BROTLI')) ->optionalPackage('brotli', ...cmake_boolean_args('CURL_BROTLI'))
->addConfigureArgs( ->addConfigureArgs(
'-DBUILD_CURL_EXE=ON', '-DBUILD_CURL_EXE=ON',
'-DZSTD_LIBRARY=zstd_static.lib', '-DZSTD_LIBRARY=' . BUILD_LIB_PATH . '/zstd_static.lib',
'-DBUILD_TESTING=OFF', '-DBUILD_TESTING=OFF',
'-DBUILD_EXAMPLES=OFF', '-DBUILD_EXAMPLES=OFF',
'-DBUILD_LIBCURL_DOCS=OFF',
'-DENABLE_CURL_MANUAL=OFF',
'-DUSE_LIBIDN2=OFF', '-DUSE_LIBIDN2=OFF',
'-DCURL_USE_LIBPSL=OFF', '-DCURL_USE_LIBPSL=OFF',
'-DUSE_WINDOWS_SSPI=ON', '-DUSE_WINDOWS_SSPI=ON',
@@ -83,9 +81,6 @@ class curl
->addConfigureArgs( ->addConfigureArgs(
'-DBUILD_CURL_EXE=ON', '-DBUILD_CURL_EXE=ON',
'-DBUILD_LIBCURL_DOCS=OFF', '-DBUILD_LIBCURL_DOCS=OFF',
'-DBUILD_TESTING=OFF',
'-DBUILD_EXAMPLES=OFF',
'-DENABLE_CURL_MANUAL=OFF',
'-DOPENSSL_ROOT_DIR=' . BUILD_ROOT_PATH, '-DOPENSSL_ROOT_DIR=' . BUILD_ROOT_PATH,
) )
->build(); ->build();

View File

@@ -255,6 +255,13 @@ class php extends TargetPackage
$installer->addBuildPackage('php-embed'); $installer->addBuildPackage('php-embed');
} }
// UPX compression: ensure the upx tool package is installed when requested.
// upx is a ToolPackage now, so it's installed directly rather than added as a
// library dependency (tool packages bypass the DependencyResolver graph).
if ($package->getBuildOption('with-upx-pack')) {
$installer->addInstallPackage('upx');
}
return [...$extensions_pkg, ...$additional_packages]; return [...$extensions_pkg, ...$additional_packages];
} }

View File

@@ -39,6 +39,13 @@ trait windows
InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('./buildconf.bat')); InteractiveTerm::setMessage('Building php: ' . ConsoleColor::yellow('./buildconf.bat'));
cmd()->cd($package->getSourceDir())->exec('.\buildconf.bat'); cmd()->cd($package->getSourceDir())->exec('.\buildconf.bat');
// Bypass the phpsdk_version check in configure.js: we use MSVC + msys2 instead of PHP SDK, so phpsdk_version is not available and the check would always fail.
FileSystem::replaceFileStr(
"{$package->getSourceDir()}\\configure.js",
'check_binary_tools_sdk();',
'/* check_binary_tools_sdk(); skipped: using MSVC + msys2 without PHP SDK */'
);
if ($package->getBuildOption('enable-micro-win32') && $installer->isPackageResolved('php-micro')) { if ($package->getBuildOption('enable-micro-win32') && $installer->isPackageResolved('php-micro')) {
SourcePatcher::patchMicroWin32(); SourcePatcher::patchMicroWin32();
} else { } else {
@@ -88,6 +95,17 @@ trait windows
cmd()->cd($package->getSourceDir())->exec(".\\configure.bat {$args} {$static_extension_str}"); cmd()->cd($package->getSourceDir())->exec(".\\configure.bat {$args} {$static_extension_str}");
} }
#[BeforeStage('php', [self::class, 'makeCliForWindows'])]
#[PatchDescription('Patch Makefile to ensure buildroot/include comes before extension CFLAGS (fixes zip.h conflict with minizip)')]
public function patchMakefileIncludeOrder(TargetPackage $package): void
{
FileSystem::replaceFileStr(
"{$package->getSourceDir()}\\Makefile",
'$(CFLAGS_PHP_OBJ) $(CFLAGS)',
'$(CFLAGS) $(CFLAGS_PHP_OBJ)'
);
}
#[BeforeStage('php', [self::class, 'makeCliForWindows'])] #[BeforeStage('php', [self::class, 'makeCliForWindows'])]
#[PatchDescription('Patch Windows Makefile for CLI target')] #[PatchDescription('Patch Windows Makefile for CLI target')]
public function patchCLITarget(TargetPackage $package): void public function patchCLITarget(TargetPackage $package): void
@@ -512,6 +530,7 @@ HEADER;
$vc_matches = ['unknown', 'unknown']; $vc_matches = ['unknown', 'unknown'];
} else { } else {
$vc_matches = match ($vc['major_version']) { $vc_matches = match ($vc['major_version']) {
'18', // VS 2026 shares the VS2022 (v143) runtime conventions, so it reports as VS17.
'17' => ['VS17', 'Visual C++ 2022'], '17' => ['VS17', 'Visual C++ 2022'],
'16' => ['VS16', 'Visual C++ 2019'], '16' => ['VS16', 'Visual C++ 2019'],
default => ['unknown', 'unknown'], default => ['unknown', 'unknown'],

View File

@@ -2,17 +2,17 @@
declare(strict_types=1); declare(strict_types=1);
namespace Package\Target; namespace Package\Tool;
use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\BuildFor;
use StaticPHP\Attribute\Package\InitPackage; use StaticPHP\Attribute\Package\InitPackage;
use StaticPHP\Attribute\Package\Target; use StaticPHP\Attribute\Package\Tool;
use StaticPHP\DI\ApplicationContext; use StaticPHP\DI\ApplicationContext;
use StaticPHP\Package\TargetPackage; use StaticPHP\Package\ToolPackage;
use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor;
use StaticPHP\Toolchain\Interface\ToolchainInterface; use StaticPHP\Toolchain\Interface\ToolchainInterface;
#[Target('pkg-config')] #[Tool('pkg-config')]
class pkgconfig class pkgconfig
{ {
#[InitPackage] #[InitPackage]
@@ -23,7 +23,7 @@ class pkgconfig
#[BuildFor('Linux')] #[BuildFor('Linux')]
#[BuildFor('Darwin')] #[BuildFor('Darwin')]
public function build(TargetPackage $package, ToolchainInterface $toolchain): void public function build(ToolPackage $package, ToolchainInterface $toolchain): void
{ {
UnixAutoconfExecutor::create($package) UnixAutoconfExecutor::create($package)
->appendEnv([ ->appendEnv([

View File

@@ -644,7 +644,7 @@ class Artifact
'{artifact_name}' => $this->name, '{artifact_name}' => $this->name,
'{pkg_root_path}' => PKG_ROOT_PATH, '{pkg_root_path}' => PKG_ROOT_PATH,
'{build_root_path}' => BUILD_ROOT_PATH, '{build_root_path}' => BUILD_ROOT_PATH,
'{php_sdk_path}' => getenv('PHP_SDK_PATH') ?: WORKING_DIR . '/php-sdk-binary-tools', '{spc_msys2_path}' => getenv('SPC_MSYS2_PATH'),
'{working_dir}' => WORKING_DIR, '{working_dir}' => WORKING_DIR,
'{download_path}' => DOWNLOAD_PATH, '{download_path}' => DOWNLOAD_PATH,
'{source_path}' => SOURCE_PATH, '{source_path}' => SOURCE_PATH,

View File

@@ -26,6 +26,7 @@ use StaticPHP\Exception\DownloaderException;
use StaticPHP\Exception\ExecutionException; use StaticPHP\Exception\ExecutionException;
use StaticPHP\Exception\ValidationException; use StaticPHP\Exception\ValidationException;
use StaticPHP\Exception\WrongUsageException; use StaticPHP\Exception\WrongUsageException;
use StaticPHP\Package\ToolVersionRegistry;
use StaticPHP\Registry\ArtifactLoader; use StaticPHP\Registry\ArtifactLoader;
use StaticPHP\Runtime\Shell\Shell; use StaticPHP\Runtime\Shell\Shell;
use StaticPHP\Runtime\SystemTarget; use StaticPHP\Runtime\SystemTarget;
@@ -346,12 +347,32 @@ class ArtifactDownloader
} }
} }
public function checkUpdate(string $artifact_name, bool $prefer_source = false, bool $bare = false): CheckUpdateResult public function checkUpdate(string $artifact_name, bool $prefer_source = false, bool $bare = false, bool $use_installed = false): CheckUpdateResult
{ {
$artifact = ArtifactLoader::getArtifactInstance($artifact_name); $artifact = ArtifactLoader::getArtifactInstance($artifact_name);
if ($artifact === null) { if ($artifact === null) {
throw new WrongUsageException("Artifact '{$artifact_name}' not found, please check the name."); throw new WrongUsageException("Artifact '{$artifact_name}' not found, please check the name.");
} }
// --installed: prefer the version actually installed on disk (tool packages only) as the
// baseline, instead of the download cache. Falls back to the normal cache/bare logic below
// if this artifact has no recorded installed version (not a tool package, or not installed
// via the package installer yet).
if ($use_installed) {
$installed_version = ToolVersionRegistry::get($artifact_name);
if ($installed_version !== null) {
[$first, $second] = $prefer_source
? [fn () => $this->probeSourceCheckUpdate($artifact, $artifact_name, $installed_version), fn () => $this->probeBinaryCheckUpdate($artifact, $artifact_name, $installed_version)]
: [fn () => $this->probeBinaryCheckUpdate($artifact, $artifact_name, $installed_version), fn () => $this->probeSourceCheckUpdate($artifact, $artifact_name, $installed_version)];
$result = $first() ?? $second();
if ($result !== null) {
return $result;
}
return new CheckUpdateResult(old: $installed_version, new: null, needUpdate: false, unsupported: true);
}
logger()->warning("Artifact '{$artifact_name}' has no recorded installed version (not a tool package, or not installed yet); falling back to download-cache based check.");
}
if ($bare) { if ($bare) {
[$first, $second] = $prefer_source [$first, $second] = $prefer_source
? [fn () => $this->probeSourceCheckUpdate($artifact, $artifact_name), fn () => $this->probeBinaryCheckUpdate($artifact, $artifact_name)] ? [fn () => $this->probeSourceCheckUpdate($artifact, $artifact_name), fn () => $this->probeBinaryCheckUpdate($artifact, $artifact_name)]
@@ -403,16 +424,17 @@ class ArtifactDownloader
* @param bool $prefer_source Whether to prefer source over binary * @param bool $prefer_source Whether to prefer source over binary
* @param bool $bare Check without requiring artifact to be downloaded first * @param bool $bare Check without requiring artifact to be downloaded first
* @param null|callable $onResult Called immediately with (string $name, CheckUpdateResult) as each result arrives * @param null|callable $onResult Called immediately with (string $name, CheckUpdateResult) as each result arrives
* @param bool $use_installed Prefer the installed (on-disk) version over the download cache (tool packages only)
* @return array<string, CheckUpdateResult> Results keyed by artifact name * @return array<string, CheckUpdateResult> Results keyed by artifact name
*/ */
public function checkUpdates(array $artifact_names, bool $prefer_source = false, bool $bare = false, ?callable $onResult = null): array public function checkUpdates(array $artifact_names, bool $prefer_source = false, bool $bare = false, ?callable $onResult = null, bool $use_installed = false): array
{ {
if ($this->parallel > 1 && count($artifact_names) > 1) { if ($this->parallel > 1 && count($artifact_names) > 1) {
return $this->checkUpdatesWithConcurrency($artifact_names, $prefer_source, $bare, $onResult); return $this->checkUpdatesWithConcurrency($artifact_names, $prefer_source, $bare, $onResult, $use_installed);
} }
$results = []; $results = [];
foreach ($artifact_names as $name) { foreach ($artifact_names as $name) {
$result = $this->checkUpdate($name, $prefer_source, $bare); $result = $this->checkUpdate($name, $prefer_source, $bare, $use_installed);
$results[$name] = $result; $results[$name] = $result;
if ($onResult !== null) { if ($onResult !== null) {
($onResult)($name, $result); ($onResult)($name, $result);
@@ -436,7 +458,7 @@ class ArtifactDownloader
return $this->options[$name] ?? $default; return $this->options[$name] ?? $default;
} }
private function checkUpdatesWithConcurrency(array $artifact_names, bool $prefer_source, bool $bare, ?callable $onResult): array private function checkUpdatesWithConcurrency(array $artifact_names, bool $prefer_source, bool $bare, ?callable $onResult, bool $use_installed = false): array
{ {
$results = []; $results = [];
$fiber_pool = []; $fiber_pool = [];
@@ -451,8 +473,8 @@ class ArtifactDownloader
// fill pool // fill pool
while (count($fiber_pool) < $this->parallel && !empty($remaining)) { while (count($fiber_pool) < $this->parallel && !empty($remaining)) {
$name = array_shift($remaining); $name = array_shift($remaining);
$fiber = new \Fiber(function () use ($name, $prefer_source, $bare) { $fiber = new \Fiber(function () use ($name, $prefer_source, $bare, $use_installed) {
return [$name, $this->checkUpdate($name, $prefer_source, $bare)]; return [$name, $this->checkUpdate($name, $prefer_source, $bare, $use_installed)];
}); });
$fiber->start(); $fiber->start();
$fiber_pool[$name] = $fiber; $fiber_pool[$name] = $fiber;
@@ -491,12 +513,12 @@ class ArtifactDownloader
return $results; return $results;
} }
private function probeSourceCheckUpdate(Artifact $artifact, string $artifact_name): ?CheckUpdateResult private function probeSourceCheckUpdate(Artifact $artifact, string $artifact_name, ?string $old_version = null): ?CheckUpdateResult
{ {
if (($callback = $artifact->getCustomSourceCheckUpdateCallback()) !== null) { if (($callback = $artifact->getCustomSourceCheckUpdateCallback()) !== null) {
return ApplicationContext::invoke($callback, [ return ApplicationContext::invoke($callback, [
ArtifactDownloader::class => $this, ArtifactDownloader::class => $this,
'old_version' => null, 'old_version' => $old_version,
]); ]);
} }
$config = $artifact->getDownloadConfig('source'); $config = $artifact->getDownloadConfig('source');
@@ -509,16 +531,16 @@ class ArtifactDownloader
} }
/** @var CheckUpdateInterface $dl */ /** @var CheckUpdateInterface $dl */
$dl = new $cls(); $dl = new $cls();
return $dl->checkUpdate($artifact_name, $config, null, $this); return $dl->checkUpdate($artifact_name, $config, $old_version, $this);
} }
private function probeBinaryCheckUpdate(Artifact $artifact, string $artifact_name): ?CheckUpdateResult private function probeBinaryCheckUpdate(Artifact $artifact, string $artifact_name, ?string $old_version = null): ?CheckUpdateResult
{ {
// custom binary callback takes precedence over config-based binary // custom binary callback takes precedence over config-based binary
if (($callback = $artifact->getCustomBinaryCheckUpdateCallback()) !== null) { if (($callback = $artifact->getCustomBinaryCheckUpdateCallback()) !== null) {
return ApplicationContext::invoke($callback, [ return ApplicationContext::invoke($callback, [
ArtifactDownloader::class => $this, ArtifactDownloader::class => $this,
'old_version' => null, 'old_version' => $old_version,
]); ]);
} }
$binary_config = $artifact->getDownloadConfig('binary'); $binary_config = $artifact->getDownloadConfig('binary');
@@ -532,7 +554,7 @@ class ArtifactDownloader
} }
/** @var CheckUpdateInterface $dl */ /** @var CheckUpdateInterface $dl */
$dl = new $cls(); $dl = new $cls();
return $dl->checkUpdate($artifact_name, $platform_config, null, $this); return $dl->checkUpdate($artifact_name, $platform_config, $old_version, $this);
} }
private function downloadWithType(Artifact $artifact, int $current, int $total, bool $parallel = false): int private function downloadWithType(Artifact $artifact, int $current, int $total, bool $parallel = false): int

View File

@@ -614,7 +614,7 @@ class ArtifactExtractor
'{source_path}' => SOURCE_PATH, '{source_path}' => SOURCE_PATH,
'{download_path}' => DOWNLOAD_PATH, '{download_path}' => DOWNLOAD_PATH,
'{working_dir}' => WORKING_DIR, '{working_dir}' => WORKING_DIR,
'{php_sdk_path}' => getenv('PHP_SDK_PATH') ?: '', '{spc_msys2_path}' => getenv('SPC_MSYS2_PATH') ?: '',
]; ];
return str_replace(array_keys($replacement), array_values($replacement), $path); return str_replace(array_keys($replacement), array_values($replacement), $path);
} }

View File

@@ -76,9 +76,10 @@ class DownloadResult
?string $version = null, ?string $version = null,
array $metadata = [], array $metadata = [],
?string $downloader = null, ?string $downloader = null,
mixed $extract = null,
): DownloadResult { ): DownloadResult {
$cache_type = self::isArchiveFile($filename) ? 'archive' : 'file'; $cache_type = self::isArchiveFile($filename) ? 'archive' : 'file';
return new self($cache_type, config: $config, filename: $filename, verified: $verified, version: $version, metadata: $metadata, downloader: $downloader); return new self($cache_type, config: $config, filename: $filename, extract: $extract, verified: $verified, version: $version, metadata: $metadata, downloader: $downloader);
} }
/** /**

Some files were not shown because too many files have changed in this diff Show More