mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-15 21:05:35 +08:00
Compare commits
140 Commits
6ab52a5181
...
docs/perfo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
387b8c9dc5 | ||
|
|
c1eefb8399 | ||
|
|
4d00e338af | ||
|
|
422323a41d | ||
|
|
6144f7affb | ||
|
|
6d58d53f7d | ||
|
|
c54fa78ad1 | ||
|
|
4d6f334cbb | ||
|
|
e99423c7d1 | ||
|
|
44daaad548 | ||
|
|
4dac0d18b4 | ||
|
|
79db27da04 | ||
|
|
d04d82a1f1 | ||
|
|
dca24585d4 | ||
|
|
7edd8359d5 | ||
|
|
be8f239259 | ||
|
|
6c7a47c9b5 | ||
|
|
859c06a470 | ||
|
|
274706084a | ||
|
|
0bd94b0ebd | ||
|
|
150998723d | ||
|
|
303dca5f59 | ||
|
|
d7902b9931 | ||
|
|
43b2da0511 | ||
|
|
6dc5c5b770 | ||
|
|
f3afd81c81 | ||
|
|
1dce506222 | ||
|
|
323f21a6f2 | ||
|
|
ab30c9dc49 | ||
|
|
996cca12c0 | ||
|
|
5451945972 | ||
|
|
fc1673e37f | ||
|
|
f1722a0f3e | ||
|
|
8034ae37ea | ||
|
|
c9f24b980d | ||
|
|
5ffbf2d5fe | ||
|
|
facc7bc5a7 | ||
|
|
160d7f5537 | ||
|
|
afa5f535e9 | ||
|
|
0dde151632 | ||
|
|
e906edb332 | ||
|
|
83ce54b62b | ||
|
|
7d6c082c86 | ||
|
|
db4f7c6a0c | ||
|
|
ca0167c83e | ||
|
|
5a5c784c4f | ||
|
|
331da67049 | ||
|
|
cc448d463b | ||
|
|
dc55881b78 | ||
|
|
a59473e4ab | ||
|
|
c6a227f4de | ||
|
|
392733b7c3 | ||
|
|
3870269330 | ||
|
|
03f1313eec | ||
|
|
b9def51f86 | ||
|
|
8533702cf6 | ||
|
|
fe3cd15f81 | ||
|
|
dc33b55fd0 | ||
|
|
c9401a0b7a | ||
|
|
fa040bc346 | ||
|
|
ab37b34fb5 | ||
|
|
0b02f62b7e | ||
|
|
924fac137c | ||
|
|
d9c41a73da | ||
|
|
dd1e70a394 | ||
|
|
1bdbdfc08c | ||
|
|
90846ab149 | ||
|
|
8dd7882869 | ||
|
|
7f6be12bf1 | ||
|
|
45b97581d8 | ||
|
|
12a5217f17 | ||
|
|
5913cb07fd | ||
|
|
dd69155539 | ||
|
|
a81dd6d5c9 | ||
|
|
b4ed673261 | ||
|
|
db2d9a909f | ||
|
|
38e01a9b88 | ||
|
|
2b210f9403 | ||
|
|
be329c1d56 | ||
|
|
227b8f0b0a | ||
|
|
c88041b7e0 | ||
|
|
3bb84f3b94 | ||
|
|
c31bf73685 | ||
|
|
c4d7ca819b | ||
|
|
fd8ab71d80 | ||
|
|
2a7966aa4b | ||
|
|
ef83ff074e | ||
|
|
06864fc3f6 | ||
|
|
408d8f755c | ||
|
|
1f291a9036 | ||
|
|
127fb1989f | ||
|
|
af771cf2b5 | ||
|
|
5df65d926c | ||
|
|
bdc7bbe1f1 | ||
|
|
89dca1f0fb | ||
|
|
064a1f05ae | ||
|
|
88cb6749b8 | ||
|
|
0010e35882 | ||
|
|
728c8dd598 | ||
|
|
bf6216e59f | ||
|
|
f66e68754e | ||
|
|
411ad7cc0f | ||
|
|
0761267eb3 | ||
|
|
072a3b5505 | ||
|
|
0e5738b710 | ||
|
|
3ff9426e50 | ||
|
|
6057394641 | ||
|
|
2f4fb9d28f | ||
|
|
96ab2de4b1 | ||
|
|
6c59456c02 | ||
|
|
0e8a806640 | ||
|
|
c641c3b8db | ||
|
|
48d6e9ebc2 | ||
|
|
6cab47db67 | ||
|
|
ec3fd0f4b0 | ||
|
|
e72f9aa623 | ||
|
|
c666cd6cd0 | ||
|
|
b8dd508148 | ||
|
|
37d8b87c3b | ||
|
|
582a88ef60 | ||
|
|
153003b75c | ||
|
|
899555a964 | ||
|
|
891a222c39 | ||
|
|
39beb68024 | ||
|
|
5172580294 | ||
|
|
99e05aa22b | ||
|
|
0807e9e253 | ||
|
|
1a779be028 | ||
|
|
bdfd3eb269 | ||
|
|
7ae5d742c2 | ||
|
|
95be291a84 | ||
|
|
d89add106a | ||
|
|
a36129c6cd | ||
|
|
3f3edd62a1 | ||
|
|
82b77af317 | ||
|
|
df26b93e58 | ||
|
|
d1b4c05381 | ||
|
|
e1658bc0e6 | ||
|
|
5053620b61 | ||
|
|
9366cbacd9 |
24
.gitattributes
vendored
Normal file
24
.gitattributes
vendored
Normal 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
23
.github/copilot-instructions.md
vendored
Normal 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/`
|
||||
56
.github/skills/staticphp-build-troubleshooting/SKILL.md
vendored
Normal file
56
.github/skills/staticphp-build-troubleshooting/SKILL.md
vendored
Normal 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.
|
||||
4
.github/skills/staticphp-build-troubleshooting/agents/openai.yaml
vendored
Normal file
4
.github/skills/staticphp-build-troubleshooting/agents/openai.yaml
vendored
Normal 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."
|
||||
209
.github/skills/staticphp-build-troubleshooting/references/log-triage.md
vendored
Normal file
209
.github/skills/staticphp-build-troubleshooting/references/log-triage.md
vendored
Normal 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.
|
||||
55
.github/skills/staticphp-package-maintenance/SKILL.md
vendored
Normal file
55
.github/skills/staticphp-package-maintenance/SKILL.md
vendored
Normal 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.
|
||||
4
.github/skills/staticphp-package-maintenance/agents/openai.yaml
vendored
Normal file
4
.github/skills/staticphp-package-maintenance/agents/openai.yaml
vendored
Normal 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."
|
||||
143
.github/skills/staticphp-package-maintenance/references/build-class-patterns.md
vendored
Normal file
143
.github/skills/staticphp-package-maintenance/references/build-class-patterns.md
vendored
Normal 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.
|
||||
157
.github/skills/staticphp-package-maintenance/references/package-reference.md
vendored
Normal file
157
.github/skills/staticphp-package-maintenance/references/package-reference.md
vendored
Normal 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
|
||||
```
|
||||
3
.github/workflows/build-unix.yml
vendored
3
.github/workflows/build-unix.yml
vendored
@@ -331,5 +331,4 @@ jobs:
|
||||
with:
|
||||
name: build-meta-${{ inputs.php-version }}-${{ inputs.os }}
|
||||
path: |
|
||||
buildroot/build-extensions.json
|
||||
buildroot/build-libraries.json
|
||||
buildroot/build-manifest.json
|
||||
|
||||
3
.github/workflows/build-windows-x86_64.yml
vendored
3
.github/workflows/build-windows-x86_64.yml
vendored
@@ -115,5 +115,4 @@ jobs:
|
||||
with:
|
||||
name: build-meta
|
||||
path: |
|
||||
buildroot/build-extensions.json
|
||||
buildroot/build-libraries.json
|
||||
buildroot/build-manifest.json
|
||||
|
||||
5
.github/workflows/ext-matrix-tests.yml
vendored
5
.github/workflows/ext-matrix-tests.yml
vendored
@@ -2,13 +2,14 @@ name: "Extension Matrix Tests"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, synchronize, labeled]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: "${{ matrix.extension }} (PHP ${{ matrix.php-version }} on ${{ matrix.operating-system }})"
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
if: contains(github.event.head_commit.message, 'extension test') || contains(github.event.head_commit.message, 'test extensions')
|
||||
if: contains(github.event.pull_request.labels.*.name, 'need-full-test')
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
48
.github/workflows/post-test-bot-comment.yml
vendored
Normal file
48
.github/workflows/post-test-bot-comment.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Post Test Bot Comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["v3 Tests"]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
actions: read
|
||||
|
||||
jobs:
|
||||
post-comment:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Download bot output
|
||||
id: download
|
||||
uses: actions/download-artifact@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: bot-output
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Post/Update comment
|
||||
if: steps.download.outcome == 'success'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
COMMENT_BODY=$(jq -r '.comment_body' bot-output.json)
|
||||
PR_NUMBER=$(jq -r '.pr_number' bot-output.json)
|
||||
MARKER="<!-- spc-test-bot -->"
|
||||
|
||||
# Find existing bot comment id
|
||||
EXISTING_ID=$(gh api \
|
||||
"repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \
|
||||
--jq "[.[] | select(.body | startswith(\"${MARKER}\")) | .id] | first // empty")
|
||||
|
||||
if [ -n "$EXISTING_ID" ]; then
|
||||
gh api --method PATCH \
|
||||
"repos/${{ github.repository }}/issues/comments/${EXISTING_ID}" \
|
||||
-f body="$COMMENT_BODY"
|
||||
else
|
||||
gh pr comment "$PR_NUMBER" \
|
||||
--repo "${{ github.repository }}" \
|
||||
--body "$COMMENT_BODY"
|
||||
fi
|
||||
9
.github/workflows/release-build.yml
vendored
9
.github/workflows/release-build.yml
vendored
@@ -38,6 +38,9 @@ jobs:
|
||||
- name: "windows-x64"
|
||||
os: "ubuntu-latest"
|
||||
filename: "spc-windows-x64.exe"
|
||||
permissions:
|
||||
id-token: write
|
||||
attestations: write
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v5"
|
||||
@@ -105,6 +108,12 @@ jobs:
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: "Generate build provenance attestation"
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: actions/attest-build-provenance@v4
|
||||
with:
|
||||
subject-path: "${{ github.workspace }}/${{ matrix.operating-system.name == 'windows-x64' && 'spc.exe' || 'spc' }}"
|
||||
|
||||
- name: "Copy file"
|
||||
run: |
|
||||
if [ "${{ matrix.operating-system.name }}" != "windows-x64" ]; then
|
||||
|
||||
31
.github/workflows/tests.yml
vendored
31
.github/workflows/tests.yml
vendored
@@ -131,7 +131,6 @@ jobs:
|
||||
if: needs.check-gate.outputs.enabled == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
outputs:
|
||||
need_test: ${{ steps.bot.outputs.need_test }}
|
||||
@@ -168,23 +167,17 @@ jobs:
|
||||
echo "php_versions=$(echo "$BOT_JSON" | jq -c '.php_versions')" >> "$GITHUB_OUTPUT"
|
||||
echo "tier2=$(echo "$BOT_JSON" | jq -r '.tier2')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
COMMENT_BODY=$(echo "$BOT_JSON" | jq -r '.comment_body')
|
||||
MARKER="<!-- spc-test-bot -->"
|
||||
# Save JSON for the comment-posting workflow
|
||||
jq -n --argjson bot "$BOT_JSON" \
|
||||
--arg pr '${{ github.event.pull_request.number }}' \
|
||||
'$bot + {pr_number: $pr}' > bot-output.json
|
||||
|
||||
# Find existing bot comment id
|
||||
EXISTING_ID=$(gh api \
|
||||
repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments \
|
||||
--jq "[.[] | select(.body | startswith(\"$MARKER\")) | .id] | first // empty")
|
||||
|
||||
if [ -n "$EXISTING_ID" ]; then
|
||||
gh api --method PATCH \
|
||||
repos/${{ github.repository }}/issues/comments/"$EXISTING_ID" \
|
||||
-f body="$COMMENT_BODY"
|
||||
else
|
||||
gh pr comment ${{ github.event.pull_request.number }} \
|
||||
--repo ${{ github.repository }} \
|
||||
--body "$COMMENT_BODY"
|
||||
fi
|
||||
- name: Upload bot output
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bot-output
|
||||
path: bot-output.json
|
||||
retention-days: 1
|
||||
|
||||
gen-matrix:
|
||||
name: "Generate test matrix"
|
||||
@@ -234,7 +227,7 @@ jobs:
|
||||
echo "matrix=$(echo "$FINAL" | jq -c '{"combo": .}')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
ext-test:
|
||||
name: "Ext test: ${{ matrix.combo.extension }} (PHP ${{ matrix.combo.php-version }} · ${{ matrix.combo.os }}-${{ matrix.combo.arch }})"
|
||||
name: "Ext test: ${{ matrix.combo.extension }} [${{ matrix.combo.sapi }}] (PHP ${{ matrix.combo.php-version }} - ${{ matrix.combo.os }}-${{ matrix.combo.arch }})"
|
||||
needs: gen-matrix
|
||||
runs-on: ${{ matrix.combo.runner }}
|
||||
timeout-minutes: 120
|
||||
@@ -273,5 +266,5 @@ jobs:
|
||||
if: always() && hashFiles('log/**') != ''
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: logs-${{ matrix.combo.os }}-${{ matrix.combo.arch }}-${{ matrix.combo.extension }}-php${{ matrix.combo.php-version }}
|
||||
name: logs-${{ matrix.combo.os }}-${{ matrix.combo.arch }}-${{ matrix.combo.sapi }}-${{ matrix.combo.extension }}-php${{ matrix.combo.php-version }}
|
||||
path: log
|
||||
|
||||
136
.github/workflows/vitepress-deploy.yml
vendored
136
.github/workflows/vitepress-deploy.yml
vendored
@@ -1,68 +1,68 @@
|
||||
name: Docs build test and auto deploy
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ "v3" ]
|
||||
types: [ opened, synchronize, reopened ]
|
||||
paths:
|
||||
- 'config/**.yml'
|
||||
- 'docs/**'
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- '.github/workflows/vitepress-deploy.yml'
|
||||
push:
|
||||
branches: [ "v3" ]
|
||||
paths:
|
||||
- 'config/**.yml'
|
||||
- 'docs/**'
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- '.github/workflows/vitepress-deploy.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Deploy docs
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'crazywhalecc/static-php-cli'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
|
||||
- run: npm install
|
||||
|
||||
- name: "Install PHP for official runners"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
php-version: 8.4
|
||||
ini-values: memory_limit=-1
|
||||
extensions: curl, openssl, mbstring
|
||||
|
||||
- name: "Get Composer Cache Directory"
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: "Cache Composer dependencies"
|
||||
uses: "actions/cache@v4"
|
||||
with:
|
||||
path: "${{ steps.composer-cache.outputs.dir }}"
|
||||
key: "php-8.2-locked-composer-${{ hashFiles('**/composer.lock') }}"
|
||||
restore-keys: |
|
||||
php-8.2-locked-composer
|
||||
|
||||
- name: "Install Locked Dependencies"
|
||||
run: "composer install --no-interaction --no-progress"
|
||||
|
||||
- name: Build
|
||||
run: npm run docs:build
|
||||
|
||||
# Deploy to GitHub Pages only when the workflow is triggered by a push to the v3 branch
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/v3'
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: docs/.vitepress/dist
|
||||
name: Docs build test and auto deploy
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ "v3" ]
|
||||
types: [ opened, synchronize, reopened ]
|
||||
paths:
|
||||
- 'config/**.yml'
|
||||
- 'docs/**'
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- '.github/workflows/vitepress-deploy.yml'
|
||||
push:
|
||||
branches: [ "v3" ]
|
||||
paths:
|
||||
- 'config/**.yml'
|
||||
- 'docs/**'
|
||||
- 'package.json'
|
||||
- 'yarn.lock'
|
||||
- '.github/workflows/vitepress-deploy.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Deploy docs
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'crazywhalecc/static-php-cli'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
|
||||
- run: npm install
|
||||
|
||||
- name: "Install PHP for official runners"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
php-version: 8.4
|
||||
ini-values: memory_limit=-1
|
||||
extensions: curl, openssl, mbstring
|
||||
|
||||
- name: "Get Composer Cache Directory"
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: "Cache Composer dependencies"
|
||||
uses: "actions/cache@v4"
|
||||
with:
|
||||
path: "${{ steps.composer-cache.outputs.dir }}"
|
||||
key: "php-8.2-locked-composer-${{ hashFiles('**/composer.lock') }}"
|
||||
restore-keys: |
|
||||
php-8.2-locked-composer
|
||||
|
||||
- name: "Install Locked Dependencies"
|
||||
run: "composer install --no-interaction --no-progress"
|
||||
|
||||
- name: Build
|
||||
run: npm run docs:build
|
||||
|
||||
# Deploy to GitHub Pages only when the workflow is triggered by a push to the v3 branch
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/v3'
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: docs/.vitepress/dist
|
||||
|
||||
59
AGENTS.md
Normal file
59
AGENTS.md
Normal 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.
|
||||
312
README-zh.md
312
README-zh.md
@@ -1,156 +1,156 @@
|
||||
# StaticPHP
|
||||
|
||||
[](README-zh.md)
|
||||
[](README.md)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/releases)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
|
||||
[](https://discord.gg/nrSRbpMJ)
|
||||
|
||||
**StaticPHP** 是一个强大的工具,用于构建可移植的可执行文件,包括 PHP、扩展等。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 我们正准备发布 **v3** 版本,届时项目名称将从 **static-php-cli** 更改为 **StaticPHP**。
|
||||
> 此分支对应 v3 版本。v2 版本请查看 [v2 分支](https://github.com/crazywhalecc/static-php-cli/tree/main)。
|
||||
> 请更新您的参考资料,并关注正式版发布。
|
||||
|
||||
## 特性
|
||||
|
||||
- :elephant: 支持多个 PHP 版本 - PHP 8.1, 8.2, 8.3, 8.4, 8.5
|
||||
- :handbag: 构建零依赖的单文件 PHP 可执行程序
|
||||
- :hamburger: 构建 **[phpmicro](https://github.com/static-php/phpmicro)** 自解压可执行文件(将 PHP 二进制和源码合并为单个文件)
|
||||
- :pill: 自动构建环境检查器,支持自动修复
|
||||
- :zap: 支持 `Linux`、`macOS`、`Windows`
|
||||
- :wrench: 通过 vendor 模式和自定义注册表实现便捷扩展
|
||||
- :books: 智能依赖管理
|
||||
- 📦 自包含 `spc` 可执行文件,便于自安装
|
||||
- :fire: 支持 100+ 热门 [PHP 扩展](https://static-php.dev/en/guide/extensions.html)
|
||||
- :floppy_disk: 支持 UPX 压缩(二进制体积可缩小 30-50%)
|
||||
|
||||
**单文件独立 php-cli:**
|
||||
|
||||
<img width="700" alt="out1" src="https://github.com/crazywhalecc/static-php-cli/assets/20330940/01a2e60f-13b0-4242-a645-f7afa4936396">
|
||||
|
||||
**使用 phpmicro 将 PHP 代码与 PHP 解释器结合:**
|
||||
|
||||
<img width="700" alt="out2" src="https://github.com/crazywhalecc/static-php-cli/assets/20330940/46b7128d-fb72-4169-957e-48564c3ff3e2">
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 下载 spc 二进制
|
||||
|
||||
```bash
|
||||
# For Linux x86_64
|
||||
curl -fsSL -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-linux-x86_64
|
||||
# For Linux aarch64
|
||||
curl -fsSL -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-linux-aarch64
|
||||
# macOS x86_64 (Intel)
|
||||
curl -fsSL -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-macos-x86_64
|
||||
# macOS aarch64 (Apple)
|
||||
curl -fsSL -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-macos-aarch64
|
||||
# Windows (x86_64, win10 build 17063 or later, please install VS2022 first)
|
||||
curl.exe -fsSL -o spc.exe https://dl.static-php.dev/v3/spc-bin/nightly/spc-windows-x64.exe
|
||||
```
|
||||
|
||||
对于 macOS 和 Linux,请先添加可执行权限:
|
||||
|
||||
```bash
|
||||
chmod +x ./spc
|
||||
```
|
||||
|
||||
### 2. 构建静态 PHP
|
||||
|
||||
首先,创建 `craft.yml` 文件,并从 [扩展列表](https://static-php.dev/en/guide/extensions.html) 或 [命令生成器](https://static-php.dev/en/guide/cli-generator.html) 指定要包含的扩展:
|
||||
|
||||
```yml
|
||||
# PHP version support: 8.1, 8.2, 8.3, 8.4, 8.5
|
||||
php-version: 8.5
|
||||
# Put your extension list here
|
||||
extensions: "apcu,bcmath,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,gd,iconv,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,readline,redis,session,simplexml,sockets,sodium,sqlite3,tokenizer,xml,xmlreader,xmlwriter,xsl,zip,zlib"
|
||||
sapi:
|
||||
- cli
|
||||
- micro
|
||||
download-options:
|
||||
parallel: 10
|
||||
```
|
||||
|
||||
运行命令:
|
||||
|
||||
```bash
|
||||
./spc craft
|
||||
|
||||
# 输出完整控制台日志
|
||||
./spc craft -vvv
|
||||
```
|
||||
|
||||
### 3. 静态 PHP 使用
|
||||
|
||||
现在你可以将 StaticPHP 构建的二进制复制到另一台机器并在无依赖环境下运行:
|
||||
|
||||
```
|
||||
# php-cli
|
||||
buildroot/bin/php -v
|
||||
|
||||
# phpmicro
|
||||
echo '<?php echo "Hello world!\n";' > a.php
|
||||
./spc micro:combine a.php -O my-app
|
||||
./my-app
|
||||
```
|
||||
|
||||
## 文档
|
||||
|
||||
当前 README 包含基础用法。有关 StaticPHP 的完整功能集,
|
||||
请访问 <https://static-php.dev>。
|
||||
|
||||
## 直接下载
|
||||
|
||||
如果你暂时不想构建,或只想先测试,可以从 [Actions](https://github.com/static-php/static-php-cli-hosted/actions/workflows/build-php-bulk.yml) 下载示例预编译产物,或从自托管服务器下载。
|
||||
|
||||
我们为每个 PHP 版本提供 2 种扩展集合:
|
||||
|
||||
- **gigantic**:尽可能包含更多扩展,二进制大小约 100-150MB。
|
||||
- **base**:仅包含 StaticPHP 自身使用的少量扩展,二进制大小约 10MB。
|
||||
|
||||
> WIP
|
||||
|
||||
### 在线构建(使用 GitHub Actions)
|
||||
|
||||
当上方直接下载的二进制无法满足你的需求时,
|
||||
你可以使用 GitHub Actions 轻松构建静态编译的 PHP,
|
||||
并同时自定义要编译的扩展列表。
|
||||
|
||||
1. Fork 此仓库。
|
||||
2. 进入项目的 Actions 并选择 `CI`。
|
||||
3. 选择 `Run workflow`,填写你要编译的 PHP 版本、目标类型和扩展列表。(扩展用逗号分隔,例如 `bcmath,curl,mbstring`)
|
||||
4. 等待工作流执行完成后,进入对应运行记录并下载 `Artifacts`。
|
||||
|
||||
如果你启用 `debug`,构建时将输出所有日志,包括编译日志,便于排查问题。
|
||||
|
||||
> 我们也计划在未来提供可复用的 GitHub Actions 工作流,
|
||||
> 这样你无需 fork 本项目,也能在自己的仓库中轻松构建 static PHP。
|
||||
|
||||
## 贡献
|
||||
|
||||
如果你需要的扩展缺失,可以创建 issue。
|
||||
如果你熟悉本项目,也欢迎发起 pull request。
|
||||
|
||||
如果你想贡献文档,请直接编辑 `docs/`。
|
||||
|
||||
## 赞助本项目
|
||||
|
||||
你可以通过 [GitHub Sponsor](https://github.com/crazywhalecc) 赞助我或我的项目。你捐赠的一部分将用于维护 **static-php.dev** 服务器。
|
||||
|
||||
**特别感谢以下赞助商:**
|
||||
|
||||
<a href="https://beyondco.de/"><img src="/docs/public/images/beyondcode-seeklogo.png" width="300" alt="Beyond Code Logo" /></a>
|
||||
|
||||
<a href="https://nativephp.com/"><img src="/docs/public/images/nativephp-logo.svg" width="300" alt="NativePHP Logo" /></a>
|
||||
|
||||
## 开源许可证
|
||||
|
||||
本项目本身采用 MIT 许可证。
|
||||
一些新添加的扩展和依赖可能来自其他项目。
|
||||
这些源码文件头部也可能包含额外的 LICENSE 和 AUTHOR 信息。
|
||||
|
||||
请在编译后使用 `bin/spc dump-license` 命令导出项目中使用的开源许可证,
|
||||
并遵守对应项目的 LICENSE。
|
||||
# StaticPHP
|
||||
|
||||
[](README-zh.md)
|
||||
[](README.md)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/releases)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
|
||||
[](https://discord.gg/xf6Rd4pEAk)
|
||||
|
||||
**StaticPHP** 是一个强大的工具,用于构建可移植的可执行文件,包括 PHP、扩展等。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 我们正准备发布 **v3** 版本,届时项目名称将从 **static-php-cli** 更改为 **StaticPHP**。
|
||||
> 此分支对应 v3 版本。v2 版本请查看 [v2 分支](https://github.com/crazywhalecc/static-php-cli/tree/main)。
|
||||
> 请更新您的参考资料,并关注正式版发布。
|
||||
|
||||
## 特性
|
||||
|
||||
- :elephant: 支持多个 PHP 版本 - PHP 8.1, 8.2, 8.3, 8.4, 8.5
|
||||
- :handbag: 构建零依赖的单文件 PHP 可执行程序
|
||||
- :hamburger: 构建 **[phpmicro](https://github.com/static-php/phpmicro)** 自解压可执行文件(将 PHP 二进制和源码合并为单个文件)
|
||||
- :pill: 自动构建环境检查器,支持自动修复
|
||||
- :zap: 支持 `Linux`、`macOS`、`Windows`
|
||||
- :wrench: 通过 vendor 模式和自定义注册表实现便捷扩展
|
||||
- :books: 智能依赖管理
|
||||
- 📦 自包含 `spc` 可执行文件,便于自安装
|
||||
- :fire: 支持 100+ 热门 [PHP 扩展](https://static-php.dev/en/guide/extensions.html)
|
||||
- :floppy_disk: 支持 UPX 压缩(二进制体积可缩小 30-50%)
|
||||
|
||||
**单文件独立 php-cli:**
|
||||
|
||||
<img width="700" alt="out1" src="https://github.com/crazywhalecc/static-php-cli/assets/20330940/01a2e60f-13b0-4242-a645-f7afa4936396">
|
||||
|
||||
**使用 phpmicro 将 PHP 代码与 PHP 解释器结合:**
|
||||
|
||||
<img width="700" alt="out2" src="https://github.com/crazywhalecc/static-php-cli/assets/20330940/46b7128d-fb72-4169-957e-48564c3ff3e2">
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 下载 spc 二进制
|
||||
|
||||
```bash
|
||||
# For Linux x86_64
|
||||
curl -fsSL -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-linux-x86_64
|
||||
# For Linux aarch64
|
||||
curl -fsSL -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-linux-aarch64
|
||||
# macOS x86_64 (Intel)
|
||||
curl -fsSL -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-macos-x86_64
|
||||
# macOS aarch64 (Apple)
|
||||
curl -fsSL -o spc https://dl.static-php.dev/v3/spc-bin/nightly/spc-macos-aarch64
|
||||
# Windows (x86_64, win10 build 17063 or later, please install VS2022 first)
|
||||
curl.exe -fsSL -o spc.exe https://dl.static-php.dev/v3/spc-bin/nightly/spc-windows-x64.exe
|
||||
```
|
||||
|
||||
对于 macOS 和 Linux,请先添加可执行权限:
|
||||
|
||||
```bash
|
||||
chmod +x ./spc
|
||||
```
|
||||
|
||||
### 2. 构建静态 PHP
|
||||
|
||||
首先,创建 `craft.yml` 文件,并从 [扩展列表](https://static-php.dev/en/guide/extensions.html) 或 [命令生成器](https://static-php.dev/en/guide/cli-generator.html) 指定要包含的扩展:
|
||||
|
||||
```yml
|
||||
# PHP version support: 8.1, 8.2, 8.3, 8.4, 8.5
|
||||
php-version: 8.5
|
||||
# Put your extension list here
|
||||
extensions: "apcu,bcmath,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,gd,iconv,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,readline,redis,session,simplexml,sockets,sodium,sqlite3,tokenizer,xml,xmlreader,xmlwriter,xsl,zip,zlib"
|
||||
sapi:
|
||||
- cli
|
||||
- micro
|
||||
download-options:
|
||||
parallel: 10
|
||||
```
|
||||
|
||||
运行命令:
|
||||
|
||||
```bash
|
||||
./spc craft
|
||||
|
||||
# 输出完整控制台日志
|
||||
./spc craft -vvv
|
||||
```
|
||||
|
||||
### 3. 静态 PHP 使用
|
||||
|
||||
现在你可以将 StaticPHP 构建的二进制复制到另一台机器并在无依赖环境下运行:
|
||||
|
||||
```
|
||||
# php-cli
|
||||
buildroot/bin/php -v
|
||||
|
||||
# phpmicro
|
||||
echo '<?php echo "Hello world!\n";' > a.php
|
||||
./spc micro:combine a.php -O my-app
|
||||
./my-app
|
||||
```
|
||||
|
||||
## 文档
|
||||
|
||||
当前 README 包含基础用法。有关 StaticPHP 的完整功能集,
|
||||
请访问 <https://static-php.dev>。
|
||||
|
||||
## 直接下载
|
||||
|
||||
如果你暂时不想构建,或只想先测试,可以从 [Actions](https://github.com/static-php/hosted/actions/workflows/build-php-bulk.yml) 下载示例预编译产物,或从自托管服务器下载。
|
||||
|
||||
我们为每个 PHP 版本提供 2 种扩展集合:
|
||||
|
||||
- **gigantic**:尽可能包含更多扩展,二进制大小约 100-150MB。
|
||||
- **base**:仅包含 StaticPHP 自身使用的少量扩展,二进制大小约 10MB。
|
||||
|
||||
> WIP
|
||||
|
||||
### 在线构建(使用 GitHub Actions)
|
||||
|
||||
当上方直接下载的二进制无法满足你的需求时,
|
||||
你可以使用 GitHub Actions 轻松构建静态编译的 PHP,
|
||||
并同时自定义要编译的扩展列表。
|
||||
|
||||
1. Fork 此仓库。
|
||||
2. 进入项目的 Actions 并选择 `CI`。
|
||||
3. 选择 `Run workflow`,填写你要编译的 PHP 版本、目标类型和扩展列表。(扩展用逗号分隔,例如 `bcmath,curl,mbstring`)
|
||||
4. 等待工作流执行完成后,进入对应运行记录并下载 `Artifacts`。
|
||||
|
||||
如果你启用 `debug`,构建时将输出所有日志,包括编译日志,便于排查问题。
|
||||
|
||||
> 我们也计划在未来提供可复用的 GitHub Actions 工作流,
|
||||
> 这样你无需 fork 本项目,也能在自己的仓库中轻松构建 static PHP。
|
||||
|
||||
## 贡献
|
||||
|
||||
如果你需要的扩展缺失,可以创建 issue。
|
||||
如果你熟悉本项目,也欢迎发起 pull request。
|
||||
|
||||
如果你想贡献文档,请直接编辑 `docs/`。
|
||||
|
||||
## 赞助本项目
|
||||
|
||||
你可以通过 [GitHub Sponsor](https://github.com/crazywhalecc) 赞助我或我的项目。你捐赠的一部分将用于维护 **static-php.dev** 服务器。
|
||||
|
||||
**特别感谢以下赞助商:**
|
||||
|
||||
<a href="https://beyondco.de/"><img src="/docs/public/images/beyondcode-seeklogo.png" width="300" alt="Beyond Code Logo" /></a>
|
||||
|
||||
<a href="https://nativephp.com/"><img src="/docs/public/images/nativephp-logo.svg" width="300" alt="NativePHP Logo" /></a>
|
||||
|
||||
## 开源许可证
|
||||
|
||||
本项目本身采用 MIT 许可证。
|
||||
一些新添加的扩展和依赖可能来自其他项目。
|
||||
这些源码文件头部也可能包含额外的 LICENSE 和 AUTHOR 信息。
|
||||
|
||||
请在编译后使用 `bin/spc dump-license` 命令导出项目中使用的开源许可证,
|
||||
并遵守对应项目的 LICENSE。
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[](https://github.com/crazywhalecc/static-php-cli/releases)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
|
||||
[](https://discord.gg/nrSRbpMJ)
|
||||
[](https://discord.gg/xf6Rd4pEAk)
|
||||
|
||||
**StaticPHP** is a powerful tool designed for building portable executables including PHP, extensions, and more.
|
||||
|
||||
@@ -104,7 +104,7 @@ see <https://static-php.dev>.
|
||||
|
||||
## 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:
|
||||
|
||||
|
||||
@@ -1,116 +1,116 @@
|
||||
param (
|
||||
[string] ${action}
|
||||
)
|
||||
|
||||
function AddToPath {
|
||||
param (
|
||||
[string]$pathToAdd
|
||||
)
|
||||
|
||||
$currentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User')
|
||||
|
||||
if ($currentPath -notlike "*$pathToAdd*") {
|
||||
$newPath = $currentPath + ";$pathToAdd"
|
||||
[System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
||||
Write-Host "Added '$pathToAdd' to Path."
|
||||
Write-Host "To remove path, use: " -NoNewline
|
||||
Write-Host "bin/setup-runtime remove-path" -ForegroundColor Cyan
|
||||
} else {
|
||||
Write-Host "Path already exists."
|
||||
}
|
||||
}
|
||||
|
||||
function RemoveFromPath {
|
||||
param (
|
||||
[string]$pathToRemove
|
||||
)
|
||||
|
||||
$currentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User')
|
||||
|
||||
if ($currentPath -like "*$pathToRemove*") {
|
||||
$newPath = $currentPath -replace [regex]::Escape(';' + $pathToRemove), ''
|
||||
[System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
||||
Write-Host "Removed Path '$pathToRemove'"
|
||||
} else {
|
||||
Write-Host "Path '$pathToRemove' not in Path"
|
||||
}
|
||||
}
|
||||
|
||||
# working dir
|
||||
$WorkingDir = (Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Definition))
|
||||
|
||||
if ($action -eq 'add-path') {
|
||||
AddToPath ($WorkingDir + '\runtime')
|
||||
exit 0
|
||||
} elseif ($action -eq 'remove-path') {
|
||||
RemoveFromPath ($WorkingDir + '\runtime')
|
||||
exit 0
|
||||
} elseif (-not($action -eq '')) {
|
||||
Write-Host ("Invalid action: " + $action) -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# get php 8.1 specific version
|
||||
|
||||
# php windows download
|
||||
$PHPRuntimeUrl = "https://windows.php.net/downloads/releases/archives/php-8.4.4-nts-Win32-vs17-x64.zip"
|
||||
Write-Host "Downloading PHP from: " -NoNewline
|
||||
Write-Host $PHPRuntimeUrl -ForegroundColor Cyan
|
||||
$ComposerUrl = "https://getcomposer.org/download/latest-stable/composer.phar"
|
||||
|
||||
# create dir
|
||||
New-Item -Path "downloads" -ItemType Directory -Force | Out-Null
|
||||
|
||||
# download php
|
||||
if (-not(Test-Path "downloads\php.zip"))
|
||||
{
|
||||
Write-Host "Downloading PHP ..."
|
||||
Invoke-WebRequest $PHPRuntimeUrl -OutFile "downloads\php.zip"
|
||||
}
|
||||
|
||||
# extract php
|
||||
New-Item -Path "runtime" -ItemType Directory -Force | Out-Null
|
||||
Write-Host "Extracting php.zip ..."
|
||||
Expand-Archive -Path "downloads/php.zip" -DestinationPath "runtime" -Force
|
||||
# make php.ini
|
||||
Move-Item -Path "runtime\php.ini-production" -Destination "runtime\php.ini" -Force
|
||||
$OriginINI = Get-Content -Path "runtime\php.ini" -Raw
|
||||
$OriginINI = $OriginINI -replace ';extension=openssl', 'extension=openssl'
|
||||
$OriginINI = $OriginINI -replace ';extension=curl', 'extension=curl'
|
||||
$OriginINI = $OriginINI -replace ';extension=mbstring', 'extension=mbstring'
|
||||
$OriginINI = $OriginINI -replace ';extension=sodium', 'extension=sodium'
|
||||
$OriginINI = $OriginINI -replace ';extension_dir = "./"', ('extension_dir = "' + (Split-Path -Parent $MyInvocation.MyCommand.Definition) + '\..\runtime\ext"')
|
||||
$OriginINI | Set-Content -Path "runtime\php.ini"
|
||||
|
||||
# download composer
|
||||
if (-not(Test-Path "runtime\composer.phar"))
|
||||
{
|
||||
Write-Host "Downloading composer ..."
|
||||
Invoke-WebRequest $ComposerUrl -OutFile "downloads\composer.phar"
|
||||
Move-Item -Path "downloads\composer.phar" -Destination "runtime\composer.phar" -Force
|
||||
}
|
||||
|
||||
# create runtime\composer.ps1
|
||||
$ComposerContent = '
|
||||
$WorkingDir = (Split-Path -Parent $MyInvocation.MyCommand.Definition)
|
||||
& ($WorkingDir + "\php.exe") (Join-Path $WorkingDir "\composer.phar") @args
|
||||
'
|
||||
$ComposerContent | Set-Content -Path 'runtime\composer.ps1' -Encoding UTF8
|
||||
|
||||
Write-Host "Successfully downloaded PHP and Composer !" -ForegroundColor Green
|
||||
Write-Host "Use static-php-cli: " -NoNewline
|
||||
Write-Host "bin/spc" -ForegroundColor Cyan
|
||||
Write-Host "Use php: " -NoNewline
|
||||
Write-Host "runtime/php" -ForegroundColor Cyan
|
||||
Write-Host "Use composer: " -NoNewline
|
||||
Write-Host "runtime/composer" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Don't forget installing composer dependencies '" -NoNewline
|
||||
Write-Host "runtime/composer install" -ForegroundColor Cyan -NoNewline
|
||||
Write-Host "' before using static-php-cli !"
|
||||
Write-Host ""
|
||||
Write-Host "If you want to use this PHP for quality tools (like phpstan, php-cs-fixer) or other project,"
|
||||
Write-Host "or use PHP, Composer as system executable,"
|
||||
Write-Host "use '" -NoNewline
|
||||
Write-Host "bin/setup-runtime add-path" -ForegroundColor Cyan -NoNewline
|
||||
Write-Host "' to add runtime dir in Path."
|
||||
param (
|
||||
[string] ${action}
|
||||
)
|
||||
|
||||
function AddToPath {
|
||||
param (
|
||||
[string]$pathToAdd
|
||||
)
|
||||
|
||||
$currentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User')
|
||||
|
||||
if ($currentPath -notlike "*$pathToAdd*") {
|
||||
$newPath = $currentPath + ";$pathToAdd"
|
||||
[System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
||||
Write-Host "Added '$pathToAdd' to Path."
|
||||
Write-Host "To remove path, use: " -NoNewline
|
||||
Write-Host "bin/setup-runtime remove-path" -ForegroundColor Cyan
|
||||
} else {
|
||||
Write-Host "Path already exists."
|
||||
}
|
||||
}
|
||||
|
||||
function RemoveFromPath {
|
||||
param (
|
||||
[string]$pathToRemove
|
||||
)
|
||||
|
||||
$currentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User')
|
||||
|
||||
if ($currentPath -like "*$pathToRemove*") {
|
||||
$newPath = $currentPath -replace [regex]::Escape(';' + $pathToRemove), ''
|
||||
[System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
||||
Write-Host "Removed Path '$pathToRemove'"
|
||||
} else {
|
||||
Write-Host "Path '$pathToRemove' not in Path"
|
||||
}
|
||||
}
|
||||
|
||||
# working dir
|
||||
$WorkingDir = (Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Definition))
|
||||
|
||||
if ($action -eq 'add-path') {
|
||||
AddToPath ($WorkingDir + '\runtime')
|
||||
exit 0
|
||||
} elseif ($action -eq 'remove-path') {
|
||||
RemoveFromPath ($WorkingDir + '\runtime')
|
||||
exit 0
|
||||
} elseif (-not($action -eq '')) {
|
||||
Write-Host ("Invalid action: " + $action) -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# get php 8.1 specific version
|
||||
|
||||
# php windows download
|
||||
$PHPRuntimeUrl = "https://windows.php.net/downloads/releases/archives/php-8.4.4-nts-Win32-vs17-x64.zip"
|
||||
Write-Host "Downloading PHP from: " -NoNewline
|
||||
Write-Host $PHPRuntimeUrl -ForegroundColor Cyan
|
||||
$ComposerUrl = "https://getcomposer.org/download/latest-stable/composer.phar"
|
||||
|
||||
# create dir
|
||||
New-Item -Path "downloads" -ItemType Directory -Force | Out-Null
|
||||
|
||||
# download php
|
||||
if (-not(Test-Path "downloads\php.zip"))
|
||||
{
|
||||
Write-Host "Downloading PHP ..."
|
||||
Invoke-WebRequest $PHPRuntimeUrl -OutFile "downloads\php.zip"
|
||||
}
|
||||
|
||||
# extract php
|
||||
New-Item -Path "runtime" -ItemType Directory -Force | Out-Null
|
||||
Write-Host "Extracting php.zip ..."
|
||||
Expand-Archive -Path "downloads/php.zip" -DestinationPath "runtime" -Force
|
||||
# make php.ini
|
||||
Move-Item -Path "runtime\php.ini-production" -Destination "runtime\php.ini" -Force
|
||||
$OriginINI = Get-Content -Path "runtime\php.ini" -Raw
|
||||
$OriginINI = $OriginINI -replace ';extension=openssl', 'extension=openssl'
|
||||
$OriginINI = $OriginINI -replace ';extension=curl', 'extension=curl'
|
||||
$OriginINI = $OriginINI -replace ';extension=mbstring', 'extension=mbstring'
|
||||
$OriginINI = $OriginINI -replace ';extension=sodium', 'extension=sodium'
|
||||
$OriginINI = $OriginINI -replace ';extension_dir = "./"', ('extension_dir = "' + (Split-Path -Parent $MyInvocation.MyCommand.Definition) + '\..\runtime\ext"')
|
||||
$OriginINI | Set-Content -Path "runtime\php.ini"
|
||||
|
||||
# download composer
|
||||
if (-not(Test-Path "runtime\composer.phar"))
|
||||
{
|
||||
Write-Host "Downloading composer ..."
|
||||
Invoke-WebRequest $ComposerUrl -OutFile "downloads\composer.phar"
|
||||
Move-Item -Path "downloads\composer.phar" -Destination "runtime\composer.phar" -Force
|
||||
}
|
||||
|
||||
# create runtime\composer.ps1
|
||||
$ComposerContent = '
|
||||
$WorkingDir = (Split-Path -Parent $MyInvocation.MyCommand.Definition)
|
||||
& ($WorkingDir + "\php.exe") (Join-Path $WorkingDir "\composer.phar") @args
|
||||
'
|
||||
$ComposerContent | Set-Content -Path 'runtime\composer.ps1' -Encoding UTF8
|
||||
|
||||
Write-Host "Successfully downloaded PHP and Composer !" -ForegroundColor Green
|
||||
Write-Host "Use static-php-cli: " -NoNewline
|
||||
Write-Host "bin/spc" -ForegroundColor Cyan
|
||||
Write-Host "Use php: " -NoNewline
|
||||
Write-Host "runtime/php" -ForegroundColor Cyan
|
||||
Write-Host "Use composer: " -NoNewline
|
||||
Write-Host "runtime/composer" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Don't forget installing composer dependencies '" -NoNewline
|
||||
Write-Host "runtime/composer install" -ForegroundColor Cyan -NoNewline
|
||||
Write-Host "' before using static-php-cli !"
|
||||
Write-Host ""
|
||||
Write-Host "If you want to use this PHP for quality tools (like phpstan, php-cs-fixer) or other project,"
|
||||
Write-Host "or use PHP, Composer as system executable,"
|
||||
Write-Host "use '" -NoNewline
|
||||
Write-Host "bin/setup-runtime add-path" -ForegroundColor Cyan -NoNewline
|
||||
Write-Host "' to add runtime dir in Path."
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
$PHP_Exec = ".\runtime\php.exe"
|
||||
|
||||
if (-not(Test-Path $PHP_Exec)) {
|
||||
$PHP_Exec = Get-Command php.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Definition
|
||||
if (-not $PHP_Exec) {
|
||||
Write-Host "Error: PHP not found, you need to install PHP on your system or use 'bin/setup-runtime'." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
& "$PHP_Exec" -d xdebug.mode=debug -d xdebug.client_host=127.0.0.1 -d xdebug.client_port=9003 -d xdebug.start_with_request=yes ("bin/spc") @args
|
||||
exit $LASTEXITCODE
|
||||
$PHP_Exec = ".\runtime\php.exe"
|
||||
|
||||
if (-not(Test-Path $PHP_Exec)) {
|
||||
$PHP_Exec = Get-Command php.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Definition
|
||||
if (-not $PHP_Exec) {
|
||||
Write-Host "Error: PHP not found, you need to install PHP on your system or use 'bin/setup-runtime'." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
& "$PHP_Exec" -d xdebug.mode=debug -d xdebug.client_host=127.0.0.1 -d xdebug.client_port=9003 -d xdebug.start_with_request=yes ("bin/spc") @args
|
||||
exit $LASTEXITCODE
|
||||
|
||||
24
bin/spc.ps1
24
bin/spc.ps1
@@ -1,12 +1,12 @@
|
||||
$PHP_Exec = ".\runtime\php.exe"
|
||||
|
||||
if (-not(Test-Path $PHP_Exec)) {
|
||||
$PHP_Exec = Get-Command php.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Definition
|
||||
if (-not $PHP_Exec) {
|
||||
Write-Host "Error: PHP not found, you need to install PHP on your system or use 'bin/setup-runtime'." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
& "$PHP_Exec" ("bin/spc") @args
|
||||
exit $LASTEXITCODE
|
||||
$PHP_Exec = ".\runtime\php.exe"
|
||||
|
||||
if (-not(Test-Path $PHP_Exec)) {
|
||||
$PHP_Exec = Get-Command php.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Definition
|
||||
if (-not $PHP_Exec) {
|
||||
Write-Host "Error: PHP not found, you need to install PHP on your system or use 'bin/setup-runtime'." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
& "$PHP_Exec" ("bin/spc") @args
|
||||
exit $LASTEXITCODE
|
||||
|
||||
1
box.json
1
box.json
@@ -10,7 +10,6 @@
|
||||
"config",
|
||||
"src",
|
||||
"vendor/psr",
|
||||
"vendor/laravel/prompts",
|
||||
"vendor/symfony",
|
||||
"vendor/php-di",
|
||||
"vendor/zhamao"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"action": "bin/spc dev:lint-config --check",
|
||||
"action": "php bin/spc dev:lint-config --check",
|
||||
"conditions": [
|
||||
{
|
||||
"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\InDirectory",
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
"php": ">=8.4",
|
||||
"ext-mbstring": "*",
|
||||
"ext-zlib": "*",
|
||||
"laravel/prompts": "~0.1",
|
||||
"php-di/php-di": "^7.1",
|
||||
"symfony/console": "^5.4 || ^6 || ^7",
|
||||
"symfony/process": "^7.2",
|
||||
"symfony/yaml": "^7.2",
|
||||
"zhamao/logger": "^1.1.4"
|
||||
},
|
||||
|
||||
568
composer.lock
generated
568
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,10 @@ ncurses:
|
||||
license-files:
|
||||
- COPYING
|
||||
source:
|
||||
type: filelist
|
||||
url: 'https://ftp.gnu.org/gnu/ncurses/'
|
||||
regex: '/href="(?<file>ncurses-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
source-mirror:
|
||||
type: filelist
|
||||
url: 'https://ftpmirror.gnu.org/gnu/ncurses/'
|
||||
regex: '/href="(?<file>ncurses-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
|
||||
@@ -53,8 +53,8 @@ PHP_BUILD_PROVIDER="StaticPHP ${SPC_VERSION}"
|
||||
SPC_ENABLE_LOG_FILE="yes"
|
||||
; The LOG DIR for spc logs
|
||||
SPC_LOGS_DIR="${WORKING_DIR}/log"
|
||||
; Preserve old logs when running new builds
|
||||
SPC_PRESERVE_LOGS="no"
|
||||
; Preserve old logs when running new builds (code checks SPC_PRESERVE_LOG, not SPC_PRESERVE_LOGS)
|
||||
SPC_PRESERVE_LOG="no"
|
||||
|
||||
; 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
|
||||
@@ -68,8 +68,8 @@ SPC_PRESERVE_LOGS="no"
|
||||
[windows]
|
||||
; build target: win7-static
|
||||
SPC_TARGET=native-windows
|
||||
; php-sdk-binary-tools path
|
||||
PHP_SDK_PATH="${WORKING_DIR}\php-sdk-binary-tools"
|
||||
; MSYS2 root directory (msys64 subfolder), used by the Windows toolchain
|
||||
SPC_MSYS2_PATH="${PKG_ROOT_PATH}\msys2-build-essentials\msys64"
|
||||
; upx executable path
|
||||
UPX_EXEC="${PKG_ROOT_PATH}\bin\upx.exe"
|
||||
; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches
|
||||
|
||||
@@ -186,6 +186,7 @@ ext-password-argon2:
|
||||
type: php-extension
|
||||
depends:
|
||||
- libargon2
|
||||
suggests:
|
||||
- ext-openssl
|
||||
php-extension:
|
||||
os:
|
||||
|
||||
20
config/pkg/ext/ext-fastchart.yml
Normal file
20
config/pkg/ext/ext-fastchart.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
ext-fastchart:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: ghtar
|
||||
repo: iliaal/fastchart
|
||||
extract: php-src/ext/fastchart
|
||||
prefer-stable: true
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
depends:
|
||||
- freetype
|
||||
suggests:
|
||||
- libpng
|
||||
- libjpeg
|
||||
- libwebp
|
||||
php-extension:
|
||||
os:
|
||||
- Linux
|
||||
- Darwin
|
||||
14
config/pkg/ext/ext-fastjson.yml
Normal file
14
config/pkg/ext/ext-fastjson.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
ext-fastjson:
|
||||
type: php-extension
|
||||
artifact:
|
||||
source:
|
||||
type: ghtar
|
||||
repo: iliaal/fastjson
|
||||
extract: php-src/ext/fastjson
|
||||
prefer-stable: true
|
||||
metadata:
|
||||
license-files: [LICENSE]
|
||||
php-extension:
|
||||
os:
|
||||
- Linux
|
||||
- Darwin
|
||||
@@ -10,3 +10,5 @@ ext-gmssl:
|
||||
license: PHP-3.01
|
||||
depends:
|
||||
- gmssl
|
||||
php-extension:
|
||||
arg-type: with-path
|
||||
|
||||
@@ -13,4 +13,5 @@ ext-imagick:
|
||||
os:
|
||||
- Linux
|
||||
- Darwin
|
||||
- Windows
|
||||
arg-type: custom
|
||||
|
||||
@@ -10,6 +10,11 @@ ext-zip:
|
||||
license: PHP-3.01
|
||||
depends:
|
||||
- libzip
|
||||
depends@windows:
|
||||
- libzip
|
||||
- zlib
|
||||
- xz
|
||||
- bzip2
|
||||
php-extension:
|
||||
arg-type: custom
|
||||
arg-type@windows: enable
|
||||
|
||||
@@ -4,6 +4,6 @@ gettext-win:
|
||||
source:
|
||||
type: git
|
||||
url: 'https://github.com/winlibs/gettext.git'
|
||||
rev: master
|
||||
rev: '0.18'
|
||||
static-libs@windows:
|
||||
- libintl_a.lib
|
||||
|
||||
@@ -2,6 +2,10 @@ gettext:
|
||||
type: library
|
||||
artifact:
|
||||
source:
|
||||
type: filelist
|
||||
url: 'https://ftp.gnu.org/gnu/gettext/'
|
||||
regex: '/href="(?<file>gettext-(?<version>[^"]+)\.tar\.xz)"/'
|
||||
source-mirror:
|
||||
type: filelist
|
||||
url: 'https://ftpmirror.gnu.org/gnu/gettext/'
|
||||
regex: '/href="(?<file>gettext-(?<version>[^"]+)\.tar\.xz)"/'
|
||||
|
||||
@@ -3,11 +3,12 @@ gmp:
|
||||
artifact:
|
||||
source:
|
||||
type: filelist
|
||||
url: 'https://ftpmirror.gnu.org/gnu/gmp/'
|
||||
url: 'https://ftp.gnu.org/gnu/gmp/'
|
||||
regex: '/href="(?<file>gmp-(?<version>[^"]+)\.tar\.xz)"/'
|
||||
source-mirror:
|
||||
type: url
|
||||
url: 'https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz'
|
||||
type: filelist
|
||||
url: 'https://ftpmirror.gnu.org/gnu/gmp/'
|
||||
regex: '/href="(?<file>gmp-(?<version>[^"]+)\.tar\.xz)"/'
|
||||
metadata:
|
||||
license-files: ['@/gmp.txt']
|
||||
license: Custom
|
||||
|
||||
@@ -2,6 +2,10 @@ idn2:
|
||||
type: library
|
||||
artifact:
|
||||
source:
|
||||
type: filelist
|
||||
url: 'https://ftp.gnu.org/gnu/libidn/'
|
||||
regex: '/href="(?<file>libidn2-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
source-mirror:
|
||||
type: filelist
|
||||
url: 'https://ftpmirror.gnu.org/gnu/libidn/'
|
||||
regex: '/href="(?<file>libidn2-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
|
||||
@@ -16,13 +16,59 @@ imagemagick:
|
||||
- libtiff
|
||||
- libheif
|
||||
- bzip2
|
||||
depends@windows:
|
||||
- zlib
|
||||
suggests:
|
||||
- zstd
|
||||
- xz
|
||||
- libzip
|
||||
- libxml2
|
||||
headers@windows:
|
||||
- imagemagick/MagickWand/MagickWand.h
|
||||
lang: cpp
|
||||
pkg-configs:
|
||||
- Magick++-7.Q16HDRI
|
||||
- MagickCore-7.Q16HDRI
|
||||
- MagickWand-7.Q16HDRI
|
||||
static-libs@windows:
|
||||
- CORE_RL_MagickWand_.lib
|
||||
- CORE_RL_MagickCore_.lib
|
||||
- CORE_RL_coders_.lib
|
||||
- CORE_RL_filters_.lib
|
||||
- CORE_RL_aom_.lib
|
||||
- CORE_RL_brotli_.lib
|
||||
- CORE_RL_bzip2_.lib
|
||||
- CORE_RL_cairo_.lib
|
||||
- CORE_RL_croco_.lib
|
||||
- CORE_RL_de265_.lib
|
||||
- CORE_RL_exr_.lib
|
||||
- CORE_RL_ffi_.lib
|
||||
- CORE_RL_freetype_.lib
|
||||
- CORE_RL_fribidi_.lib
|
||||
- CORE_RL_gdk-pixbuf_.lib
|
||||
- CORE_RL_glib_.lib
|
||||
- CORE_RL_harfbuzz_.lib
|
||||
- CORE_RL_heif_.lib
|
||||
- CORE_RL_highway_.lib
|
||||
- CORE_RL_imath_.lib
|
||||
- CORE_RL_jpeg-turbo-12_.lib
|
||||
- CORE_RL_jpeg-turbo-16_.lib
|
||||
- CORE_RL_jpeg-turbo_.lib
|
||||
- CORE_RL_jpeg-xl_.lib
|
||||
- CORE_RL_lcms_.lib
|
||||
- CORE_RL_lqr_.lib
|
||||
- CORE_RL_lzma_.lib
|
||||
- CORE_RL_openh264_.lib
|
||||
- CORE_RL_openjpeg_.lib
|
||||
- CORE_RL_openjph_.lib
|
||||
- CORE_RL_pango_.lib
|
||||
- CORE_RL_pixman_.lib
|
||||
- CORE_RL_png_.lib
|
||||
- CORE_RL_raqm_.lib
|
||||
- CORE_RL_raw_.lib
|
||||
- CORE_RL_rsvg_.lib
|
||||
- CORE_RL_tiff_.lib
|
||||
- CORE_RL_webp_.lib
|
||||
- CORE_RL_xml_.lib
|
||||
- CORE_RL_zip_.lib
|
||||
- CORE_RL_zlib_.lib
|
||||
|
||||
@@ -9,5 +9,4 @@ libiconv-win:
|
||||
license-files: [source/COPYING]
|
||||
license: GPL-3.0-or-later
|
||||
static-libs@windows:
|
||||
- libiconv.lib
|
||||
- libiconv_a.lib
|
||||
|
||||
@@ -2,6 +2,10 @@ libiconv:
|
||||
type: library
|
||||
artifact:
|
||||
source:
|
||||
type: filelist
|
||||
url: 'https://ftp.gnu.org/gnu/libiconv/'
|
||||
regex: '/href="(?<file>libiconv-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
source-mirror:
|
||||
type: filelist
|
||||
url: 'https://ftpmirror.gnu.org/gnu/libiconv/'
|
||||
regex: '/href="(?<file>libiconv-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
|
||||
@@ -9,8 +9,10 @@ libssh2:
|
||||
metadata:
|
||||
license-files: [COPYING]
|
||||
license: BSD-3-Clause
|
||||
depends:
|
||||
depends@unix:
|
||||
- openssl
|
||||
depends@windows:
|
||||
- zlib
|
||||
headers:
|
||||
- libssh2.h
|
||||
- libssh2_publickey.h
|
||||
|
||||
@@ -2,6 +2,10 @@ libunistring:
|
||||
type: library
|
||||
artifact:
|
||||
source:
|
||||
type: filelist
|
||||
url: 'https://ftp.gnu.org/gnu/libunistring/'
|
||||
regex: '/href="(?<file>libunistring-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
source-mirror:
|
||||
type: filelist
|
||||
url: 'https://ftpmirror.gnu.org/gnu/libunistring/'
|
||||
regex: '/href="(?<file>libunistring-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
|
||||
@@ -11,6 +11,10 @@ libzip:
|
||||
license: BSD-3-Clause
|
||||
depends:
|
||||
- zlib
|
||||
depends@windows:
|
||||
- zlib
|
||||
- bzip2
|
||||
- xz
|
||||
suggests:
|
||||
- bzip2
|
||||
- xz
|
||||
|
||||
@@ -17,7 +17,6 @@ openssl:
|
||||
- zlib
|
||||
depends@windows:
|
||||
- zlib
|
||||
- jom
|
||||
headers:
|
||||
- openssl
|
||||
static-libs@unix:
|
||||
@@ -26,3 +25,7 @@ openssl:
|
||||
static-libs@windows:
|
||||
- libssl.lib
|
||||
- libcrypto.lib
|
||||
tools@windows:
|
||||
- jom
|
||||
- nasm
|
||||
- strawberry-perl
|
||||
|
||||
@@ -5,8 +5,6 @@ postgresql:
|
||||
type: ghtagtar
|
||||
repo: postgres/postgres
|
||||
match: REL_18_\d+
|
||||
binary:
|
||||
windows-x86_64: { type: url, url: 'https://get.enterprisedb.com/postgresql/postgresql-16.8-1-windows-x64-binaries.zip', extract: { lib/libpq.lib: '{build_root_path}/lib/libpq.lib', lib/libpgport.lib: '{build_root_path}/lib/libpgport.lib', lib/libpgcommon.lib: '{build_root_path}/lib/libpgcommon.lib', include/libpq-fe.h: '{build_root_path}/include/libpq-fe.h', include/postgres_ext.h: '{build_root_path}/include/postgres_ext.h', include/pg_config_ext.h: '{build_root_path}/include/pg_config_ext.h', include/libpq/libpq-fs.h: '{build_root_path}/include/libpq/libpq-fs.h' } }
|
||||
metadata:
|
||||
license-files: ['@/postgresql.txt']
|
||||
license: PostgreSQL
|
||||
@@ -16,6 +14,9 @@ postgresql:
|
||||
- openssl
|
||||
- zlib
|
||||
- libedit
|
||||
depends@windows:
|
||||
- openssl
|
||||
- zlib
|
||||
suggests@unix:
|
||||
- icu
|
||||
- libxslt
|
||||
@@ -27,3 +28,9 @@ postgresql:
|
||||
- libpq.lib
|
||||
- libpgport.lib
|
||||
- libpgcommon.lib
|
||||
tools@windows:
|
||||
- python-win
|
||||
- meson
|
||||
- ninja
|
||||
- winflexbison
|
||||
- strawberry-perl
|
||||
|
||||
@@ -2,6 +2,10 @@ readline:
|
||||
type: library
|
||||
artifact:
|
||||
source:
|
||||
type: filelist
|
||||
url: 'https://ftp.gnu.org/gnu/readline/'
|
||||
regex: '/href="(?<file>readline-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
source-mirror:
|
||||
type: filelist
|
||||
url: 'https://ftpmirror.gnu.org/gnu/readline/'
|
||||
regex: '/href="(?<file>readline-(?<version>[^"]+)\.tar\.gz)"/'
|
||||
|
||||
@@ -10,10 +10,8 @@ frankenphp:
|
||||
license: MIT
|
||||
depends:
|
||||
- php-embed
|
||||
- go-xcaddy
|
||||
depends@windows:
|
||||
- php-embed
|
||||
- go-win
|
||||
- pthreads4w
|
||||
suggests@unix:
|
||||
- brotli
|
||||
@@ -24,3 +22,7 @@ frankenphp:
|
||||
- frankenphp
|
||||
static-bins@windows:
|
||||
- frankenphp.exe
|
||||
tools:
|
||||
- go-xcaddy
|
||||
tools@windows:
|
||||
- go-win
|
||||
|
||||
8
config/pkg/target/msys2-build-essentials.yml
Normal file
8
config/pkg/target/msys2-build-essentials.yml
Normal 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'
|
||||
@@ -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' } }
|
||||
@@ -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}' }
|
||||
@@ -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' } }
|
||||
@@ -1,4 +0,0 @@
|
||||
zig:
|
||||
type: target
|
||||
artifact:
|
||||
binary: custom
|
||||
9
config/pkg/tool/7za-win.yml
Normal file
9
config/pkg/tool/7za-win.yml
Normal 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
|
||||
@@ -1,10 +1,15 @@
|
||||
go-win:
|
||||
type: target
|
||||
type: tool
|
||||
artifact:
|
||||
binary: custom
|
||||
env:
|
||||
GOROOT: '{pkg_root_path}/go-win'
|
||||
GOBIN: '{pkg_root_path}/go-win/bin'
|
||||
GOPATH: '{pkg_root_path}/go-win/go'
|
||||
GOPATH: '{pkg_root_path}/go-win/gopath'
|
||||
path@windows:
|
||||
- '{pkg_root_path}/go-win/bin'
|
||||
tool:
|
||||
provides:
|
||||
- go.exe
|
||||
- gofmt.exe
|
||||
binary-subdir: go-win/bin
|
||||
@@ -1,5 +1,5 @@
|
||||
go-xcaddy:
|
||||
type: target
|
||||
type: tool
|
||||
artifact:
|
||||
binary: custom
|
||||
env:
|
||||
@@ -8,5 +8,8 @@ go-xcaddy:
|
||||
GOPATH: '{pkg_root_path}/go-xcaddy/go'
|
||||
path@unix:
|
||||
- '{pkg_root_path}/go-xcaddy/bin'
|
||||
static-bins:
|
||||
- xcaddy
|
||||
tool:
|
||||
provides:
|
||||
- go
|
||||
- gofmt
|
||||
binary-subdir: go-xcaddy/bin
|
||||
@@ -1,7 +1,11 @@
|
||||
jom:
|
||||
type: target
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
windows-x86_64: { type: url, url: 'https://download.qt.io/official_releases/jom/jom.zip', extract: '{pkg_root_path}/jom' }
|
||||
path@windows:
|
||||
- '{pkg_root_path}\jom'
|
||||
tool:
|
||||
provides:
|
||||
- jom.exe
|
||||
binary-subdir: jom
|
||||
11
config/pkg/tool/meson.yml
Normal file
11
config/pkg/tool/meson.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
meson:
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
windows-x86_64: { type: url, url: 'https://github.com/mesonbuild/meson/releases/download/1.11.1/meson-1.11.1-py3-none-any.whl', extract: '{pkg_root_path}/meson/meson-1.11.1-py3-none-any.whl' }
|
||||
path@windows:
|
||||
- '{pkg_root_path}\meson'
|
||||
tool:
|
||||
provides:
|
||||
- meson.bat
|
||||
binary-subdir: meson
|
||||
10
config/pkg/tool/nasm.yml
Normal file
10
config/pkg/tool/nasm.yml
Normal 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
|
||||
9
config/pkg/tool/ninja.yml
Normal file
9
config/pkg/tool/ninja.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
ninja:
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
windows-x86_64: { type: url, url: 'https://github.com/ninja-build/ninja/releases/download/v1.13.2/ninja-win.zip', extract: { ninja.exe: '{pkg_root_path}/bin/ninja.exe' } }
|
||||
tool:
|
||||
provides:
|
||||
- ninja.exe
|
||||
binary-subdir: bin
|
||||
13
config/pkg/tool/pkg-config.yml
Normal file
13
config/pkg/tool/pkg-config.yml
Normal 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
|
||||
@@ -1,8 +1,12 @@
|
||||
protoc:
|
||||
type: target
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
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' }
|
||||
path:
|
||||
- '{pkg_root_path}/protoc/bin'
|
||||
tool:
|
||||
provides:
|
||||
- protoc
|
||||
binary-subdir: protoc/bin
|
||||
8
config/pkg/tool/python-win.yml
Normal file
8
config/pkg/tool/python-win.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
python-win:
|
||||
type: tool
|
||||
artifact:
|
||||
binary: custom
|
||||
tool:
|
||||
provides:
|
||||
- python.exe
|
||||
binary-subdir: python-win/tools
|
||||
@@ -1,5 +1,9 @@
|
||||
strawberry-perl:
|
||||
type: target
|
||||
type: tool
|
||||
artifact:
|
||||
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' }
|
||||
tool:
|
||||
provides:
|
||||
- perl.exe
|
||||
binary-subdir: strawberry-perl/perl/bin
|
||||
@@ -1,7 +1,13 @@
|
||||
upx:
|
||||
type: target
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
linux-x86_64: { type: ghrel, repo: upx/upx, match: upx.+-amd64_linux\.tar\.xz, extract: { upx: '{pkg_root_path}/bin/upx' } }
|
||||
linux-aarch64: { type: ghrel, repo: upx/upx, match: upx.+-arm64_linux\.tar\.xz, extract: { upx: '{pkg_root_path}/bin/upx' } }
|
||||
windows-x86_64: { type: ghrel, repo: upx/upx, match: upx.+-win64\.zip, extract: { upx.exe: '{pkg_root_path}/bin/upx.exe' } }
|
||||
tool:
|
||||
provides:
|
||||
- upx
|
||||
provides@windows:
|
||||
- upx.exe
|
||||
binary-subdir: bin
|
||||
@@ -1,5 +1,9 @@
|
||||
vswhere:
|
||||
type: target
|
||||
type: tool
|
||||
artifact:
|
||||
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' }
|
||||
tool:
|
||||
provides:
|
||||
- vswhere.exe
|
||||
binary-subdir: bin
|
||||
12
config/pkg/tool/winflexbison.yml
Normal file
12
config/pkg/tool/winflexbison.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
winflexbison:
|
||||
type: tool
|
||||
artifact:
|
||||
binary:
|
||||
windows-x86_64: { type: url, url: 'https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip', extract: '{pkg_root_path}/winflexbison' }
|
||||
path@windows:
|
||||
- '{pkg_root_path}\winflexbison'
|
||||
tool:
|
||||
provides:
|
||||
- win_flex.exe
|
||||
- win_bison.exe
|
||||
binary-subdir: winflexbison
|
||||
14
config/pkg/tool/zig.yml
Normal file
14
config/pkg/tool/zig.yml
Normal 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
|
||||
@@ -51,6 +51,7 @@ export default {
|
||||
{ text: 'Build Lifecycle', link: '/en/develop/build-lifecycle' },
|
||||
{ text: 'Compilation Tools', link: '/en/develop/system-build-tools' },
|
||||
{ text: 'Doctor', link: '/en/develop/doctor-module' },
|
||||
{ text: 'Performance Engineering', link: '/en/develop/performance' },
|
||||
{ text: 'PHP Source Modifications', link: '/en/develop/php-src-changes' },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -51,6 +51,7 @@ export default {
|
||||
{ text: '构建生命周期', link: '/zh/develop/build-lifecycle' },
|
||||
{ text: '编译工具', link: '/zh/develop/system-build-tools' },
|
||||
{ text: 'Doctor 环境检查', link: '/zh/develop/doctor-module' },
|
||||
{ text: '性能工程', link: '/zh/develop/performance' },
|
||||
{ text: '对 PHP 源码的修改', link: '/zh/develop/php-src-changes' },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -229,7 +229,7 @@ The following path placeholders are supported in string values of the `path`, `e
|
||||
| `{working_dir}` | Working directory (project root) |
|
||||
| `{download_path}` | Download cache directory (`downloads/`) |
|
||||
| `{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
|
||||
|
||||
|
||||
301
docs/en/develop/performance.md
Normal file
301
docs/en/develop/performance.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# Performance Engineering
|
||||
|
||||
StaticPHP controls how PHP, its extensions, dependency libraries, and SAPIs are compiled. These choices can affect runtime throughput and latency, startup time, memory use, binary size, portability, and build time. They are related, but they are not the same metric: a smaller binary is not necessarily faster, and a slower build can still produce a faster program.
|
||||
|
||||
This page records the current v3 defaults, the optimization work already incorporated into the build, and the areas still being investigated. On Linux, libc and linkage form the first layer: the default fully static musl build and a dynamically linked glibc build have different portability, extension-loading, and performance characteristics. Compiler flags, PGO, and LTO form later layers of the same ongoing work.
|
||||
|
||||
This page does not claim that a StaticPHP binary is always faster than another PHP distribution. Results depend on the PHP version, CPU, toolchain, extension set, SAPI, libc, linkage, runtime configuration, and workload.
|
||||
|
||||
::: warning Current v3 status
|
||||
The v3 branch does not currently expose stable `--pgi`, `--pgo`, or `--lto` CLI options. PGO orchestration and broader LTO compatibility remain active areas of investigation. The sections below describe their design, current constraints, and the direction of that work rather than a supported release recipe.
|
||||
:::
|
||||
|
||||
## Linux Linkage and libc
|
||||
|
||||
StaticPHP's Linux default optimizes for a self-contained artifact, not for the highest possible score on every server workload. `config/env.ini` selects `${GNU_ARCH}-linux-musl`; with the default Zig toolchain this produces a fully static musl binary.
|
||||
|
||||
Current performance investigations distinguish three Linux targets:
|
||||
|
||||
| Target | libc and final linkage | Runtime requirements | Shared extensions / FFI | Current role |
|
||||
|---|---|---|---|---|
|
||||
| `native-native-musl` | musl, fully static | Linux kernel on a compatible CPU | No | Default portable single-file release |
|
||||
| `native-native-musl -dynamic` | musl, dynamically linked | Compatible musl loader and libraries | Yes | Isolate static-versus-dynamic effects while keeping musl |
|
||||
| `native-native-gnu.2.17` | glibc, dynamically linked with a 2.17 baseline | glibc 2.17 or newer | Yes | Broad GNU/Linux compatibility and a glibc performance baseline |
|
||||
|
||||
The architecture may replace either `native` component, for example `x86_64-linux-musl`. A `-gnu` target without an explicit version targets the selected/current glibc ABI instead of promising the 2.17 floor.
|
||||
|
||||
In this context, “dynamically linked PHP” does not mean every dependency is a system `.so`. StaticPHP still builds most selected third-party libraries and PHP extensions as static archives and links them into the PHP executable. The dynamic part is primarily the libc/runtime loader and any extensions explicitly requested through `--build-shared`. This differs from a conventional distribution PHP in which PHP and many dependencies are separate shared objects.
|
||||
|
||||
Likewise, a “static extension” and a “static libc” are independent choices. A glibc-dynamic PHP can contain all PHP extensions statically, while a musl-dynamic PHP can load selected `.so` extensions. Only a fully static musl target prevents runtime loading because no dynamic loader participates in the process.
|
||||
|
||||
### What Static versus Dynamic Linking Changes
|
||||
|
||||
Static and dynamic linkage mainly change startup work, relocation, symbol resolution, deployment, and library sharing. They do not automatically change PHP VM code generation.
|
||||
|
||||
- A fully static process does not start through a runtime dynamic loader or relocate a set of DSOs. This can help very short-lived CLI startup, but PHP initialization, extension startup, script parsing, and Opcache often cost more.
|
||||
- A dynamic process pays loader and relocation costs at startup. Long-running FPM or FrankenPHP workers amortize this cost over many requests.
|
||||
- Static linking gives the linker a larger closed world for section garbage collection and, when explicitly enabled, LTO. Static linking alone does not perform cross-object optimization.
|
||||
- Dynamic glibc allows shared extensions, FFI, NSS integration, and replacement or security updates of runtime libraries without rebuilding PHP. A fully static artifact must be rebuilt to receive libc or embedded-library fixes.
|
||||
- Shared-library code pages can be reused across different programs. Identical static PHP worker processes still share file-backed executable pages with one another, so “static means every worker duplicates all code in RAM” is not an accurate model.
|
||||
|
||||
StaticPHP's [performance testing issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838) recorded one PHP 8.4 test in which static and dynamic builds stayed within about 1% in either direction across repeated runs. This is useful evidence that linkage alone may not dominate steady-state PHP execution, but it is not a universal result. Short CLI programs, many DSOs, different loaders, and I/O-heavy extensions can produce a different outcome.
|
||||
|
||||
### musl versus glibc Performance Surfaces
|
||||
|
||||
libc differences appear only when a workload reaches libc or behavior implemented around it. Pure PHP code spends much of its time in the Zend VM, Opcache, and Zend Memory Manager. PHP's own [Zend Memory Manager](https://wiki.php.net/internals/zend_mm) handles most request-bound allocations, so a microbenchmark dominated by PHP arrays and opcodes may expose less of the system allocator than a C extension or server runtime does.
|
||||
|
||||
| Workload area | Why the libc can matter | Main observed signals |
|
||||
|---|---|---|
|
||||
| CPU-bound PHP opcodes | Usually dominated by PHP VM, compiler, CPU target, and Opcache rather than libc | Same PHP/VM/compiler first; then change only libc/linkage |
|
||||
| Persistent and native allocations | Persistent PHP allocations, C extensions, libraries, and server code can call libc allocation directly | throughput, allocation contention, RSS, fragmentation after a long soak |
|
||||
| ZTS and FrankenPHP | Thread creation, TLS, mutexes, allocator contention, and per-thread caches differ | scaling by worker/thread count, p95/p99, RSS per thread |
|
||||
| DNS and name services | Resolver strategy, NSS, `/etc/resolv.conf`, and caching differ | cached and uncached lookup latency, failure/failover latency, query volume |
|
||||
| Locale, iconv, regex, and stdio | Implementations and supported behavior differ, not merely speed | correctness first, then throughput with production locale/data |
|
||||
| Very short CLI commands | Loader/relocation and initialization are a larger fraction of total time | cold and warm wall time over many process launches |
|
||||
| Long-running workers | Startup is amortized; allocator, threading, syscalls, and application behavior become more important | sustained throughput, tail latency, peak/steady RSS |
|
||||
|
||||
glibc's allocator provides per-thread caches and multiple arenas whose limits can be tuned; these can improve concurrent allocation throughput at the cost of retained memory. The [glibc allocation tunables](https://sourceware.org/glibc/manual/latest/html_node/Memory-Allocation-Tunables.html) therefore belong in a benchmark record. musl uses a different allocator and prioritizes low baseline overhead, bounded fragmentation, and static-linking suitability; neither design guarantees lower latency or RSS for every PHP application.
|
||||
|
||||
Resolver behavior can reverse an apparent “libc performance” result. The [musl functional-differences documentation](https://wiki.musl-libc.org/functional-differences-from-glibc.html) notes that musl queries configured nameservers in parallel, while traditional glibc behavior tries them sequentially. This can improve failover latency but increase DNS traffic. glibc also participates in configurable NSS modules. StaticPHP's DNS comparisons therefore keep resolver, cache state, search domains, and failure conditions consistent instead of treating resolver results as a CPU-only benchmark.
|
||||
|
||||
musl uses a much smaller default thread stack than typical glibc configurations. That can reduce reserved address space for thread-heavy programs but can also expose stack assumptions in extensions. It is a deployment and memory characteristic, not proof that one libc executes PHP opcodes faster.
|
||||
|
||||
### Current Comparison Model
|
||||
|
||||
A direct comparison between the default musl-static binary and a distribution glibc PHP changes libc, linker, compiler, flags, PHP configuration, extensions, dependency versions, and INI at once. It therefore cannot attribute the full difference to libc.
|
||||
|
||||
The project uses a controlled matrix with the same StaticPHP commit, PHP source, Zig version, flags, extensions, and SAPI. The three builds are represented by the following commands:
|
||||
|
||||
```bash
|
||||
EXTENSIONS="bcmath,curl,openssl,opcache"
|
||||
|
||||
# A: default-style, fully static musl
|
||||
SPC_TARGET=native-native-musl spc build:php "$EXTENSIONS" --build-cli
|
||||
|
||||
# B: dynamically linked musl; requires a musl runtime
|
||||
SPC_TARGET="native-native-musl -dynamic" spc build:php "$EXTENSIONS" --build-cli
|
||||
|
||||
# C: dynamically linked glibc with a defined compatibility floor
|
||||
SPC_TARGET=native-native-gnu.2.17 spc build:php "$EXTENSIONS" --build-cli
|
||||
```
|
||||
|
||||
Each result is associated with its output, build manifest, `php -i`, and logs. The actual linkage is identified from the binary rather than inferred from its filename:
|
||||
|
||||
```bash
|
||||
file buildroot/bin/php
|
||||
readelf -l buildroot/bin/php | grep 'Requesting program interpreter'
|
||||
```
|
||||
|
||||
A versus B estimates the linkage effect while holding musl constant. B versus C estimates libc/runtime effects with dynamic linkage on both sides. A distribution PHP remains useful as an external reference, but it is reported separately because its compiler and packaging configuration are different.
|
||||
|
||||
The current comparison set covers both no-op startup and real CLI scripts. FPM and FrankenPHP measurements separate worker warmup from sustained throughput and tail latency. libc-sensitive coverage includes allocation-heavy extension work, concurrent requests, DNS cache hit/miss/failure cases, file I/O, and long-running RSS/fragmentation behavior.
|
||||
|
||||
### Deployment Characteristics
|
||||
|
||||
- **musl static** is the StaticPHP default and represents the portable, self-contained deployment profile without shared extensions or FFI.
|
||||
- **glibc dynamic** represents integration with a GNU/Linux runtime, including `.so` extensions, FFI, the host name-service stack, and workloads for which glibc produces better measured behavior.
|
||||
- **musl dynamic** represents a musl-based runtime that still requires shared extensions. It also provides the middle point in the controlled comparison above, while giving up much of the default's single-file portability.
|
||||
|
||||
The default is designed to remain predictable and broadly deployable. The fastest target is workload-specific and continues to be evaluated against the actual CPU, PHP version, SAPI, and application behavior.
|
||||
|
||||
## Where Optimization Enters the v3 Build
|
||||
|
||||
The v3 build passes optimization settings through several layers:
|
||||
|
||||
1. `config/env.ini` supplies platform defaults. `config/env.custom.ini` or the process environment can override them.
|
||||
2. `ToolchainManager` selects Zig on Linux, MSVC on Windows, and system, Homebrew, or MacPorts Clang on macOS by default. It initializes `CC`, `CXX`, `AR`, `RANLIB`, and `LD`.
|
||||
3. Package executors and `Package::getLibExtra*Flags()` pass the default flags into Autoconf, CMake, and package-specific builds.
|
||||
4. The PHP target passes its PHP-specific flags to both `./configure` and `make` on Unix. Static extensions compiled as part of php-src see the same compiler environment.
|
||||
5. The FrankenPHP target links the PHP embed library through CGO. Its `CGO_CFLAGS` and `CGO_LDFLAGS` include the PHP and dependency-library flags, followed by Go and external-linker settings.
|
||||
6. Deployment extracts separate debug information and strips Unix binaries by default. UPX is optional and affects size and startup behavior, not generated PHP code.
|
||||
|
||||
This propagation is intentionally broad, but it is not yet perfectly uniform. Packages with hand-written compiler commands or unusual upstream build systems may ignore part of the global flag set. Extending consistent C, C++, and linker-flag propagation across those adapters remains part of the optimization work.
|
||||
|
||||
## Current Default Configuration
|
||||
|
||||
The authoritative values are in `config/env.ini`. The following tables explain the current v3 defaults rather than replacing that file.
|
||||
|
||||
### Linux Compiler Defaults
|
||||
|
||||
These compiler defaults apply to the Linux targets above. The v3 toolchain manager selects Zig unless a maintainer-level `SPC_TOOLCHAIN` override is used.
|
||||
|
||||
| Variable | Current default | Purpose |
|
||||
|---|---|---|
|
||||
| `SPC_DEFAULT_CFLAGS` | `-fPIC -O3 -pipe -fno-plt -fno-semantic-interposition -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections` | Common C flags for libraries and PHP |
|
||||
| `SPC_DEFAULT_CXXFLAGS` | `${SPC_DEFAULT_CFLAGS}` | Common C++ flags |
|
||||
| `SPC_DEFAULT_LDFLAGS` | `-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -Wl,-z,noexecstack -Wl,--gc-sections` | Link hardening, dependency pruning, and unused-section removal |
|
||||
| `SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS` | `-g -fstack-protector-strong -fno-ident -fPIE -fvisibility=hidden -fvisibility-inlines-hidden ${SPC_DEFAULT_CFLAGS}` | PHP and in-tree extension C flags |
|
||||
| `SPC_CMD_VAR_PHP_MAKE_EXTRA_CXXFLAGS` | The corresponding C++ form | PHP and in-tree extension C++ flags |
|
||||
| `SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS` | Empty | Additional PHP program linker flags |
|
||||
|
||||
The important performance-related defaults are:
|
||||
|
||||
- `-O3` favors runtime speed over compilation time and code size.
|
||||
- `-fno-semantic-interposition` gives the optimizer more freedom for ELF symbols that cannot be interposed in the final program.
|
||||
- `-fno-plt` avoids the traditional ELF procedure linkage table sequence where the toolchain can do so.
|
||||
- `-ffunction-sections -fdata-sections` combined with `--gc-sections` lets the linker remove unused functions and data.
|
||||
- Frame pointers and `-g` are deliberately retained during compilation for profiling and debugging. The deployed Unix binary is stripped by default, while separate debug information is written under `buildroot/debug/`.
|
||||
|
||||
The default PHP configure command also enables `--enable-re2c-cgoto`, disables unused SAPIs and shared PHP libraries, and builds only the requested extensions. These choices reduce unnecessary code; their runtime effect remains workload-dependent.
|
||||
|
||||
### macOS
|
||||
|
||||
macOS uses the native target and system Clang by default. v3 also supports the newer upstream LLVM distributions from Homebrew and MacPorts through `SPC_USE_LLVM=brew` and `SPC_USE_LLVM=port`. The Homebrew variant selects its `clang`, `clang++`, `llvm-ar`, and `llvm-ranlib` as one coherent toolchain rather than mixing them with the Apple-provided tools.
|
||||
|
||||
Homebrew LLVM is one of StaticPHP's current macOS performance paths. Its newer optimizer and code-generation backend can produce faster PHP binaries for some PHP versions and workloads, while also allowing the project to evaluate compiler improvements without waiting for Apple's system Clang release cycle. This is not a guaranteed uplift: PHP VM changes, CPU architecture, extensions, Opcache, and compiler flags can change the result. The project's [performance testing issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838) shows that compiler and optimization-level effects are version- and workload-specific, while the later [v3 toolchain discussion](https://github.com/crazywhalecc/static-php-cli/issues/985#issuecomment-3860775962) records access to an up-to-date compiler as the motivation for the additional macOS LLVM path.
|
||||
|
||||
| Variable | Current default | Purpose |
|
||||
|---|---|---|
|
||||
| `SPC_DEFAULT_CFLAGS` | `--target=${MAC_ARCH}-apple-darwin -O3 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections` | Target selection, optimization, observability, and section splitting |
|
||||
| `SPC_DEFAULT_CXXFLAGS` | `${SPC_DEFAULT_CFLAGS}` | Common C++ flags |
|
||||
| `SPC_DEFAULT_LDFLAGS` | `-Wl,-dead_strip` | Removes unreachable Mach-O code and data |
|
||||
| PHP extra flags | `-g`, stack protection, PIC/PIE, hidden visibility, and the defaults above | PHP and in-tree extension compilation |
|
||||
|
||||
### Windows
|
||||
|
||||
Windows uses MSVC and the static CRT patches described in [PHP Source Modifications](./php-src-changes). PHP's release configuration supplies its upstream optimization flags, while StaticPHP rewrites the final CLI, CGI, micro, and embed link rules to include `/LTCG`. Dependency CMake builds commonly use `/MT /Os /Ob1 /DNDEBUG`; individual packages may choose other release flags.
|
||||
|
||||
`--no-strip` preserves PDB/debug information while keeping `/O2` optimization in StaticPHP's rewritten build command. This is intentional: debug symbols and disabled optimization are separate concerns.
|
||||
|
||||
Windows FrankenPHP uses Clang/LLD for the CGO link. Some Windows libraries explicitly avoid `/GL` because MSVC LTCG objects are not accepted by this link path. `/LTCG` on the final link line therefore does not mean every input participates in whole-program optimization.
|
||||
|
||||
## Optimization Dimensions
|
||||
|
||||
StaticPHP treats performance as several related metrics rather than one score. Each dimension is affected by a different part of the build:
|
||||
|
||||
| Goal | Usually measured as | Main influencing controls |
|
||||
|---|---|---|
|
||||
| Request throughput | requests/s at fixed concurrency | SAPI mode, Opcache, worker model, PHP version, compiler and CPU target |
|
||||
| Tail latency | p50/p95/p99 and error rate | workload, warmup, contention, worker count, JIT/Opcache, memory pressure |
|
||||
| CLI execution | wall time, CPU time, peak RSS | startup cost, Opcache CLI setting, extension set, PHP/compiler version |
|
||||
| Binary size | deployed bytes and debug-file bytes | extension set, section GC/dead stripping, symbol stripping, UPX |
|
||||
| Portability | oldest CPU/OS/libc that runs the binary | `SPC_TARGET`, CPU ISA flags, static versus dynamic libc |
|
||||
| Build speed | clean build wall time and peak disk/RAM | `SPC_CONCURRENCY`, toolchain, LTO/PGO, number of packages |
|
||||
|
||||
Comparable results keep the PHP version, commit, extensions, dependency versions, SAPI, ZTS/NTS mode, INI, target libc, compiler, CPU frequency policy, and workload constant.
|
||||
|
||||
## Runtime Optimization Surfaces
|
||||
|
||||
### 1. Reproducible Configuration Overrides
|
||||
|
||||
`config/env.custom.ini` provides the reproducible override layer while leaving `config/env.ini` as the project baseline. Values replace the complete default string rather than being appended automatically, so performance investigations preserve the baseline and isolate one changed factor.
|
||||
|
||||
For example, an x86-64-v3-specific investigation retains the Linux defaults and adds the ISA level:
|
||||
|
||||
```ini
|
||||
[linux]
|
||||
SPC_DEFAULT_CFLAGS="-fPIC -O3 -pipe -fno-plt -fno-semantic-interposition -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections -march=x86-64-v3"
|
||||
SPC_DEFAULT_CXXFLAGS="${SPC_DEFAULT_CFLAGS}"
|
||||
```
|
||||
|
||||
This may allow more vector and instruction selection, but the output no longer runs on CPUs below that ISA level. `-march=native` narrows portability further by coupling the result to the build host's CPU class.
|
||||
|
||||
PHP-only investigations are represented by `SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS` and its C++ counterpart rather than the global defaults. Individual-package investigations use snake-case variables such as `libaom_CFLAGS`, `libaom_CXXFLAGS`, and `libaom_LDFLAGS`. Package-specific flags are combined with the defaults when that package uses the common v3 executors.
|
||||
|
||||
### 2. Toolchain and PHP-Version Effects
|
||||
|
||||
The compiler can matter more than an individual optimization flag. [Issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838) found large GCC-versus-Clang differences for some PHP 8.4 x86-64 tests because PHP's older VM can use GCC global register variables. That result is not universal: architecture, PHP version, VM implementation, and workload all matter, and PHP 8.5 changes the comparison with its newer VM.
|
||||
|
||||
Linux v3 defaults to Zig for target flexibility and reproducible libc selection, not because it is guaranteed to produce the fastest binary for every workload. The project's performance work compares this predictable baseline with native toolchains on deployment architectures. `SPC_TOOLCHAIN` remains an internal/maintainer control until a stable user-facing selector is documented.
|
||||
|
||||
### 3. SAPI, Thread Safety, and Runtime Settings
|
||||
|
||||
- FrankenPHP requires ZTS. CLI, FPM, CGI, micro, and embed remain NTS by default unless the selected SAPI or application requires thread safety.
|
||||
- Historical tests in issue #838 observed small ZTS/NTS differences in that particular suite; the result remains specific to that workload.
|
||||
- Including `ext-opcache` only builds the extension. Its performance characteristics also depend on runtime INI, including `opcache.enable_cli` for repeated CLI execution and application-specific JIT settings.
|
||||
- `--disable-opcache-jit` changes build capability; it is not a substitute for runtime benchmarking. StaticPHP disables the undefined-behavior sanitizer where necessary when Opcache JIT is built on Linux.
|
||||
- FrankenPHP performance also depends on worker versus classic mode, worker count, application boot behavior, Caddy modules, and Go runtime settings. Compiler flags cannot compensate for an unrepresentative server configuration.
|
||||
|
||||
### 4. Speed, Symbols, and Compression
|
||||
|
||||
The default Unix deployment extracts debug information, strips the runtime binary, and keeps the debug file separately. `--no-strip` represents the unstripped variant while current v3 keeps optimization enabled.
|
||||
|
||||
`--with-upx-pack` is a size optimization for Linux and Windows. It can change startup time, memory mapping, security-tool behavior, and debuggability, so the project treats it as a packaging tradeoff rather than a PHP execution optimization.
|
||||
|
||||
## Profile-Guided Optimization (PGO)
|
||||
|
||||
PGO builds an instrumented program, runs a representative workload to collect profiles, and recompiles using the observed branch, call, and value frequencies. The compiler can then improve code layout, inlining, and hot/cold decisions beyond static heuristics.
|
||||
|
||||
A complete PGO design contains three distinct phases:
|
||||
|
||||
1. **Instrumentation** builds the same PHP version, SAPI, extensions, dependencies, and target with profile-generation flags.
|
||||
2. **Training** covers startup and important production paths at representative traffic mixes and concurrency, including a clean shutdown so raw profiles are flushed.
|
||||
3. **Profile use** merges the raw profiles with the matching toolchain utility and rebuilds the identical source/configuration with profile-use flags.
|
||||
|
||||
Profiles are inputs to the build, not portable benchmark artifacts. Meaningful changes to PHP, extensions, dependencies, compiler version, flags, SAPI linkage, or workload invalidate them. A narrow or stale profile can improve the trained route while making untrained behavior worse.
|
||||
|
||||
### StaticPHP PGO Status
|
||||
|
||||
The experimental v3 design explores a dedicated PGO context and lifecycle hooks for CLI, CGI, FPM, micro, embed, and FrankenPHP. The concepts under evaluation include:
|
||||
|
||||
- instrument and profile-use phases, plus an optional context-sensitive second instrumentation phase;
|
||||
- per-SAPI raw-profile directories and merged `.profdata` files;
|
||||
- clean rebuilds when switching the active SAPI profile;
|
||||
- shutdown patches for php-src and FrankenPHP, because the Go/CGO process does not reliably run the libc `atexit` path that normally flushes profiles;
|
||||
- LLVM profile tooling and special linker/runtime handling for Zig, Clang, GCC, and FrankenPHP.
|
||||
|
||||
This work is not part of the stable v3 feature set. The current v3 tree contains some preparatory compatibility handling—for example, FrankenPHP detects manual `-fprofile*` C flags when using native GCC, suppresses missing-profile errors, and links `libgcov`—but complete training, merging, invalidation, and rebuilding orchestration remains under investigation.
|
||||
|
||||
A raw `-fprofile-generate` addition to the global defaults is not equivalent to this orchestration: it also instruments dependency libraries, changes link requirements, increases build and runtime cost, and may fail to flush usable data. For that reason, the current internal variables do not yet constitute a stable release workflow.
|
||||
|
||||
### FrankenPHP's Go PGO
|
||||
|
||||
[PR #1142](https://github.com/crazywhalecc/static-php-cli/pull/1142) added FrankenPHP's upstream `default.pgo` to the v2 xcaddy build when present. That profile optimizes the Go portion using a profile distributed with FrankenPHP. It does not train php-src, the PHP embed library, extensions, or CGO glue against your application.
|
||||
|
||||
A future end-to-end FrankenPHP PGO design may therefore contain two profile sources:
|
||||
|
||||
- FrankenPHP's upstream Go profile for the Go/Caddy code;
|
||||
- application-specific compiler profiles for PHP, static extensions, and CGO-linked C code.
|
||||
|
||||
Their ownership and invalidation rules are separate concerns in the current design exploration.
|
||||
|
||||
## Link-Time Optimization (LTO)
|
||||
|
||||
LTO retains compiler intermediate representation until link time so the optimizer can work across translation units. Full LTO processes the combined program more aggressively; ThinLTO distributes more work and usually reduces memory and build-time cost.
|
||||
|
||||
Static linking does not automatically enable LTO. Conversely, adding `-flto` to only the final link is insufficient: relevant objects and archives must be produced with a compatible compiler, LTO mode, archiver, ranlib, and linker plugin.
|
||||
|
||||
Unix v3 does not enable LTO by default. Historical work made more archive commands respect the selected `AR`, but the project later removed default LTO work because compatibility fixes across dependency libraries were costly. In [issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838), one test environment observed only about 2% runtime improvement while ThinLTO roughly doubled build time and full LTO increased it by about seven times. These are historical measurements on one setup, not a promised ratio.
|
||||
|
||||
Current Unix LTO investigations account for the following constraints:
|
||||
|
||||
1. Objects, archives, and the final link need one compatible LLVM/Clang or GCC toolchain family.
|
||||
2. C, C++, PHP, and linker flags need the same mode, such as `-flto=thin`.
|
||||
3. Limiting the initial scope to PHP and its in-tree extensions separates core results from dependency-library compatibility.
|
||||
4. Archive contents and the final link log reveal whether LTO reached the intended objects; build completion alone does not.
|
||||
5. SAPI and extension smoke tests, clean build time, binary size, throughput, and tail latency together describe the result.
|
||||
|
||||
LTO can expose package bugs, unsupported assembly, incompatible archives, symbol-export problems, and Go/CGO linker limitations. It can also increase code size or regress instruction-cache behavior. These compatibility and maintenance costs are why Unix LTO remains opt-in while its benefits continue to be evaluated.
|
||||
|
||||
## Performance Evidence and Reproducibility
|
||||
|
||||
StaticPHP performance investigations record enough context for another maintainer to reproduce the result:
|
||||
|
||||
- StaticPHP commit and registry/package revisions;
|
||||
- PHP, FrankenPHP, Go, compiler, linker, and profile-tool versions;
|
||||
- host and target OS, libc, architecture, and exact `SPC_TARGET`;
|
||||
- CPU model, available instruction set, power/frequency policy, memory, and virtualization;
|
||||
- complete extension and dependency set, ZTS/NTS, SAPI, static/dynamic linkage, and INI;
|
||||
- all overridden environment variables and whether the binary was stripped or UPX-packed;
|
||||
- workload source revision, dataset, route mix, concurrency, duration, warmup, and repetitions;
|
||||
- median result, variation, p95/p99 where relevant, peak RSS, binary size, and clean build time.
|
||||
|
||||
The project alternates a baseline and one changed build on the same machine. Multiple repetitions and confidence intervals carry more weight than a single best run, and benchmark scripts remain part of the result alongside the raw measurements.
|
||||
|
||||
## History and Design Lessons
|
||||
|
||||
The following merged changes and issue discussions explain why the current defaults and cautions exist. Unmerged implementation work is represented only by its technical concepts elsewhere on this page.
|
||||
|
||||
| Record | Outcome and lesson |
|
||||
|---|---|
|
||||
| [Issue #385](https://github.com/crazywhalecc/static-php-cli/issues/385), performance degradation | A v2 `--no-strip` path also selected `-O0`, making one reported Laravel test about three times slower. This led to customizable PHP compiler variables and reinforced that debug symbols must not silently disable optimization. Current v3 keeps optimized flags with `--no-strip`. |
|
||||
| [PR #806](https://github.com/crazywhalecc/static-php-cli/pull/806), Zig toolchain | Added target-flexible Zig support and documented its build/compatibility tradeoffs. Its discussion also contains the static/dynamic within-1% observation and early GCC/Clang/Zig comparisons. Toolchain choice is partly about portability and libc targeting, not only benchmark speed. |
|
||||
| [Issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838), performance testing | Established reproducible compiler, ZTS/NTS, Opcache, LTO, architecture, and PHP VM comparisons. Its results provide background for the `-O3` defaults but also show why conclusions must remain version- and workload-specific. The issue remains the main historical performance notebook. |
|
||||
| [Issue #985](https://github.com/crazywhalecc/static-php-cli/issues/985), v3 toolchains | Recorded the decision to prefer predictable defaults while retaining performance-oriented alternatives. On Linux this means Zig alongside native GCC paths; on macOS the discussion also motivated access to a current upstream LLVM instead of being limited to Apple's compiler release cycle. |
|
||||
| [Issue #862](https://github.com/crazywhalecc/static-php-cli/issues/862), `--pgo=script.php` proposal | Closed after concluding that one universal training script interface was unrealistic. PGO needs SAPI-aware lifecycle orchestration and user-owned representative training. |
|
||||
| [PR #966](https://github.com/crazywhalecc/static-php-cli/pull/966), flags and stripping | Unified PHP make flags and improved separate debug stripping, helping decouple optimization from symbol handling. |
|
||||
| [PR #1142](https://github.com/crazywhalecc/static-php-cli/pull/1142), FrankenPHP Go PGO | Added use of FrankenPHP's bundled Go `default.pgo` in the v2 build. This is distinct from application-trained PHP/CGO PGO. |
|
||||
| [Issue #1088](https://github.com/crazywhalecc/static-php-cli/issues/1088), native intrinsics | Open design request for declaring CPU intrinsic levels across both libraries and PHP/extensions instead of managing every ISA flag manually. |
|
||||
| [PR #1150](https://github.com/crazywhalecc/static-php-cli/pull/1150), macOS `-fno-plt` | Removed an ELF-only flag from the macOS defaults after it broke dependency configure checks. Optimization flags must be target-format aware. |
|
||||
|
||||
Most of this investigation and implementation has been led by [@henderkes](https://github.com/henderkes), with reviews, integration, platform fixes, and testing from the other StaticPHP contributors. The project continues to preserve workloads, raw results, and rationale as this work evolves; an individual compiler flag is only the last line of a much broader performance decision.
|
||||
@@ -47,7 +47,7 @@ Build your CLI with [symfony/console](https://symfony.com/doc/current/components
|
||||
|
||||
## Community
|
||||
|
||||
Join our [Discord server](https://discord.gg/nrSRbpMJ) to ask questions, share your builds, and connect with other StaticPHP users.
|
||||
Join our [Discord server](https://discord.gg/xf6Rd4pEAk) to ask questions, share your builds, and connect with other StaticPHP users.
|
||||
|
||||
## Next steps
|
||||
|
||||
|
||||
@@ -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`
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ openssl:
|
||||
| `{working_dir}` | 工作目录(项目根目录) |
|
||||
| `{download_path}` | 下载缓存目录(`downloads/`) |
|
||||
| `{source_path}` | 解压源码目录(`source/`) |
|
||||
| `{php_sdk_path}` | Windows PHP SDK 目录 |
|
||||
| `{spc_msys2_path}` | MSYS2 根目录(`msys64/`)——仅 Windows |
|
||||
|
||||
## target 包类型
|
||||
|
||||
|
||||
301
docs/zh/develop/performance.md
Normal file
301
docs/zh/develop/performance.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# 性能工程
|
||||
|
||||
StaticPHP 控制 PHP、扩展、依赖库以及各个 SAPI 的编译方式。这些选择会影响运行时吞吐量与延迟、启动时间、内存占用、二进制体积、可移植性和构建时间。不过它们并不是同一个指标:更小的二进制不一定更快,更慢的构建过程也可能生成更快的程序。
|
||||
|
||||
本页记录当前 v3 的默认值、已经进入构建流程的优化,以及仍在探索的方向。在 Linux 上,libc 和链接模型构成第一层:默认的 musl 全静态构建与 glibc 动态构建在可移植性、扩展加载和性能方面具有不同特征;编译参数、PGO 和 LTO 则是这项持续优化工作的后续层次。
|
||||
|
||||
本页并不宣称 StaticPHP 二进制在所有情况下都比其他 PHP 发行方式更快。结果取决于 PHP 版本、CPU、工具链、扩展集合、SAPI、libc、链接方式、运行时配置和实际负载。
|
||||
|
||||
::: warning 当前 v3 状态
|
||||
v3 分支目前没有提供稳定的 `--pgi`、`--pgo` 或 `--lto` CLI 选项。PGO 编排和更广泛的 LTO 兼容性仍处于持续探索阶段。下文描述的是设计、当前约束和优化方向,而不是受支持的正式版本构建方法。
|
||||
:::
|
||||
|
||||
## Linux 链接方式与 libc
|
||||
|
||||
StaticPHP 的 Linux 默认配置优先保证产物自包含,并不追求在所有服务器负载中获得最高分。`config/env.ini` 默认选择 `${GNU_ARCH}-linux-musl`;配合默认 Zig 工具链,会生成完全静态链接 musl 的二进制。
|
||||
|
||||
当前性能研究会区分以下三个 Linux target:
|
||||
|
||||
| Target | libc 与最终链接方式 | 运行时要求 | 共享扩展 / FFI | 当前定位 |
|
||||
|---|---|---|---|---|
|
||||
| `native-native-musl` | musl,全静态 | 兼容 CPU 上的 Linux 内核 | 不支持 | 默认的可移植单文件发布 |
|
||||
| `native-native-musl -dynamic` | musl,动态链接 | 兼容的 musl loader 和库 | 支持 | 保持 musl 不变,隔离静态/动态链接影响 |
|
||||
| `native-native-gnu.2.17` | glibc,动态链接,以 2.17 为基线 | glibc 2.17 或更高版本 | 支持 | 广泛兼容 GNU/Linux,并作为 glibc 性能基线 |
|
||||
|
||||
可以用具体架构替换任一 `native`,例如 `x86_64-linux-musl`。不指定版本的 `-gnu` target 会面向所选/当前 glibc ABI,而不是承诺兼容 glibc 2.17。
|
||||
|
||||
这里的“动态链接 PHP”并不意味着每个依赖都是系统 `.so`。StaticPHP 仍会把大多数选中的第三方库和 PHP 扩展构建为静态 archive,并链接进 PHP 可执行文件。动态部分主要是 libc/runtime loader,以及通过 `--build-shared` 明确选择的扩展。这与 PHP 和许多依赖都作为独立共享对象提供的传统发行版 PHP 不同。
|
||||
|
||||
同样,“静态扩展”和“静态 libc”是两个独立选择。glibc 动态 PHP 可以把所有 PHP 扩展静态编入,musl 动态 PHP 也可以加载指定的 `.so` 扩展。只有 musl 全静态 target 因进程中不存在动态 loader 而无法在运行时加载扩展。
|
||||
|
||||
### 静态与动态链接改变了什么
|
||||
|
||||
静态和动态链接主要改变启动工作、重定位、符号解析、部署方式和库共享,并不会自动改变 PHP VM 的代码生成方式。
|
||||
|
||||
- 全静态进程不会通过 runtime dynamic loader 启动,也不需要重定位一组 DSO。这可能有利于极短 CLI 的启动,但 PHP 初始化、扩展启动、脚本解析和 Opcache 往往占据更多时间。
|
||||
- 动态进程需要在启动时支付 loader 和 relocation 成本。长时间运行的 FPM 或 FrankenPHP worker 会把这部分成本分摊到许多请求上。
|
||||
- 静态链接为 section garbage collection 以及显式启用的 LTO 提供了更完整的 closed world;但静态链接本身不会进行跨 object 优化。
|
||||
- glibc 动态构建支持共享扩展、FFI、NSS 集成,并允许在不重建 PHP 的情况下替换或安全更新运行时库。全静态产物则必须重建才能获得 libc 或内嵌依赖修复。
|
||||
- 不同程序可以复用共享库的代码页;相同的静态 PHP worker 进程之间也会共享文件映射的可执行代码页,因此“静态链接会让每个 worker 在内存里复制所有代码”并不准确。
|
||||
|
||||
StaticPHP 的[性能测试 Issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838) 记录过一组 PHP 8.4 测试:多次运行时,静态和动态构建在两个方向上的差异都不超过约 1%。这说明仅链接方式未必会主导 PHP 稳态执行性能,但不能把它当作普遍结论。短 CLI、大量 DSO、不同 loader 以及 I/O 密集扩展都可能得到不同结果。
|
||||
|
||||
### musl 与 glibc 的性能影响面
|
||||
|
||||
只有负载实际进入 libc 或围绕 libc 实现的功能时,两者差异才会出现。纯 PHP 代码的大量时间会花在 Zend VM、Opcache 和 Zend Memory Manager 中。PHP 自己的 [Zend Memory Manager](https://wiki.php.net/internals/zend_mm) 处理大多数 request-bound allocation,因此以 PHP array 和 opcode 为主的 microbenchmark,对系统 allocator 的敏感度可能低于 C 扩展或服务器 runtime。
|
||||
|
||||
| 负载领域 | libc 可能产生影响的原因 | 主要观测项 |
|
||||
|---|---|---|
|
||||
| CPU 密集 PHP opcode | 通常由 PHP VM、编译器、CPU target 和 Opcache 主导,而不是 libc | 先保持 PHP/VM/编译器一致,再只改变 libc/链接方式 |
|
||||
| 持久及原生内存分配 | PHP persistent allocation、C 扩展、依赖库和服务器代码可能直接调用 libc allocator | 吞吐量、allocation contention、RSS、长时间运行后的 fragmentation |
|
||||
| ZTS 与 FrankenPHP | 线程创建、TLS、mutex、allocator contention 和 per-thread cache 存在差异 | 随 worker/thread 数量的扩展性、p95/p99、每线程 RSS |
|
||||
| DNS 与名称服务 | resolver 策略、NSS、`/etc/resolv.conf` 和缓存不同 | 有/无缓存的查询延迟、失败/切换延迟、查询量 |
|
||||
| Locale、iconv、regex、stdio | 实现和支持行为不同,不只是速度不同 | 先验证正确性,再用生产 locale/数据测试吞吐量 |
|
||||
| 极短 CLI 命令 | loader/relocation 和初始化占总时间的比例更大 | 大量进程启动的 cold/warm wall time |
|
||||
| 长时间运行的 worker | 启动成本被分摊,allocator、线程、系统调用和应用行为更加重要 | 持续吞吐量、尾延迟、峰值/稳定 RSS |
|
||||
|
||||
glibc allocator 提供 per-thread cache 和多个 arena,并允许调整其上限;这可能提高并发分配吞吐量,但代价是保留更多内存。因此,StaticPHP 的基准记录会包含 [glibc allocation tunable](https://sourceware.org/glibc/manual/latest/html_node/Memory-Allocation-Tunables.html)。musl 使用不同的 allocator,更关注较低基线开销、受控 fragmentation 及静态链接适用性;两种设计都不能保证在所有 PHP 应用中具有更低延迟或 RSS。
|
||||
|
||||
Resolver 行为甚至可能反转一个表面上的“libc 性能”结果。[musl 功能差异文档](https://wiki.musl-libc.org/functional-differences-from-glibc.html)指出,musl 会并行查询配置的 nameserver,而传统 glibc 行为会依次尝试。这可能改善故障切换延迟,也可能增加 DNS 流量;glibc 还会参与可配置的 NSS module。因此,StaticPHP 的 DNS 对比会保持 resolver、缓存状态、search domain 和失败条件一致,而不会把 resolver 结果当作单纯 CPU benchmark。
|
||||
|
||||
musl 的默认线程栈明显小于典型 glibc 配置。这可以减少线程密集程序保留的地址空间,也可能暴露扩展对栈大小的假设。它属于部署和内存特征,不能证明某个 libc 执行 PHP opcode 更快。
|
||||
|
||||
### 当前对比模型
|
||||
|
||||
默认 musl 静态二进制与发行版 glibc PHP 的直接对比会同时改变 libc、linker、编译器、参数、PHP 配置、扩展、依赖版本和 INI,因此无法把全部差异归因于 libc。
|
||||
|
||||
项目采用相同 StaticPHP commit、PHP 源码、Zig 版本、参数、扩展和 SAPI 形成受控矩阵。三个构建对应以下命令:
|
||||
|
||||
```bash
|
||||
EXTENSIONS="bcmath,curl,openssl,opcache"
|
||||
|
||||
# A:默认形式的 musl 全静态构建
|
||||
SPC_TARGET=native-native-musl spc build:php "$EXTENSIONS" --build-cli
|
||||
|
||||
# B:musl 动态构建,需要 musl runtime
|
||||
SPC_TARGET="native-native-musl -dynamic" spc build:php "$EXTENSIONS" --build-cli
|
||||
|
||||
# C:glibc 动态构建,并指定兼容性下限
|
||||
SPC_TARGET=native-native-gnu.2.17 spc build:php "$EXTENSIONS" --build-cli
|
||||
```
|
||||
|
||||
每项结果都与其产物、build manifest、`php -i` 和日志一起保存。实际链接方式由二进制本身确认,而不是根据文件名推断:
|
||||
|
||||
```bash
|
||||
file buildroot/bin/php
|
||||
readelf -l buildroot/bin/php | grep 'Requesting program interpreter'
|
||||
```
|
||||
|
||||
A 对比 B 用于在保持 musl 不变时估计链接方式的影响;B 对比 C 用于在两者均动态链接时估计 libc/runtime 的影响。发行版 PHP 仍可作为外部参考,但由于编译器和打包配置不同,会单独记录。
|
||||
|
||||
当前对比集合同时覆盖 no-op 启动和实际 CLI 脚本。FPM 与 FrankenPHP 会把 worker 预热和持续吞吐量、尾延迟分开记录。libc 敏感场景则包括使用扩展的大量内存分配、并发请求、DNS cache hit/miss/failure、文件 I/O,以及长时间运行后的 RSS/fragmentation。
|
||||
|
||||
### 部署特征
|
||||
|
||||
- **musl 静态**是 StaticPHP 默认值,代表不依赖共享扩展或 FFI 的可移植、自包含部署形态。
|
||||
- **glibc 动态**代表与 GNU/Linux runtime 集成的部署形态,包括 `.so` 扩展、FFI、宿主名称服务栈,以及实测更适合 glibc 的负载。
|
||||
- **musl 动态**代表仍需要共享扩展的 musl runtime,同时也是上述受控对比的中间项;它会放弃默认构建的大部分单文件可移植性。
|
||||
|
||||
默认值以可预测和广泛部署为目标。最快 target 与具体负载相关,项目仍在结合实际 CPU、PHP 版本、SAPI 和应用行为持续评估。
|
||||
|
||||
## 优化配置如何进入 v3 构建
|
||||
|
||||
v3 会通过多个层次传递优化配置:
|
||||
|
||||
1. `config/env.ini` 提供各平台默认值;`config/env.custom.ini` 或进程环境变量可以覆盖它们。
|
||||
2. `ToolchainManager` 默认在 Linux 选择 Zig、Windows 选择 MSVC、macOS 选择系统/Homebrew/MacPorts Clang,并初始化 `CC`、`CXX`、`AR`、`RANLIB` 和 `LD`。
|
||||
3. Package executor 和 `Package::getLibExtra*Flags()` 把默认参数传入 Autoconf、CMake 及包专用构建过程。
|
||||
4. Unix 上的 PHP target 会把 PHP 专用参数同时传给 `./configure` 和 `make`。作为 php-src 一部分编译的静态扩展会看到相同的编译环境。
|
||||
5. FrankenPHP target 通过 CGO 链接 PHP embed 库。它的 `CGO_CFLAGS` 和 `CGO_LDFLAGS` 会包含 PHP 与依赖库参数,再加入 Go 和外部链接器配置。
|
||||
6. 部署阶段默认提取单独的调试信息并精简 Unix 二进制。UPX 是可选项,它影响体积和启动行为,而不会优化生成的 PHP 机器码。
|
||||
|
||||
这种传递有意覆盖较大范围,但目前还不是完全一致。使用手写编译命令或特殊上游构建系统的包可能忽略部分全局参数。让这些 adapter 一致传递 C、C++ 和 linker 参数,仍是当前优化工作的组成部分。
|
||||
|
||||
## 当前默认配置
|
||||
|
||||
权威值位于 `config/env.ini`。下面的表格用于解释当前 v3 默认值,不能替代该文件。
|
||||
|
||||
### Linux 编译器默认值
|
||||
|
||||
这些编译器默认值适用于上文各 Linux target。除非使用维护者级别的 `SPC_TOOLCHAIN` 覆盖项,否则 v3 toolchain manager 会选择 Zig。
|
||||
|
||||
| 变量 | 当前默认值 | 用途 |
|
||||
|---|---|---|
|
||||
| `SPC_DEFAULT_CFLAGS` | `-fPIC -O3 -pipe -fno-plt -fno-semantic-interposition -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections` | 依赖库和 PHP 共用的 C 参数 |
|
||||
| `SPC_DEFAULT_CXXFLAGS` | `${SPC_DEFAULT_CFLAGS}` | 共用 C++ 参数 |
|
||||
| `SPC_DEFAULT_LDFLAGS` | `-Wl,-z,relro -Wl,--as-needed -Wl,-z,now -Wl,-z,noexecstack -Wl,--gc-sections` | 链接加固、依赖裁剪及未使用 section 移除 |
|
||||
| `SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS` | `-g -fstack-protector-strong -fno-ident -fPIE -fvisibility=hidden -fvisibility-inlines-hidden ${SPC_DEFAULT_CFLAGS}` | PHP 和源码树内扩展的 C 参数 |
|
||||
| `SPC_CMD_VAR_PHP_MAKE_EXTRA_CXXFLAGS` | 对应的 C++ 形式 | PHP 和源码树内扩展的 C++ 参数 |
|
||||
| `SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS` | 空 | PHP 程序的附加链接参数 |
|
||||
|
||||
其中与性能最相关的默认项是:
|
||||
|
||||
- `-O3` 偏向运行速度,而不是编译时间和代码体积。
|
||||
- `-fno-semantic-interposition` 让优化器能够更自由地处理最终程序中不会被 interpose 的 ELF 符号。
|
||||
- `-fno-plt` 在工具链允许时避免传统的 ELF procedure linkage table 调用序列。
|
||||
- `-ffunction-sections -fdata-sections` 配合 `--gc-sections`,使链接器可以移除未使用的函数和数据。
|
||||
- 编译阶段有意保留 frame pointer 和 `-g`,方便性能分析和调试。部署 Unix 二进制时默认会执行 strip,同时把独立调试信息写入 `buildroot/debug/`。
|
||||
|
||||
默认 PHP configure 命令还会启用 `--enable-re2c-cgoto`、禁用未选择的 SAPI 和共享 PHP 库,并只构建请求的扩展。这些选择能减少无关代码,实际运行效果仍取决于具体负载。
|
||||
|
||||
### macOS
|
||||
|
||||
macOS 默认使用 native target 和系统 Clang。v3 也通过 `SPC_USE_LLVM=brew` 和 `SPC_USE_LLVM=port` 支持 Homebrew、MacPorts 提供的较新 upstream LLVM。Homebrew 变体会把其中的 `clang`、`clang++`、`llvm-ar` 和 `llvm-ranlib` 作为一套完整工具链使用,避免与 Apple 自带工具混用。
|
||||
|
||||
Homebrew LLVM 是 StaticPHP 当前在 macOS 上采用的性能优化路径之一。较新的 optimizer 和 code-generation backend 在部分 PHP 版本及负载中可以生成运行性能更好的 PHP 二进制,也让项目不必等待 Apple 系统 Clang 的发布节奏即可评估新的编译器优化。这并不是固定的性能保证:PHP VM 变化、CPU 架构、扩展、Opcache 和编译参数都会改变结果。项目的[性能测试 Issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838)表明编译器及优化等级的影响与版本和负载相关,后续的 [v3 工具链讨论](https://github.com/crazywhalecc/static-php-cli/issues/985#issuecomment-3860775962)则记录了增加 macOS LLVM 路径的动机,即获得不受 Apple 编译器版本限制的较新工具链。
|
||||
|
||||
| 变量 | 当前默认值 | 用途 |
|
||||
|---|---|---|
|
||||
| `SPC_DEFAULT_CFLAGS` | `--target=${MAC_ARCH}-apple-darwin -O3 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections` | 目标选择、优化、可观测性及 section 拆分 |
|
||||
| `SPC_DEFAULT_CXXFLAGS` | `${SPC_DEFAULT_CFLAGS}` | 共用 C++ 参数 |
|
||||
| `SPC_DEFAULT_LDFLAGS` | `-Wl,-dead_strip` | 移除不可达的 Mach-O 代码和数据 |
|
||||
| PHP 附加参数 | `-g`、stack protection、PIC/PIE、hidden visibility 以及上述默认项 | PHP 和源码树内扩展编译 |
|
||||
|
||||
### Windows
|
||||
|
||||
Windows 使用 MSVC,以及[对 PHP 源码的修改](./php-src-changes)中介绍的静态 CRT 补丁。PHP release 配置提供上游优化参数,StaticPHP 会改写最终 CLI、CGI、micro 和 embed 的链接规则并加入 `/LTCG`。依赖的 CMake 构建通常使用 `/MT /Os /Ob1 /DNDEBUG`,个别 Package 可能选择其他 release 参数。
|
||||
|
||||
使用 `--no-strip` 时,StaticPHP 会保留 PDB/调试信息,同时在改写的构建命令中继续使用 `/O2`。这是有意设计:调试符号与关闭优化是两件不同的事。
|
||||
|
||||
Windows FrankenPHP 通过 Clang/LLD 完成 CGO 链接。部分 Windows 库会明确禁用 `/GL`,因为该链接路径无法接受 MSVC LTCG object。最终链接行出现 `/LTCG`,并不意味着每个输入都参与了 whole-program optimization。
|
||||
|
||||
## 优化维度
|
||||
|
||||
StaticPHP 将性能视为多个彼此相关的指标,而不是单一分数。每个维度受到不同构建环节影响:
|
||||
|
||||
| 目标 | 通常记录为 | 主要影响项 |
|
||||
|---|---|---|
|
||||
| 请求吞吐量 | 固定并发下的 requests/s | SAPI 模式、Opcache、worker 模型、PHP 版本、编译器和 CPU target |
|
||||
| 尾延迟 | p50/p95/p99 和错误率 | 负载、预热、竞争、worker 数量、JIT/Opcache、内存压力 |
|
||||
| CLI 执行 | wall time、CPU time、peak RSS | 启动成本、Opcache CLI 设置、扩展集合、PHP/编译器版本 |
|
||||
| 二进制体积 | 部署文件和调试文件字节数 | 扩展集合、section GC/dead stripping、符号精简、UPX |
|
||||
| 可移植性 | 能运行该二进制的最旧 CPU/OS/libc | `SPC_TARGET`、CPU ISA 参数、静态或动态 libc |
|
||||
| 构建速度 | 干净构建 wall time、峰值磁盘和内存 | `SPC_CONCURRENCY`、工具链、LTO/PGO、Package 数量 |
|
||||
|
||||
可比较的结果会保持 PHP 版本、commit、扩展、依赖版本、SAPI、ZTS/NTS、INI、目标 libc、编译器、CPU 频率策略及负载一致。
|
||||
|
||||
## 运行时优化层面
|
||||
|
||||
### 1. 可复现的配置覆盖
|
||||
|
||||
`config/env.custom.ini` 提供可复现的覆盖层,同时让 `config/env.ini` 保持为项目基线。配置值会替换完整默认字符串而不会自动追加,因此性能研究会保留基线,并一次隔离一个变化因素。
|
||||
|
||||
例如,面向 x86-64-v3 的研究会保留 Linux 默认值并加入对应 ISA level:
|
||||
|
||||
```ini
|
||||
[linux]
|
||||
SPC_DEFAULT_CFLAGS="-fPIC -O3 -pipe -fno-plt -fno-semantic-interposition -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections -march=x86-64-v3"
|
||||
SPC_DEFAULT_CXXFLAGS="${SPC_DEFAULT_CFLAGS}"
|
||||
```
|
||||
|
||||
这可能让编译器使用更多向量和指令选择,但产物无法在低于该 ISA level 的 CPU 上运行。`-march=native` 会进一步收窄可移植性,使产物与构建机的 CPU 类型绑定。
|
||||
|
||||
PHP 范围的研究由 `SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS` 及其 C++ 对应项表示,而不是改变全局默认值。单个 Package 的研究使用 snake-case 变量,例如 `libaom_CFLAGS`、`libaom_CXXFLAGS` 和 `libaom_LDFLAGS`。当 Package 使用 v3 通用 executor 时,Package 专用参数会与默认参数合并。
|
||||
|
||||
### 2. 工具链和 PHP 版本的影响
|
||||
|
||||
编译器造成的差异可能大于单个优化参数。[Issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838) 在部分 PHP 8.4 x86-64 测试中发现 GCC 与 Clang 之间有较大差异,因为较旧的 PHP VM 可以使用 GCC global register variable。该结果并不普遍适用:架构、PHP 版本、VM 实现和负载都会影响结论,PHP 8.5 的新 VM 也改变了这项比较。
|
||||
|
||||
Linux v3 默认使用 Zig,是为了 target 灵活性和可复现的 libc 选择,并不代表它在所有负载下都一定生成最快的二进制。项目的性能工作会在实际部署架构上对比这个可预测基线与 native toolchain。在稳定的用户级选择器得到正式文档前,`SPC_TOOLCHAIN` 仍属于内部/维护者控制项。
|
||||
|
||||
### 3. SAPI、线程安全及运行时配置
|
||||
|
||||
- FrankenPHP 要求 ZTS。CLI、FPM、CGI、micro 和 embed 默认保持 NTS,只有所选 SAPI 或应用确实需要线程安全时才涉及 ZTS。
|
||||
- Issue #838 的历史测试在特定测试集中观察到的 ZTS/NTS 差异较小;该结论仍局限于当时的负载。
|
||||
- 加入 `ext-opcache` 只代表构建该扩展;它的性能特征还取决于运行时 INI,包括重复 CLI 执行中的 `opcache.enable_cli` 和应用特定的 JIT 配置。
|
||||
- `--disable-opcache-jit` 改变的是构建能力,不能代替运行时测试。在 Linux 构建 Opcache JIT 时,StaticPHP 会在必要位置禁用 undefined-behavior sanitizer。
|
||||
- FrankenPHP 性能还取决于 worker/classic 模式、worker 数量、应用启动行为、Caddy 模块及 Go runtime 设置。编译参数无法弥补不具代表性的服务器配置。
|
||||
|
||||
### 4. 速度、符号和压缩
|
||||
|
||||
Unix 默认部署流程会提取调试信息、精简运行时二进制,并单独保留调试文件。`--no-strip` 代表未精简形态,当前 v3 在这种形态下仍会保留优化参数。
|
||||
|
||||
`--with-upx-pack` 是 Linux 和 Windows 的体积优化。它可能改变启动时间、内存映射、安全工具行为和可调试性,因此项目将它视为打包取舍,而不是 PHP 执行性能优化。
|
||||
|
||||
## Profile-Guided Optimization(PGO)
|
||||
|
||||
PGO 会先生成插桩程序,运行具有代表性的负载收集 profile,然后根据观察到的分支、调用和值频率重新编译。这样,编译器能够在代码布局、inline 和 hot/cold 决策方面超越静态启发式规则。
|
||||
|
||||
完整的 PGO 设计包含三个独立阶段:
|
||||
|
||||
1. **插桩阶段**使用相同的 PHP 版本、SAPI、扩展、依赖和 target,并加入 profile-generation 参数完成构建。
|
||||
2. **训练阶段**以具有代表性的流量比例和并发覆盖启动及重要生产路径,也包含正常关闭进程以 flush raw profile。
|
||||
3. **Profile-use 阶段**通过匹配工具链的 profile 工具合并 raw profile,并用 profile-use 参数重新构建完全一致的源码和配置。
|
||||
|
||||
Profile 是构建输入,不是可移植的基准产物。PHP、扩展、依赖、编译器版本、参数、SAPI 链接方式或负载发生实质变化后,原有 profile 即会失效。范围过窄或已经过期的 profile 可能加速训练过的 route,却让未训练路径变慢。
|
||||
|
||||
### StaticPHP PGO 状态
|
||||
|
||||
v3 的实验性设计正在探索面向 CLI、CGI、FPM、micro、embed 和 FrankenPHP 的独立 PGO context 与 lifecycle hook。目前评估的概念包括:
|
||||
|
||||
- 插桩和 profile-use 阶段,以及可选的第二轮 context-sensitive 插桩;
|
||||
- 每个 SAPI 独立的 raw-profile 目录和合并后的 `.profdata` 文件;
|
||||
- 切换活动 SAPI profile 时执行干净重建;
|
||||
- php-src 和 FrankenPHP 的 shutdown 补丁,因为 Go/CGO 进程不会可靠执行通常负责 flush profile 的 libc `atexit` 路径;
|
||||
- LLVM profile 工具,以及 Zig、Clang、GCC 和 FrankenPHP 所需的特殊链接/runtime 处理。
|
||||
|
||||
这项工作尚未进入稳定的 v3 功能集。当前 v3 源码已经包含部分前置兼容处理,例如 FrankenPHP 在 native GCC 下发现手动 `-fprofile*` C 参数时,会忽略 missing-profile error 并链接 `libgcov`;完整的训练、合并、失效和重建编排仍在探索中。
|
||||
|
||||
仅把 `-fprofile-generate` 加入全局默认值并不等同于完整编排:它还会同时插桩依赖库、改变链接要求、增加构建和运行成本,并且可能无法 flush 出可用数据。因此,当前内部变量尚不构成稳定的发布流程。
|
||||
|
||||
### FrankenPHP 的 Go PGO
|
||||
|
||||
[PR #1142](https://github.com/crazywhalecc/static-php-cli/pull/1142) 在 v2 xcaddy 构建中加入了对 FrankenPHP 上游 `default.pgo` 的使用。这个 profile 使用随 FrankenPHP 分发的数据优化 Go 部分;它不会针对你的应用训练 php-src、PHP embed 库、扩展或 CGO glue。
|
||||
|
||||
未来的端到端 FrankenPHP PGO 设计可能同时包含两类 profile:
|
||||
|
||||
- FrankenPHP 上游为 Go/Caddy 代码提供的 Go profile;
|
||||
- 针对 PHP、静态扩展和 CGO 链接 C 代码的应用专用编译器 profile。
|
||||
|
||||
两者的归属及失效规则,是当前设计探索中彼此独立的问题。
|
||||
|
||||
## Link-Time Optimization(LTO)
|
||||
|
||||
LTO 会把编译器中间表示保留到链接阶段,让优化器跨 translation unit 工作。Full LTO 会更激进地处理合并后的程序;ThinLTO 会分散更多工作,通常能降低内存及构建时间成本。
|
||||
|
||||
静态链接不会自动启用 LTO。反过来,只给最终链接加入 `-flto` 也不够:相关 object 和 archive 必须由兼容的编译器、LTO mode、archiver、ranlib 及 linker plugin 生成。
|
||||
|
||||
Unix v3 默认不启用 LTO。历史工作让更多 archive 命令使用所选 `AR`,但项目后来移除了默认 LTO 尝试,因为跨依赖库维护兼容修复的成本过高。在 [Issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838) 的一个测试环境中,运行时提升只有约 2%,ThinLTO 构建时间约变成两倍,Full LTO 约变成七倍。这只是特定环境的历史测量结果,不是承诺的固定比例。
|
||||
|
||||
当前 Unix LTO 研究会考虑以下约束:
|
||||
|
||||
1. object、archive 和最终链接需要使用同一个兼容的 LLVM/Clang 或 GCC 工具链家族。
|
||||
2. C、C++、PHP 和 linker 参数需要采用相同模式,例如 `-flto=thin`。
|
||||
3. 初期只覆盖 PHP 和源码树内扩展,有助于把核心结果与依赖库兼容性分开。
|
||||
4. archive 内容和最终链接日志可以确认 LTO 是否进入预期 object;仅构建成功并不能说明这一点。
|
||||
5. SAPI 与扩展 smoke test、干净构建时间、二进制体积、吞吐量和尾延迟共同构成结果。
|
||||
|
||||
LTO 可能暴露 Package bug、不支持的汇编、archive 不兼容、符号导出问题以及 Go/CGO 链接限制,也可能增加代码体积或造成 instruction cache 退化。这些兼容性与维护成本,是 Unix LTO 在持续评估收益期间仍保持 opt-in 的原因。
|
||||
|
||||
## 性能证据与可复现性
|
||||
|
||||
StaticPHP 的性能研究会记录足够的上下文,使其他维护者可以复现结果:
|
||||
|
||||
- StaticPHP commit 以及 registry/Package revision;
|
||||
- PHP、FrankenPHP、Go、编译器、链接器和 profile 工具版本;
|
||||
- 宿主与目标 OS、libc、架构,以及完整的 `SPC_TARGET`;
|
||||
- CPU 型号、可用指令集、电源/频率策略、内存和虚拟化环境;
|
||||
- 完整扩展与依赖集合、ZTS/NTS、SAPI、静态/动态链接方式和 INI;
|
||||
- 所有覆盖的环境变量,以及二进制是否 strip 或使用 UPX;
|
||||
- 负载源码 revision、数据集、route 比例、并发、持续时间、预热和重复次数;
|
||||
- 中位数、波动范围、适用时的 p95/p99、peak RSS、二进制体积和干净构建时间。
|
||||
|
||||
项目会在同一台机器上交替运行基线和单项改动构建。多次重复和置信区间比一次最佳结果更有意义,基准脚本也会和原始测量结果一起保留。
|
||||
|
||||
## 历史记录与设计经验
|
||||
|
||||
以下已合并修改和 Issue 讨论解释了当前默认值和注意事项的来源。未合并的实现工作仅以技术概念的形式出现在本文其他位置。
|
||||
|
||||
| 记录 | 结果与经验 |
|
||||
|---|---|
|
||||
| [Issue #385](https://github.com/crazywhalecc/static-php-cli/issues/385),性能退化 | v2 的一条 `--no-strip` 路径同时选择了 `-O0`,使报告中的一个 Laravel 测试约慢了三倍。这促成了可定制 PHP 编译变量,并再次说明调试符号不能静默关闭优化。当前 v3 的 `--no-strip` 会保留优化参数。 |
|
||||
| [PR #806](https://github.com/crazywhalecc/static-php-cli/pull/806),Zig 工具链 | 加入 target 灵活的 Zig 支持并记录构建/兼容性取舍;讨论中还包含静态/动态差异在 1% 内的观察,以及早期 GCC/Clang/Zig 对比。工具链选择部分是为了可移植性与 libc target,而不只是基准速度。 |
|
||||
| [Issue #838](https://github.com/crazywhalecc/static-php-cli/issues/838),性能测试 | 建立了可复现的编译器、ZTS/NTS、Opcache、LTO、架构及 PHP VM 对比。其结果为 `-O3` 默认值提供了背景,也展示了为什么结论必须绑定版本和负载。该 Issue 仍是主要的历史性能笔记。 |
|
||||
| [Issue #985](https://github.com/crazywhalecc/static-php-cli/issues/985),v3 工具链 | 记录了优先采用可预测默认值,同时保留性能导向替代方案的决策。Linux 对应 Zig 与 native GCC 路径;macOS 的讨论也促成了较新 upstream LLVM 的接入,使构建不受 Apple 编译器发布节奏限制。 |
|
||||
| [Issue #862](https://github.com/crazywhalecc/static-php-cli/issues/862),`--pgo=script.php` 提案 | 因一个通用训练脚本接口并不现实而关闭。PGO 需要感知 SAPI 的 lifecycle 编排,以及由用户负责的代表性训练。 |
|
||||
| [PR #966](https://github.com/crazywhalecc/static-php-cli/pull/966),参数和 strip | 统一 PHP make 参数并改进独立调试信息精简流程,帮助解耦优化与符号处理。 |
|
||||
| [PR #1142](https://github.com/crazywhalecc/static-php-cli/pull/1142),FrankenPHP Go PGO | 在 v2 构建中加入 FrankenPHP 自带 Go `default.pgo` 的使用;它不同于应用训练的 PHP/CGO PGO。 |
|
||||
| [Issue #1088](https://github.com/crazywhalecc/static-php-cli/issues/1088),native intrinsic | 尚未关闭的设计需求,希望在依赖库与 PHP/扩展之间统一声明 CPU intrinsic level,而不是手工管理每一项 ISA 参数。 |
|
||||
| [PR #1150](https://github.com/crazywhalecc/static-php-cli/pull/1150),macOS `-fno-plt` | 因一个 ELF 专用参数破坏依赖 configure 检查,将其从 macOS 默认值移除。优化参数必须感知目标文件格式。 |
|
||||
|
||||
其中大部分调查和性能优化由 [@henderkes](https://github.com/henderkes) 主导,其他 StaticPHP 贡献者参与了 review、集成、平台修复和测试。随着这项工作继续推进,项目会保留负载、原始结果和决策理由;单个编译参数只是更广泛性能决策的最后一行。
|
||||
@@ -55,7 +55,7 @@ StaticPHP 支持将 FrankenPHP 连同所需扩展一起静态编译,
|
||||
|
||||
## 社区
|
||||
|
||||
加入我们的 [Discord 服务器](https://discord.gg/nrSRbpMJ),提问、分享构建成果,与其他 StaticPHP 用户交流。
|
||||
加入我们的 [Discord 服务器](https://discord.gg/xf6Rd4pEAk),提问、分享构建成果,与其他 StaticPHP 用户交流。
|
||||
|
||||
## 接下来
|
||||
|
||||
|
||||
@@ -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`
|
||||
|
||||
这两个选项已不再被命令行接受。请改为设置 `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 构建环境的配置。
|
||||
:::
|
||||
|
||||
## 已重命名 / 已弃用的选项
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
parameters:
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
level: 4
|
||||
level: 5
|
||||
phpVersion: 80400
|
||||
paths:
|
||||
- ./src/
|
||||
|
||||
@@ -10,6 +10,7 @@ package:
|
||||
- config/pkg/lib/
|
||||
- config/pkg/target/
|
||||
- config/pkg/ext/
|
||||
- config/pkg/tool/
|
||||
artifact:
|
||||
config:
|
||||
- config/artifact/
|
||||
|
||||
@@ -20,8 +20,6 @@ class go_win
|
||||
])]
|
||||
public function downBinary(ArtifactDownloader $downloader): DownloadResult
|
||||
{
|
||||
$pkgroot = PKG_ROOT_PATH;
|
||||
|
||||
// get version
|
||||
[$version] = explode("\n", default_shell()->executeCurl('https://go.dev/VERSION?m=text', retries: $downloader->getRetry()) ?: '');
|
||||
if ($version === '') {
|
||||
@@ -52,7 +50,7 @@ class go_win
|
||||
throw new DownloaderException("Hash mismatch for downloaded go-win binary. Expected {$hash}, got {$file_hash}");
|
||||
}
|
||||
|
||||
return DownloadResult::archive(basename($path), ['url' => $url, 'version' => $version], extract: "{$pkgroot}/go-win", verified: true, version: $version);
|
||||
return DownloadResult::archive(basename($path), ['url' => $url, 'version' => $version], extract: '{pkg_root_path}/go-win', verified: true, version: $version);
|
||||
}
|
||||
|
||||
#[CustomBinaryCheckUpdate('go-win', ['windows-x86_64'])]
|
||||
|
||||
48
src/Package/Artifact/meson_win.php
Normal file
48
src/Package/Artifact/meson_win.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Package\Artifact;
|
||||
|
||||
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
|
||||
use StaticPHP\Exception\EnvironmentException;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
|
||||
class meson_win
|
||||
{
|
||||
/**
|
||||
* Meson 1.11 dropped the Windows MSI, so the artifact is the wheel, installed offline
|
||||
* into a private venv. The venv is not just packaging hygiene: pip generates a real
|
||||
* meson.exe launcher there, and PostgreSQL needs one because its build re-invokes meson
|
||||
* through find_program(), which rejects non-executables like the meson.pyz zipapp.
|
||||
*/
|
||||
#[AfterBinaryExtract('meson', ['windows-x86_64'])]
|
||||
public function afterExtract(string $target_path): void
|
||||
{
|
||||
$dir = dirname($target_path);
|
||||
$venv = "{$dir}\\venv";
|
||||
|
||||
// Prefer the python-win tool package (installed alongside via tools@windows),
|
||||
// fall back to whatever Python the machine already has.
|
||||
$candidates = ['"' . PKG_ROOT_PATH . '\python-win\tools\python.exe"', 'python', 'py -3'];
|
||||
$python = null;
|
||||
foreach ($candidates as $candidate) {
|
||||
[$code] = cmd()->execWithResult("{$candidate} --version", false);
|
||||
if ($code === 0) {
|
||||
$python = $candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($python === null) {
|
||||
throw new EnvironmentException('meson needs Python 3; the python-win tool package did not install and no system Python was found.');
|
||||
}
|
||||
|
||||
if (is_dir($venv)) {
|
||||
FileSystem::removeDir($venv);
|
||||
}
|
||||
cmd()->exec("{$python} -m venv \"{$venv}\"")
|
||||
->exec("\"{$venv}\\Scripts\\python.exe\" -m pip install --no-index --no-deps \"{$target_path}\"");
|
||||
|
||||
FileSystem::writeFile("{$dir}\\meson.bat", "@echo off\r\n\"%~dp0venv\\Scripts\\meson.exe\" %*\r\n");
|
||||
}
|
||||
}
|
||||
93
src/Package/Artifact/msys2_build_essentials.php
Normal file
93
src/Package/Artifact/msys2_build_essentials.php
Normal 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");
|
||||
}
|
||||
}
|
||||
66
src/Package/Artifact/python_win.php
Normal file
66
src/Package/Artifact/python_win.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Package\Artifact;
|
||||
|
||||
use StaticPHP\Artifact\ArtifactDownloader;
|
||||
use StaticPHP\Artifact\Downloader\DownloadResult;
|
||||
use StaticPHP\Artifact\Downloader\Type\CheckUpdateResult;
|
||||
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
|
||||
use StaticPHP\Attribute\Artifact\CustomBinary;
|
||||
use StaticPHP\Attribute\Artifact\CustomBinaryCheckUpdate;
|
||||
use StaticPHP\Exception\DownloaderException;
|
||||
|
||||
/**
|
||||
* Full CPython for Windows from the official python.org nuget package. It is a plain zip
|
||||
* (python.exe plus stdlib under tools/, venv and ensurepip included), so it installs into
|
||||
* the pkgroot without touching the system. Used by the meson tool package.
|
||||
*/
|
||||
class python_win
|
||||
{
|
||||
#[CustomBinary('python-win', [
|
||||
'windows-x86_64',
|
||||
])]
|
||||
public function downBinary(ArtifactDownloader $downloader): DownloadResult
|
||||
{
|
||||
$version = $this->getLatestVersion($downloader->getRetry());
|
||||
|
||||
$url = "https://api.nuget.org/v3-flatcontainer/python/{$version}/python.{$version}.nupkg";
|
||||
// .nupkg is a zip; name the cache file .zip so the extractor treats it as one
|
||||
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . "python-win-{$version}.zip";
|
||||
default_shell()->executeCurlDownload($url, $path, retries: $downloader->getRetry());
|
||||
|
||||
return DownloadResult::archive(basename($path), ['url' => $url, 'version' => $version], extract: '{pkg_root_path}/python-win', version: $version);
|
||||
}
|
||||
|
||||
#[CustomBinaryCheckUpdate('python-win', ['windows-x86_64'])]
|
||||
public function checkUpdateBinary(?string $old_version): CheckUpdateResult
|
||||
{
|
||||
$version = $this->getLatestVersion();
|
||||
return new CheckUpdateResult(
|
||||
old: $old_version,
|
||||
new: $version,
|
||||
needUpdate: $old_version === null || $version !== $old_version,
|
||||
);
|
||||
}
|
||||
|
||||
#[AfterBinaryExtract('python-win', ['windows-x86_64'])]
|
||||
public function afterExtract(string $target_path): void
|
||||
{
|
||||
if (!file_exists("{$target_path}\\tools\\python.exe")) {
|
||||
throw new DownloaderException("Python installation appears incomplete: python.exe not found at {$target_path}\\tools\\python.exe");
|
||||
}
|
||||
}
|
||||
|
||||
private function getLatestVersion(int $retries = 0): string
|
||||
{
|
||||
$index = default_shell()->executeCurl('https://api.nuget.org/v3-flatcontainer/python/index.json', retries: $retries);
|
||||
$versions = $index ? (json_decode($index, true)['versions'] ?? []) : [];
|
||||
$stable = array_filter($versions, fn ($v) => preg_match('/^\d+\.\d+\.\d+$/', $v));
|
||||
if ($stable === []) {
|
||||
throw new DownloaderException('Failed to get Python versions from the nuget index');
|
||||
}
|
||||
return end($stable);
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ class rust
|
||||
$download_url = "https://static.rust-lang.org/dist/rust-{$latest_version}-{$arch}-unknown-linux-{$distro}.tar.xz";
|
||||
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . basename($download_url);
|
||||
default_shell()->executeCurlDownload($download_url, $path, retries: $downloader->getRetry());
|
||||
return DownloadResult::archive(basename($path), ['url' => $download_url, 'version' => $latest_version], extract: PKG_ROOT_PATH . '/rust-install', verified: false, version: $latest_version);
|
||||
return DownloadResult::archive(basename($path), ['url' => $download_url, 'version' => $latest_version], extract: '{pkg_root_path}/rust-install', verified: false, version: $latest_version);
|
||||
}
|
||||
|
||||
#[CustomBinaryCheckUpdate('rust', [
|
||||
|
||||
@@ -4,29 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace Package\Extension;
|
||||
|
||||
use Package\Target\php;
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\CustomPhpConfigureArg;
|
||||
use StaticPHP\Attribute\Package\Extension;
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Package\PhpExtensionPackage;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
|
||||
#[Extension('clickhouse')]
|
||||
class clickhouse extends PhpExtensionPackage
|
||||
{
|
||||
#[BeforeStage('php', [php::class, 'buildconfForUnix'], 'ext-clickhouse')]
|
||||
#[PatchDescription('Replace THIS_DIR=`dirname $0` with PHP_EXT_SRCDIR() in config.m4 so include paths resolve to the ext source dir during PHP main configure (dirname $0 returns "." when run from php-src root).')]
|
||||
public function patchBeforeBuildconfUnix(): void
|
||||
{
|
||||
FileSystem::replaceFileRegex(
|
||||
"{$this->getSourceDir()}/config.m4",
|
||||
'/^(\s*)THIS_DIR=.*/m',
|
||||
'$1THIS_DIR=PHP_EXT_SRCDIR()',
|
||||
);
|
||||
}
|
||||
|
||||
#[CustomPhpConfigureArg('Darwin')]
|
||||
#[CustomPhpConfigureArg('Linux')]
|
||||
public function getUnixConfigureArg(bool $shared, PackageInstaller $installer): string
|
||||
|
||||
@@ -20,7 +20,7 @@ class curl
|
||||
// which requires secur32.lib for SSL/TLS functions (SslEncryptPackage, etc.).
|
||||
$extra_libs = getenv('SPC_EXTRA_LIBS') ?: '';
|
||||
if (!str_contains($extra_libs, 'secur32.lib')) {
|
||||
putenv('SPC_EXTRA_LIBS=' . trim($extra_libs . ' secur32.lib'));
|
||||
putenv('SPC_EXTRA_LIBS=' . trim("{$extra_libs} secur32.lib"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
57
src/Package/Extension/gmssl.php
Normal file
57
src/Package/Extension/gmssl.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace Package\Extension;
|
||||
|
||||
use Package\Target\php;
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\CustomPhpConfigureArg;
|
||||
use StaticPHP\Attribute\Package\Extension;
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Package\PackageBuilder;
|
||||
use StaticPHP\Package\PhpExtensionPackage;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
|
||||
#[Extension('imagick')]
|
||||
class imagick
|
||||
class imagick extends PhpExtensionPackage
|
||||
{
|
||||
#[CustomPhpConfigureArg('Darwin')]
|
||||
#[CustomPhpConfigureArg('Linux')]
|
||||
@@ -18,4 +23,35 @@ class imagick
|
||||
$disable_omp = ' ac_cv_func_omp_pause_resource_all=no';
|
||||
return '--with-imagick=' . ($shared ? 'shared,' : '') . $builder->getBuildRootPath() . $disable_omp;
|
||||
}
|
||||
|
||||
#[CustomPhpConfigureArg('Windows')]
|
||||
public function getWindowsConfigureArg(bool $shared): string
|
||||
{
|
||||
// config.w32 uses PHP_IMAGICK as an extra search path for CORE_RL_*.lib; the static
|
||||
// ImageMagick libs are installed flat in buildroot/lib (headers in buildroot/include/imagemagick).
|
||||
return '--with-imagick=' . BUILD_LIB_PATH;
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-imagick')]
|
||||
#[PatchDescription('Add the Win32 system libraries the static ImageMagick stack needs')]
|
||||
public function patchConfigW32ForWindows(): void
|
||||
{
|
||||
$config = $this->getSourceDir() . '/config.w32';
|
||||
|
||||
// Idempotency guard (the source dir may be patched in place and reused across builds).
|
||||
if (str_contains(FileSystem::readFile($config), 'LIBS_IMAGICK')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The static ImageMagick stack needs several Win32 system libraries (GDI/GDI+, WIC, urlmon, ...)
|
||||
// that aren't already pulled in by the other extensions. (imagick itself builds as plain C:
|
||||
// ImageMagick is built with a 32-bit channel mask, see imagemagick.php buildWin, so the
|
||||
// MagickCore headers don't require a C++ translation unit.)
|
||||
FileSystem::replaceFileStr(
|
||||
$config,
|
||||
"AC_DEFINE('HAVE_IMAGICK', 1);",
|
||||
'ADD_FLAG("LIBS_IMAGICK", "gdi32.lib gdiplus.lib urlmon.lib msimg32.lib oleaut32.lib windowscodecs.lib iphlpapi.lib");' . "\n\t\t" .
|
||||
"AC_DEFINE('HAVE_IMAGICK', 1);"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,14 @@ use StaticPHP\Util\FileSystem;
|
||||
#[Extension('mongodb')]
|
||||
class mongodb extends PhpExtensionPackage
|
||||
{
|
||||
#[BeforeStage('php', [php::class, 'configureForUnix'], 'ext-mongodb')]
|
||||
#[PatchDescription('Export PHP_VERSION_ID so mongo-php-driver >= 2.3.3 skips its php-config lookup (in-tree builds have no php-config).')]
|
||||
public function exportPhpVersionIdForUnix(): void
|
||||
{
|
||||
$id = php::getPHPVersionID();
|
||||
f_putenv("PHP_VERSION_ID={$id}");
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-mongodb')]
|
||||
#[PatchDescription('Add /utf-8 flag to CFLAGS_MONGODB for Windows build to fix compilation error on non-English Windows.')]
|
||||
public function patchBeforeBuild(): void
|
||||
|
||||
@@ -72,6 +72,10 @@ class opcache extends PhpExtensionPackage
|
||||
) {
|
||||
$opcache_jit = ' --disable-opcache-jit';
|
||||
}
|
||||
return '--enable-opcache' . ($shared ? '=shared' : '') . $opcache_jit;
|
||||
// PHP 8.5+ has opcache built-in
|
||||
if ($phpVersionID < 80500) {
|
||||
return '--enable-opcache' . ($shared ? '=shared' : '') . $opcache_jit;
|
||||
}
|
||||
return trim($opcache_jit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class password_argon2 extends PhpExtensionPackage
|
||||
#[CustomPhpConfigureArg('Darwin')]
|
||||
public function getConfigureArg(PackageInstaller $installer, PackageBuilder $builder): string
|
||||
{
|
||||
if ($installer->getLibraryPackage('openssl') !== null) {
|
||||
if ($installer->getPhpExtensionPackage('openssl')?->isBuildStatic()) {
|
||||
if (php::getPHPVersionID() >= 80500 || (php::getPHPVersionID() >= 80400 && !$builder->getOption('enable-zts'))) {
|
||||
return '--without-password-argon2'; // use --with-openssl-argon2 in openssl extension instead
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Package\Extension;
|
||||
|
||||
use Package\Target\php;
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\Extension;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
|
||||
#[Extension('pdo_sqlite')]
|
||||
class pdo_sqlite
|
||||
{
|
||||
#[BeforeStage('php', [php::class, 'configureForUnix'], 'ext-pdo_sqlite')]
|
||||
public function patchBeforeConfigure(PackageInstaller $installer): void
|
||||
{
|
||||
FileSystem::replaceFileRegex(
|
||||
"{$installer->getTargetPackage('php')->getSourceDir()}/configure",
|
||||
'/sqlite3_column_table_name=yes/',
|
||||
'sqlite3_column_table_name=no'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,15 @@ declare(strict_types=1);
|
||||
namespace Package\Extension;
|
||||
|
||||
use Package\Target\php;
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\CustomPhpConfigureArg;
|
||||
use StaticPHP\Attribute\Package\Extension;
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Package\PackageBuilder;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Package\PhpExtensionPackage;
|
||||
use StaticPHP\Package\TargetPackage;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
use StaticPHP\Util\SPCConfigUtil;
|
||||
|
||||
#[Extension('pgsql')]
|
||||
@@ -20,7 +24,7 @@ class pgsql extends PhpExtensionPackage
|
||||
public function getUnixConfigureArg(bool $shared, PackageBuilder $builder, PackageInstaller $installer): string
|
||||
{
|
||||
if (php::getPHPVersionID() >= 80400) {
|
||||
$libfiles = new SPCConfigUtil(['libs_only_deps' => true, 'absolute_libs' => true])->getPackageDepsConfig('postgresql', array_keys($installer->getResolvedPackages()), $builder->getOption('with-suggests'))['libs'];
|
||||
$libfiles = new SPCConfigUtil(['libs_only_deps' => true, 'absolute_libs' => true])->getPackageDepsConfig('postgresql', array_keys($installer->getResolvedPackages()))['libs'];
|
||||
$libfiles = str_replace("{$builder->getLibDir()}/lib", '-l', $libfiles);
|
||||
$libfiles = str_replace('.a', '', $libfiles);
|
||||
return '--with-pgsql' . ($shared ? '=shared' : '') .
|
||||
@@ -39,6 +43,27 @@ class pgsql extends PhpExtensionPackage
|
||||
return "--with-pgsql={$builder->getBuildRootPath()}";
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-pgsql')]
|
||||
#[PatchDescription('Link the Win32 system libraries the static libpq needs')]
|
||||
public function patchConfigW32ForWindows(TargetPackage $package): void
|
||||
{
|
||||
$config = "{$package->getSourceDir()}\\ext\\pgsql\\config.w32";
|
||||
|
||||
if (str_contains(FileSystem::readFile($config), 'LIBS_PGSQL')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// libpq uses SSPI for Windows auth (secur32) and the static libcrypto behind it
|
||||
// reads the system cert store (crypt32). Nothing else puts these on the link line
|
||||
// when the openssl extension itself is not part of the build.
|
||||
FileSystem::replaceFileStr(
|
||||
$config,
|
||||
'EXTENSION("pgsql", "pgsql.c", PHP_PGSQL_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");',
|
||||
'EXTENSION("pgsql", "pgsql.c", PHP_PGSQL_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");' . "\n\t\t" .
|
||||
'ADD_FLAG("LIBS_PGSQL", "secur32.lib crypt32.lib");'
|
||||
);
|
||||
}
|
||||
|
||||
public function getSharedExtensionEnv(): array
|
||||
{
|
||||
$parent = parent::getSharedExtensionEnv();
|
||||
|
||||
@@ -50,8 +50,9 @@ class simdjson extends PhpExtensionPackage
|
||||
if (!str_contains((string) $extra, '-lstdc++')) {
|
||||
f_putenv('SPC_COMPILER_EXTRA=' . clean_spaces($extra . ' -lstdc++'));
|
||||
}
|
||||
$env['CFLAGS'] .= ' -Xclang -target-feature -Xclang +evex512';
|
||||
$env['CXXFLAGS'] .= ' -Xclang -target-feature -Xclang +evex512';
|
||||
|
||||
$env['CFLAGS'] .= ' -fno-sanitize=undefined -Xclang -target-feature -Xclang +evex512';
|
||||
$env['CXXFLAGS'] .= ' -fno-sanitize=undefined -Xclang -target-feature -Xclang +evex512';
|
||||
}
|
||||
return $env;
|
||||
}
|
||||
@@ -63,8 +64,8 @@ class simdjson extends PhpExtensionPackage
|
||||
return;
|
||||
}
|
||||
$extra_cflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') ?: '';
|
||||
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . trim($extra_cflags . ' -Xclang -target-feature -Xclang +evex512'));
|
||||
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . trim($extra_cflags . ' -fno-sanitize=undefined -Xclang -target-feature -Xclang +evex512'));
|
||||
$extra_cxxflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CXXFLAGS') ?: '';
|
||||
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CXXFLAGS=' . trim($extra_cxxflags . ' -Xclang -target-feature -Xclang +evex512'));
|
||||
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CXXFLAGS=' . trim($extra_cxxflags . ' -fno-sanitize=undefined -Xclang -target-feature -Xclang +evex512'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,27 @@ namespace Package\Extension;
|
||||
|
||||
use Package\Target\php;
|
||||
use StaticPHP\Attribute\Package\BeforeStage;
|
||||
use StaticPHP\Attribute\Package\CustomPhpConfigureArg;
|
||||
use StaticPHP\Attribute\Package\Extension;
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Package\PhpExtensionPackage;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
|
||||
#[Extension('spx')]
|
||||
class spx extends PhpExtensionPackage
|
||||
{
|
||||
#[CustomPhpConfigureArg('Linux')]
|
||||
#[CustomPhpConfigureArg('Darwin')]
|
||||
public function getUnixConfigureArg(bool $shared, PackageInstaller $installer): string
|
||||
{
|
||||
$arg = '--enable-SPX' . ($shared ? '=shared' : '');
|
||||
if ($installer->getLibraryPackage('zlib') !== null) {
|
||||
$arg .= ' --with-zlib-dir=' . BUILD_ROOT_PATH;
|
||||
}
|
||||
return $arg;
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [php::class, 'buildconfForUnix'], 'ext-spx')]
|
||||
#[PatchDescription('Fix spx extension compile error when building as static')]
|
||||
public function patchBeforeBuildconf(): bool
|
||||
|
||||
@@ -30,6 +30,7 @@ class swoole extends PhpExtensionPackage
|
||||
if ($installer->getPhpExtensionPackage('swoole-hook-odbc') && $installer->getPhpExtensionPackage('pdo_odbc')?->isBuildStatic()) {
|
||||
throw new WrongUsageException('swoole-hook-odbc provides pdo_odbc, if you enable odbc hook for swoole, you must remove pdo_odbc extension.');
|
||||
}
|
||||
|
||||
// swoole-hook-pgsql conflicts with pdo_pgsql
|
||||
if ($installer->getPhpExtensionPackage('swoole-hook-pgsql') && $installer->getPhpExtensionPackage('pdo_pgsql')?->isBuildStatic()) {
|
||||
throw new WrongUsageException('swoole-hook-pgsql provides pdo_pgsql, if you enable pgsql hook for swoole, you must remove pdo_pgsql extension.');
|
||||
|
||||
@@ -11,7 +11,7 @@ use StaticPHP\Attribute\Package\Extension;
|
||||
use StaticPHP\Attribute\PatchDescription;
|
||||
use StaticPHP\Package\PackageInstaller;
|
||||
use StaticPHP\Package\PhpExtensionPackage;
|
||||
use StaticPHP\Util\GlobalEnvManager;
|
||||
use StaticPHP\Util\FileSystem;
|
||||
use StaticPHP\Util\SourcePatcher;
|
||||
|
||||
#[Extension('xlswriter')]
|
||||
@@ -21,37 +21,38 @@ class xlswriter extends PhpExtensionPackage
|
||||
#[CustomPhpConfigureArg('Linux')]
|
||||
public function getUnixConfigureArg(bool $shared, PackageInstaller $installer): string
|
||||
{
|
||||
$arg = '--with-xlswriter --enable-reader';
|
||||
$shared = $shared ? '=shared' : '';
|
||||
$arg = "--with-xlswriter{$shared} --enable-reader";
|
||||
if ($installer->getLibraryPackage('openssl')) {
|
||||
$arg .= ' --with-openssl=' . $installer->getLibraryPackage('openssl')->getBuildRootPath();
|
||||
}
|
||||
return $arg;
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [php::class, 'makeForUnix'], 'ext-xlswriter')]
|
||||
#[PatchDescription('Fix Unix build: add -std=gnu17 to CFLAGS to fix build errors on older GCC versions')]
|
||||
public function patchBeforeUnixMake(): void
|
||||
#[BeforeStage('php', [php::class, 'buildconfForWindows'], 'ext-xlswriter')]
|
||||
#[PatchDescription('Define XML_STATIC so bundled Expat uses plain symbols instead of __declspec(dllimport) in static builds')]
|
||||
public function patchConfigForStaticExpat(): void
|
||||
{
|
||||
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -std=gnu17');
|
||||
FileSystem::replaceFileStr(
|
||||
"{$this->getSourceDir()}/config.w32",
|
||||
"' /D USE_SYSTEM_MINIZIP",
|
||||
"' /D XML_STATIC /D USE_SYSTEM_MINIZIP"
|
||||
);
|
||||
}
|
||||
|
||||
#[BeforeStage('php', [php::class, 'makeForWindows'], 'ext-xlswriter')]
|
||||
#[PatchDescription('Fix Windows build: apply win32 patch and add UTF-8 BOM to theme.c')]
|
||||
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
|
||||
SourcePatcher::patchFile('spc_fix_xlswriter_win32.patch', $this->getSourceDir());
|
||||
$content = file_get_contents($this->getSourceDir() . '/library/libxlsxwriter/src/theme.c');
|
||||
SourcePatcher::patchFile('spc_fix_xlswriter_win32.patch', $source_dir);
|
||||
$content = file_get_contents($theme_file);
|
||||
$bom = pack('CCC', 0xEF, 0xBB, 0xBF);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public function getSharedExtensionEnv(): array
|
||||
{
|
||||
$parent = parent::getSharedExtensionEnv();
|
||||
$parent['CFLAGS'] .= ' -std=gnu17';
|
||||
return $parent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ class gettext_win
|
||||
{
|
||||
$ver = WindowsUtil::findVisualStudio();
|
||||
$vs_ver_dir = match ($ver['major_version']) {
|
||||
'18', // VS 2026 reuses the VS2022 (MSVC17) solution, which msbuild builds via forward compatibility.
|
||||
'17' => '\MSVC17',
|
||||
'16' => '\MSVC16',
|
||||
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');
|
||||
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->getIncludeDir());
|
||||
// libintl_a.lib is the static library output; copy as libintl.lib for linker compatibility
|
||||
|
||||
@@ -18,7 +18,9 @@ class gmssl
|
||||
#[BuildFor('Darwin')]
|
||||
public function build(LibraryPackage $lib): void
|
||||
{
|
||||
UnixCMakeExecutor::create($lib)->build();
|
||||
UnixCMakeExecutor::create($lib)
|
||||
->addConfigureArgs('-DENABLE_SM2_PRIVATE_KEY_EXPORT=ON')
|
||||
->build();
|
||||
}
|
||||
|
||||
#[BuildFor('Windows')]
|
||||
@@ -33,6 +35,7 @@ class gmssl
|
||||
'-G "NMake Makefiles"',
|
||||
'-DWIN32=ON',
|
||||
'-DBUILD_SHARED_LIBS=OFF',
|
||||
'-DENABLE_SM2_PRIVATE_KEY_EXPORT=ON',
|
||||
'-DCMAKE_BUILD_TYPE=Release',
|
||||
'-DCMAKE_C_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"',
|
||||
'-DCMAKE_CXX_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"',
|
||||
@@ -42,13 +45,13 @@ class gmssl
|
||||
->toStep(1)
|
||||
->build();
|
||||
|
||||
// fix cmake_install.cmake install prefix (GmSSL overrides it internally)
|
||||
$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 gmssl XCFLAGS=/MT');
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user