Files
static-php-cli/docs/zh/develop/package-model.md

279 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Package 模型
## Package 定义
Package 是 StaticPHP 构建系统中的核心概念,代表一个可构建/可安装的单元,如 PHP 扩展、库、构建目标等。
每个 Package 包含构建信息、依赖关系、构建逻辑等,构成了 StaticPHP 的构建模型。Package 的定义主要通过 YAML/JSON 配置文件来实现。`core` Registry 的 Package 配置位于 `config/pkg/` 目录下,可选 recipe class 位于 `src/Package/` 对应的子目录中。
Package 分为五种类型:
- **php-extension**PHP 扩展包,包含 PHP 扩展的构建信息和构建逻辑。
- **library**:依赖库 Package通常安装到 `buildroot/`,供其他 Package 编译和链接。
- **target**:构建目标包,代表最终的构建产物,如 PHP 二进制、curl 二进制等,继承自 `library` 包类型。
- **virtual-target**:虚构建目标包,代表一个抽象的构建目标,不直接对应构建产物,主要用于依赖管理和构建调度。
- **tool**:宿主机侧构建工具 Package单独安装在 `pkgroot/` 下,不作为链接期库依赖处理。
```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 Package 代表一个 PHP 扩展,它的配置文件位于 `config/pkg/ext/` 目录下。可选的 recipe class 通常放在 `src/Package/Extension/`,通过 `#[Extension]` 注册,并从 callback context 接收对应的 `PhpExtensionPackage`。当前 core recipe 支持继承 `PhpExtensionPackage`,但并不要求继承。
```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 / tools 支持 @windows / @unix / @linux / @macos 后缀
depends: [] # 可选硬依赖列表库名直接写PHP 扩展需加 ext- 前缀)
depends@unix: [] # 可选,仅 Unix 平台生效的硬依赖
depends@windows: [] # 可选,仅 Windows 平台生效的硬依赖
suggests: [] # 可选,可选依赖列表(格式同 depends
suggests@unix: []
tools: [] # 可选,宿主机侧构建工具依赖,单独解析
tools@windows: [] # 可选,特定平台的工具依赖
# ── 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-my-extension@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 Package 代表 openssl、zlib 等依赖库,可以从源码或预构建二进制安装。其配置文件位于 `config/pkg/lib/` 目录下。可选的 recipe class 通常放在 `src/Package/Library/`,通过 `#[Library]` 注册,并从 callback context 接收 `LibraryPackage`;不要求继承该类。
以 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: # 可选,从源码构建后复制的许可证内容
type: file # type 可为 file 或 text也可填写多个条目的列表
path: LICENSE
lang: c # 可选库的实现语言c / c++ 等)
frameworks: [] # 可选,相关框架标签列表
artifact: '{artifact-name}' # 必填;字符串时引用指定名称的 Artifact 定义,对象时为内联 Artifact
# depends / suggests / tools 支持 @windows / @unix / @linux / @macos 后缀
depends: [] # 可选,硬依赖列表(库名或 ext- 前缀的 PHP 扩展名)
depends@unix: []
depends@windows: []
suggests: [] # 可选,可选依赖列表(格式同 depends
tools: [] # 可选,仅构建时需要的 ToolPackage 名称
tools@windows: []
# ── library / target 专属字段 ────────────────────────────────────────────
# 以下字段用于构建完成后验证产物是否已正确安装headers、static-libs、static-bins
# 支持 @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/` |
| `{spc_msys2_path}` | MSYS2 根目录(`msys64/`)——仅 Windows |
## tool 包类型
`tool` Package 表示构建其他 Package 时需要的可执行工具,而不是链接进最终 target 的库。Tool Package 可以使用预构建二进制,也可以从源码构建,默认安装在 `pkgroot/` 下的共享 `bin/` 或配置的子目录。其他 Package 通过顶层 `tools` 字段请求这些工具;该依赖集合与 `depends``suggests` 分开解析。
```yaml
nasm:
type: tool
artifact:
binary:
windows-x86_64:
type: url
url: 'https://example.com/nasm-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
min-version: '2.16'
```
嵌套的 `tool` 对象支持:
| 字段 | 是否必填 | 含义 |
|---|---|---|
| `provides` | 是 | 用于判断工具是否已经安装的可执行文件名 |
| `binary-subdir` | 否 | `install-root` 下存放可执行文件的目录;默认就是安装根目录 |
| `install-root` | 否 | 安装根目录;默认为 `PKG_ROOT_PATH`,支持路径占位符 |
| `min-version` | 否 | 由 `ToolPackage` 暴露的最低版本元数据installer 当前不会强制校验 |
`tool` 内的字段可以使用 `@windows``@unix``@linux``@macos` 后缀。例如,`provides@windows` 可以列出 `.exe` 名称,`provides@unix` 列出 Unix 名称。
## target 包类型
`target` Package 代表一个最终的构建产物,它继承于 `library`,所以包含 `library` 的所有定义字段。其配置文件位于 `config/pkg/target/`。可选的 recipe class 通常放在 `src/Package/Target/`,通过 `#[Target]` 注册,并接收 `TargetPackage`;是否继承 `TargetPackage` 是可选的。
`library` 的唯一区别是,`target` 包可以注册成为构建目标,且自动注册构建命令 `spc build:{target-name}`
## virtual-target 包类型
`target` 不同,`virtual-target` 可以省略 `artifact`,即不直接对应一个可构建的实体,而是用于依赖管理和构建调度的抽象构建目标。它与 `target` 使用相同的配置目录、可选 recipe class 目录和 `#[Target]` 注册方式。其余定义基本相同,但 `artifact` 字段可选且通常不设置。`virtual-target` 主要用于以下场景:
- 定义一个抽象的构建目标,供其他包依赖,但不直接对应一个可构建的实体。
- 作为多个 `target` 包的公共依赖,简化依赖关系管理。
典型例子是 `php-cli``php-fpm` 构建目标。它们没有独立源码,依赖 Artifact 为 `php-src``php` target构建调度会决定最终生成 CLI 还是 FPM 二进制。