feat(docs): add agent guide, build class patterns, log triage, and AI instructions

This commit is contained in:
crazywhalecc
2026-07-06 20:39:44 +08:00
parent 8dd7882869
commit fe3cd15f81
9 changed files with 738 additions and 0 deletions

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

@@ -0,0 +1,52 @@
# StaticPHP v3 AI Instructions
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`.
Use the repository skills when the task matches them:
- `.github/skills/staticphp-package-maintenance`: adding, changing, reviewing, or validating package, artifact, extension, library, target, or tool definitions.
- `.github/skills/staticphp-build-troubleshooting`: diagnosing build, download, doctor, shell, terminal, CI, or log failures.
## 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.
- `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
php bin/spc dev:lint-config
composer cs-fix
```
For broader PHP code changes, also run:
```bash
composer test
composer analyse
```
Use build commands only when needed for the task or when the user provided a repro, because full static builds can be slow and platform-sensitive.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

58
AGENTS.md Normal file
View File

@@ -0,0 +1,58 @@
# 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.
- `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.