Compare commits

..

101 Commits

Author SHA1 Message Date
crazywhalecc
f7730735c0 prepare to release rc3 2023-07-27 23:23:57 +08:00
crazywhalecc
752b88f62d prepare to release rc3, add dev:php-ver command 2023-07-27 23:18:44 +08:00
crazywhalecc
6131e1881b enable compile optimization for other libraries 2023-07-27 22:22:47 +08:00
crazywhalecc
980da4ea0f fix mbregex without mbstring failed check (fix #96) 2023-07-27 18:47:09 +08:00
crazywhalecc
b698ae2f50 add strip option (fix #97) 2023-07-27 18:43:18 +08:00
crazywhalecc
50632f6527 fix libpng build bug for linux 2023-07-27 18:17:06 +08:00
crazywhalecc
6d4755d8c9 fix pgsql dependency 2023-07-27 18:16:51 +08:00
crazywhalecc
75b85c26dc add memcached for macOS 2023-07-26 00:13:27 +08:00
crazywhalecc
1c8bbfbbdf fix libevent bug 2023-07-26 00:13:27 +08:00
crazywhalecc
c5a70f101a fix macOS C++ space 2023-07-26 00:13:27 +08:00
crazywhalecc
956c87a657 add memcache support 2023-07-25 21:46:57 +08:00
crazywhalecc
778b0eadcd add default openssl.cnf path for macOS 2023-07-25 00:31:12 +08:00
crazywhalecc
b8e6f9d1be add hasCppExtension check 2023-07-24 23:49:52 +08:00
crazywhalecc
0e024a8c43 change default to docker (some c++ packages needed) 2023-07-23 23:16:18 +08:00
crazywhalecc
65b0bd01c8 add auto-detect icu support for postgresql 2023-07-23 22:56:04 +08:00
crazywhalecc
3745dfc931 fix #75 2023-07-23 22:54:32 +08:00
crazywhalecc
0186ae5ff2 remove build upload downloads.zip, separated workflow instead 2023-07-23 11:30:54 +08:00
crazywhalecc
f1eacac4fd change extension count 2023-07-22 17:34:33 +08:00
crazywhalecc
4abe0064e6 add dev commands 2023-07-22 17:33:38 +08:00
crazywhalecc
cbc3adbec0 fix pgsql env problem 2023-07-22 16:29:46 +08:00
Jerry Ma
0902f80b46 Merge pull request #84 from jingjingxyk/pgsql
添加pgsql 库
2023-07-22 16:19:43 +08:00
crazywhalecc
47101d058b reformat code 2023-07-22 16:12:12 +08:00
crazywhalecc
bc978ecbde add macOS support for pgsql 2023-07-22 15:07:53 +08:00
Jerry
a2cb5165d3 add english tips 2023-07-21 17:09:11 +08:00
Jerry
e582fa8b22 Merge remote-tracking branch 'origin/refactor' into refactor 2023-07-21 16:34:56 +08:00
Jerry
8ec8838634 bold 2023-07-21 16:34:40 +08:00
Jerry Ma
8f259ffed9 Update README-en.md, add branch rename notes 2023-07-21 14:46:45 +08:00
Jerry Ma
74c2cf824b Update README.md, add branch name change notes 2023-07-21 14:46:12 +08:00
Jerry Ma
9ea3b04e82 Update README-en.md 2023-07-21 09:48:28 +08:00
Jerry Ma
99cb8c77b7 Update README.md 2023-07-21 09:47:39 +08:00
Jerry Ma
7056280c57 Update README-en.md 2023-07-20 11:41:15 +08:00
Jerry Ma
c14421c9ca Update README.md 2023-07-20 11:40:57 +08:00
crazywhalecc
97eff64b5b add micro:combine command 2023-07-20 01:15:28 +08:00
crazywhalecc
e522258693 fix libpng mac source bug 2023-07-20 01:15:05 +08:00
crazywhalecc
b84c68fe11 add doctor linux support 2023-07-17 21:44:17 +08:00
crazywhalecc
8505feaa66 fix createDir not working 2023-07-17 21:41:26 +08:00
crazywhalecc
41f49c20ff add --from-zip command to download locally 2023-07-17 21:36:50 +08:00
crazywhalecc
1912ae36e6 separate system tools list 2023-07-17 21:11:06 +08:00
crazywhalecc
08efc81cf0 add --auto-fix option 2023-07-17 21:10:49 +08:00
crazywhalecc
a3b09c69cc correct alpine build commands 2023-07-17 21:05:39 +08:00
crazywhalecc
5cf105c3a5 fix distro 2023-07-17 20:59:59 +08:00
crazywhalecc
7408781d13 add linux-header installer for alpine 2023-07-17 20:58:48 +08:00
crazywhalecc
0afc8ea2c3 add linux tool check 2023-07-17 20:31:42 +08:00
crazywhalecc
67b073776c add linux tool check 2023-07-17 20:29:02 +08:00
crazywhalecc
8b48cf7f70 add linux tool check 2023-07-17 20:28:08 +08:00
crazywhalecc
63287dd9c4 add linux tool check 2023-07-17 20:26:48 +08:00
crazywhalecc
fc7ac921e2 add document contributing guide 2023-07-17 18:39:34 +08:00
crazywhalecc
57e3193a2a add document 2023-07-17 18:01:45 +08:00
crazywhalecc
388f547878 add document 2023-07-17 17:59:44 +08:00
crazywhalecc
f2e483540b add opcache support 2023-07-16 18:13:11 +08:00
crazywhalecc
7d31c371e0 change gmp to github mirror 2023-07-16 17:59:21 +08:00
crazywhalecc
bc750733d5 mark php version 2023-07-16 17:55:20 +08:00
crazywhalecc
a66e22d9ed fix cron 2023-07-16 17:54:30 +08:00
crazywhalecc
cc5974d07d add download cache builder 2023-07-16 17:53:37 +08:00
jingjingxyk
085437e925 pgsql 禁用 依赖libzstd icu库 2023-07-01 18:04:42 +08:00
jingjingxyk
fa17a48483 pgsql 禁用 依赖libzstd icu库 2023-07-01 17:31:46 +08:00
jingjingxyk
78c1484570 解决debian 环境下 pgsql 构建共享库报错 2023-07-01 13:01:53 +08:00
jingjingxyk
9c2ea79bec update pgsql config 2023-06-30 21:00:49 +08:00
jingjingxyk
b7ffe3fd1f 添加pgsql 配置 2023-06-30 20:53:18 +08:00
jingjingxyk
dac14ae16e 添加pgsql 库 2023-06-30 20:36:51 +08:00
Jerry Ma
4872ff58bb Merge pull request #81 from jingjingxyk/feature_delete_quick_start
移除 quick start
2023-06-30 17:13:30 +08:00
Jerry Ma
755246cb6a Merge pull request #82 from jingjingxyk/feature_fix_pecl_url
解决pecl http下载地址被劫持的问题
2023-06-30 15:08:19 +08:00
jingjingxyk
9806422279 解决pecl http下载地址被劫持的问题 2023-06-30 15:00:25 +08:00
jingjingxyk
d5aea9f7d6 移除 quick start 2023-06-30 14:57:10 +08:00
crazywhalecc
b852471596 add manual doctors 2023-06-28 18:38:14 +08:00
crazywhalecc
fdf36ad726 fix mongodb library dependency 2023-06-27 00:59:10 +08:00
crazywhalecc
c49e6ba0a2 fix libwebp version (imagemagick with webp-1.3.1-rc1 crashed) 2023-06-15 22:22:07 +08:00
Jerry Ma
74a34362c3 Update README-en.md 2023-06-02 23:42:23 +08:00
Jerry Ma
0e33380df5 Update README-en.md 2023-06-02 23:40:49 +08:00
Jerry Ma
3db9c70e1b Update README.md 2023-06-02 23:39:01 +08:00
crazywhalecc
b2f3ffcc00 fix xml and intl depend order 2023-06-02 23:00:48 +08:00
crazywhalecc
aa9ec6e50e add xlswriter support 2023-06-02 21:40:17 +08:00
crazywhalecc
dcb3d91610 update ext-support.md 2023-06-02 21:39:32 +08:00
crazywhalecc
9e71a98eda fix enable-zts option error on build:libs command 2023-06-02 21:19:17 +08:00
Jerry Ma
f2ef783b13 Merge pull request #67 from mpociot/intl-support
Add intl/ICU support
2023-06-02 21:12:53 +08:00
crazywhalecc
874e104570 sort config and change icu libs order 2023-06-02 20:27:25 +08:00
crazywhalecc
1398086c38 add icu configure options for linux 2023-06-02 20:26:19 +08:00
Marcel Pociot
db1586e2ec Remove empty headers array 2023-06-02 11:52:27 +02:00
Marcel Pociot
1158931d91 Add intl/ICU support 2023-06-02 11:47:11 +02:00
Jerry Ma
ee1b03b060 Update README-en.md 2023-06-02 09:59:47 +08:00
Jerry Ma
b99378ea38 Update README-en.md 2023-06-02 09:55:33 +08:00
Jerry Ma
c9692d502c Update README.md 2023-06-02 09:55:13 +08:00
Jerry Ma
3f6e659c6a Update ext-support.md 2023-06-02 09:52:34 +08:00
Jerry Ma
37556c9e02 Update FUNDING.yml 2023-05-29 23:53:50 +08:00
Jerry Ma
34cd9d7cc1 Update README-en.md 2023-05-29 23:53:26 +08:00
Jerry Ma
030ac531a6 Update README.md 2023-05-29 23:49:55 +08:00
Jerry Ma
e19bd39fea Update FUNDING.yml 2023-05-29 22:16:46 +08:00
Jerry Ma
0fe432dd8e Update FUNDING.yml 2023-05-29 22:16:06 +08:00
Jerry Ma
c5b24ab136 Update FUNDING.yml 2023-05-29 22:12:34 +08:00
Jerry Ma
fb06cc1e1a Create FUNDING.yml 2023-05-29 21:57:58 +08:00
Jerry Ma
71e4ea166c Update ext.json 2023-05-26 12:25:53 +08:00
Jerry Ma
fdf8834163 Merge pull request #56 from jingjingxyk/feature_ext_mongodb
mongodb 添加参数
2023-05-25 19:20:34 +08:00
jingjingxyk
1fd70c9a99 验证 swow 2023-05-24 14:40:09 +08:00
jingjingxyk
7c3826f4a4 编译验证 2023-05-24 13:50:23 +08:00
jingjingxyk
7fb3d05b2c 调整quickstart 脚本 2023-05-24 13:30:22 +08:00
jingjingxyk
f831b4d61d 验证 2023-05-24 13:20:56 +08:00
jingjingxyk
56b5c1b138 Merge branch 'refactor' into feature_ext_mongodb 2023-05-24 12:31:12 +08:00
jingjingxyk
1cca826e8a update mongodb extension config 2023-05-24 12:29:57 +08:00
jingjingxyk
41aa129b97 update 2023-05-24 03:48:40 +08:00
crazywhalecc
09ba11affb update README and version 2023-05-17 23:07:39 +08:00
jingjingxyk
2767ac524f mongodb 添加参数 2023-05-08 11:44:44 +08:00
57 changed files with 1071 additions and 455 deletions

13
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: 'https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md' # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -77,10 +77,10 @@ jobs:
# If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true'
run: CACHE_API_EXEC=yes ./bin/spc download --with-php=${{ inputs.version }} --all ${{ env.SPC_BUILD_DEBUG }}
run: CACHE_API_EXEC=yes ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --all ${{ env.SPC_BUILD_DEBUG }}
# Run build command
- run: ./bin/spc build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}
- run: ./bin/spc-alpine-docker build ${{ inputs.extensions }} ${{ env.SPC_BUILD_DEBUG }} ${{ env.SPC_BUILD_CLI }} ${{ env.SPC_BUILD_MICRO }} ${{ env.SPC_BUILD_FPM }}
# Upload cli executable
- if: ${{ inputs.build-cli == true }}
@@ -115,8 +115,3 @@ jobs:
buildroot/build-extensions.json
buildroot/build-libraries.json
# Upload downloaded files
- uses: actions/upload-artifact@v3
with:
name: download-files
path: downloads/

View File

@@ -115,8 +115,3 @@ jobs:
buildroot/build-extensions.json
buildroot/build-libraries.json
# Upload downloaded files
- uses: actions/upload-artifact@v3
with:
name: download-files
path: downloads/

40
.github/workflows/download-cache.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: archive download sources weekly
on:
workflow_dispatch:
schedule:
- cron: "* 14 * * 5"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
download:
name: cache download sources
runs-on: ubuntu-latest
strategy:
matrix:
php-version: [ "8.0", "8.1", "8.2" ]
steps:
- uses: actions/checkout@v3
# Cache composer dependencies
- id: cache-composer-deps
uses: actions/cache@v3
with:
path: vendor
key: composer-dependencies
# If there's no Composer cache, install dependencies
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
run: composer update --no-dev
# If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true'
run: ./bin/spc download --with-php=${{ matrix.php-version }} --all --debug
# Upload downloaded files
- uses: actions/upload-artifact@v3
with:
name: download-files-${{ matrix.php-version }}
path: downloads/

View File

@@ -11,16 +11,16 @@ This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
> This branch is new version, if you are looking for old bash version of static-php-cli, see [bash-version](https://github.com/crazywhalecc/static-php-cli/tree/bash-version).
[![Version](https://img.shields.io/badge/Version-2.0--rc1-pink.svg?style=flat-square)]()
[![Version](https://img.shields.io/badge/Version-2.0--rc3-pink.svg?style=flat-square)]()
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]()
[![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-linux-x86_64.yml?branch=refactor&label=Linux%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
[![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-macos-x86_64.yml?branch=refactor&label=macOS%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
[![](https://img.shields.io/badge/Extension%20Counter-50+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/badge/Extension%20Counter-55+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]()
> The project has renamed the `refactor` branch to the `main` branch, please pay attention to changing the branch name for dependent projects.
## Compilation Requirements
Yes, this project is written in PHP, pretty funny.
@@ -39,7 +39,11 @@ Here is the architecture support status, where `CI` represents support for GitHu
Currently supported PHP versions for compilation are: `7.4`, `8.0`, `8.1`, `8.2`.
## Usage
## Docs
docs here: <https://static-php-cli.zhamao.me>.
## Simple Usage
Please first select the extension you want to compile based on the extension list below.
@@ -51,7 +55,7 @@ If you don't compile yourself, you can download pre-compiled artifact from Actio
### Supported Extensions
[Supported Extension List](/ext-support.md)
[Supported Extension List](https://static-php-cli.zhamao.me/en/guide/extensions.html)
> If there is no extension you need here, you can submit an issue.
@@ -78,13 +82,15 @@ Clone repo first:
git clone https://github.com/crazywhalecc/static-php-cli.git
```
If you have not installed php on your system, you can download single-file php binary and composer first.
If you have not installed php on your system, you can use package management to install PHP (such as brew, apt, yum, apk etc.).
And you can also download single-file php binary and composer using command `bin/setup-runtime`.
The PHP runtime for static-php-cli itself will be downloaded at `bin/php`, and composer is at `bin/composer`.
```bash
cd static-php-cli
chmod +x bin/setup-runtime
# It will download php-cli from self-hosted server and composer from getcomposer.org
./bin/setup-runtime
# Use this php runtime to run static-php-cli compiler
@@ -100,7 +106,7 @@ Basic usage for building php and micro with some extensions:
cd static-php-cli
composer update
chmod +x bin/spc
# Check system tool dependencies, fix them automatically (only support macOS) (TODO: Linux distro support)
# Check system tool dependencies, fix them automatically
./bin/spc doctor
# fetch all libraries
./bin/spc fetch --all
@@ -129,6 +135,14 @@ If anything goes wrong, use `--debug` option to display full terminal output:
./bin/spc fetch --all --debug
```
In addition, we build NTS by default. If you are going to build ZTS version, just add `--enable-zts` option.
```bash
./bin/spc build openssl,pcntl --build-all --enable-zts
```
Adding option `--no-strip` can produce binaries with debug symbols, in order to debug (using gdb). Disabling strip will increase the size of static binary.
### php-cli Usage
> php-cli is a single static binary, you can use it like normal php installed on your system.
@@ -148,7 +162,7 @@ cd buildroot/bin/
### micro.sfx Usage
> phpmicro is a Self-Extracted Executable SAPI module,
> phpmicro is a SelF-extracted eXecutable SAPI module,
> provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro).
> It can put php runtime and your source code together.
@@ -209,6 +223,17 @@ The basic principles for contributing are as follows:
camelCase and underscore formats should be followed, and mixing within the same module is prohibited.
- When compiling external libraries and creating patches, compatibility with different operating systems should be considered.
If you want to contribute document content, please go to [crazywhalecc/static-php-cli-docs](https://github.com/crazywhalecc/static-php-cli-docs).
Part of the English document is written by me, and part is translated by Google,
and there may be inaccurate descriptions, strange or offensive expressions.
If you are a native English speaker, some corrections to the documentation are welcome.
## Sponsor this project
You can sponsor my project on [this page](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md).
## Open-Source License
This project is based on the tradition of using the MIT License for old versions,
@@ -221,11 +246,11 @@ Due to the special nature of this project,
many other open source projects such as curl and protobuf will be used during the project compilation process,
and they all have their own open source licenses.
Please use the `dump-license`(TODO) command to export the open source licenses used in the project after compilation,
Please use the `bin/spc dump-license` command to export the open source licenses used in the project after compilation,
and comply with the corresponding project's LICENSE.
## Advanced
This project is pure open source project, and some modules are separated for developing.
This section will be improved after refactor version released.
The refactoring branch of this project is written modularly.
If you are interested in this project and want to join the development,
you can refer to the [Contribution Guide](https://static-php-cli.zhamao.me) of the documentation to contribute code or documentation. (TODO)

View File

@@ -2,7 +2,7 @@
Compile A Statically Linked PHP With Swoole and other Extensions.
If you are using English, see [English README](README-en.md).
**If you are using English, see [English README](README-en.md).**
编译纯静态的 PHP Binary 二进制文件,带有各种扩展,让 PHP-cli 应用变得更便携cli SAPI
@@ -12,15 +12,15 @@ If you are using English, see [English README](README-en.md).
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
> 此分支为重构的新版,如果你在找纯 Bash 编写的旧版本,请到 [bash-version 分支](https://github.com/crazywhalecc/static-php-cli/tree/bash-version)。
[![Version](https://img.shields.io/badge/Version-2.0--rc1-pink.svg?style=flat-square)]()
[![Version](https://img.shields.io/badge/Version-2.0--rc3-pink.svg?style=flat-square)]()
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]()
[![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-linux-x86_64.yml?branch=refactor&label=Linux%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
[![](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/build-macos-x86_64.yml?branch=refactor&label=macOS%20Build&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
[![](https://img.shields.io/badge/Extension%20Counter-50+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/badge/Extension%20Counter-55+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]()
> 项目已重命名 `refactor` 分支为 `main` 分支,请依赖的项目注意更改分支名称。
## 编译环境需求
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。
@@ -38,6 +38,10 @@ If you are using English, see [English README](README-en.md).
目前支持编译的 PHP 版本为:`7.4``8.0``8.1``8.2`
## 文档
点击这里查看文档:<https://static-php-cli.zhamao.me>。
## 使用
请先根据下方扩展列表选择你要编译的扩展。
@@ -50,7 +54,7 @@ If you are using English, see [English README](README-en.md).
### 支持的扩展情况
[扩展支持列表](/ext-support.md)
[扩展支持列表](https://static-php-cli.zhamao.me/zh/guide/extensions.html)
> 如果这里没有你需要的扩展,可以提交 Issue。
@@ -73,9 +77,9 @@ If you are using English, see [English README](README-en.md).
git clone https://github.com/crazywhalecc/static-php-cli.git
```
如果你本机没有安装 PHP可以通过命令下载静态编译好的 php-cli 和 Composer
如果你本机没有安装 PHP需要先使用包管理(例如 brew、apt、yum、apk 等)安装 php
下载的 php 和 Composer 将保存为 `bin/php``bin/composer`
你也可以通过 `bin/setup-runtime` 命令下载静态编译好的 php-cli 和 Composer。下载的 php 和 Composer 将保存为 `bin/php``bin/composer`
```bash
cd static-php-cli
@@ -96,7 +100,7 @@ chmod +x bin/setup-runtime
cd static-php-cli
composer update
chmod +x bin/spc
# 检查环境依赖,并根据提示的命令安装缺失的编译工具(目前仅支持 macOSLinux 后续会支持)
# 检查环境依赖,并根据提示的命令安装缺失的编译工具
./bin/spc doctor
# 拉取所有依赖库
./bin/spc fetch --all
@@ -125,6 +129,14 @@ chmod +x bin/spc
./bin/spc fetch --all --debug
```
此外,默认编译的 PHP 为 NTS 版本。如需编译线程安全版本ZTS只需添加参数 `--enable-zts` 即可。
```bash
./bin/spc build openssl,pcntl --build-all --enable-zts
```
同时,你也可以使用参数 `--no-strip` 来关闭裁剪,关闭裁剪后可以使用 gdb 等工具调试,但这样会让静态二进制体积变大。
### 使用 php-cli
> php-cli 是一个静态的二进制文件,类似 Go、Rust 语言编译后的单个可移植的二进制文件。
@@ -194,6 +206,12 @@ cat micro.sfx code.php > single-app && chmod +x single-app
另外,添加新扩展的贡献方式,可以参考下方 `进阶`
如果你想贡献文档内容,请到项目仓库 [crazywhalecc/static-php-cli-docs](https://github.com/crazywhalecc/static-php-cli-docs) 贡献。
## 赞助本项目
你可以在 [我的个人赞助页](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md) 支持我和我的项目。
## 开源协议
本项目依据旧版本惯例采用 MIT License 开源,自身的部分代码引用或修改自以下项目:
@@ -202,10 +220,8 @@ cat micro.sfx code.php > single-app && chmod +x single-app
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)Apache 2.0 LICENSE、SWOOLE-CLI LICENSE
因本项目的特殊性,使用项目编译过程中会使用很多其他开源项目,例如 curl、protobuf 等,它们都有各自的开源协议。
请在编译完成后,使用命令 `dump-license`(TODO) 导出项目使用项目的开源协议,并遵守对应项目的 LICENSE。
请在编译完成后,使用命令 `bin/spc dump-license` 导出项目使用项目的开源协议,并遵守对应项目的 LICENSE。
## 进阶
本项目重构分支为模块化编写。
TODO这部分将在基础功能完成后编写完成。
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php-cli.zhamao.me) 贡献代码或文档。TODO

View File

@@ -25,7 +25,7 @@ __DIR__=$(cd "$(dirname "$0")" && pwd)
__PROJECT__=$(cd ${__DIR__}/../ && pwd)
# set download dir
__PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.5-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
__PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.6-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
__COMPOSER_URL__="https://getcomposer.org/download/latest-stable/composer.phar"
# use china mirror
@@ -46,7 +46,7 @@ done
case "$mirror" in
china)
__PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.5-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
__PHP_RUNTIME_URL__="https://dl.zhamao.xin/static-php-cli/php-8.2.6-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
__COMPOSER_URL__="https://mirrors.aliyun.com/composer/composer.phar"
;;

View File

@@ -53,6 +53,19 @@
"sockets"
]
},
"memcached": {
"type": "external",
"source": "memcached",
"arg-type": "custom",
"cpp-extension": true,
"lib-depends": [
"libmemcached"
],
"ext-depends": [
"session",
"zlib"
]
},
"exif": {
"type": "builtin"
},
@@ -138,6 +151,7 @@
},
"intl": {
"type": "builtin",
"cpp-extension": true,
"lib-depends": [
"icu"
]
@@ -151,8 +165,9 @@
},
"mbregex": {
"type": "builtin",
"lib-depends": [
"onig"
"arg-type": "custom",
"ext-depends": [
"mbstring"
]
},
"mbstring": {
@@ -162,10 +177,27 @@
"onig"
]
},
"memcache": {
"type": "external",
"source": "ext-memcache",
"arg-type": "custom",
"lib-depends": [
"zlib"
],
"ext-depends": [
"session"
]
},
"mongodb": {
"type": "external",
"source": "mongodb",
"arg-type": "custom"
"arg-type": "custom",
"lib-suggests": [
"icu",
"openssl",
"zstd",
"zlib"
]
},
"mysqli": {
"type": "builtin",
@@ -205,12 +237,13 @@
},
"pdo_pgsql": {
"type": "builtin",
"arg-type": "with",
"arg-type": "with-prefix",
"ext-depends": [
"pdo"
"pdo",
"pgsql"
],
"lib-depends": [
"pq"
"postgresql"
]
},
"pdo_sqlite": {
@@ -224,6 +257,13 @@
"sqlite"
]
},
"pgsql": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends": [
"postgresql"
]
},
"phar": {
"type": "builtin",
"ext-depends": [
@@ -314,6 +354,7 @@
"type": "external",
"source": "swoole",
"arg-type": "custom",
"cpp-extension": true,
"lib-depends": [
"openssl"
],
@@ -360,6 +401,15 @@
"tokenizer": {
"type": "builtin"
},
"xlswriter": {
"type": "external",
"source": "xlswriter",
"arg-type": "custom",
"ext-depends": [
"zlib",
"zip"
]
},
"xml": {
"type": "builtin",
"arg-type": "custom",
@@ -421,4 +471,4 @@
"zstd"
]
}
}
}

View File

@@ -96,6 +96,15 @@
"gmp.h"
]
},
"icu": {
"source": "icu",
"static-libs-unix": [
"libicui18n.a",
"libicuio.a",
"libicuuc.a",
"libicudata.a"
]
},
"imagemagick": {
"source": "imagemagick",
"static-libs-unix": [
@@ -200,6 +209,12 @@
"zlib"
]
},
"libsodium": {
"source": "libsodium",
"static-libs-unix": [
"libsodium.a"
]
},
"libssh2": {
"source": "libssh2",
"static-libs-unix": [
@@ -249,7 +264,8 @@
],
"lib-suggests": [
"xz",
"zlib"
"zlib",
"icu"
],
"lib-suggests-windows": [
"icu",
@@ -365,7 +381,19 @@
"postgresql": {
"source": "postgresql",
"static-libs-unix": [
"libpg.a"
"libpq.a",
"libpgport.a",
"libpgcommon.a"
],
"lib-depends": [
"libiconv",
"libxml2",
"openssl",
"zlib",
"readline"
],
"lib-suggests": [
"icu"
]
},
"pthreads4w": {
@@ -434,6 +462,13 @@
"zconf.h"
]
},
"libmemcached": {
"source": "libmemcached",
"static-libs-unix": [
"libmemcached.a",
"libmemcachedutil.a"
]
},
"zstd": {
"source": "zstd",
"static-libs-unix": [
@@ -454,11 +489,5 @@
"zstd.h",
"zstd_errors.h"
]
},
"libsodium": {
"source": "libsodium",
"static-libs-unix": [
"libsodium.a"
]
}
}

View File

@@ -8,7 +8,7 @@
},
"apcu": {
"type": "url",
"url": "http://pecl.php.net/get/APCu",
"url": "https://pecl.php.net/get/APCu",
"path": "php-src/ext/apcu",
"filename": "apcu.tgz",
"license": {
@@ -16,6 +16,25 @@
"path": "LICENSE"
}
},
"memcached": {
"type": "url",
"url": "https://pecl.php.net/get/memcached",
"path": "php-src/ext/memcached",
"filename": "memcached.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"libmemcached": {
"type": "git",
"url": "https://github.com/crazywhalecc/libmemcached-macos.git",
"rev": "master",
"license": {
"type": "file",
"path": "COPYING"
}
},
"brotli": {
"type": "ghtar",
"repo": "google/brotli",
@@ -61,9 +80,19 @@
"path": "LICENSE"
}
},
"ext-memcache": {
"type": "url",
"url": "https://pecl.php.net/get/memcache",
"path": "php-src/ext/memcache",
"filename": "memcache.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-ssh2": {
"type": "url",
"url": "http://pecl.php.net/get/ssh2",
"url": "https://pecl.php.net/get/ssh2",
"path": "php-src/ext/ssh2",
"filename": "ssh2.tgz",
"license": {
@@ -91,14 +120,21 @@
}
},
"gmp": {
"type": "filelist",
"url": "https://gmplib.org/download/gmp/",
"regex": "/href=\"(?<file>gmp-(?<version>[^\"]+)\\.tar\\.xz)\"/",
"type": "ghtagtar",
"repo": "alisw/GMP",
"license": {
"type": "text",
"text": "Since version 6, GMP is distributed under the dual licenses, GNU LGPL v3 and GNU GPL v2. These licenses make the library free to use, share, and improve, and allow you to pass on the result. The GNU licenses give freedoms, but also set firm restrictions on the use with non-free programs."
}
},
"icu": {
"type": "url",
"url": "https://github.com/unicode-org/icu/releases/download/release-73-1/icu4c-73_1-src.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"imagemagick": {
"type": "ghtar",
"repo": "ImageMagick/ImageMagick",
@@ -109,7 +145,7 @@
},
"inotify": {
"type": "url",
"url": "http://pecl.php.net/get/inotify",
"url": "https://pecl.php.net/get/inotify",
"path": "php-src/ext/inotify",
"filename": "inotify.tgz",
"license": {
@@ -186,6 +222,14 @@
"path": "COPYING"
}
},
"libsodium": {
"type": "url",
"url": "https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"libssh2": {
"type": "ghrel",
"repo": "libssh2/libssh2",
@@ -196,8 +240,8 @@
}
},
"libwebp": {
"type": "ghtagtar",
"repo": "webmproject/libwebp",
"type": "url",
"url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.0.tar.gz",
"license": {
"type": "file",
"path": "COPYING"
@@ -303,7 +347,8 @@
}
},
"postgresql": {
"type": "custom",
"type": "url",
"url": "https://ftp.postgresql.org/pub/source/v15.1/postgresql-15.1.tar.gz",
"license": {
"type": "file",
"path": "COPYRIGHT"
@@ -311,7 +356,7 @@
},
"protobuf": {
"type": "url",
"url": "http://pecl.php.net/get/protobuf",
"url": "https://pecl.php.net/get/protobuf",
"path": "php-src/ext/protobuf",
"filename": "protobuf.tgz",
"license": {
@@ -375,6 +420,16 @@
"path": "LICENSE"
}
},
"xlswriter": {
"type": "url",
"url": "https://pecl.php.net/get/xlswriter",
"path": "php-src/ext/xlswriter",
"filename": "xlswriter.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"xz": {
"type": "filelist",
"url": "https://tukaani.org/xz/",
@@ -411,13 +466,5 @@
"type": "file",
"path": "LICENSE"
}
},
"libsodium": {
"type": "url",
"url": "https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz",
"license": {
"type": "file",
"path": "LICENSE"
}
}
}

View File

@@ -1,108 +1,3 @@
# Extension List
> - yes: supported and tested
> - untested: supported, but not tested
> - empty: not supported yet
> - no with issue link: not supported yet due to issue
> - partial with issue link: supported but not perfect due to issue
| | Linux | macOS | Windows |
|------------|---------------------------------------------------------------------|----------------------------------------------------------------|---------|
| apcu | yes, untested | yes, untested | |
| bcmath | yes | yes | |
| bz2 | yes | yes | |
| calendar | yes | yes | |
| ctype | yes | yes | |
| curl | yes | yes | |
| dba | yes | yes | |
| dom | yes | yes | |
| enchant | | | |
| event | yes | yes | |
| exif | yes | yes | |
| ffi | | yes, [docs]() | |
| filter | yes | yes | |
| fileinfo | yes | yes | |
| ftp | yes | yes | |
| gd | yes | yes | |
| gettext | | | |
| gmp | yes | yes | |
| iconv | yes | yes | |
| imagick | yes | yes | |
| inotify | yes | yes | |
| mbstring | yes | yes | |
| mbregex | yes | yes | |
| mcrypt | | [no](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
| mongodb | yes | yes | |
| mysqli | yes | yes | |
| mysqlnd | yes | yes | |
| openssl | yes | yes | |
| pcntl | yes | yes | |
| pdo | yes | yes | |
| pdo_mysql | yes | yes | |
| pdo_sqlite | yes | yes | |
| pdo_pgsql | | | |
| phar | yes | yes | |
| posix | yes | yes | |
| protobuf | yes | yes | |
| readline | yes, untested | yes, untested | |
| redis | yes | yes | |
| session | yes | yes | |
| shmop | yes | yes | |
| simplexml | yes | yes | |
| soap | yes | yes | |
| sockets | yes | yes | |
| sodium | yes | yes | |
| sqlite3 | yes | yes | |
| ssh2 | yes, untested | yes, untested | |
| swow | yes | yes | |
| swoole | [partial](https://github.com/crazywhalecc/static-php-cli/issues/51) | yes | |
| tokenizer | yes | yes | |
| xml | yes | yes | |
| xmlreader | yes, untested | yes, untested | |
| xmlwriter | yes, untested | yes, untested | |
| zip | yes, untested | yes, untested | |
| zlib | yes | yes | |
| zstd | yes | yes | |
## Additional Requirements
- phpmicro requires PHP >= 8.0
- swoole >= 5.0 requires PHP >= 8.0
- swow requires PHP >= 8.0
## Typical Extension List Example
Here are some extension list example for different use.
- For general use: `"bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,ftp,filter,gd,iconv,xml,mbstring,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip"`
- For static-php-cli self: `"posix,pcntl,phar,tokenizer,iconv,zlib"`
- For static-php-cli self (with dev dependencies): `"posix,pcntl,phar,tokenizer,iconv,zlib,xml,dom,xmlwriter,xmlreader,fileinfo"`
- Minimum, with no extension: `""`
Compile with all supported extensions (exclude `swow`, `swoole` due to c++ extension):
```bash
bin/spc build --build-all bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,mbregex,mbstring,mongodb,mysqli,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,protobuf,redis,session,shmop,simplexml,soap,sockets,sqlite3,tokenizer,xml,xmlreader,xmlwriter,yaml,zip,zlib,zstd --with-libs=libjpeg,freetype,libwebp,libavif --debug
```
## Additional Libraries
Some extensions have soft dependencies, you can enable extra features by adding these libs using `--with-libs`.
For example, to compile with gd extension, with `libwebp, libgif, libavif, libjpeg, freetype` extra features:
```bash
bin/spc build gd --with-libs=libjpeg,freetype,libwebp,libavif --build-cli
```
> If you don't add them, your compilation will not enable these features.
## Limitations
- swow and swoole cannot be compiled at the same time.
- openssl needs manual configuration for ssl certificate. (TODO: I will write a wiki about it)
- some extensions need system configuration, e.g. `curl` and `openssl` will search ssl certificate on your system.
## Bugs and TODOs
See [#32](https://github.com/crazywhalecc/static-php-cli/issues/32).
See: [Docs - Extensions](https://static-php-cli.zhamao.me/en/guide/extensions.html)

View File

@@ -1,34 +0,0 @@
# 快速启动容器环境
> 提供了 debian 11 构建 和 alpine 构建环境
> 任意选一个就可以
## debian 11 构建环境
```bash
# 启动 debian 11 容器环境
sh quickstart/linux/x86_64/run-debian-11-container.sh
# 进入容器
sh quickstart/linux/x86_64/connection-static-php-cli.sh
# 准备构建基础软件
sh quickstart/linux/x86_64/debian-11-init.sh
```
## aline 构建环境
```bash
# 启动 alpine 容器环境
sh quickstart/linux/x86_64/run-alpine-3.16-container.sh
# 进入容器
sh sh quickstart/linux/x86_64/connection-static-php-cli.sh
# 准备构建基础软件
sh quickstart/linux/x86_64/alpine-3.16-init.sh
```

View File

@@ -1,38 +0,0 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
cd ${__DIR__}
# use china mirror
# bash quickstart/linux/x86_64/alpine-3.16-init.sh --mirror china
mirror=''
while [ $# -gt 0 ]; do
case "$1" in
--mirror)
mirror="$2"
shift
;;
--*)
echo "Illegal option $1"
;;
esac
shift $(( $# > 0 ? 1 : 0 ))
done
case "$mirror" in
china)
test -f /etc/apk/repositories.save || cp /etc/apk/repositories /etc/apk/repositories.save
sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
;;
esac
apk update
apk add vim alpine-sdk xz autoconf automake linux-headers clang-dev clang lld libtool cmake bison re2c gettext coreutils

View File

@@ -1,11 +0,0 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
cd ${__DIR__}
docker exec -it static-php-cli-dev-1 sh

View File

@@ -1,42 +0,0 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
cd ${__DIR__}
# use china mirror
# bash quickstart/linux/x86_64/debian-11-init.sh --mirror china
mirror=''
while [ $# -gt 0 ]; do
case "$1" in
--mirror)
mirror="$2"
shift
;;
--*)
echo "Illegal option $1"
;;
esac
shift $(( $# > 0 ? 1 : 0 ))
done
case "$mirror" in
china)
test -f /etc/apt/sources.list.save || cp /etc/apt/sources.list /etc/apt/sources.list.save
sed -i "s@deb.debian.org@mirrors.ustc.edu.cn@g" /etc/apt/sources.list && \
sed -i "s@security.debian.org@mirrors.ustc.edu.cn@g" /etc/apt/sources.list
;;
esac
apt update -y
apt install -y git curl wget ca-certificates
apt install -y xz-utils autoconf automake lld libtool cmake bison re2c gettext coreutils lzip zip unzip
apt install -y pkg-config bzip2 flex
apt install -y musl-tools g++
apt install -y clang

View File

@@ -1,25 +0,0 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
__PROJECT__=$(
cd ${__DIR__}/../../../
pwd
)
cd ${__PROJECT__}
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
chmod +x bin/spc
./bin/spc fetch --all --debug
./bin/spc list-ext
#./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo,pdo_sqlite,ftp,curl" --cc=gcc --cxx=g++ --debug
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo,pdo_sqlite,ftp,curl" --cc=clang --cxx=clang++ --debug

View File

@@ -1,25 +0,0 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
__PROJECT__=$(
cd ${__DIR__}/../../../
pwd
)
cd ${__DIR__}
{
docker stop static-php-cli-dev-1
} || {
echo $?
}
cd ${__DIR__}
IMAGE=alpine:3.16
cd ${__DIR__}
docker run --rm --name static-php-cli-dev-1 -d -v ${__PROJECT__}:/work -w /work $IMAGE tail -f /dev/null

View File

@@ -1,25 +0,0 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
__PROJECT__=$(
cd ${__DIR__}/../../../
pwd
)
cd ${__DIR__}
{
docker stop static-php-cli-dev-1
} || {
echo $?
}
cd ${__DIR__}
IMAGE=debian:11
cd ${__DIR__}
docker run --rm --name static-php-cli-dev-1 -d -v ${__PROJECT__}:/work -w /work $IMAGE tail -f /dev/null

View File

@@ -1,24 +0,0 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
__PROJECT__=$(
cd ${__DIR__}/../../../
pwd
)
cd ${__PROJECT__}
export PATH=${__PROJECT__}/bin/runtime:$PATH
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
chmod +x bin/spc
./bin/spc fetch --all --debug
./bin/spc list-ext
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo,pdo_sqlite,ftp,curl" --cc=clang --cxx=clang++ --debug

View File

@@ -16,7 +16,7 @@ use Symfony\Component\Console\Command\ListCommand;
*/
class ConsoleApplication extends Application
{
public const VERSION = '2.0-rc1';
public const VERSION = '2.0-rc3';
/**
* @throws \ReflectionException

View File

@@ -140,6 +140,37 @@ abstract class BuilderBase
return $this->exts[$name] ?? null;
}
/**
* 获取所有要编译的扩展对象
*
* @return Extension[]
*/
public function getExts(): array
{
return $this->exts;
}
/**
* 检查 C++ 扩展是否存在
*
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function hasCppExtension(): bool
{
// judge cpp-extension
$exts = array_keys($this->getExts());
$cpp = false;
foreach ($exts as $ext) {
if (Config::getExt($ext, 'cpp-extension', false) === true) {
$cpp = true;
break;
}
}
return $cpp;
}
/**
* 设置本次 Builder 是否为仅编译库的模式
*/

View File

@@ -31,13 +31,13 @@ class BuilderProvider
cc: $input->getOption('cc'),
cxx: $input->getOption('cxx'),
arch: $input->getOption('arch'),
zts: $input->getOption('enable-zts'),
zts: $input->hasOption('enable-zts') ? $input->getOption('enable-zts') : false,
),
'Linux' => new LinuxBuilder(
cc: $input->getOption('cc'),
cxx: $input->getOption('cxx'),
arch: $input->getOption('arch'),
zts: $input->getOption('enable-zts'),
zts: $input->hasOption('enable-zts') ? $input->getOption('enable-zts') : false,
),
default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'),
};

View File

@@ -14,4 +14,9 @@ class mbregex extends Extension
{
return 'mbstring';
}
public function getConfigureArg(): string
{
return '';
}
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('memcache')]
class memcache extends Extension
{
public function getUnixConfigureArg(): string
{
return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH;
}
}

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('memcached')]
class memcached extends Extension
{
public function getUnixConfigureArg(): string
{
$rootdir = BUILD_ROOT_PATH;
return "--enable-memcached --with-zlib-dir={$rootdir} --with-libmemcached-dir={$rootdir} --disable-memcached-sasl --enable-memcached-json";
}
}

View File

@@ -12,6 +12,16 @@ class mongodb extends Extension
{
public function getUnixConfigureArg(): string
{
return '--enable-mongodb --without-mongodb-sasl';
$arg = ' --enable-mongodb ';
$arg .= ' --with-mongodb-system-libs=no --with-mongodb-client-side-encryption=no ';
$arg .= ' --with-mongodb-sasl=no ';
if ($this->builder->getLib('openssl')) {
$arg .= '--with-mongodb-ssl=openssl';
}
$arg .= $this->builder->getLib('icu') ? ' --with-mongodb-icu=yes ' : ' --with-mongodb-icu=no ';
$arg .= $this->builder->getLib('zstd') ? ' --with-mongodb-zstd=yes ' : ' --with-mongodb-zstd=no ';
// $arg .= $this->builder->getLib('snappy') ? ' --with-mongodb-snappy=yes ' : ' --with-mongodb-snappy=no ';
$arg .= $this->builder->getLib('zlib') ? ' --with-mongodb-zlib=yes ' : ' --with-mongodb-zlib=bundled ';
return $arg;
}
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('xlswriter')]
class xlswriter extends Extension
{
public function getUnixConfigureArg(): string
{
return '--with-xlswriter --enable-reader';
}
}

View File

@@ -21,7 +21,7 @@ class LinuxBuilder extends BuilderBase
use UnixBuilderTrait;
/** @var string[] Linux 环境下编译依赖的命令 */
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'pkg-config', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
/** @var string 使用的 libc */
public string $libc;
@@ -139,7 +139,8 @@ class LinuxBuilder extends BuilderBase
)
);
}
if ($this->getExt('swoole')) {
if ($this->hasCppExtension()) {
$extra_libs .= ' -lstdc++';
}
if ($this->getExt('imagick')) {

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class icu extends LinuxLibraryBase
{
public const NAME = 'icu';
protected function build()
{
$root = BUILD_ROOT_PATH;
$cppflag = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1"';
shell()->cd($this->source_dir . '/source')
->exec(
"{$this->builder->configure_env} {$cppflag} ./runConfigureICU Linux " .
'--enable-static ' .
'--disable-shared ' .
'--with-data-packaging=static ' .
'--enable-release=yes ' .
'--enable-extras=yes ' .
'--enable-icuio=yes ' .
'--enable-dyload=no ' .
'--enable-tools=yes ' .
'--enable-tests=no ' .
'--enable-samples=no ' .
"--prefix={$root}"
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
}
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\exception\RuntimeException;
/**
* gmp is a template library class for unix
*/
class libmemcached extends LinuxLibraryBase
{
public const NAME = 'libmemcached';
public function build()
{
throw new RuntimeException('libmemcached is currently not supported on Linux platform');
}
}

View File

@@ -45,6 +45,7 @@ class libpng extends LinuxLibraryBase
shell()->cd($this->source_dir)
->exec('chmod +x ./configure')
->exec('chmod +x ./install-sh')
->exec(
"{$this->builder->configure_env} ./configure " .
"--host={$this->builder->gnu_arch}-unknown-linux " .

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class postgresql extends LinuxLibraryBase
{
use \SPC\builder\unix\library\postgresql;
public const NAME = 'postgresql';
}

View File

@@ -54,7 +54,7 @@ class MacOSBuilder extends BuilderBase
'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig/" ' .
"CC='{$this->cc}' " .
"CXX='{$this->cxx}' " .
"CFLAGS='{$this->arch_c_flags} -Wimplicit-function-declaration'";
"CFLAGS='{$this->arch_c_flags} -Wimplicit-function-declaration -Os'";
// 创立 pkg-config 和放头文件的目录
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
@@ -118,12 +118,15 @@ class MacOSBuilder extends BuilderBase
}
/**
* @throws RuntimeException
* @param int $build_target build target
* @param bool $bloat just raw add all lib files
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function buildPHP(int $build_target = BUILD_TARGET_NONE, bool $bloat = false): void
{
$extra_libs = $this->getFrameworks(true) . ' ' . ($this->getExt('swoole') ? '-lc++ ' : '');
$extra_libs = $this->getFrameworks(true) . ' ' . ($this->hasCppExtension() ? '-lc++ ' : '');
if (!$bloat) {
$extra_libs .= implode(' ', $this->getAllStaticLibFiles());
} else {
@@ -209,7 +212,7 @@ class MacOSBuilder extends BuilderBase
public function buildCli(string $extra_libs): void
{
$shell = shell()->cd(SOURCE_PATH . '/php-src');
$shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" cli");
$shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" cli");
if ($this->strip) {
$shell->exec('dsymutil -f sapi/cli/php')->exec('strip sapi/cli/php');
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class icu extends MacOSLibraryBase
{
public const NAME = 'icu';
protected function build()
{
$root = BUILD_ROOT_PATH;
shell()->cd($this->source_dir . '/source')
->exec("{$this->builder->configure_env} ./runConfigureICU MacOSX --enable-static --disable-shared --prefix={$root}")
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
/**
* gmp is a template library class for unix
*/
class libmemcached extends MacOSLibraryBase
{
public const NAME = 'libmemcached';
public function build()
{
$rootdir = BUILD_ROOT_PATH;
shell()->cd($this->source_dir)
->exec('chmod +x configure')
->exec(
"{$this->builder->configure_env} ./configure " .
'--enable-static --disable-shared ' .
'--disable-sasl ' .
"--prefix={$rootdir}"
)
->exec('make clean')
->exec('sed -ie "s/-Werror//g" ' . $this->source_dir . '/Makefile')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
}
}

View File

@@ -40,6 +40,7 @@ class libpng extends MacOSLibraryBase
};
shell()->cd($this->source_dir)
->exec('chmod +x ./configure')
->exec('chmod +x ./install-sh')
->exec(
"{$this->builder->configure_env} ./configure " .
"--host={$this->builder->gnu_arch}-apple-darwin " .

View File

@@ -31,18 +31,16 @@ class libxml2 extends MacOSLibraryBase
'-DBUILD_SHARED_LIBS=OFF ' .
'-DLIBXML2_WITH_ICONV=ON ' .
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
"-DLIBXML2_WITH_ICU={$enable_icu} " .
'-DLIBXML2_WITH_ICU=OFF ' .
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
'-DLIBXML2_WITH_PYTHON=OFF ' .
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
'-DLIBXML2_WITH_TESTS=OFF ' .
'-DCMAKE_INSTALL_PREFIX=/ ' .
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
"-DCMAKE_INSTALL_PREFIX={$destdir} " .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'..'
)
->exec("cmake --build . -j {$this->builder->concurrency}")
->exec("make install DESTDIR={$destdir}");
->exec('make install');
}
}

View File

@@ -42,7 +42,8 @@ class openssl extends MacOSLibraryBase
"{$this->builder->configure_env} ./Configure no-shared {$extra} " .
'--prefix=/ ' . // use prefix=/
"--libdir={$lib} " .
" darwin64-{$this->builder->arch}-cc"
'--openssldir=/System/Library/OpenSSL ' .
"darwin64-{$this->builder->arch}-cc"
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class postgresql extends MacOSLibraryBase
{
use \SPC\builder\unix\library\postgresql;
public const NAME = 'postgresql';
}

View File

@@ -22,6 +22,7 @@ trait libevent
'-DEVENT__LIBRARY_TYPE=STATIC ' .
'-DEVENT__DISABLE_BENCHMARK=ON ' .
'-DEVENT__DISABLE_THREAD_SUPPORT=ON ' .
'-DEVENT__DISABLE_MBEDTLS=ON ' .
'-DEVENT__DISABLE_TESTS=ON ' .
'-DEVENT__DISABLE_SAMPLES=ON ' .
'..'

View File

@@ -0,0 +1,89 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait postgresql
{
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build()
{
$builddir = BUILD_ROOT_PATH;
$env = $this->builder->configure_env;
$envs = $env;
$packages = 'openssl zlib readline libxml-2.0'; // icu-uc icu-io icu-i18n libzstd
$pkgconfig_executable = $builddir . '/bin/pkg-config';
$output = shell()->execWithResult($env . " {$pkgconfig_executable} --cflags-only-I --static " . $packages);
if (!empty($output[1][0])) {
$cppflags = $output[1][0];
$envs .= " CPPFLAGS=\"{$cppflags}\"";
}
$output = shell()->execWithResult($env . " {$pkgconfig_executable} --libs-only-L --static " . $packages);
if (!empty($output[1][0])) {
$ldflags = $output[1][0];
$envs .= $this instanceof MacOSLibraryBase ? " LDFLAGS=\"{$ldflags}\" " : " LDFLAGS=\"{$ldflags} -static\" ";
}
$output = shell()->execWithResult($env . " {$pkgconfig_executable} --libs-only-l --static " . $packages);
if (!empty($output[1][0])) {
$libs = $output[1][0];
$envs .= " LIBS=\"{$libs}\" ";
}
FileSystem::resetDir($this->source_dir . '/build');
# 有静态链接配置 参考文件: src/interfaces/libpq/Makefile
shell()->cd($this->source_dir . '/build')
->exec('sed -i.backup "s/invokes exit\'; exit 1;/invokes exit\';/" ../src/interfaces/libpq/Makefile')
->exec(' sed -i.backup "293 s/^/#$/" ../src/Makefile.shlib')
->exec('sed -i.backup "441 s/^/#$/" ../src/Makefile.shlib');
// configure
shell()->cd($this->source_dir . '/build')
->exec(
"{$envs} ../configure " .
"--prefix={$builddir} " .
'--disable-thread-safety ' .
'--enable-coverage=no ' .
'--with-ssl=openssl ' .
'--with-readline ' .
'--with-libxml ' .
($this->builder->getLib('icu') ? '--with-icu ' : '--without-icu ') .
'--without-ldap ' .
'--without-libxslt ' .
'--without-lz4 ' .
'--without-zstd ' .
'--without-perl ' .
'--without-python ' .
'--without-pam ' .
'--without-ldap ' .
'--without-bonjour ' .
'--without-tcl '
);
// build
shell()->cd($this->source_dir . '/build')
->exec($envs . ' make -C src/bin/pg_config install')
->exec($envs . ' make -C src/include install')
->exec($envs . ' make -C src/common install')
->exec($envs . ' make -C src/backend/port install')
->exec($envs . ' make -C src/port install')
->exec($envs . ' make -C src/backend/libpq install')
->exec($envs . ' make -C src/interfaces/libpq install');
// remove dynamic libs
shell()->cd($this->source_dir . '/build')
->exec("rm -rf {$builddir}/lib/*.so.*")
->exec("rm -rf {$builddir}/lib/*.so")
->exec("rm -rf {$builddir}/lib/*.dylib");
}
}

View File

@@ -71,7 +71,7 @@ class BuildCliCommand extends BuildCommand
// 执行扩展检测
$builder->proveExts($extensions);
// strip
$builder->setStrip(false);
$builder->setStrip(!$this->getOption('no-strip'));
// 构建
$builder->buildPHP($rule, $this->getOption('bloat'));
// 统计时间

View File

@@ -10,11 +10,16 @@ use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand('doctor', 'Diagnose whether the current environment can compile normally')]
class DoctorCommand extends BaseCommand
{
public function configure()
{
$this->addOption('auto-fix', null, null, 'Automatically fix failed items (if possible)');
}
public function handle(): int
{
try {
$checker = new CheckListHandler($this->input, $this->output);
$checker->runCheck(FIX_POLICY_PROMPT);
$checker->runCheck($this->input->getOption('auto-fix') ? FIX_POLICY_AUTOFIX : FIX_POLICY_PROMPT);
$this->output->writeln('<info>Doctor check complete !</info>');
} catch (\Throwable $e) {
$this->output->writeln('<error>' . $e->getMessage() . '</error>');

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SPC\command;
use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\exception\DownloaderException;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
@@ -18,6 +19,8 @@ use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand('download', 'Download required sources', ['fetch'])]
class DownloadCommand extends BaseCommand
{
use UnixSystemUtilTrait;
protected string $php_major_ver;
public function configure()
@@ -28,12 +31,13 @@ class DownloadCommand extends BaseCommand
$this->addOption('with-php', null, InputOption::VALUE_REQUIRED, 'version in major.minor format like 8.1', '8.1');
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
$this->addOption('all', 'A', null, 'Fetch all sources that static-php-cli needed');
$this->addOption('from-zip', 'Z', InputOption::VALUE_REQUIRED, 'Fetch from zip archive');
}
public function initialize(InputInterface $input, OutputInterface $output)
{
// --all 等于 "" "",也就是所有东西都要下载
if ($input->getOption('all') || $input->getOption('clean')) {
if ($input->getOption('all') || $input->getOption('clean') || $input->getOption('from-zip')) {
$input->setArgument('sources', '');
}
parent::initialize($input, $output);
@@ -66,6 +70,44 @@ class DownloadCommand extends BaseCommand
return 0;
}
// --from-zip
if ($path = $this->getOption('from-zip')) {
if (!file_exists($path)) {
logger()->critical('File ' . $path . ' not exist or not a zip archive.');
return 1;
}
// remove old download files first
if (is_dir(DOWNLOAD_PATH)) {
logger()->warning('You are doing some operations that not recoverable: removing directories below');
logger()->warning(DOWNLOAD_PATH);
logger()->alert('I will remove these dir after 5 seconds !');
sleep(5);
f_passthru((PHP_OS_FAMILY === 'Windows' ? 'rmdir /s /q ' : 'rm -rf ') . DOWNLOAD_PATH);
}
// unzip command check
if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) {
logger()->critical('Missing unzip command, you need to install it first !');
logger()->critical('You can use "bin/spc doctor" command to check and install required tools');
return 1;
}
// create downloads
try {
if (PHP_OS_FAMILY !== 'Windows') {
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($path));
}
// Windows TODO
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
throw new RuntimeException('.lock.json not exist in "downloads/"');
}
} catch (RuntimeException $e) {
logger()->critical('Extract failed: ' . $e->getMessage());
return 1;
}
logger()->info('Extract success');
return 0;
}
// Define PHP major version
$ver = $this->php_major_ver = $this->getOption('with-php') ?? '8.1';
define('SPC_BUILD_PHP_VERSION', $ver);

View File

@@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
namespace SPC\command;
use SPC\store\FileSystem;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
#[AsCommand('micro:combine', 'Combine micro.sfx and php code together')]
class MicroCombineCommand extends BaseCommand
{
public function configure()
{
$this->addArgument('file', InputArgument::REQUIRED, 'The php or phar file to be combined');
$this->addOption('with-micro', 'M', InputOption::VALUE_REQUIRED, 'Customize your micro.sfx file');
$this->addOption('with-ini-set', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'ini to inject into micro.sfx when combining');
$this->addOption('with-ini-file', 'N', InputOption::VALUE_REQUIRED, 'ini file to inject into micro.sfx when combining');
$this->addOption('output', 'O', InputOption::VALUE_REQUIRED, 'Customize your output binary file name');
}
public function handle(): int
{
// 0. Initialize path variables
$internal = FileSystem::convertPath(BUILD_ROOT_PATH . '/bin/micro.sfx');
$micro_file = $this->input->getOption('with-micro');
$file = $this->getArgument('file');
$ini_set = $this->input->getOption('with-ini-set');
$ini_file = $this->input->getOption('with-ini-file');
$target_ini = [];
$output = $this->input->getOption('output') ?? 'my-app';
$ini_part = '';
// 1. Make sure specified micro.sfx file exists
if ($micro_file !== null && !file_exists($micro_file)) {
$this->output->writeln('<error>The micro.sfx file you specified is incorrect or does not exist!</error>');
return 1;
}
// 2. Make sure buildroot/bin/micro.sfx exists
if ($micro_file === null && !file_exists($internal)) {
$this->output->writeln('<error>You haven\'t compiled micro.sfx yet, please use "build" command and "--build-micro" to compile phpmicro first!</error>');
return 1;
}
// 3. Use buildroot/bin/micro.sfx
if ($micro_file === null) {
$micro_file = $internal;
}
// 4. Make sure php or phar file exists
if (!is_file(FileSystem::convertPath($file))) {
$this->output->writeln('<error>The file to combine does not exist!</error>');
return 1;
}
// 5. Confirm ini files (ini-set has higher priority)
if ($ini_file !== null) {
// Check file exist first
if (!file_exists($ini_file)) {
$this->output->writeln('<error>The ini file to combine does not exist! (' . $ini_file . ')</error>');
return 1;
}
$arr = parse_ini_file($ini_file);
if ($arr === false) {
$this->output->writeln('<error>Cannot parse ini file</error>');
return 1;
}
$target_ini = array_merge($target_ini, $arr);
}
// 6. Confirm ini sets
if ($ini_set !== []) {
foreach ($ini_set as $item) {
$arr = parse_ini_string($item);
if ($arr === false) {
$this->output->writeln('<error>--with-ini-set parse failed</error>');
return 1;
}
$target_ini = array_merge($target_ini, $arr);
}
}
// 7. Generate ini injection parts
if (!empty($target_ini)) {
$ini_str = $this->encodeINI($target_ini);
logger()->debug('Injecting ini parts: ' . PHP_EOL . $ini_str);
$ini_part = "\xfd\xf6\x69\xe6";
$ini_part .= pack('N', strlen($ini_str));
$ini_part .= $ini_str;
}
// 8. Combine !
$output = FileSystem::isRelativePath($output) ? (WORKING_DIR . '/' . $output) : $output;
$file_target = file_get_contents($micro_file) . $ini_part . file_get_contents($file);
$result = file_put_contents($output, $file_target);
if ($result === false) {
$this->output->writeln('<error>Combine failed.</error>');
return 1;
}
// 9. chmod +x
chmod($output, 0755);
$this->output->writeln('<info>Combine success! Binary file: ' . $output . '</info>');
return 0;
}
private function encodeINI(array $array): string
{
$res = [];
foreach ($array as $key => $val) {
if (is_array($val)) {
$res[] = "[{$key}]";
foreach ($val as $skey => $sval) {
$res[] = "{$skey}=" . (is_numeric($sval) ? $sval : '"' . $sval . '"');
}
} else {
$res[] = "{$key}=" . (is_numeric($val) ? $val : '"' . $val . '"');
}
}
return implode("\n", $res);
}
}

View File

@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace SPC\command\dev;
use SPC\command\BaseCommand;
use SPC\store\Config;
use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand('dev:ext-all', 'Dev command')]
class AllExtCommand extends BaseCommand
{
public function configure()
{
}
public function handle(): int
{
$this->output->writeln(implode(',', array_keys(Config::getExts())));
return 0;
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace SPC\command\dev;
use SPC\command\BaseCommand;
use SPC\store\Config;
use SPC\util\DependencyUtil;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
#[AsCommand('dev:ext-info', 'Dev command')]
class ExtInfoCommand extends BaseCommand
{
public function configure()
{
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extension name you need to get info');
}
public function handle(): int
{
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions'))));
// 根据提供的扩展列表获取依赖库列表并编译
foreach ($extensions as $extension) {
$this->output->writeln('<comment>[ ' . $extension . ' ]</comment>');
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]);
$lib_suggests = Config::getExt($extension, 'lib-suggests', []);
$ext_suggests = Config::getExt($extension, 'ext-suggests', []);
$this->output->writeln("<info>lib-depends:\t" . implode(', ', $libraries) . '</info>');
$this->output->writeln("<info>lib-suggests:\t" . implode(', ', $lib_suggests) . '</info>');
$this->output->writeln("<info>ext-depends:\t" . implode(',', $not_included) . '</info>');
$this->output->writeln("<info>ext-suggests:\t" . implode(', ', $ext_suggests) . '</info>');
if (Config::getExt($extension, 'unix-only', false)) {
$this->output->writeln("<info>Unix only:\ttrue</info>");
}
$this->output->writeln('');
}
return 0;
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace SPC\command\dev;
use SPC\command\BaseCommand;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand('dev:php-ver', 'Dev command')]
class PhpVerCommand extends BaseCommand
{
public function initialize(InputInterface $input, OutputInterface $output)
{
$this->no_motd = true;
parent::initialize($input, $output);
}
public function handle(): int
{
// Find php from source/php-src
$file = SOURCE_PATH . '/php-src/main/php_version.h';
$result = preg_match('/#define PHP_VERSION "(\d+\.\d+\.\d+)"/', file_get_contents($file), $match);
if ($result === false) {
$this->output->writeln('<error>PHP source not found, maybe you need to extract first ?</error>');
return 1;
}
$this->output->writeln('<info>' . $match[1] . '</info>');
return 0;
}
}

View File

@@ -12,7 +12,8 @@ class AsCheckItem
public function __construct(
public string $item_name,
public ?string $limit_os = null,
public int $level = 100
public int $level = 100,
public bool $manual = false,
) {
}
}

View File

@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace SPC\doctor;
#[\Attribute(\Attribute::TARGET_METHOD)]
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class AsFixItem
{
public function __construct(public string $name)

View File

@@ -24,9 +24,20 @@ class CheckListHandler
* @throws FileSystemException
* @throws RuntimeException
*/
public function __construct(private InputInterface $input, private OutputInterface $output)
public function __construct(private InputInterface $input, private OutputInterface $output, bool $include_manual = false)
{
$this->loadCheckList();
$this->loadCheckList($include_manual);
}
public function runSingleCheck(string $item_name, int $fix_policy = FIX_POLICY_DIE): void
{
foreach ($this->check_list as $item) {
if ($item->item_name === $item_name) {
$this->check_list = [$item];
break;
}
}
$this->runCheck($fix_policy);
}
/**
@@ -44,7 +55,7 @@ class CheckListHandler
$this->output->writeln('skipped');
} elseif ($result instanceof CheckResult) {
if ($result->isOK()) {
$this->output->writeln('ok');
$this->output->writeln($result->getMessage() ?? 'ok');
continue;
}
// Failed
@@ -85,28 +96,30 @@ class CheckListHandler
* @throws RuntimeException
* @throws FileSystemException
*/
private function loadCheckList(): void
private function loadCheckList(bool $include_manual = false): void
{
foreach (FileSystem::getClassesPsr4(__DIR__ . '/item', 'SPC\\doctor\\item') as $class) {
$ref = new \ReflectionClass($class);
foreach ($ref->getMethods() as $method) {
$attr = $method->getAttributes(AsCheckItem::class);
if (isset($attr[0])) {
/** @var AsCheckItem $instance */
$instance = $attr[0]->newInstance();
$instance->callback = [new $class(), $method->getName()];
$this->check_list[] = $instance;
continue;
}
$attr = $method->getAttributes(AsFixItem::class);
if (isset($attr[0])) {
/** @var AsFixItem $instance */
$instance = $attr[0]->newInstance();
// Redundant fix item
if (isset($this->fix_map[$instance->name])) {
throw new RuntimeException('Redundant doctor fix item: ' . $instance->name);
$attr = $method->getAttributes();
foreach ($attr as $a) {
if (is_a($a->getName(), AsCheckItem::class, true)) {
/** @var AsCheckItem $instance */
$instance = $a->newInstance();
if (!$include_manual && $instance->manual) {
continue;
}
$instance->callback = [new $class(), $method->getName()];
$this->check_list[] = $instance;
} elseif (is_a($a->getName(), AsFixItem::class, true)) {
/** @var AsFixItem $instance */
$instance = $a->newInstance();
// Redundant fix item
if (isset($this->fix_map[$instance->name])) {
throw new RuntimeException('Redundant doctor fix item: ' . $instance->name);
}
$this->fix_map[$instance->name] = [new $class(), $method->getName()];
}
$this->fix_map[$instance->name] = [new $class(), $method->getName()];
}
}
}

View File

@@ -6,21 +6,21 @@ namespace SPC\doctor;
class CheckResult
{
public function __construct(private string $message = '', private string $fix_item = '', private array $fix_params = [])
public function __construct(private bool $ok, private ?string $message = null, private string $fix_item = '', private array $fix_params = [])
{
}
public static function fail(string $message, string $fix_item = '', array $fix_params = []): CheckResult
{
return new static($message, $fix_item, $fix_params);
return new static(false, $message, $fix_item, $fix_params);
}
public static function ok(): CheckResult
public static function ok(?string $message = null): CheckResult
{
return new static();
return new static(true, $message);
}
public function getMessage(): string
public function getMessage(): ?string
{
return $this->message;
}
@@ -37,7 +37,7 @@ class CheckResult
public function isOK(): bool
{
return empty($this->message);
return $this->ok;
}
public function setFixItem(string $fix_item = '', array $fix_params = [])

View File

@@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
namespace SPC\doctor\item;
use SPC\builder\linux\SystemUtil;
use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\doctor\AsCheckItem;
use SPC\doctor\AsFixItem;
use SPC\doctor\CheckResult;
use SPC\exception\RuntimeException;
class LinuxToolCheckList
{
use UnixSystemUtilTrait;
public const TOOLS_ALPINE = [
'make', 'bison', 'flex',
'git', 'autoconf', 'automake',
'tar', 'unzip', 'gzip',
'bzip2', 'cmake', 'gcc',
'g++', 'patch',
];
public const TOOLS_DEBIAN = [
'make', 'bison', 'flex',
'git', 'autoconf', 'automake',
'tar', 'unzip', 'gzip',
'bzip2', 'cmake', 'patch',
];
#[AsCheckItem('if necessary tools are installed', limit_os: 'Linux')]
public function checkCliTools(): ?CheckResult
{
$distro = SystemUtil::getOSRelease();
$required = match ($distro['dist']) {
'alpine' => self::TOOLS_ALPINE,
default => self::TOOLS_DEBIAN,
};
$missing = [];
foreach ($required as $cmd) {
if ($this->findCommand($cmd) === null) {
$missing[] = $cmd;
}
}
if (!empty($missing)) {
return match ($distro['dist']) {
'ubuntu', 'alpine', 'debian' => CheckResult::fail(implode(', ', $missing) . ' not installed on your system', 'install-linux-tools', [$distro, $missing]),
default => CheckResult::fail(implode(', ', $missing) . ' not installed on your system'),
};
}
return CheckResult::ok();
}
#[AsCheckItem('if necessary packages are installed', limit_os: 'Linux')]
public function checkSystemOSPackages(): ?CheckResult
{
$distro = SystemUtil::getOSRelease();
if ($distro['dist'] === 'alpine') {
// check linux-headers installation
if (!file_exists('/usr/include/linux/mman.h')) {
return CheckResult::fail('linux-headers not installed on your system', 'install-linux-tools', [$distro, ['linux-headers']]);
}
}
return CheckResult::ok();
}
#[AsFixItem('install-linux-tools')]
public function fixBuildTools(array $distro, array $missing): bool
{
$install_cmd = match ($distro['dist']) {
'ubuntu', 'debian' => 'apt install -y',
'alpine' => 'apk add',
default => throw new RuntimeException('Current linux distro is not supported for auto-install musl packages'),
};
$prefix = '';
if (get_current_user() !== 'root') {
$prefix = 'sudo ';
logger()->warning('Current user is not root, using sudo for running command');
}
try {
shell(true)->exec($prefix . $install_cmd . ' ' . implode(' ', $missing));
} catch (RuntimeException) {
return false;
}
return true;
}
}

View File

@@ -12,12 +12,12 @@ class OSCheckList
{
use UnixSystemUtilTrait;
#[AsCheckItem('if current os are supported', level: 999)]
#[AsCheckItem('if current OS are supported', level: 999)]
public function checkOS(): ?CheckResult
{
if (!in_array(PHP_OS_FAMILY, ['Darwin', 'Linux'])) {
return CheckResult::fail('Current OS is not supported');
}
return CheckResult::ok();
return CheckResult::ok(PHP_OS_FAMILY . ' ' . php_uname('m') . ', supported');
}
}

View File

@@ -439,6 +439,20 @@ class FileSystem
self::$_extract_hook[$name][] = $callback;
}
/**
* Check whether the path is a relative path (judging according to whether the first character is "/")
*
* @param string $path Path
*/
public static function isRelativePath(string $path): bool
{
// 适配 Windows 的多盘符目录形式
if (DIRECTORY_SEPARATOR === '\\') {
return !(strlen($path) > 2 && ctype_alpha($path[0]) && $path[1] === ':');
}
return strlen($path) > 0 && $path[0] !== '/';
}
private static function emitSourceExtractHook(string $name)
{
foreach ((self::$_extract_hook[$name] ?? []) as $hook) {

View File

@@ -48,9 +48,33 @@ class SourcePatcher
file_put_contents(SOURCE_PATH . '/php-src/ext/curl/config.m4', $file1 . "\n" . $files . "\n" . $file2);
}
// if ($builder->getExt('pdo_sqlite')) {
// FileSystem::replaceFile()
// }
if ($builder->getExt('memcache')) {
FileSystem::replaceFile(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
REPLACE_FILE_STR,
'if test -d $abs_srcdir/src ; then',
'if test -d $abs_srcdir/main ; then'
);
FileSystem::replaceFile(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
REPLACE_FILE_STR,
'export CPPFLAGS="$CPPFLAGS $INCLUDES"',
'export CPPFLAGS="$CPPFLAGS $INCLUDES -I$abs_srcdir/main"'
);
// add for in-tree building
file_put_contents(
SOURCE_PATH . '/php-src/ext/memcache/php_memcache.h',
<<<'EOF'
#ifndef PHP_MEMCACHE_H
#define PHP_MEMCACHE_H
extern zend_module_entry memcache_module_entry;
#define phpext_memcache_ptr &memcache_module_entry
#endif
EOF
);
}
}
public static function patchSwow(): bool
@@ -88,6 +112,9 @@ class SourcePatcher
if ($ssh2 = $builder->getExt('ssh2')) {
$patch[] = ['ssh2 patch', '/-lssh2/', $ssh2->getLibFilesString()];
}
if ($pgsql = $builder->getExt('pgsql')) {
$patch[] = ['pgsql patch', '/-lpq/', $pgsql->getLibFilesString()];
}
$patch[] = ['disable capstone', '/have_capstone="yes"/', 'have_capstone="no"'];
foreach ($patch as $item) {
logger()->info('Patching configure: ' . $item[0]);

View File

@@ -0,0 +1,5 @@
<?php
declare(strict_types=1);
assert(class_exists(NumberFormatter::class));