Update latest docs

This commit is contained in:
crazywhalecc
2026-04-23 14:09:20 +08:00
parent 3583cbe119
commit 860ff38dae
10 changed files with 916 additions and 24 deletions

View File

@@ -1,4 +1,48 @@
# 开发简介
<!-- TODO: 开发者简介、环境准备、所需 PHP 扩展
Vendor 模式链接到 vendor-mode/,代码贡献链接到 contributing/。 -->
本章节将介绍 StaticPHP 的开发流程,以及了解 StaticPHP 内部工作原理所需的基础知识
## 概述
StaticPHP 是一个静态二进制的构建工具,核心功能是管理构建流程,包括下载和配置 PHP 源码、处理扩展依赖、调用底层构建系统(如 Docker 或本地编译器)等。
从开发的角度来看StaticPHP 本身是一个开放的框架,它提供了静态构建包括 PHP 在内的各种开源工具的能力。项目主要由 [@crazywhalecc](https://github.com/crazywhalecc) 和 [@henderkes](https://github.com/henderkes) 维护,由广大社区成员贡献代码、完善构建脚本和修复问题。
你可以将 StaticPHP 当作一个典型的 PHP 开发的 CLI 项目来看待,它使用了 [symfony/console](https://symfony.com/doc/current/components/console.html) 来构建命令行界面。
## 开发环境
要开始开发 StaticPHP你需要设置一个 PHP 开发环境,安装必要的依赖,并了解项目的构建流程。
StaticPHP 的开发环境要求如下:
- PHP 8.4 或更高版本
- Composer
- Git
- PHP 扩展:`curl,dom,filter,mbstring,openssl,pcntl,phar,posix,sodium,tokenizer,xml,xmlwriter`
> 这些 PHP 扩展是 StaticPHP 的 `dev` 环境依赖。
以下是一些基本步骤:
1. 克隆项目代码:
```bash
git clone https://github.com/crazywhalecc/static-php-cli.git
cd static-php-cli
```
2. 安装 PHP 依赖:
```bash
composer install
```
3. 运行测试:
```bash
bin/spc --version
```
------------------------------
你可以继续阅读 [项目结构](./structure) 来深入了解 StaticPHP 的框架结构。

View File

@@ -3,3 +3,239 @@
<!-- TODO: 统一 Package 模型说明library / php-extension / target 类型。
config/pkg/ 下 per-package YAML 格式、depends 字段、平台覆盖(@windows / @unix 写法)。
artifact.source 和 artifact.binary 字段。附注释的 library 和 extension YAML 示例。 -->
## Package 定义
Package 是 StaticPHP 构建系统中的核心概念,代表一个可构建/可安装的单元,如 PHP 扩展、库、构建目标等。
每个 Package 包含构建信息、依赖关系、构建逻辑等,构成了 StaticPHP 的构建模型。Package 的定义主要通过 YAML/JSON 配置文件来实现。`core` 注册表的包配置文件位于 `config/pkg/` 目录下,对应的构建类位于 `src/Package/` 目录下。
Package 主要分为四种类型:
- **php-extension**PHP 扩展包,包含 PHP 扩展的构建信息和构建逻辑。
- **library**:库包,包含构建工具链、依赖库等的构建信息和构建逻辑。
- **target**:构建目标包,代表最终的构建产物,如 PHP 二进制、curl 二进制等,继承自 `library` 包类型。
- **virtual-target**:虚构建目标包,代表一个抽象的构建目标,不直接对应构建产物,主要用于依赖管理和构建调度。
```yaml
{pkg-name}:
type: {pkg-type}
...
```
## Artifact 定义
Artifact 是独立于 Package 的定义,它包含构建包的源码归档文件或预构建的二进制文件。每个 Artifact 定义了下载 URL、解压方式、构建产物的文件路径等信息。Package 可以通过 `artifact` 字段引用一个或多个 Artifact 来获取构建所需的源码或二进制文件。
简单来说,默认情况下,一个 Package 对应一个 Artifact如果多个 Package 共用一份源码时,可以定义一个 Artifact 供多个 Package 引用。Artifact 的定义位于 `config/artifact/` 目录下,对应的自定义下载/解压逻辑类位于 `src/Package/Artifact/` 目录下对于虚拟目标、PHP 内置扩展等特殊包类型Package 也可以不设置 Artifact 字段。
我们假设 `example-library-package` 是一个依赖库,它的源码归档文件托管在 `https://example.com/example-library.tar.gz`,则它的 Package 定义和 Artifact 定义可以如下所示:
```yaml
example-library-package:
type: library
artifact:
source:
type: url
url: 'https://example.com/example-library.tar.gz'
```
更多有关 Artifact 定义的内容,请参阅 [Artifact 模型](./artifact-model) 章节。
## php-extension 包类型
php-extension 一个包代表一个 PHP 扩展,它的配置文件位于 `config/pkg/ext/` 目录下,构建类继承自 `PhpExtensionPackage`,位于 `src/Package/Extension/` 目录下。PHP 扩展包的配置文件包含扩展名称、版本、依赖关系、构建选项等信息。
```yaml
ext-lz4:
type: php-extension
artifact:
source:
type: git
url: 'https://github.com/kjdev/php-ext-lz4.git'
rev: master
extract: php-src/ext/lz4
metadata:
license-files: [LICENSE]
license: MIT
depends:
- liblz4
php-extension:
arg-type@unix: '--enable-lz4=@shared_suffix@ --with-lz4-includedir=@build_root_path@'
arg-type@windows: '--enable-lz4'
```
`php-extension` 允许的定义字段:
```yaml
ext-{ext-name}: # 包名必须以 ext- 前缀开头
type: php-extension
# ── 通用字段 ─────────────────────────────────────────────────────────────
description: '...' # 可选,人类可读的包描述
lang: c # 可选扩展的实现语言c / c++ 等)
frameworks: [] # 可选相关macOS框架依赖列表
artifact: '{artifact-name}' # 可选;字符串时引用同名 Artifact 定义,
# 对象时为内联 Artifact内置扩展无需此字段
# depends / suggests 支持 @windows / @unix / @linux / @macos 后缀
depends: [] # 可选硬依赖列表库名直接写PHP 扩展需加 ext- 前缀)
depends@unix: [] # 可选,仅 Unix 平台生效的硬依赖
depends@windows: [] # 可选,仅 Windows 平台生效的硬依赖
suggests: [] # 可选,可选依赖列表(格式同 depends
suggests@unix: []
# ── php-extension 专属字段(嵌套在 php-extension: 对象中)─────────────────
php-extension:
# arg-type 决定传递给 ./configure 的参数形式,支持平台后缀
# 支持的平台后缀:@unixLinux + macOS、@linux、@macos、@windows
# 优先级(以 Linux 为例arg-type@linux > arg-type@unix > arg-type无后缀
# 内置关键字:
# enable → --enable-{extname}(默认值,未配置时使用)
# enable-path → --enable-{extname}={buildroot}
# with → --with-{extname}
# with-path → --with-{extname}={buildroot}
# custom/none → 不传递任何参数(由 PHP 类的 #[CustomPhpConfigureArg] 方法处理)
# 也可直接写完整参数字符串,支持以下占位符:
# @build_root_path@ → BUILD_ROOT_PATHbuildroot 绝对路径)
# @shared_suffix@ → 共享构建时展开为 =shared静态构建时为空
# @shared_path_suffix@ → 共享构建时展开为 =shared,{buildroot},静态构建时为 ={buildroot}
arg-type: enable
arg-type@unix: '--enable-{extname}=@shared_suffix@'
arg-type@windows: with-path
zend-extension: false # 可选true 表示这是 Zend 扩展(如 opcache、xdebug
build-shared: true # 可选,是否允许构建为共享扩展(.so默认 true
build-static: true # 可选,是否允许内联静态构建(编译进 PHP默认 true
build-with-php: true # 可选true 表示该扩展通过 PHP 源码树一同编译(内置扩展使用)
# display-name 影响 smoke test 中 php --ri 的参数及许可证导出显示名称
# 不填时默认使用扩展名ext- 后缀部分);填空字符串则跳过 --ri 检查
display-name: 'My Extension'
# os 限制该扩展仅在指定平台上可用,不在列表内的平台会拒绝构建
# 可选值Linux、Darwin、Windows
os: [Linux, Darwin]
```
## library 包类型
library 包代表一个需要从源码编译的依赖库(如 openssl、zlib 等),其配置文件位于 `config/pkg/lib/` 目录下,构建类继承自 `LibraryPackage`,位于 `src/Package/Library/` 目录下。
以 openssl 为例:
```yaml
openssl:
type: library
artifact:
source:
type: ghrel
repo: openssl/openssl
match: openssl.+\.tar\.gz
prefer-stable: true
binary: hosted
metadata:
license-files: [LICENSE.txt]
license: OpenSSL
depends:
- zlib
depends@windows:
- zlib
- jom
headers:
- openssl
static-libs@unix:
- libssl.a
- libcrypto.a
static-libs@windows:
- libssl.lib
- libcrypto.lib
```
`library` 允许的定义字段:
```yaml
{lib-name}:
type: library # library 或 targettarget 继承 library 的所有字段)
# ── 通用字段 ─────────────────────────────────────────────────────────────
description: '...' # 可选,人类可读的包描述
license: MIT # 可选SPDX 许可证标识符(用于许可证导出)
lang: c # 可选库的实现语言c / c++ 等)
frameworks: [] # 可选,相关框架标签列表
artifact: '{artifact-name}' # 必填;字符串时引用同名 Artifact 定义,对象时为内联 Artifact
# depends / suggests 支持 @windows / @unix / @linux / @macos 后缀
depends: [] # 可选,硬依赖列表(库名或 ext- 前缀的 PHP 扩展名)
depends@unix: []
depends@windows: []
suggests: [] # 可选,可选依赖列表(格式同 depends
# ── library / target 专属字段 ────────────────────────────────────────────
# 以下字段用于构建完成后验证产物是否已正确安装,支持 @unix / @windows / @linux / @macos 后缀
# 验证 buildroot/include/ 下是否存在指定头文件或目录
# 相对路径基于 buildroot/include/,绝对路径直接使用
headers:
- openssl # 对应 buildroot/include/openssl/
- zlib.h # 对应 buildroot/include/zlib.h
headers@unix:
- ffi.h
# 验证 buildroot/lib/ 下是否存在指定静态库文件
# 相对路径基于 buildroot/lib/,绝对路径直接使用
static-libs@unix:
- libssl.a
static-libs@windows:
- libssl.lib
# 验证 buildroot/lib/pkgconfig/ 下是否存在指定 .pc 文件
# 仅在非 Windows 平台检查pkg-config 在 Windows 上不适用)
pkg-configs:
- openssl # 对应 buildroot/lib/pkgconfig/openssl.pc
- libssl # 自动补全 .pc 后缀
# 验证 buildroot/bin/ 下是否存在指定可执行文件
# 相对路径基于 buildroot/bin/,绝对路径直接使用
static-bins:
- my-tool
# 包安装完成后注入到全局 PATH 的目录列表,支持路径占位符(见下方说明)
path:
- '{pkg_root_path}/rust/bin'
# 包安装完成后设置的环境变量(覆盖已有值),支持路径占位符
env:
MY_VAR: '{build_root_path}/lib'
# 包安装完成后追加到已有环境变量末尾的值,支持路径占位符
append-env:
CFLAGS: ' -I{build_root_path}/include'
```
`path``env``append-env` 字段的字符串值中支持以下路径占位符:
| 占位符 | 实际路径 |
|---|---|
| `{build_root_path}` | buildroot 目录(`buildroot/` |
| `{pkg_root_path}` | pkgroot 目录(`pkgroot/` |
| `{working_dir}` | 工作目录(项目根目录) |
| `{download_path}` | 下载缓存目录(`downloads/` |
| `{source_path}` | 解压源码目录(`source/` |
| `{php_sdk_path}` | Windows PHP SDK 目录 |
## target 包类型
`target` 包代表一个最终的构建产物,它继承于 `library`,所以包含 `library` 的所有定义字段。`target` 包的配置文件位于 `config/pkg/target/` 目录下,构建类继承自 `TargetPackage`,位于 `src/Package/Target/` 目录下。
`library` 的唯一区别是,`target` 包可以注册成为构建目标,且自动注册构建命令 `spc build:{target-name}`
## virtual-target 包类型
`target` 不同的是,`virtual-target` 可以不包含 `artifact`,即不直接对应一个可构建的实体,而是一个抽象的构建目标,主要用于依赖管理和构建调度。`virtual-target` 的配置文件位于 `config/pkg/target/` 目录下,构建类继承自 `TargetPackage`,位于 `src/Package/Target/` 目录下。它的定义与 `target` 基本相同,但 `artifact` 字段可选且通常不设置。`virtual-target` 主要用于以下场景:
- 定义一个抽象的构建目标,供其他包依赖,但不直接对应一个可构建的实体。
- 作为多个 `target` 包的公共依赖,简化依赖关系管理。
典型例子就是 PHP 包的 `php-cli``php-fpm` 等构建目标,他们没有独立的源码,依赖于 `php-src`,通过构建调度来决定最终构建成 CLI 还是 FPM 二进制。

View File

@@ -3,3 +3,82 @@
<!-- TODO: spc.registry.yml 结构说明。
通过 SPC_REGISTRIES 环境变量添加外部 Registry。
Vendor 特定配置、覆盖核心包。Registry 解析顺序与冲突规则。 -->
## 概述
**Registry注册表** 是 StaticPHP 的核心扩展机制。你可以把它理解成一个"插件包":一个 Registry 由一个声明文件(`spc.registry.yml`和它所指向的配置文件、PHP 类共同组成描述了一组包的定义YAML 配置和对应的构建逻辑PHP 类)。构建系统在启动时会加载所有已注册的 Registry将它们的包定义合并后用于整个构建流程。
StaticPHP 本身携带一个内置的核心注册表(`core`),其中包含了 PHP 及相关扩展、库、构建工具等的全部定义。`core` 注册表的声明文件即项目根目录下的 `spc.registry.yml`,它描述了配置文件目录(`config/pkg/``config/artifact/`)和构建类的 PSR-4 命名空间(`src/Package/`)之间的映射关系。
外部 Registry 只能定义 `core` 中尚不存在的新包,不能覆盖或修改核心注册表中已有的定义。根据你的需求,有以下三种方式来扩展或修改 StaticPHP 的构建能力:
- **修改 `core` 注册表**:直接修改 `src/Package``config/pkg/` 下的文件,适用于希望将改动合并回 StaticPHP 主线的情况。请先阅读 [贡献指南](../contributing/) 中关于贡献新包的部分,再提交 PR。
- **Vendor 模式**:将自定义包封装为一个独立的子注册表,以 Composer 包的形式分发,适用于需要私有包或希望以库的形式复用构建逻辑的场景。详见 [Vendor 模式](./vendor-mode/)。
- **外部注册表(`SPC_REGISTRIES`**:通过环境变量 `SPC_REGISTRIES` 指定一个或多个外部注册表文件的路径StaticPHP 会在启动时加载它们。适用于临时扩展或不便打包为 Composer 包的场景,与其他包管理器的外部源机制类似。
## Registry 定义文件
每个 Registry 都有一个声明文件,通常命名为 `spc.registry.yml`,位于项目根目录或 Composer 包的根目录下。文件格式支持 YAML`.yml` / `.yaml`)和 JSON`.json`)。文件中所有路径均相对于声明文件自身所在目录解析。
StaticPHP 在源码模式(直接 git clone会默认加载项目根目录下的 `spc.registry.yml` 作为核心注册表(`core`)。在 Vendor 模式下,会自动检测当前 Composer 包根目录下是否存在 `spc.registry.yml`,如果存在则加载为一个独立的注册表。通过 `SPC_REGISTRIES` 环境变量指定的外部注册表也必须包含一个有效的声明文件。
下面是一个包含所有可用字段的完整示例(参照 `core` 注册表):
```yaml
# [必填] 注册表唯一名称,重复加载同名注册表时会自动跳过
name: my-registry
# [可选] Composer autoload 文件路径,外部注册表有自己的依赖时使用
autoload: vendor/autoload.php
# 包library / php-extension / target相关配置
package:
# 包的 YAML 配置文件目录或具体文件路径,可以是数组
config:
- config/pkg/lib/
- config/pkg/target/
- config/pkg/ext/
# 包构建类的 PSR-4 命名空间 → 目录路径映射,加载器会扫描目录下所有 PHP 类
psr-4:
Package: src/Package
# 也可以按需加载指定的类,支持数组格式或 {"类名": "文件路径"} 映射格式
# classes:
# - Package\Library\MyLib
# MyLib: src/Package/Library/MyLib.php
# 构建产物Artifact相关配置
artifact:
# Artifact 的 YAML 配置文件目录或具体文件路径
config:
- config/artifact/
# Artifact 自定义下载/解压类的 PSR-4 命名空间 → 目录路径映射
psr-4:
Package\Artifact: src/Package/Artifact
# classes: ...(同 package.classes 格式)
# Doctor 环境检查项配置
doctor:
# Doctor 检查项类的 PSR-4 命名空间 → 目录路径映射
psr-4:
StaticPHP\Doctor\Item: src/StaticPHP/Doctor/Item
# classes: ...(同 package.classes 格式)
# 额外的 CLI 命令配置
command:
# 自定义命令类的 PSR-4 命名空间 → 目录路径映射
psr-4:
Package\Command: src/Package/Command
# classes: ...(同 package.classes 格式)
```
各顶层字段说明:
| 字段 | 必填 | 说明 |
|---|---|---|
| `name` | ✅ | 注册表唯一名称,重复加载同名注册表时自动跳过 |
| `autoload` | | Composer autoload 文件路径,适用于外部注册表携带自己的依赖时 |
| `package` | | 包定义,含 YAML 配置(`config`)和构建类(`psr-4` / `classes` |
| `artifact` | | Artifact 定义,含 YAML 配置(`config`)和自定义类(`psr-4` / `classes` |
| `doctor` | | Doctor 检查项定义,仅含类加载(`psr-4` / `classes` |
| `command` | | 额外的 CLI 命令定义,仅含类加载(`psr-4` / `classes` |
其中 `psr-4``classes` 的区别:`psr-4` 会扫描整个目录下所有符合命名空间规则的 PHP 类并批量注册;`classes` 则用于精确指定某几个类,支持纯数组格式(`["ClassName"]`,需已在 autoload 中可用)或键值映射格式(`{"ClassName": "path/to/file.php"}`,加载器会自动 `require` 对应文件)。

View File

@@ -1,4 +1,85 @@
# 项目结构
<!-- TODO: v3 目录结构说明bin/、config/pkg/、src/StaticPHP/、src/Package/ 等)。
每个顶层目录的职责说明。内部类结构简述,深入内容见核心概念页。 -->
## 概念
StaticPHP 本身是一个基于 `symfony/console` 的 CLI 应用,核心代码位于 `src/StaticPHP` 目录下。
它主要分为几个模块:
- **Registry**负责管理注册表数据每个注册表含有多个包PackageStaticPHP 项目本身内置一个 `core` 注册表,包含 PHP 及相关扩展、依赖等。
- **Package**:代表一个包,包的种类有四种:`php-extension`PHP 扩展)、`library`(库)、`target`(构建目标)、`virtual-target`(虚构建目标)。每个包包含构建信息、依赖关系等。
- **Installer/Builder**:负责处理包的安装和构建逻辑,调用构建命令、解压构建产物、处理构建结果等。
- **Doctor**:提供系统环境检查功能,负责安装和检查系统层面依赖的工具、需要的文件等,如 `make``cmake``autoconf` 等。
- **Runtime/Executor**:包含运行时相关的工具类,如执行 shell 命令、执行 CMake 构建等。
- **Toolchain**:对不同操作系统及环境,提供对应系统的工具链抽象接口,负责处理构建过程中与系统环境相关的差异。
- **Utils**:一些通用的工具类,如文件系统操作、日志记录、操作系统相关助手方法等。
- **DependencyResolver**:负责解析包之间的依赖关系,生成构建顺序等。
## 目录结构
```
static-php-cli/
├── bin/ # 可执行入口脚本spc、spc.ps1、setup-runtime 等)
├── config/
│ ├── env.ini # 默认环境变量配置
│ ├── env.custom.ini # 用户自定义环境变量(覆盖 env.ini
│ ├── artifact/ # 构建产物配置(下载工具链、预构建二进制等)
│ └── pkg/ # 包配置文件YAML
│ ├── ext/ # PHP 扩展包配置ext-*.yml、builtin-extensions.yml
│ ├── lib/ # 库包配置(*.yml
│ └── target/ # 构建目标配置php.yml、curl.yml 等)
├── src/
│ ├── bootstrap.php # 应用引导注册自动加载、DI 容器等)
│ ├── globals/ # 全局辅助函数
│ ├── Package/ # 各包的构建逻辑实现PHP 类)
│ │ ├── Artifact/ # 构建产物的自定义下载/解压逻辑
│ │ ├── Command/ # 包级别自定义命令
│ │ ├── Extension/ # PHP 扩展构建类ext-*.php
│ │ ├── Library/ # 库构建类(*.php
│ │ └── Target/ # 构建目标类php.php、curl.php 等)
│ └── StaticPHP/ # 框架核心代码
│ ├── ConsoleApplication.php # Symfony Console 应用入口
│ ├── Artifact/ # 构建产物下载与解压Downloader、Extractor 等)
│ ├── Attribute/ # PHP 注解定义
│ │ ├── Artifact/ # 产物相关注解CustomSource、BinaryExtract 等)
│ │ ├── Doctor/ # Doctor 相关注解CheckItem、FixItem 等)
│ │ └── Package/ # 包构建相关注解BuildFor、BeforeStage、AfterStage、
│ │ # CustomPhpConfigureArg、PatchBeforeBuild 等)
│ ├── Command/ # CLI 命令实现build-libs、build-target、doctor 等)
│ ├── Config/ # 配置加载与验证PackageConfig、ArtifactConfig 等)
│ ├── DI/ # 依赖注入容器ApplicationContext、CallbackInvoker
│ ├── Doctor/ # 系统环境检查与修复Doctor、CheckResult
│ ├── Exception/ # 自定义异常类
│ ├── Package/ # 包核心模型与构建调度
│ │ ├── Package.php # 包基类
│ │ ├── LibraryPackage.php # 库包类型
│ │ ├── PhpExtensionPackage.php # PHP 扩展包类型
│ │ ├── TargetPackage.php # 构建目标包类型
│ │ ├── PackageInstaller.php # 包安装器(下载、解压源码)
│ │ └── PackageBuilder.php # 包构建器(执行构建流程)
│ ├── Registry/ # 注册表管理Registry、PackageLoader、ArtifactLoader
│ ├── Runtime/ # 运行时工具
│ │ ├── Executor/ # 命令执行器UnixAutoconfExecutor、UnixCMakeExecutor、
│ │ │ # WindowsCMakeExecutor、Executor 基类)
│ │ ├── Shell/ # Shell 抽象UnixShell、WindowsCmd 等)
│ │ └── SystemTarget.php # 系统目标信息
│ ├── Toolchain/ # 工具链抽象GccNative、Musl、MSVC、Zig、ClangBrew 等)
│ └── Util/ # 通用工具类
│ ├── System/ # 系统平台工具LinuxUtil、MacOSUtil、WindowsUtil 等)
│ ├── BuildRootTracker.php # buildroot 文件追踪
│ ├── DependencyResolver.php # 依赖解析与构建顺序
│ ├── FileSystem.php # 文件系统操作
│ ├── GlobalEnvManager.php # 全局环境变量管理
│ ├── InteractiveTerm.php # 交互式终端输出
│ ├── LicenseDumper.php # 开源协议导出
│ ├── PkgConfigUtil.php # pkg-config 工具封装
│ ├── SourcePatcher.php # 源码补丁工具
│ └── SPCConfigUtil.php # SPC 配置读取工具
├── tests/ # 单元测试与集成测试
├── downloads/ # 下载缓存目录(源码包、预构建二进制)
├── source/ # 解压后的源码目录
├── buildroot/ # 构建输出目录(头文件、静态库等)
├── pkgroot/ # 按平台归档的构建产物
└── spc.registry.yml # core 注册表定义文件
```
需要注意的是,`src/Package` 目录下的类主要负责实现具体包的构建逻辑,而 `src/StaticPHP` 目录下的类则提供了构建框架的核心功能,如命令调度、环境检查、工具链抽象等,两者是解耦的。`src/Package` 对应的是 `core` 注册表中的包,其中包含 PHP 及相关扩展、库、构建目标等的具体实现,而 `src/StaticPHP` 则是整个构建系统的基础设施,支持不同注册表和包的构建需求。