mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-06 08:15:39 +08:00
Temp
This commit is contained in:
5
docs/zh/develop/build-lifecycle.md
Normal file
5
docs/zh/develop/build-lifecycle.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 构建生命周期
|
||||
|
||||
<!-- TODO: 完整构建流水线阶段顺序说明。
|
||||
各 Hook 触发时机:#[BeforeStage]、#[AfterStage]、#[PatchBeforeBuild]。
|
||||
#[BuildFor] 运行时平台选择机制。典型 library 和 extension 构建的阶段顺序图示。 -->
|
||||
@@ -2,6 +2,6 @@
|
||||
aside: false
|
||||
---
|
||||
|
||||
# craft.yml 配置
|
||||
# craft.yml 配置详解
|
||||
|
||||
<!--@include: ../../deps-craft-yml.md-->
|
||||
<!-- TODO: craft.yml 字段完整参考。 -->
|
||||
|
||||
@@ -1,60 +1,4 @@
|
||||
# Doctor 模块
|
||||
# Doctor 环境检查
|
||||
|
||||
Doctor 模块是一个较为独立的用于检查系统环境的模块,可使用命令 `bin/spc doctor` 进入,入口的命令类在 `DoctorCommand.php` 中。
|
||||
|
||||
Doctor 模块是一个检查单,里面有一系列的检查项目和自动修复项目。这些项目都存放在 `src/SPC/doctor/item/` 目录中,
|
||||
并且使用了两种 Attribute 用作检查项标记和自动修复项目标记:`#[AsCheckItem]` 和 `#[AsFixItem]`。
|
||||
|
||||
以现有的检查项 `if necessary tools are installed`,它是用于检查编译必需的包是否安装在 macOS 系统内,下面是它的源码:
|
||||
|
||||
```php
|
||||
use SPC\doctor\AsCheckItem;
|
||||
use SPC\doctor\AsFixItem;
|
||||
use SPC\doctor\CheckResult;
|
||||
|
||||
#[AsCheckItem('if necessary tools are installed', limit_os: 'Darwin', level: 997)]
|
||||
public function checkCliTools(): ?CheckResult
|
||||
{
|
||||
$missing = [];
|
||||
foreach (self::REQUIRED_COMMANDS as $cmd) {
|
||||
if ($this->findCommand($cmd) === null) {
|
||||
$missing[] = $cmd;
|
||||
}
|
||||
}
|
||||
if (!empty($missing)) {
|
||||
return CheckResult::fail('missing system commands: ' . implode(', ', $missing), 'build-tools', [$missing]);
|
||||
}
|
||||
return CheckResult::ok();
|
||||
}
|
||||
```
|
||||
|
||||
属性的第一个参数就是检查项目的名称,后面的 `limit_os` 参数是限制了该检查项仅在指定的系统下触发,`level` 是执行该检查项的优先级,数字越大,优先级越高。
|
||||
|
||||
里面用到的 `$this->findCommand()` 方法为 `SPC\builder\traits\UnixSystemUtilTrait` 的方法,用途是查找系统命令所在位置,找不到时返回 NULL。
|
||||
|
||||
每个检查项的方法都应该返回一个 `SPC\doctor\CheckResult`:
|
||||
|
||||
- 在返回 `CheckResult::fail()` 时,第一个参数用于输出终端的错误提示,第二个参数是在这个检查项可自动修复时的修复项目名称。
|
||||
- 在返回 `CheckResult::ok()` 时,表明检查通过。你也可以传递一个参数,用于返回检查结果,例如:`CheckResult::ok('OS supported')`。
|
||||
- 在返回 `CheckResult::fail()` 时,如果包含了第三个参数,第三个参数的数组将被当作 `AsFixItem` 的参数。
|
||||
|
||||
下面是这个检查项对应的自动修复项的方法:
|
||||
|
||||
```php
|
||||
#[AsFixItem('build-tools')]
|
||||
public function fixBuildTools(array $missing): bool
|
||||
{
|
||||
foreach ($missing as $cmd) {
|
||||
try {
|
||||
shell(true)->exec('brew install ' . escapeshellarg($cmd));
|
||||
} catch (RuntimeException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
`#[AsFixItem()]` 属性传入的参数即修复项的名称,该方法必须返回 True 或 False。当返回 False 时,表明自动修复失败,需要手动处理。
|
||||
|
||||
此处的代码中 `shell()->exec()` 是项目的执行命令的方法,用于替代 `exec()`、`system()`,同时提供了 debug、获取执行状态、进入目录等特性。
|
||||
<!-- TODO: 从 v2 doctor-module.md 迁移并更新。
|
||||
涵盖 v3 变化:--auto-fix、.spc-doctor.lock、v3 工具链新增检查项。 -->
|
||||
|
||||
@@ -1,27 +1,4 @@
|
||||
# 开发简介
|
||||
|
||||
开发本项目需要安装部署 PHP 环境,以及一些 PHP 项目常用的扩展和 Composer。
|
||||
|
||||
项目的开发环境和运行环境几乎完全一致。你可以参照 **手动构建** 部分安装系统 PHP 或使用本项目预构建的静态 PHP 作为环境。这里不再赘述。
|
||||
|
||||
抛开用途,本项目本身其实就是一个 `php-cli` 程序,你可以将它当作一个正常的 PHP 项目进行编辑和开发,同时你需要了解不同系统的 Shell 命令行。
|
||||
|
||||
本项目目前的目的就是为了编译静态编译的独立 PHP,但主体部分也包含编译很多依赖库的静态版本,所以你可以复用这套编译逻辑,用于构建其他程序的独立二进制版本,例如 Nginx 等。
|
||||
|
||||
## 环境准备
|
||||
|
||||
开发本项目需要 PHP 环境。你可以使用系统自带的 PHP,也可以使用本项目构建的静态 PHP。
|
||||
|
||||
无论是使用哪种 PHP,在开发环境,你需要安装这些扩展:
|
||||
|
||||
```
|
||||
curl,dom,filter,mbstring,openssl,pcntl,phar,posix,sodium,tokenizer,xml,xmlwriter
|
||||
```
|
||||
|
||||
static-php-cli 项目本身不需要这么多扩展,但在开发过程中,你会用到 Composer 和 PHPUnit 等工具,它们需要这些扩展。
|
||||
|
||||
> 对于 static-php-cli 自身构建的 micro 自执行二进制,仅需要 `pcntl,posix,mbstring,tokenizer,phar`。
|
||||
|
||||
## 开始开发
|
||||
|
||||
继续向下查看项目结构文档,你可以学习 `static-php-cli` 是如何工作的。
|
||||
<!-- TODO: 开发者简介、环境准备、所需 PHP 扩展。
|
||||
Vendor 模式链接到 vendor-mode/,代码贡献链接到 contributing/。 -->
|
||||
|
||||
5
docs/zh/develop/package-model.md
Normal file
5
docs/zh/develop/package-model.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Package 模型
|
||||
|
||||
<!-- TODO: 统一 Package 模型说明:library / php-extension / target 类型。
|
||||
config/pkg/ 下 per-package YAML 格式、depends 字段、平台覆盖(@windows / @unix 写法)。
|
||||
artifact.source 和 artifact.binary 字段。附注释的 library 和 extension YAML 示例。 -->
|
||||
@@ -1,51 +1,3 @@
|
||||
# 对 PHP 源码的修改
|
||||
|
||||
由于 static-php-cli 在静态编译过程中为了实现良好的兼容性、性能和安全性,对 PHP 源码进行了一些修改。下面是目前对 PHP 源码修改的说明。
|
||||
|
||||
## micro 相关补丁
|
||||
|
||||
基于 phpmicro 项目提供的补丁,static-php-cli 对 PHP 源码进行了一些修改,以适应静态编译的需求。[补丁列表](https://github.com/easysoft/phpmicro/tree/master/patches) 包含:
|
||||
|
||||
目前 static-php-cli 在编译时用到的补丁有:
|
||||
|
||||
- static_opcache
|
||||
- static_extensions_win32
|
||||
- cli_checks
|
||||
- disable_huge_page
|
||||
- vcruntime140
|
||||
- win32
|
||||
- zend_stream
|
||||
- cli_static
|
||||
- macos_iconv
|
||||
- phar
|
||||
|
||||
## PHP <= 8.1 libxml 补丁
|
||||
|
||||
因为 PHP 官方仅对 8.1 进行安全更新,旧版本停止更新,所以 static-php-cli 对 PHP 8.1 及以下版本应用了在新版本 PHP 中已经应用的 libxml 编译补丁。
|
||||
|
||||
## gd 扩展 Windows 补丁
|
||||
|
||||
在 Windows 下编译 gd 扩展需要大幅改动 `config.w32` 文件,static-php-cli 对 gd 扩展进行了一些修改,使其在 Windows 下编译更加方便。
|
||||
|
||||
## yaml 扩展 Windows 补丁
|
||||
|
||||
yaml 扩展在 Windows 下编译需要修改 `config.w32` 文件,static-php-cli 对 yaml 扩展进行了一些修改,使其在 Windows 下编译更加方便。
|
||||
|
||||
## static-php-cli 版本信息插入
|
||||
|
||||
static-php-cli 在编译时会在 PHP 版本信息中插入 static-php-cli 的版本信息,以便于识别。
|
||||
|
||||
## 加入硬编码 INI 的选项
|
||||
|
||||
在使用 `-I` 参数硬编码 INI 到静态 PHP 的功能中,static-php-cli 会修改 PHP 源码以插入硬编码内容。
|
||||
|
||||
## Linux 系统修复补丁
|
||||
|
||||
部分编译环境可能缺少一些头文件或库,static-php-cli 会在编译时自动修复这些问题,如:
|
||||
|
||||
- HAVE_STRLCAT missing problem
|
||||
- HAVE_STRLCPY missing problem
|
||||
|
||||
## Windows 系统下 Fiber 问题修复补丁
|
||||
|
||||
在 Windows 下编译 PHP 时,Fiber 扩展会出现一些问题,static-php-cli 会在编译时自动修复这些问题(修改 php-src 的 `config.w32`)。
|
||||
<!-- TODO: 从 v2 php-src-changes.md 迁移并更新。补充 v3 新增 patch(FrankenPHP embed、Windows fiber 修复等)。 -->
|
||||
|
||||
5
docs/zh/develop/registry.md
Normal file
5
docs/zh/develop/registry.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Registry 与插件系统
|
||||
|
||||
<!-- TODO: spc.registry.yml 结构说明。
|
||||
通过 SPC_REGISTRIES 环境变量添加外部 Registry。
|
||||
Vendor 特定配置、覆盖核心包。Registry 解析顺序与冲突规则。 -->
|
||||
@@ -1,350 +1,5 @@
|
||||
# 资源模块
|
||||
|
||||
static-php-cli 的下载资源模块是一个主要的功能,它包含了所依赖的库、外部扩展、PHP 源码的下载方式和资源解压方式。
|
||||
下载的配置文件主要涉及 `source.json` 和 `pkg.json` 文件,这个文件记录了所有可下载的资源的下载方式。
|
||||
|
||||
下载功能主要涉及的命令有 `bin/spc download` 和 `bin/spc extract`。其中 `download` 命令是一个下载器,它会根据配置文件下载资源;
|
||||
`extract` 命令是一个解压器,它会根据配置文件解压资源。
|
||||
|
||||
一般来说,下载资源可能会比较慢,因为这些资源来源于各个官网、GitHub 等不同位置,同时它们也占用了较大空间,所以你可以在一次下载资源后,可重复使用。
|
||||
|
||||
下载器的配置文件是 `source.json`,它包含了所有资源的下载方式,你可以在其中添加你需要的资源下载方式,也可以修改已有的资源下载方式。
|
||||
|
||||
每个资源的下载配置结构如下,下面是 `libevent` 扩展对应的资源下载配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"libevent": {
|
||||
"type": "ghrel",
|
||||
"repo": "libevent/libevent",
|
||||
"match": "libevent.+\\.tar\\.gz",
|
||||
"provide-pre-built": true,
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这里最主要的字段是 `type`,目前它支持的类型有:
|
||||
|
||||
- `url`: 直接使用 URL 下载,例如:`https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz`。
|
||||
- `pie`: 使用 PIE(PHP Installer for Extensions)标准从 Packagist 下载 PHP 扩展。
|
||||
- `ghrel`: 使用 GitHub Release API 下载,即从 GitHub 项目发布的最新版本中上传的附件下载。
|
||||
- `ghtar`: 使用 GitHub Release API 下载,与 `ghrel` 不同的是,`ghtar` 是从项目的最新 Release 中找 `source code (tar.gz)` 下载的。
|
||||
- `ghtagtar`: 使用 GitHub Release API 下载,与 `ghtar` 相比,`ghtagtar` 可以从 `tags` 列表找最新的,并下载 `tar.gz` 格式的源码(因为有些项目只使用了 `tag` 发布版本)。
|
||||
- `bitbuckettag`: 使用 BitBucket API 下载,基本和 `ghtagtar` 相同,只是这个适用于 BitBucket。
|
||||
- `git`: 直接从一个 Git 地址克隆项目来下载资源,适用于任何公开 Git 仓库。
|
||||
- `filelist`: 使用爬虫爬取提供文件索引的 Web 下载站点,并获取最新版本的文件名并下载。
|
||||
- `custom`: 如果以上下载方式都不能满足,你可以编写 `custom` 后,在 `src/SPC/store/source/` 下新建一个类,并继承 `CustomSourceBase`,自己编写下载脚本。
|
||||
|
||||
## source.json 通用参数
|
||||
|
||||
source.json 中每个源文件拥有以下字段:
|
||||
|
||||
- `license`: 源代码的开源许可证,见下方 **开源许可证** 章节
|
||||
- `type`: 必须为上面提到的类型之一
|
||||
- `path`(可选): 释放源码到指定目录而非 `source/{name}`
|
||||
- `provide-pre-built`(可选): 是否提供预编译的二进制文件,如果为 `true`,则会在 `bin/spc download` 时尝试自动下载预编译的二进制文件
|
||||
|
||||
::: tip
|
||||
`source.json` 中的 `path` 参数可指定相对路径或绝对路径。当指定为相对路径时,路径基于 `source/`。
|
||||
:::
|
||||
|
||||
## 下载类型 - url
|
||||
|
||||
url 类型的资源指的是从 URL 直接下载文件。
|
||||
|
||||
包含的参数有:
|
||||
|
||||
- `url`: 文件的下载地址,如 `https://example.com/file.tgz`
|
||||
- `filename`(可选): 保存到本地的文件名,如不指定,则使用 url 的文件名
|
||||
|
||||
例子(下载 imagick 扩展,并解压缩到 php 源码的扩展存放路径):
|
||||
|
||||
```json
|
||||
{
|
||||
"ext-imagick": {
|
||||
"type": "url",
|
||||
"url": "https://pecl.php.net/get/imagick",
|
||||
"path": "php-src/ext/imagick",
|
||||
"filename": "imagick.tgz",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 下载类型 - pie
|
||||
|
||||
PIE(PHP Installer for Extensions)类型的资源是从 Packagist 下载遵循 PIE 标准的 PHP 扩展。
|
||||
该方法会自动从 Packagist 仓库获取扩展信息,并下载相应的分发文件。
|
||||
|
||||
包含的参数有:
|
||||
|
||||
- `repo`: Packagist 的 vendor/package 名称,如 `vendor/package-name`
|
||||
|
||||
例子(使用 PIE 从 Packagist 下载 PHP 扩展):
|
||||
|
||||
```json
|
||||
{
|
||||
"ext-example": {
|
||||
"type": "pie",
|
||||
"repo": "vendor/example-extension",
|
||||
"path": "php-src/ext/example",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
::: tip
|
||||
PIE 下载类型会自动从 Packagist 元数据中检测扩展信息,包括下载 URL、版本和分发类型。
|
||||
扩展必须在其 Packagist 包定义中标记为 `type: php-ext` 或包含 `php-ext` 元数据。
|
||||
:::
|
||||
|
||||
## 下载类型 - ghrel
|
||||
|
||||
ghrel 会从 GitHub Release 中上传的 Assets 下载文件。首先使用 GitHub Release API 获取最新版本,然后根据正则匹配方式下载相应的文件。
|
||||
|
||||
包含的参数有:
|
||||
|
||||
- `repo`: GitHub 仓库名称
|
||||
- `match`: 匹配 Assets 文件的正则表达式
|
||||
- `prefer-stable`: 是否优先下载稳定版本(默认为 `false`)
|
||||
|
||||
例子(下载 libsodium 库,匹配 Release 中的 libsodium-x.y.tar.gz 文件):
|
||||
|
||||
```json
|
||||
{
|
||||
"libsodium": {
|
||||
"type": "ghrel",
|
||||
"repo": "jedisct1/libsodium",
|
||||
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 下载类型 - ghtar
|
||||
|
||||
ghtar 会从 GitHub Release Tag 下载文件,与 `ghrel` 不同的是,`ghtar` 是从项目的最新 Release 中找 `source code (tar.gz)` 下载的。
|
||||
|
||||
包含的参数有:
|
||||
|
||||
- `repo`: GitHub 仓库名称
|
||||
- `prefer-stable`: 是否优先下载稳定版本(默认为 `false`)
|
||||
|
||||
例子(brotli 库):
|
||||
|
||||
```json
|
||||
{
|
||||
"brotli": {
|
||||
"type": "ghtar",
|
||||
"repo": "google/brotli",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 下载类型 - ghtagtar
|
||||
|
||||
使用 GitHub Release API 下载,与 `ghtar` 相比,`ghtagtar` 可以从 `tags` 列表找最新的,并下载 `tar.gz` 格式的源码(因为有些项目只使用了 `tag` 发布版本)。
|
||||
|
||||
包含的参数有:
|
||||
|
||||
- `repo`: GitHub 仓库名称
|
||||
- `prefer-stable`: 是否优先下载稳定版本(默认为 `false`)
|
||||
|
||||
例子(gmp 库):
|
||||
|
||||
```json
|
||||
{
|
||||
"gmp": {
|
||||
"type": "ghtagtar",
|
||||
"repo": "alisw/GMP",
|
||||
"license": {
|
||||
"type": "text",
|
||||
"text": "EXAMPLE LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 下载类型 - bitbuckettag
|
||||
|
||||
使用 BitBucket API 下载,基本和 `ghtagtar` 相同,只是这个适用于 BitBucket。
|
||||
|
||||
包含的参数有:
|
||||
|
||||
- `repo`: BitBucket 仓库名称
|
||||
|
||||
## 下载类型 - git
|
||||
|
||||
直接从一个 Git 地址克隆项目来下载资源,适用于任何公开 Git 仓库。
|
||||
|
||||
包含的参数有:
|
||||
|
||||
- `url`: Git 链接(仅限 HTTPS)
|
||||
- `rev`: 分支名称
|
||||
|
||||
```json
|
||||
{
|
||||
"imap": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/static-php/imap.git",
|
||||
"rev": "master",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 下载类型 - filelist
|
||||
|
||||
使用爬虫爬取提供文件索引的 Web 下载站点,并获取最新版本的文件名并下载。
|
||||
|
||||
注意,该方法仅限于镜像站、GNU 官网等具有页面 index 功能的静态站点使用。
|
||||
|
||||
包含的参数有:
|
||||
|
||||
- `url`: 要爬取文件最新版本的页面 URL
|
||||
- `regex`: 匹配文件名及下载链接的正则表达式
|
||||
|
||||
例子(从 GNU 官网下载 libiconv 库):
|
||||
|
||||
```json
|
||||
{
|
||||
"libiconv": {
|
||||
"type": "filelist",
|
||||
"url": "https://ftp.gnu.org/gnu/libiconv/",
|
||||
"regex": "/href=\"(?<file>libiconv-(?<version>[^\"]+)\\.tar\\.gz)\"/",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "COPYING"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 下载类型 - custom
|
||||
|
||||
如果以上下载方式都不能满足,你可以编写 `custom` 后,在 `src/SPC/store/source/` 下新建一个类,并继承 `CustomSourceBase`,自己编写下载脚本。
|
||||
|
||||
这里不再赘述,你可以查看 `src/SPC/store/source/PhpSource.php` 或 `src/SPC/store/source/PostgreSQLSource.php` 作为例子。
|
||||
|
||||
## pkg.json 通用参数
|
||||
|
||||
pkg.json 存放的是非源码类型的文件资源,例如 musl-toolchain、UPX 等预编译的工具。它的使用包含:
|
||||
|
||||
- `type`: 与 `source.json` 相同的类型及不同种类的参数。
|
||||
- `extract`(可选): 下载后解压缩的路径,默认为 `pkgroot/{pkg_name}`。
|
||||
- `extract-files`(可选): 下载后仅解压指定的文件到指定位置。
|
||||
|
||||
需要注意的是,`pkg.json` 不涉及源代码的编译和修改分发,所以没有 `license` 开源许可证字段。并且你不能同时使用 `extract` 和 `extract-files` 参数。
|
||||
|
||||
例子(下载 nasm 到本地,并只提取程序文件到 PHP SDK):
|
||||
|
||||
```json
|
||||
{
|
||||
"nasm-x86_64-win": {
|
||||
"type": "url",
|
||||
"url": "https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-win64.zip",
|
||||
"extract-files": {
|
||||
"nasm-2.16.01/nasm.exe": "{php_sdk_path}/bin/nasm.exe",
|
||||
"nasm-2.16.01/ndisasm.exe": "{php_sdk_path}/bin/ndisasm.exe"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`extract-files` 中的键名为源文件夹下的文件,键值为存放的路径。存放的路径可以使用以下变量:
|
||||
|
||||
- `{php_sdk_path}`: (仅限 Windows)PHP SDK 路径
|
||||
- `{pkg_root_path}`: `pkgroot/`
|
||||
- `{working_dir}`: 当前工作目录
|
||||
- `{download_path}`: 下载目录
|
||||
- `{source_path}`: 源码解压缩目录
|
||||
|
||||
当 `extract-files` 不使用变量且为相对路径时,相对路径的目录为 `{working_dir}`。
|
||||
|
||||
## 开源许可证
|
||||
|
||||
对于 `source.json` 而言,每个源文件都应包含开源许可证。`license` 字段存放了开源许可证的信息。
|
||||
|
||||
每个 `license` 包含的参数有:
|
||||
|
||||
- `type`: `file` 或 `text`
|
||||
- `path`: 源代码目录中的许可证文件(当 `type` 为 `file` 时,此项必填)
|
||||
- `text`: 许可证文本(当 `type` 为 `text` 时,此项必填)
|
||||
|
||||
例子(yaml 扩展的源代码中带有 LICENSE 文件):
|
||||
|
||||
```json
|
||||
{
|
||||
"yaml": {
|
||||
"type": "git",
|
||||
"path": "php-src/ext/yaml",
|
||||
"rev": "php7",
|
||||
"url": "https://github.com/php/pecl-file_formats-yaml",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当开源项目拥有多个许可证时,可指定多个文件:
|
||||
|
||||
```json
|
||||
{
|
||||
"libuv": {
|
||||
"type": "ghtar",
|
||||
"repo": "libuv/libuv",
|
||||
"license": [
|
||||
{
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"path": "LICENSE-extra"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当一个开源项目的许可证在不同版本间使用不同的文件,`path` 参数可以使用数组将可能的许可证文件列出:
|
||||
|
||||
```json
|
||||
{
|
||||
"redis": {
|
||||
"type": "git",
|
||||
"path": "php-src/ext/redis",
|
||||
"rev": "release/6.0.2",
|
||||
"url": "https://github.com/phpredis/phpredis",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": [
|
||||
"LICENSE",
|
||||
"COPYING"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
<!-- TODO: 从 v2 source-module.md 迁移并更新。
|
||||
记录 v3 source 类型:url、ghrel、ghtar、ghtagtar、git、pecl(新增)、filelist、custom。
|
||||
per-package YAML source 块格式。并行下载(--parallel N)。 -->
|
||||
|
||||
@@ -1,163 +1,4 @@
|
||||
# 项目结构简介
|
||||
# 项目结构
|
||||
|
||||
static-php-cli 主要包含三种逻辑组件:资源、依赖库、扩展。这三种组件四个配置文件:`source.json`、`lib.json`、`ext.json`、`pkg.json`。
|
||||
|
||||
一个完整的构建静态 PHP 流程是:
|
||||
|
||||
1. 使用资源下载模块 `Downloader` 下载指定或所有资源,这些资源包含 PHP 源码、依赖库源码、扩展源码。
|
||||
2. 使用资源解压模块 `SourceExtractor` 解压下载的资源到编译目录。
|
||||
3. 使用依赖工具计算出当前加入的扩展的依赖扩展、依赖库,然后对每个需要编译的依赖库进行编译,按照依赖顺序。
|
||||
4. 使用对应操作系统下的 `Builder` 构建每个依赖库后,将其安装到 `buildroot` 目录。
|
||||
5. 如果包含外部扩展(源码没有包含在 PHP 内的扩展),将外部扩展拷贝到 `source/php-src/ext/` 目录。
|
||||
6. 使用 `Builder` 构建 PHP 源码,将其安装到 `buildroot` 目录。
|
||||
|
||||
项目主要分为几个文件夹:
|
||||
|
||||
- `bin/`: 用于存放程序入口文件,包含 `bin/spc`、`bin/spc-alpine-docker`、`bin/setup-runtime`。
|
||||
- `config/`: 包含了所有项目支持的扩展、依赖库以及这些资源下载的地址、下载方式等,:`lib.json`、`ext.json`、`source.json`、`pkg.json`、`pre-built.json`。
|
||||
- `src/SPC/`: 项目的核心代码,包含了整个框架以及编译各种扩展和库的命令。
|
||||
- `src/globals/`: 项目的全局方法和常量、运行时需要的测试文件(例如:扩展的可用性检查代码)。
|
||||
- `vendor/`: Composer 依赖的目录,你无需对它做出任何修改。
|
||||
|
||||
其中运行原理就是启动一个 `symfony/console` 的 `ConsoleApplication`,然后解析用户在终端输入的命令。
|
||||
|
||||
## 基本命令行结构
|
||||
|
||||
`bin/spc` 是一个 PHP 代码入口文件,包含了 Unix 通用的 `#!/usr/bin/env php` 用来让系统自动以系统安装好的 PHP 解释器执行。
|
||||
在项目执行了 `new ConsoleApplication()` 后,框架会自动使用反射的方式,解析 `src/SPC/command` 目录下的所有类,并将其注册成为命令。
|
||||
|
||||
项目并没有直接使用 Symfony 推荐的 Command 注册方式和命令执行方式,这里做出了一点小变动:
|
||||
|
||||
1. 每个命令都使用 `#[AsCommand()]` Attribute 来注册名称和简介。
|
||||
2. 将 `execute()` 抽象化,让所有命令基于 `BaseCommand`(它基于 `Symfony\Component\Console\Command\Command`),每个命令本身的执行代码写到了 `handle()` 方法中。
|
||||
3. `BaseCommand` 添加了变量 `$no_motd`,用于是否在该命令执行时显示 Figlet 欢迎词。
|
||||
4. `BaseCommand` 将 `InputInterface` 和 `OutputInterface` 保存为成员变量,你可以在命令的类内使用 `$this->input` 和 `$this->output`。
|
||||
|
||||
## 基本源码结构
|
||||
|
||||
项目的源码位于 `src/SPC` 目录,支持 PSR-4 标准的自动加载,包含以下子目录和类:
|
||||
|
||||
- `src/SPC/builder/`: 用于不同操作系统下构建依赖库、PHP 及相关扩展的核心编译命令代码,还包含了一些编译的系统工具方法。
|
||||
- `src/SPC/command/`: 项目的所有命令都在这里。
|
||||
- `src/SPC/doctor/`: Doctor 模块,它是一个较为独立的用于检查系统环境的模块,可使用命令 `bin/spc doctor` 进入。
|
||||
- `src/SPC/exception/`: 异常类。
|
||||
- `src/SPC/store/`: 有关存储、文件和资源的类都在这里。
|
||||
- `src/SPC/util/`: 一些可以复用的工具方法都在这里。
|
||||
- `src/SPC/ConsoleApplication.php`: 命令行程序入口文件。
|
||||
|
||||
如果你阅读过源码,你可能会发现还有一个 `src/globals/` 目录,它是用于存放一些全局变量、全局方法、构建过程中依赖的非 PSR-4 标准的 PHP 源码,例如测试扩展代码等。
|
||||
|
||||
## Phar 应用目录问题
|
||||
|
||||
和其他 php-cli 项目一样,spc 自身对路径有额外的考虑。
|
||||
因为 spc 可以在 `php-cli directly`、`micro SAPI`、`php-cli with Phar`、`vendor with Phar` 等多种模式下运行,各类根目录存在歧义。这里会进行一个完整的说明。
|
||||
此问题一般常见于 PHP 项目中存取文件的基类路径选择问题,尤其是在配合 `micro.sfx` 使用时容易出现路径问题。
|
||||
|
||||
注意,此处仅对你在开发 Phar 项目或 PHP 框架时可能有用。
|
||||
|
||||
> 接下来我们都将 `static-php-cli`(也就是 spc)当作一个普通的 `php` 命令行程序来看,你可以将 spc 理解为你自己的任何 php-cli 应用以参考。
|
||||
|
||||
下面主要有三个基本的常量理论值,我们建议你在编写 php 项目时引入这三种常量:
|
||||
|
||||
- `WORKING_DIR`:执行 PHP 脚本时的工作目录
|
||||
- `SOURCE_ROOT_DIR` 或 `ROOT_DIR`:项目文件夹的根目录,一般为 `composer.json` 所在目录
|
||||
- `FRAMEWORK_ROOT_DIR`:使用框架的根目录,自行开发的框架可能会用到,一般框架目录为只读
|
||||
|
||||
你可以在你的框架或者 cli 应用程序入口中定义这些常量,以方便在你的项目中使用路径。
|
||||
|
||||
下面是 PHP 内置的常量值,在 PHP 解释器内部已被定义:
|
||||
|
||||
- `__DIR__`:当前执行脚本的文件所在目录
|
||||
- `__FILE__`:当前执行脚本的文件路径
|
||||
|
||||
### Git 项目模式(source)
|
||||
|
||||
Git 项目模式指的是一个框架或程序本身在当前文件夹以纯文本形式存放,运行通过 `php path/to/entry.php` 方式。
|
||||
|
||||
假设你的项目存放在 `/home/example/static-php-cli/` 目录下,或你的项目就是框架本身,里面包含 `composer.json` 等项目文件:
|
||||
|
||||
```
|
||||
composer.json
|
||||
src/App/MyCommand.app
|
||||
vendor/*
|
||||
bin/entry.php
|
||||
```
|
||||
|
||||
我们假设从 `src/App/MyCommand.php` 中获取以上常量:
|
||||
|
||||
| Constant | Value |
|
||||
|----------------------|------------------------------------------------------|
|
||||
| `WORKING_DIR` | `/home/example/static-php-cli` |
|
||||
| `SOURCE_ROOT_DIR` | `/home/example/static-php-cli` |
|
||||
| `FRAMEWORK_ROOT_DIR` | `/home/example/static-php-cli` |
|
||||
| `__DIR__` | `/home/example/static-php-cli/src/App` |
|
||||
| `__FILE__` | `/home/example/static-php-cli/src/App/MyCommand.php` |
|
||||
|
||||
这种情况下,`WORKING_DIR`、`SOURCE_ROOT_DIR`、`FRAMEWORK_ROOT_DIR` 的值是完全一致的:`/home/example/static-php-cli`。
|
||||
框架的源码和应用的源码都在当前路径下。
|
||||
|
||||
### Vendor 库模式(vendor)
|
||||
|
||||
Vendor 库模式一般是指你的项目为框架类或者被其他应用作为 composer 依赖项安装到项目中,存放位置在 `vendor/author/XXX` 目录。
|
||||
|
||||
假设你的项目是 `crazywhalecc/static-php-cli`,你或其他人在另一个项目使用 `composer require` 安装了这个项目。
|
||||
|
||||
我们假设 static-php-cli 中包含同 `Git 模式` 的除 `vendor` 目录外的所有文件,并从 `src/App/MyCommand` 中获取常量值,
|
||||
目录常量应该是:
|
||||
|
||||
| Constant | Value |
|
||||
|----------------------|--------------------------------------------------------------------------------------|
|
||||
| `WORKING_DIR` | `/home/example/another-app` |
|
||||
| `SOURCE_ROOT_DIR` | `/home/example/another-app` |
|
||||
| `FRAMEWORK_ROOT_DIR` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli` |
|
||||
| `__DIR__` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli/src/App` |
|
||||
| `__FILE__` | `/home/example/another-app/vendor/crazywhalecc/static-php-cli/src/App/MyCommand.php` |
|
||||
|
||||
|
||||
这里的 `SOURCE_ROOT_DIR` 就指的是使用 `static-php-cli` 的项目的根目录。
|
||||
|
||||
### Git 项目 Phar 模式(source-phar)
|
||||
|
||||
Git 项目 Phar 模式指的是将 Git 项目模式的项目目录打包为一个 `phar` 文件的模式。我们假设 `/home/example/static-php-cli` 将打包为一个 Phar 文件,目录有以下文件:
|
||||
|
||||
```
|
||||
composer.json
|
||||
src/App/MyCommand.app
|
||||
vendor/*
|
||||
bin/entry.php
|
||||
```
|
||||
|
||||
打包为 `app.phar` 并存放到 `/home/example/static-php-cli` 目录下时,此时执行 `app.phar`,假设执行了 `src/App/MyCommand` 代码,常量在该文件内获取:
|
||||
|
||||
| Constant | Value |
|
||||
|----------------------|----------------------------------------------------------------------|
|
||||
| `WORKING_DIR` | `/home/example/static-php-cli` |
|
||||
| `SOURCE_ROOT_DIR` | `phar:///home/example/static-php-cli/app.phar/` |
|
||||
| `FRAMEWORK_ROOT_DIR` | `phar:///home/example/static-php-cli/app.phar/` |
|
||||
| `__DIR__` | `phar:///home/example/static-php-cli/app.phar/src/App` |
|
||||
| `__FILE__` | `phar:///home/example/static-php-cli/app.phar/src/App/MyCommand.php` |
|
||||
|
||||
因为在 phar 内读取自身 phar 的文件需要 `phar://` 协议进行,所以项目根目录和框架目录将会和 `WORKING_DIR` 不同。
|
||||
|
||||
### Vendor 库 Phar 模式(vendor-phar)
|
||||
|
||||
Vendor 库 Phar 模式指的是你的项目作为框架安装在其他项目内,存储于 `vendor` 目录下。
|
||||
|
||||
我们假设你的项目目录结构如下:
|
||||
|
||||
```
|
||||
composer.json # 当前项目的 Composer 配置文件
|
||||
box.json # 打包 Phar 的配置文件
|
||||
another-app.php # 另一个项目的入口文件
|
||||
vendor/crazywhalecc/static-php-cli/* # 你的项目被作为依赖库
|
||||
```
|
||||
|
||||
将该目录 `/home/example/another-app/` 下的这些文件打包为 `app.phar` 时,对于你的项目而言,下面常量的值应为:
|
||||
|
||||
| Constant | Value |
|
||||
|----------------------|------------------------------------------------------------------------------------------------------|
|
||||
| `WORKING_DIR` | `/home/example/another-app` |
|
||||
| `SOURCE_ROOT_DIR` | `phar:///home/example/another-app/app.phar/` |
|
||||
| `FRAMEWORK_ROOT_DIR` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli` |
|
||||
| `__DIR__` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli/src/App` |
|
||||
| `__FILE__` | `phar:///home/example/another-app/app.phar/vendor/crazywhalecc/static-php-cli/src/App/MyCommand.php` |
|
||||
<!-- TODO: v3 目录结构说明(bin/、config/pkg/、src/StaticPHP/、src/Package/ 等)。
|
||||
每个顶层目录的职责说明。内部类结构简述,深入内容见核心概念页。 -->
|
||||
|
||||
@@ -1,204 +1,4 @@
|
||||
# 系统编译工具
|
||||
# 编译工具
|
||||
|
||||
static-php-cli 在构建静态 PHP 时使用了许多系统编译工具,这些工具主要包括:
|
||||
|
||||
- `autoconf`: 用于生成 `configure` 脚本。
|
||||
- `make`: 用于执行 `Makefile`。
|
||||
- `cmake`: 用于执行 `CMakeLists.txt`。
|
||||
- `pkg-config`: 用于查找依赖库的安装路径。
|
||||
- `gcc`: 用于在 Linux 下编译 C/C++ 语言代码。
|
||||
- `clang`: 用于在 macOS 下编译 C/C++ 语言代码。
|
||||
|
||||
对于 Linux 和 macOS 操作系统,这些工具通常可以通过包管理安装,这部分在 doctor 模块中编写了。
|
||||
理论上我们也可以通过编译和手动下载这些工具,但这样会增加编译的复杂度,所以我们不推荐这样做。
|
||||
|
||||
## Linux 环境编译工具
|
||||
|
||||
对于 Linux 系统来说,不同发行版的编译工具安装方式不同。而且对于静态编译来说,某些发行版的包管理无法安装用于纯静态编译的库和工具,
|
||||
所以对于 Linux 平台及其不同发行版,我们目前提供了多种编译环境的部署措施。
|
||||
|
||||
### glibc 环境
|
||||
|
||||
glibc 环境指的是系统底层的 `libc` 库(即所有 C 语言编写的程序动态链接的 C 标准库)使用的是 `glibc`,这是大多数发行版的默认环境。
|
||||
例如:Ubuntu、Debian、CentOS、RHEL、openSUSE、Arch Linux 等。
|
||||
|
||||
而 glibc 环境下,我们使用的包管理、编译器都是默认指向 glibc 的,glibc 不能被良好地静态链接。它不能被静态链接的原因之一是它的网络库 `nss` 无法静态编译。
|
||||
|
||||
对于 glibc 环境,在 2.0 RC8 及以后的 static-php-cli 及 spc 中,你可以选择两种方式来构建静态 PHP:
|
||||
|
||||
1. 使用 Docker 构建,这是最简单的方式,你可以使用 `bin/spc-alpine-docker` 来构建,它会在 Alpine Linux 环境下构建。
|
||||
2. 使用 `bin/spc doctor` 安装 musl-wrapper 和 musl-cross-make 套件,然后直接正常构建。([相关源码](https://github.com/crazywhalecc/static-php-cli/blob/main/src/SPC/doctor/item/LinuxMuslCheck.php))
|
||||
|
||||
一般来说,这两种构建方式的构建结果是一致的,你可以根据实际需求选择。
|
||||
|
||||
在 doctor 模块中,static-php-cli 会先检测当前的 Linux 发行版。如果当前发行版是 glibc 环境,会提示需要安装 musl-wrapper 和 musl-cross-make 套件。
|
||||
|
||||
在 glibc 环境下安装 musl-wrapper 的过程如下:
|
||||
|
||||
1. 从 musl 官网下载特定版本的 [musl-wrapper 源码](https://musl.libc.org/releases/)。
|
||||
2. 使用从包管理安装的 `gcc` 编译 musl-wrapper 源码,生成 `musl-libc` 等库:`./configure --disable-gcc-wrapper && make -j && sudo make install`。
|
||||
3. musl-wrapper 相关库将被安装在 `/usr/local/musl` 目录。
|
||||
|
||||
在 glibc 环境下安装 musl-cross-make 的过程如下:
|
||||
|
||||
1. 从 dl.static-php.dev 下载预编译好的 [musl-cross-make](https://dl.static-php.dev/static-php-cli/deps/musl-toolchain/) 压缩包。
|
||||
2. 解压到 `/usr/local/musl` 目录。
|
||||
|
||||
::: tip
|
||||
在 glibc 环境下,静态编译可以通过直接安装 musl-wrapper 来实现,但是 musl-wrapper 仅包含了 `musl-gcc`,而没有 `musl-g++`,这也就意味着无法编译 C++ 代码。
|
||||
所以我们需要 musl-cross-make 来提供 `musl-g++`。
|
||||
|
||||
而 musl-cross-make 套件无法在本地直接编译的原因是它的编译环境要求比较高(需要 36GB 以上内存,Alpine Linux 下编译),所以我们提供了预编译好的二进制包,可用于所有 Linux 发行版。
|
||||
|
||||
同时,部分发行版的包管理提供了 musl-wrapper,但 musl-cross-make 需要匹配对应的 musl-wrapper 版本,所以我们不使用包管理安装 musl-wrapper。
|
||||
|
||||
对于如何编译 musl-cross-make,将在本章节内的 **编译 musl-cross-make** 小节中介绍。
|
||||
:::
|
||||
|
||||
### musl 环境
|
||||
|
||||
musl 环境指的是系统底层的 `libc` 库使用的是 `musl`,这是一种轻量级的 C 标准库,它的特点是可以被良好地静态链接。
|
||||
|
||||
对于目前流行的 Linux 发行版,Alpine Linux 使用的就是 musl 环境,所以 static-php-cli 在 Alpine Linux 下可以直接构建静态 PHP,仅需直接从包管理安装基础编译工具(如 gcc、cmake 等)即可。
|
||||
|
||||
对于其他发行版,如果你的发行版使用的是 musl 环境,那么你也可以在安装必要的编译工具后直接使用 static-php-cli 构建静态 PHP。
|
||||
|
||||
::: tip
|
||||
在 musl 环境下,static-php-cli 会自动跳过 musl-wrapper 和 musl-cross-make 的安装。
|
||||
:::
|
||||
|
||||
### Docker 环境
|
||||
|
||||
Docker 环境指的是使用 Docker 容器来构建静态 PHP,你可以使用 `bin/spc-alpine-docker` 来构建。
|
||||
执行这个命令前需要先安装 Docker,然后在项目根目录执行 `bin/spc-alpine-docker` 即可。
|
||||
|
||||
在执行 `bin/spc-alpine-docker` 后,static-php-cli 会自动下载 Alpine Linux 镜像,然后构建一个 `cwcc-spc-x86_64` 或 `cwcc-spc-aarch64` 的镜像。
|
||||
然后一切的构建都在这个镜像内进行,相当于在 Alpine Linux 内编译。总的来说,Docker 环境就是 musl 环境。
|
||||
|
||||
## musl-cross-make 工具链编译
|
||||
|
||||
在 Linux 中,尽管你不需要手动编译 musl-cross-make 工具,但是如果你想了解它的编译过程,可以参考这里。
|
||||
还有一个重要的原因就是,这个可能无法使用 CI、Actions 等自动化工具编译,因为现有的 CI 服务编译环境不满足 musl-cross-make 的编译要求,满足要求的配置价格太高。
|
||||
|
||||
musl-cross-make 的编译过程如下:
|
||||
|
||||
准备一个 Alpine Linux 环境(直接安装或使用 Docker 均可),编译的过程需要 36GB 以上内存,所以你需要在内存较大的机器上编译。如果没有这么多内存,可能会导致编译失败。
|
||||
|
||||
然后将以下内容写入 `config.mak` 文件内:
|
||||
|
||||
```makefile
|
||||
STAT = -static --static
|
||||
FLAG = -g0 -Os -Wno-error
|
||||
|
||||
ifneq ($(NATIVE),)
|
||||
COMMON_CONFIG += CC="$(HOST)-gcc ${STAT}" CXX="$(HOST)-g++ ${STAT}"
|
||||
else
|
||||
COMMON_CONFIG += CC="gcc ${STAT}" CXX="g++ ${STAT}"
|
||||
endif
|
||||
|
||||
COMMON_CONFIG += CFLAGS="${FLAG}" CXXFLAGS="${FLAG}" LDFLAGS="${STAT}"
|
||||
|
||||
BINUTILS_CONFIG += --enable-gold=yes --enable-gprofng=no
|
||||
GCC_CONFIG += --enable-static-pie --disable-cet --enable-default-pie
|
||||
#--enable-default-pie
|
||||
|
||||
CONFIG_SUB_REV = 888c8e3d5f7b
|
||||
GCC_VER = 13.2.0
|
||||
BINUTILS_VER = 2.40
|
||||
MUSL_VER = 1.2.4
|
||||
GMP_VER = 6.2.1
|
||||
MPC_VER = 1.2.1
|
||||
MPFR_VER = 4.2.0
|
||||
LINUX_VER = 6.1.36
|
||||
```
|
||||
|
||||
同时,你需要新建一个 `gcc-13.2.0.tar.xz.sha1` 文件,文件内容如下:
|
||||
|
||||
```
|
||||
5f95b6d042fb37d45c6cbebfc91decfbc4fb493c gcc-13.2.0.tar.xz
|
||||
```
|
||||
|
||||
如果你使用的是 Docker 构建,新建一个 `Dockerfile` 文件,写入以下内容:
|
||||
|
||||
```dockerfile
|
||||
FROM alpine:edge
|
||||
|
||||
RUN apk add --no-cache \
|
||||
gcc g++ git make curl perl \
|
||||
rsync patch wget libtool \
|
||||
texinfo autoconf automake \
|
||||
bison tar xz bzip2 zlib \
|
||||
file binutils flex \
|
||||
linux-headers libintl \
|
||||
gettext gettext-dev icu-libs pkgconf \
|
||||
pkgconfig icu-dev bash \
|
||||
ccache libarchive-tools zip
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
RUN git clone https://git.zv.io/toolchains/musl-cross-make.git
|
||||
WORKDIR /opt/musl-cross-make
|
||||
COPY config.mak /opt/musl-cross-make
|
||||
COPY gcc-13.2.0.tar.xz.sha1 /opt/musl-cross-make/hashes
|
||||
|
||||
RUN make TARGET=x86_64-linux-musl -j || :
|
||||
RUN sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h
|
||||
RUN make TARGET=x86_64-linux-musl -j
|
||||
RUN make TARGET=x86_64-linux-musl install -j
|
||||
RUN tar cvzf x86_64-musl-toolchain.tgz output/*
|
||||
```
|
||||
|
||||
如果你使用的是非 Docker 环境的 Alpine Linux,可以直接执行 Dockerfile 中的命令,例如:
|
||||
|
||||
```bash
|
||||
apk add --no-cache \
|
||||
gcc g++ git make curl perl \
|
||||
rsync patch wget libtool \
|
||||
texinfo autoconf automake \
|
||||
bison tar xz bzip2 zlib \
|
||||
file binutils flex \
|
||||
linux-headers libintl \
|
||||
gettext gettext-dev icu-libs pkgconf \
|
||||
pkgconfig icu-dev bash \
|
||||
ccache libarchive-tools zip
|
||||
|
||||
git clone https://git.zv.io/toolchains/musl-cross-make.git
|
||||
# 将 config.mak 拷贝到 musl-cross-make 的工作目录内,你需要将 /path/to/config.mak 替换为你的 config.mak 文件路径
|
||||
cp /path/to/config.mak musl-cross-make/
|
||||
cp /path/to/gcc-13.2.0.tar.xz.sha1 musl-cross-make/hashes
|
||||
|
||||
make TARGET=x86_64-linux-musl -j || :
|
||||
sed -i 's/poison calloc/poison/g' ./gcc-13.2.0/gcc/system.h
|
||||
make TARGET=x86_64-linux-musl -j
|
||||
make TARGET=x86_64-linux-musl install -j
|
||||
tar cvzf x86_64-musl-toolchain.tgz output/*
|
||||
```
|
||||
|
||||
::: tip
|
||||
以上所有脚本都适用于 x86_64 架构的 Linux。如果你需要构建 ARM 环境的 musl-cross-make,只需要将上方所有 `x86_64` 替换为 `aarch64` 即可。
|
||||
:::
|
||||
|
||||
这个编译过程可能会因为内存不足、网络问题等原因导致编译失败,你可以多尝试几次,或者使用更大内存的机器来编译。
|
||||
如果遇到了问题,或者你有更好的改进方案,可以在 [讨论](https://github.com/crazywhalecc/static-php-cli-hosted/issues/1) 中提出。
|
||||
|
||||
## macOS 环境编译工具
|
||||
|
||||
对于 macOS 系统来说,我们使用的编译工具主要是 `clang`,它是 macOS 系统默认的编译器,同时也是 Xcode 的编译器。
|
||||
|
||||
在 macOS 下编译,主要依赖于 Xcode 或 Xcode Command Line Tools,你可以在 App Store 下载 Xcode,或者在终端执行 `xcode-select --install` 来安装 Xcode Command Line Tools。
|
||||
|
||||
此外,在 `doctor` 环境检查模块中,static-php-cli 会检查 macOS 系统是否安装了 Homebrew、编译工具等,如果没有,会提示你安装,这里不再赘述。
|
||||
|
||||
## FreeBSD 环境编译工具
|
||||
|
||||
FreeBSD 也是 Unix 系统,它的编译工具和 macOS 类似,你可以直接使用包管理 `pkg` 安装 `clang` 等编译工具,通过 `doctor` 命令。
|
||||
|
||||
## pkg-config 编译
|
||||
|
||||
如果你在使用 static-php-cli 构建静态 PHP 时仔细观察编译的日志,你会发现无论编译什么,都会先编译 `pkg-config`,这是因为 `pkg-config` 是一个用于查找依赖库的工具。
|
||||
在早期的 static-php-cli 版本中,我们直接使用了包管理安装的 `pkg-config` 工具,但是这样会导致一些问题,例如:
|
||||
|
||||
- 即使指定了 `PKG_CONFIG_PATH`,`pkg-config` 也会尝试从系统路径中查找依赖包。
|
||||
- 由于 `pkg-config` 会从系统路径中查找依赖包,所以如果系统中存在同名的依赖包,可能会导致编译失败。
|
||||
|
||||
为了避免以上问题,我们将 `pkg-config` 编译到用户态的 `buildroot/bin` 内并使用,使用了 `--without-sysroot` 等参数来避免从系统路径中查找依赖包。
|
||||
<!-- TODO: 从 v2 system-build-tools.md 迁移并更新。
|
||||
涵盖 v3 新增内容:WindowsCMakeExecutor、vswhere.exe 检测、FrankenPHP 的 LLVM/Clang 支持。 -->
|
||||
|
||||
6
docs/zh/develop/vendor-mode/annotations.md
Normal file
6
docs/zh/develop/vendor-mode/annotations.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 注解参考
|
||||
|
||||
<!-- TODO: 所有 v3 PHP 注解的完整参考。
|
||||
#[Library]、#[Extension]、#[BuildFor]、#[BeforeStage]、#[AfterStage]、
|
||||
#[PatchBeforeBuild]、#[CustomPhpConfigureArg]、#[AsCheckItem]、#[AsFixItem]。
|
||||
每个注解:参数、类型、允许的 target、示例。 -->
|
||||
5
docs/zh/develop/vendor-mode/dependency-injection.md
Normal file
5
docs/zh/develop/vendor-mode/dependency-injection.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 依赖注入
|
||||
|
||||
<!-- TODO: v3 中 PHP-DI 自动装配的工作方式。
|
||||
ApplicationContext::get() 用法。注册自定义服务。
|
||||
向命令类、构建类和阶段方法注入依赖。 -->
|
||||
6
docs/zh/develop/vendor-mode/index.md
Normal file
6
docs/zh/develop/vendor-mode/index.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Vendor 模式
|
||||
|
||||
<!-- TODO: Vendor 模式是什么,适用场景。
|
||||
安装:`composer require crazywhalecc/static-php-cli`。
|
||||
注册指向自定义包类的外部 Registry。
|
||||
最小工作示例:一个 Library 类 + 一个配置 YAML + 运行 spc。 -->
|
||||
6
docs/zh/develop/vendor-mode/lifecycle-hooks.md
Normal file
6
docs/zh/develop/vendor-mode/lifecycle-hooks.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 生命周期 Hook
|
||||
|
||||
<!-- TODO: Hook 执行顺序与方法签名的详细说明。
|
||||
#[BeforeStage('lib-name', 'build')]、#[AfterStage(...)]、#[PatchBeforeBuild]。
|
||||
不同包的 Hook 如何合并与排序。
|
||||
常见模式:修补 config.m4、注入编译标志、安装后修复。 -->
|
||||
6
docs/zh/develop/vendor-mode/package-classes.md
Normal file
6
docs/zh/develop/vendor-mode/package-classes.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# 编写 Package 类
|
||||
|
||||
<!-- TODO: 编写 Library 类和 Extension 类的分步指南。
|
||||
使用 #[Library]、#[Extension]、#[BuildFor] 的完整注释代码示例。
|
||||
UnixAutoconfExecutor / UnixCmakeExecutor / WindowsCMakeExecutor 用法。
|
||||
文件放置位置(src/Package/Library/、src/Package/Extension/)与自动加载。 -->
|
||||
Reference in New Issue
Block a user