Compare commits

..

4 Commits

Author SHA1 Message Date
Jerry Ma
cecf204f7b Update README.md 2023-04-30 17:21:27 +08:00
Jerry
8391d3a60c Update README-en.md 2023-03-28 10:29:49 +08:00
Jerry
1a516a13dd Update README.md 2023-03-28 10:28:18 +08:00
Jerry
62bee67274 Update README.md 2023-03-18 17:48:46 +08:00
240 changed files with 1431 additions and 18388 deletions

13
.github/FUNDING.yml vendored
View File

@@ -1,13 +0,0 @@
# 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

@@ -1,106 +0,0 @@
name: CI on arm linux
on:
workflow_dispatch:
inputs:
operating-system:
required: true
description: Compile target arch (Linux only)
type: choice
options:
- aarch64
version:
required: true
description: php version to compile
default: '8.2'
type: choice
options:
- '8.2'
- '8.1'
- '8.0'
- '7.4'
build-cli:
description: build cli binary
default: true
type: boolean
build-micro:
description: build phpmicro binary
type: boolean
build-fpm:
description: build fpm binary
type: boolean
extensions:
description: extensions to compile (comma separated)
required: true
type: string
debug:
type: boolean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build:
name: build ${{ inputs.version }} on ${{ inputs.operating-system }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Cache downloaded source
- id: cache-download
uses: actions/cache@v3
with:
path: downloads
key: php-${{ inputs.version }}-dependencies
# With or without debug
- if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
# With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }}
run: echo "SPC_BUILD_CLI=--build-cli" >> $GITHUB_ENV
- if: ${{ inputs.build-micro == true }}
run: echo "SPC_BUILD_MICRO=--build-micro" >> $GITHUB_ENV
- if: ${{ inputs.build-fpm == true }}
run: echo "SPC_BUILD_FPM=--build-fpm" >> $GITHUB_ENV
# If there's no dependencies cache, fetch sources, with or without debug
- if: steps.cache-download.outputs.cache-hit != 'true'
run: SPC_USE_ARCH=${{ inputs.operating-system }} ./bin/spc-alpine-docker download --with-php=${{ inputs.version }} --all ${{ env.SPC_BUILD_DEBUG }}
# Run build command
- run: SPC_USE_ARCH=${{ inputs.operating-system }} ./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 }}
uses: actions/upload-artifact@v3
with:
name: php-${{ inputs.version }}-linux-${{ inputs.operating-system }}
path: buildroot/bin/php
# Upload micro self-extracted executable
- if: ${{ inputs.build-micro == true }}
uses: actions/upload-artifact@v3
with:
name: micro-${{ inputs.version }}-linux-${{ inputs.operating-system }}
path: buildroot/bin/micro.sfx
# Upload fpm executable
- if: ${{ inputs.build-fpm == true }}
uses: actions/upload-artifact@v3
with:
name: php-fpm-${{ inputs.version }}-linux-${{ inputs.operating-system }}
path: buildroot/bin/php-fpm
# Upload extensions metadata
- uses: actions/upload-artifact@v3
with:
name: license-files
path: buildroot/license/
- uses: actions/upload-artifact@v3
with:
name: build-meta
path: |
buildroot/build-extensions.json
buildroot/build-libraries.json

View File

@@ -1,112 +0,0 @@
name: CI on x86_64 linux
on:
workflow_dispatch:
inputs:
version:
required: true
description: php version to compile
default: '8.2'
type: choice
options:
- '8.2'
- '8.1'
- '8.0'
- '7.4'
build-cli:
description: build cli binary
default: true
type: boolean
build-micro:
description: build phpmicro binary
type: boolean
build-fpm:
description: build fpm binary
type: boolean
extensions:
description: extensions to compile (comma separated)
required: true
type: string
debug:
type: boolean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build:
name: build ${{ inputs.version }} on Linux x86_64
runs-on: ubuntu-latest
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 --classmap-authoritative
# Cache downloaded source
- id: cache-download
uses: actions/cache@v3
with:
path: downloads
key: php-${{ inputs.version }}-dependencies
# With or without debug
- if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
# With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }}
run: echo "SPC_BUILD_CLI=--build-cli" >> $GITHUB_ENV
- if: ${{ inputs.build-micro == true }}
run: echo "SPC_BUILD_MICRO=--build-micro" >> $GITHUB_ENV
- if: ${{ inputs.build-fpm == true }}
run: echo "SPC_BUILD_FPM=--build-fpm" >> $GITHUB_ENV
# 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-alpine-docker download --with-php=${{ inputs.version }} --all ${{ env.SPC_BUILD_DEBUG }}
# Run build command
- 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 }}
uses: actions/upload-artifact@v3
with:
name: php-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
path: buildroot/bin/php
# Upload micro self-extracted executable
- if: ${{ inputs.build-micro == true }}
uses: actions/upload-artifact@v3
with:
name: micro-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
path: buildroot/bin/micro.sfx
# Upload fpm executable
- if: ${{ inputs.build-fpm == true }}
uses: actions/upload-artifact@v3
with:
name: php-fpm-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
path: buildroot/bin/php-fpm
# Upload extensions metadata
- uses: actions/upload-artifact@v3
with:
name: license-files
path: buildroot/license/
- uses: actions/upload-artifact@v3
with:
name: build-meta
path: |
buildroot/build-extensions.json
buildroot/build-libraries.json

View File

@@ -1,117 +0,0 @@
name: CI on x86_64 macOS
on:
workflow_dispatch:
inputs:
version:
required: true
description: php version to compile
default: '8.2'
type: choice
options:
- '8.2'
- '8.1'
- '8.0'
- '7.4'
build-cli:
description: build cli binary
default: true
type: boolean
build-micro:
description: build phpmicro binary
type: boolean
build-fpm:
description: build fpm binary
type: boolean
extensions:
description: extensions to compile (comma separated)
required: true
type: string
debug:
type: boolean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build:
name: build ${{ inputs.version }} on macOS x86_64
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
# Install macOS missing packages and mark os suffix
- run: |
brew install automake gzip
echo "SPC_BUILD_OS=macos" >> $GITHUB_ENV
# 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 --classmap-authoritative
# Cache downloaded source
- id: cache-download
uses: actions/cache@v3
with:
path: downloads
key: php-${{ inputs.version }}-dependencies
# With or without debug
- if: inputs.debug == true
run: echo "SPC_BUILD_DEBUG=--debug" >> $GITHUB_ENV
# With target select: cli, micro or both
- if: ${{ inputs.build-cli == true }}
run: echo "SPC_BUILD_CLI=--build-cli" >> $GITHUB_ENV
- if: ${{ inputs.build-micro == true }}
run: echo "SPC_BUILD_MICRO=--build-micro" >> $GITHUB_ENV
- if: ${{ inputs.build-fpm == true }}
run: echo "SPC_BUILD_FPM=--build-fpm" >> $GITHUB_ENV
# 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=${{ 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 }}
# Upload cli executable
- if: ${{ inputs.build-cli == true }}
uses: actions/upload-artifact@v3
with:
name: php-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
path: buildroot/bin/php
# Upload micro self-extracted executable
- if: ${{ inputs.build-micro == true }}
uses: actions/upload-artifact@v3
with:
name: micro-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
path: buildroot/bin/micro.sfx
# Upload fpm executable
- if: ${{ inputs.build-fpm == true }}
uses: actions/upload-artifact@v3
with:
name: php-fpm-${{ inputs.version }}-${{ env.SPC_BUILD_OS }}
path: buildroot/bin/php-fpm
# Upload extensions metadata
- uses: actions/upload-artifact@v3
with:
name: license-files
path: buildroot/license/
- uses: actions/upload-artifact@v3
with:
name: build-meta
path: |
buildroot/build-extensions.json
buildroot/build-libraries.json

67
.github/workflows/build-php.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: Build PHP
on:
push:
branches: [ master ]
paths:
- ".github/workflows/**.yml"
- "docker/**"
jobs:
integration:
name: Build PHP ${{ matrix.php-versions }} for ${{ matrix.arch }}
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: [ "7.4.30", "8.0.23", "8.1.10", "8.2.0" ]
arch: [ "x86_64", "aarch64", "armv7l" ]
steps:
- uses: actions/checkout@v2
- name: Check Dockerfile to ${{ matrix.arch }}
run: |
cd docker/
if [[ "${{ matrix.arch }}" != "x86_64" ]]; then
if [[ "${{ matrix.arch }}" = "armv7l" ]]; then
sed -ie 's/alpine:latest/multiarch\/alpine:armv7-latest-stable/g' Dockerfile
else
sed -ie 's/alpine:latest/multiarch\/alpine:${{ matrix.arch }}-v3.16/g' Dockerfile
fi
docker run --rm --privileged multiarch/qemu-user-static:register --reset
fi
- name: Build micro and PHP distribution ${{ matrix.php-versions }} for ${{ matrix.arch }}
id: buildphp
run: |
cd docker/ && docker build . --tag static-php --build-arg USE_BACKUP_ADDRESS=yes && \
mkdir ../dist && \
docker run --rm -v $(pwd)/../dist:/dist/ static-php build-php original ${{ matrix.php-versions }} all /dist/
- name: Fail if anything failed
if: steps.buildphp == 'failure'
run: |
false
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: static-php-cli_${{ matrix.php-versions }}_${{ matrix.arch }}
path: |
dist
- name: Pack PHP ${{ matrix.php-versions }} to archive
run: |
cd dist
tar -zcvf "php-${{ matrix.php-versions }}-static-bin-${{ matrix.arch }}.tar.gz" ./php && rm ./php
if [ -f "./micro.sfx" ]; then
tar -zcvf "micro-${{ matrix.php-versions }}-${{ matrix.arch }}.tar.gz" ./micro.sfx && rm ./micro.sfx
fi
- name: Deploy to Zhamao Server
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SERVER_SECRET_KEY }}
ARGS: "-rltgoDzvO"
SOURCE: "dist/"
REMOTE_HOST: ${{ secrets.DEPLOY_SERVER_HOST }}
REMOTE_PORT: ${{ secrets.DEPLOY_SERVER_PORT }}
REMOTE_USER: ${{ secrets.DEPLOY_SERVER_USER }}
TARGET: ${{ secrets.DEPLOY_SERVER_TARGET }}
- name: Remove dist directory
run: |
rm -rf dist/
docker images | grep -v REPOSITORY | awk '{print $3}' | xargs docker rmi --force

View File

@@ -1,40 +0,0 @@
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

@@ -1,47 +0,0 @@
name: Upload SPC Binary (Release)
on:
release:
types:
- published
workflow_dispatch:
jobs:
build-release-artifacts:
name: "Upload SPC Binary (Release)"
runs-on: ubuntu-latest
strategy:
matrix:
operating-system:
- "linux-x86_64"
- "macos-x86_64"
- "linux-aarch64"
- "macos-aarch64"
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
- name: Reuse static-php-cli-hosted artifacts
uses: dawidd6/action-download-artifact@v2
with:
repo: crazywhalecc/static-php-cli-hosted
branch: master
workflow: build-spc-release.yml
name: "spc-${{ matrix.operating-system }}"
- name: "Archive Executable"
run: |
tar -czf spc-${{ matrix.operating-system }}.tar.gz spc
echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV
- name: upload binaries to release
uses: softprops/action-gh-release@v1
if: ${{startsWith(github.ref, 'refs/tags/') }}
with:
files: ${{ env.filename }}
- name: "Upload Artifact"
uses: actions/upload-artifact@v3
with:
path: spc
name: spc-${{ matrix.operating-system }}

View File

@@ -1,98 +0,0 @@
name: Tests
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
php-cs-fixer:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: curl, openssl, mbstring
ini-values: memory_limit=-1
tools: pecl, composer, php-cs-fixer
- name: Run PHP-CS-Fixer fix
run: php-cs-fixer fix --dry-run --diff --ansi
phpstan:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: curl, openssl, mbstring
ini-values: memory_limit=-1
tools: composer
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-phpstan-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-phpstan-
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Run phpstan
run: vendor/bin/phpstan analyse
phpunit:
name: PHPUnit (PHP ${{ matrix.php }})
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
include:
- php: '8.1'
- php: '8.2'
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php }}"
tools: pecl, composer
extensions: curl, openssl, mbstring
ini-values: memory_limit=-1
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Run PHPUnit tests
run: |
vendor/bin/phpunit tests/ --no-coverage

25
.gitignore vendored
View File

@@ -3,28 +3,3 @@ runtime/
docker/libraries/ docker/libraries/
docker/extensions/ docker/extensions/
docker/source/ docker/source/
# Vendor files
/vendor/
# default source extract directory
/source/
# default source download directory
/downloads/
# default source build root directory
/buildroot/
# tools cache files
.php-cs-fixer.cache
.phpunit.result.cache
# exclude self-runtime
/bin/*
!/bin/spc
!/bin/setup-runtime
!/bin/spc-alpine-docker
# default test directory
/tests/var/

View File

@@ -1,69 +0,0 @@
<?php
declare(strict_types=1);
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PSR12' => true,
'@Symfony' => true,
'@PhpCsFixer' => true,
'array_syntax' => [
'syntax' => 'short',
],
'list_syntax' => [
'syntax' => 'short',
],
'concat_space' => [
'spacing' => 'one',
],
'blank_line_before_statement' => [
'statements' => [
'declare',
],
],
'ordered_imports' => [
'imports_order' => [
'class',
'function',
'const',
],
'sort_algorithm' => 'alpha',
],
'single_line_comment_style' => [
'comment_types' => [
],
],
'yoda_style' => [
'always_move_variable' => false,
'equal' => false,
'identical' => false,
],
'multiline_whitespace_before_semicolons' => [
'strategy' => 'no_multi_line',
],
'constant_case' => [
'case' => 'lower',
],
'class_attributes_separation' => true,
'combine_consecutive_unsets' => true,
'declare_strict_types' => true,
'linebreak_after_opening_tag' => true,
'lowercase_static_reference' => true,
'no_useless_else' => true,
'no_unused_imports' => true,
'not_operator_with_successor_space' => false,
'not_operator_with_space' => false,
'ordered_class_elements' => true,
'php_unit_strict' => false,
'phpdoc_separation' => false,
'single_quote' => true,
'standardize_not_equals' => true,
'multiline_comment_opening_closing' => true,
'phpdoc_summary' => false,
'php_unit_test_class_requires_covers' => false,
'phpdoc_var_without_name' => false,
])
->setFinder(
PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests/SPC'])
);

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2022-2023 Jerry Ma Copyright (c) 2022 Jerry Ma
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,257 +1,187 @@
# static-php-cli # static-php-cli
Build single static PHP binary, with PHP project together, with popular extensions included. Compile A Statically Linked PHP With Swoole and other Popular Extensions.
The project name is static-php-cli, but it actually supports cli, fpm, micro and embed SAPI 😎 Compile A Single Binary With PHP Code.
Compile a purely static php-cli binary file with various extensions to make PHP applications more portable! (cli SAPI) [![version](https://img.shields.io/badge/version-1.5.2-green.svg)]()
![Build Actions](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build-php.yml/badge.svg)
<img width="600" alt="2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png"> ## Refactoring
You can also use the micro binary file to combine php binary and php source code into one for distribution! The current project is under reconstruction, and this branch is an older version.
This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro). (micro SAPI) The refactored version supports many new features. The following is the current progress of refactoring:
<img width="600" alt="2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png"> - **Discussionhttps://github.com/crazywhalecc/static-php-cli/discussions/29**
- **Branch[refactor](https://github.com/crazywhalecc/static-php-cli/tree/refactor)**
[![Version](https://img.shields.io/badge/Version-2.0--rc5-pink.svg?style=flat-square)]() - **Bugs and TODOshttps://github.com/crazywhalecc/static-php-cli/issues/32**
[![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-55+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]()
## Compilation Requirements ## Compilation Requirements
Yes, this project is written in PHP, pretty funny. - Supporting architecture: `x86_64`, `arm64(aarch64)`, `armv7(armv7l)`
But static-php-cli runtime only requires an environment above PHP 8.1 and `mbstring`, `pcntl` extension. - Docker required (or alpine linux 3.13+)
- PHP version from 7.2 to 8.1
- Micro Package requires PHP >= 8.0
Here is the architecture support status, where `CI` represents support for GitHub Action builds, ## Runtime Requirements
`Local` represents support for local builds, and blank represents not currently supported.
| | x86_64 | aarch64 | Linux
|---------|-----------|-----------|
| macOS | CI, Local | Local |
| Linux | CI, Local | CI, Local |
| Windows | | |
> macOS-arm64 is not supported for GitHub Actions, if you are going to build on arm, you can build it manually on your own machine. ## Usage
Currently supported PHP versions for compilation are: `7.3`, `7.4`, `8.0`, `8.1`, `8.2`, `8.3`. 1. Directly download static binary from this link or [Actions uploaded artifacts](https://github.com/crazywhalecc/static-php-cli/actions).
## Docs <https://dl.zhamao.xin/php-bin/file/>
docs here: <https://static-php.dev>. 2. Use fast install script `install-runtime.sh` to download static php and composer distribution into `runtime/` directory
## Simple Usage But this script has some Chinese comments and prompts, if you cannot understand or have to use it in English, I will make an pure international version! :)
Please first select the extension you want to compile based on the extension list below.
### Direct Download
If you don't compile yourself, you can download pre-compiled artifact from Actions, or from self-hosted server: [Here](https://dl.static-php.dev/static-php-cli/common/)
> self-hosted server contains extensions: `bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip`
### Supported Extensions
[Supported Extension List](https://static-php.dev/en/guide/extensions.html)
> If there is no extension you need here, you can submit an issue.
### GitHub Actions Build
Use GitHub Action to easily build a statically compiled PHP and phpmicro,
and at the same time define the extensions to be compiled by yourself.
1. Fork me.
2. Go to the Actions of the project and select `CI`.
3. Select `Run workflow`, fill in the PHP version you want to compile, the target type, and the list of extensions. (extensions comma separated, e.g. `bcmath,curl,mbstring`)
4. After waiting for about a period of time, enter the corresponding task and get `Artifacts`.
If you enable `debug`, all logs will be output at build time, including compiled logs, for troubleshooting.
- When using ubuntu-latest, it will build linux-x86_64 binary.
- When using macos-latest, it will build macOS-x86_64 binary.
### Manual Build
Clone repo first:
```bash ```bash
git clone https://github.com/crazywhalecc/static-php-cli.git bash -c "`curl -fsSL https://raw.githubusercontent.com/crazywhalecc/static-php-cli/master/install-runtime.sh`"
``` ```
If you have not installed php on your system, you can use package management to install PHP (such as brew, apt, yum, apk etc.). ## Packing PHP Code into a Static Binary
And you can also download single-file php binary and composer using command `bin/setup-runtime`. From v1.5.0, we support packing PHP code into a static binary. You can pack your PHP code into a static binary by micro.
The PHP runtime for static-php-cli itself will be downloaded at `bin/php`, and composer is at `bin/composer`.
```bash You can directly download `micro-` prefix file, untar it and you will get file `micro.sfx`.
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 Here's a simple example to use it:
./bin/php bin/spc
# Use composer
./bin/php bin/composer
```
Basic usage for building php and micro with some extensions:
```bash
cd static-php-cli
composer update
chmod +x bin/spc
# Check system tool dependencies, fix them automatically
./bin/spc doctor
# fetch all libraries
./bin/spc fetch --all
# with bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl extension, build both CLI and phpmicro SAPI
./bin/spc build bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl --build-cli --build-micro
```
You can also use the parameter `--with-php=x.y` to specify the downloaded PHP version, currently supports 7.4 ~ 8.2:
```bash
# Using PHP >= 8.0 is recommended, because PHP7 cannot use phpmicro
./bin/spc fetch --with-php=8.2 --all
```
Now we support `cli`, `micro`, `fpm`, you can use one or more of the following parameters to specify the compiled SAPI:
- `--build-cli`: build static cli executable
- `--build-micro`: build static phpmicro self-extracted executable
- `--build-fpm`: build static fpm binary
- `--build-embed`: build embed (libphp)
- `--build-all`: build all
If anything goes wrong, use `--debug` option to display full terminal output:
```bash
./bin/spc build openssl,pcntl,mbstring --debug --build-all
./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.
When using the parameter `--build-cli` or `--build-all`,
the final compilation result will output a binary file named `./php`,
which can be distributed and used directly.
This file will be located in the directory `buildroot/bin/`, copy it out for use.
```bash
cd buildroot/bin/
./php -v # check version
./php -m # check extensions
./php your_code.php # run your php code
./php your_project.phar # run your phar (project archive)
```
### micro.sfx Usage
> 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.
When using the parameter `--build-all` or `--build-micro`,
the final compilation result will output a file named `./micro.sfx`,
which needs to be used with your PHP source code like `code.php`.
This file will be located in the path `buildroot/bin/micro.sfx`, simply copy it out for use.
Prepare your project source code, which can be a single PHP file or a Phar file, for use.
```bash ```bash
echo "<?php echo 'Hello world' . PHP_EOL;" > code.php echo "<?php echo 'Hello world' . PHP_EOL;" > code.php
cat micro.sfx code.php > single-app && chmod +x single-app cat micro.sfx code.php > single-app && chmod +x single-app
./single-app ./single-app
# If packing a PHAR file, replace code.php with the Phar file path. # If packing phar into a static binary, just change code.php to your phar path.
```
> Note: It means that your PHP code won't be compiled and you can't protect your source code by using micro!
>
> If you are looking for compiling PHP code or encrypting code, here's not your solution.
>
> Special thanks: <https://github.com/dixyes/phpmicro>
## Compiling
Here's help command to compile it yourself:
```bash
git clone https://github.com/crazywhalecc/static-php-cli.git
cd static-php-cli/docker
docker build -t static-php . --build-arg USE_BACKUP_ADDRESS=yes
# Making a directory to put binary files
mkdir dist
# It will ask you for PHP version, extensions, and compile static binaries
docker run --rm -v $(pwd)/dist:/dist/ -it static-php build-php
``` ```
> In some cases, PHAR files may not run in a micro environment. After compilation you can use command to get static php binary file.
### php-fpm Usage ```bash
cd dist
file ./php
```
When using the parameter `--build-all` or `--build-fpm`, If you don't want to use docker, a single script for compiling in **Alpine Linux**:
the final compilation result will output a file named `./php-fpm`,
This file will be located in the path `buildroot/bin/`, simply copy it out for use.
In normal Linux distributions and macOS systems, the package manager will automatically generate a default fpm configuration file after installing php-fpm. ```bash
Because php-fpm must specify a configuration file before running, the php-fpm compiled by this project will not have any configuration files, so you need to write `php-fpm.conf` and `pool.conf` configuration files yourself. cd docker
# Change PHP Version
export VER_PHP="8.1.7"
# Use Original download link (Default is China mainland mirror link, for others please use 'yes' for original link)
export USE_BACKUP="yes"
./fast-compiler.sh
```
Specifying `php-fpm.conf` can use the command parameter `-y`, for example: `./php-fpm -y php-fpm.conf`. To customize PHP extensions, edit `docker/extensions.txt` file, and rules below:
- Use `^` as deselect, to mark not install. Use `#` as comments.
- extensions name uses lower case, and default file contains all supported extensions, if u need other extensions, consider write an Issue
### Embed Usage ## Supported PHP extensions
| Support | PHP Ext Name | Version | Comments |
| ------- | ------------ | ------- | ---------------------------------------- |
| yes | bcmath | * | |
| yes | calendar | * | |
| yes | ctype | * | |
| yes | curl | * | |
| yes | dom | * | |
| yes | event | >=3.0.8 | author's bitbucket version, not pecl |
| yes | exif | * | |
| yes | filter | * | |
| yes | fileinfo | * | |
| yes | gd | * | |
| yes | hash | * | |
| yes | iconv | * | |
| yes | inotify | 3.0.0 | |
| yes | json | * | |
| yes | libxml | * | |
| yes | mbstring | * | |
| yes | mongodb | >=1.9.1 | not tested |
| | mysqli | | |
| yes | mysqlnd | * | |
| yes | openssl | * | |
| yes | pcntl | * | |
| yes | pdo | * | |
| yes | pdo_mysql | * | |
| yes | pdo_sqlite | * | |
| | pdo_pgsql | * | |
| yes | phar | * | |
| yes | posix | * | |
| yes, not compiled | protobuf | * | Not compiled and enabled as default |
| yes | readline | * | Not support `./php -a` |
| yes | redis | * | |
| yes | shmop | * | |
| yes | simplexml | * | |
| yes | soap | * | |
| yes | sockets | * | |
| yes | sqlite3 | * | |
| yes | swoole | >=4.6.6 | support mysqlnd, sockets, openssl, redis |
| yes | tokenizer | * | |
| yes | xml | * | |
| yes | xmlreader | * | |
| yes | xmlwriter | * | |
| yes | zip | * | not support `bzip2`, `lzma` compression |
| yes | zlib | * | |
When using the project parameters `--build-embed` or `--build-all`, ## Customization
the final compilation result will output a `libphp.a`, `php-config` and a series of header files, - If you are going to run without prompt, Just add it to the end of `docker run xxx` cmd according to the parameters given below.
stored in `buildroot/`. You can introduce them in your other projects.
If you know [embed SAPI](https://github.com/php/php-src/tree/master/sapi/embed), you should know how to use it. > 1st parameter `original` represents that you are using global original download address to fetch dependencies, if you are in mainland China, use `mirror`.
You may require the introduction of other libraries during compilation, >
you can use `buildroot/bin/php-config` to obtain the compile-time configuration. > 2nd parameter `8.1.7` is your PHP version you are compiling.
>
> 3rd parameter `all` represents that you will compile all supported extensions.
>
> 4th parameter `/dist/` is your binary output directory.
>
> For example, `docker run --rm -v $(pwd)/dist:/dist/ -it static-php build-php original 8.1.7 all /dist/`
For an advanced example of how to use this feature, take a look at [how to use it to build a static version of FrankenPHP](https://github.com/dunglas/frankenphp/blob/main/docs/static.md). - `docker/extensions.txt` edit extensions.
- `docker/compile-php.sh` file `php_compile_args` function to adjust PHP configure arguments.
- `docker/check-extensions.sh` file `check_in_configure` function to adjust extensions' configure arguments.
- `docker/config.json` edit extensions and dependencies version and download links.
## Contribution ## Current Issue
- [X] Not support event(libevent), because of its `config.m4` and code.
- [ ] Swoole not support `--enable-swoole-curl`.
- [X] Not support readline, maybe caused by ncurses library.
- [X] Not support curl (solved)
- [X] Customize extensions to compile
- [X] php.ini integration
- [X] i18n (including README and scripts)
If the extension you need is missing, you can create an issue. ## Running preview
If you are familiar with this project, you are also welcome to initiate a pull request.
The basic principles for contributing are as follows: ### Using static binary
- This project uses php-cs-fixer and phpstan as code formatting tools. Before contributing, please run `composer analyse` and `composer cs-fix` on the updated code. <img width="881" alt="未命名" src="https://user-images.githubusercontent.com/20330940/168441751-e62cb8d4-a3c8-42d9-b34e-d804b39756a1.png">
- If other open source libraries are involved, the corresponding licenses should be provided.
Also, configuration files should be sorted using the command `sort-config` after modification.
For more information about sorting commands, see the documentation.
- Naming conventions should be followed, such as using the extension name registered in PHP for the extension name itself,
and external library names should follow the project's own naming conventions. For internal logic functions, class names, variables, etc.,
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). ### Using swoole application packed with micro
Part of the English document is written by me, and part is translated by Google, <img width="937" alt="all" src="https://user-images.githubusercontent.com/20330940/168557743-b8f92263-712f-490e-9fe0-831597741595.png">
and there may be inaccurate descriptions, strange or offensive expressions.
If you are a native English speaker, some corrections to the documentation are welcome.
## References
## Sponsor this project - <https://blog.terrywh.net/post/2019/php-static-openssl/>
- <https://stackoverflow.com/a/37245653>
You can sponsor my project on [this page](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md). - <http://blog.gaoyuan.xyz/2014/04/09/statically-compile-php/>
## Open-Source License
This project itself is based on MIT License,
some newly added extensions and dependencies may originate from the following projects (including but not limited to),
and the headers of these code files will also be given additional instructions LICENSE and AUTHOR:
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs) (Mulun Permissive License)
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli) (Apache 2.0 LICENSE+SWOOLE-CLI LICENSE)
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 `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
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.dev) of the documentation to contribute code or documentation.

339
README.md
View File

@@ -1,166 +1,54 @@
# static-php-cli # static-php-cli
Compile A Statically Linked PHP With Swoole and other Extensions. [English README](README-en.md)
Build single static PHP binary, with PHP project together, with popular extensions included. 编译纯静态的 PHP Binary 二进制文件,带有各种扩展,让 PHP-cli 应用变得更便携!
**If you are using English, see [English README](README-en.md).** 同时可以使用 micro 二进制文件,将 PHP 源码和 PHP 二进制构建为一个文件分发!
编译纯静态的 PHP Binary 二进制文件,带有各种扩展,让 PHP-cli 应用变得更便携cli SAPI 注:只能编译 CLI 模式,暂不支持 CGI 和 FPM 模式
<img width="600" alt="截屏2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png"> [![版本](https://img.shields.io/badge/script--version-1.5.2-green.svg)]()
[![License](https://img.shields.io/badge/License-MIT-blue.svg)]()
![Build Actions](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build-php.yml/badge.svg)
同时可以使用 micro 二进制文件,将 PHP 源码和 PHP 二进制构建为一个文件分发!(由 [dixyes/phpmicro](https://github.com/dixyes/phpmicro) 提供支持micro SAPI ## 重构
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png"> 本分支为旧版。重构版支持很多新特性。下面是目前重构的进度:
[![Version](https://img.shields.io/badge/Version-2.0--rc5-pink.svg?style=flat-square)]() - **关于重构版的讨论https://github.com/crazywhalecc/static-php-cli/discussions/29**
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]() - **重构的分支:[refactor](https://github.com/crazywhalecc/static-php-cli/tree/refactor)**
[![](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://github.com/crazywhalecc/static-php-cli/issues/32**
[![](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-55+-yellow.svg?style=flat-square)]()
[![](https://img.shields.io/github/search/crazywhalecc/static-php-cli/TODO?label=TODO%20Counter&style=flat-square)]()
> 项目名称是 static-php-cli但其实支持 cli、fpm、micro 和 embed SAPI 😎 **目前重构版已经完成本分支的所有扩展,并且还支持更多扩展**
## 编译环境需求 ## 编译环境需求
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。 - 目前支持 arm64、x86_64、armv7l 架构
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 mbstring、pcntl 扩展和 PHP 版本大于等于 8.1 即可。 - 需要 Docker也可以直接在 Alpine Linux 上使用)
- 脚本支持编译的 PHP 版本7.2 ~ 8.1
下面是架构支持情况,`CI` 代表支持 GitHub Action 构建,`Local` 代表支持本地构建,空 代表暂不支持。 ## 运行环境需求
| | x86_64 | aarch64 | Linux
|---------|-----------|-----------|
| macOS | CI, Local | Local |
| Linux | CI, Local | CI, Local |
| Windows | | |
> macOS-arm64 因 GitHub 暂未提供 arm runner如果要构建 arm 二进制,可以使用手动构建。 ## 直接使用
目前支持编译的 PHP 版本为:`7.3``7.4``8.0``8.1``8.2``8.3` 1. 可以直接下面的托管服务器或到 `Actions` 找到最新的构建项目下载 Actions 构建的文件
## 文档 <https://dl.zhamao.xin/php-bin/file/>
点击这里查看文档:<https://static-php.dev>。 2. 可以直接使用快速脚本 `install-runtime.sh`,将静态 PHP 二进制及 Composer 下载到当前目录的 `runtime/` 子目录下:
## 使用
请先根据下方扩展列表选择你要编译的扩展。
### 自托管直接下载
如果你不想自行编译,可以从本项目现有的 Action 下载 Artifact也可以从自托管的服务器下载[进入](https://dl.static-php.dev/static-php-cli/common/)
> 自托管的服务器默认包含的扩展有:`bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,xml,mbstring,mbregex,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,session,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip`
### 支持的扩展情况
[扩展支持列表](https://static-php.dev/zh/guide/extensions.html)
> 如果这里没有你需要的扩展,可以提交 Issue。
### 使用 Actions 构建
使用 GitHub Action 可以方便地构建一个静态编译的 PHP 和 phpmicro同时可以自行定义要编译的扩展。
1. Fork 本项目。
2. 进入项目的 Actions选择 CI。
3. 选择 `Run workflow`,填入你要编译的 PHP 版本、目标类型、扩展列表。(扩展列表使用英文逗号分割,例如 `bcmath,curl,mbstring`
4. 等待大约一段时间后,进入对应的任务中,获取 `Artifacts`
如果你选择了 `debug`,则会在构建时输出所有日志,包括编译的日志,以供排查错误。
### 手动构建
先克隆本项目:
```bash ```bash
git clone https://github.com/crazywhalecc/static-php-cli.git # 可以使用 export ZM_DOWN_PHP_VERION=8.0 来切换 PHP 版本
bash <(curl -fsSL https://dl.zhamao.xin/php-bin/install-runtime.sh)
``` ```
如果你本机没有安装 PHP你需要先使用包管理例如 brew、apt、yum、apk 等)安装 php。 ## PHP 代码打包使用
你也可以通过 `bin/setup-runtime` 命令下载静态编译好的 php-cli 和 Composer。下载的 php 和 Composer 将保存为 `bin/php``bin/composer` v1.5.0 脚本开始,脚本新增了对 PHP 代码打包的支持,可以将 PHP 代码打包为一个文件分发,方便在 Linux 系统使用。(仅支持 PHP >= 8.0
```bash 1. 可以直接在上面的下载链接中下载 `micro-` 开头的文件并解压,获得 `micro.sfx` 文件后,使用以下命令和 PHP 源码或 PHAR 结合:
cd static-php-cli
chmod +x bin/setup-runtime
./bin/setup-runtime
# 使用独立的 php 运行 static-php-cli
./bin/php bin/spc
# 使用 composer
./bin/php bin/composer
```
下面是使用 static-php-cli 编译静态 php 和 micro 的基础用法:
```bash
# 克隆本项目
cd static-php-cli
composer update
chmod +x bin/spc
# 检查环境依赖,并根据提示的命令安装缺失的编译工具
./bin/spc doctor
# 拉取所有依赖库
./bin/spc fetch --all
# 构建包含 bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl 扩展的 php-cli 和 micro.sfx
./bin/spc build "bcmath,openssl,tokenizer,sqlite3,pdo_sqlite,ftp,curl" --build-cli --build-micro
```
你也可以使用参数 `--with-php=x.y` 来指定下载的 PHP 版本,目前支持 7.3 ~ 8.3
```bash
# 优先考虑使用 >= 8.0 的 PHP 版本,因为 phpmicro 不支持在 PHP7 中构建
./bin/spc fetch --with-php=8.2 --all
```
其中,目前支持构建 climicrofpm 三种静态二进制,使用以下参数的一个或多个来指定编译的 SAPI
- `--build-cli`:构建 cli 二进制
- `--build-micro`:构建 phpmicro 自执行二进制
- `--build-fpm`:构建 fpm
- `--build-embed`:构建 embedlibphp
- `--build-all`:构建所有
如果出现了任何错误,可以使用 `--debug` 参数来展示完整的输出日志,以供排查错误:
```bash
./bin/spc build openssl,pcntl,mbstring --debug --build-all
./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 语言编译后的单个可移植的二进制文件。
采用参数 `--build-cli``--build-all` 参数时,最后编译结果会输出一个 `./php` 的二进制文件,此文件可分发、可直接使用。
该文件编译后会存放在 `buildroot/bin/` 目录中,名称为 `php`,拷贝出来即可。
```bash
cd buildroot/bin/
./php -v # 检查版本
./php -m # 检查编译的扩展
./php your_code.php # 运行代码
./php your_project.phar # 运行打包为 phar 单文件的项目
```
### 使用 micro.sfx
> phpmicro 是一个提供自执行二进制 PHP 的项目,本项目依赖 phpmicro 进行编译自执行二进制。详见 [dixyes/phpmicro](https://github.com/dixyes/phpmicro)。
采用项目参数 `--build-micro``--build-all` 时,最后编译结果会输出一个 `./micro.sfx` 的文件,此文件需要配合你的 PHP 源码使用。
该文件编译后会存放在 `buildroot/bin/` 目录中,拷贝出来即可。
使用时应准备好你的项目源码文件,可以是单个 PHP 文件,也可以是 Phar 文件。
```bash ```bash
echo "<?php echo 'Hello world' . PHP_EOL;" > code.php echo "<?php echo 'Hello world' . PHP_EOL;" > code.php
@@ -170,55 +58,168 @@ cat micro.sfx code.php > single-app && chmod +x single-app
# 如果打包 PHAR 文件,仅需把 code.php 更换为 phar 文件路径即可 # 如果打包 PHAR 文件,仅需把 code.php 更换为 phar 文件路径即可
``` ```
> 有些情况下的 phar 文件可能无法在 micro 环境下运行 2. 如果打包项目,可以先将项目打包为 phar + entry然后结合打包 micro 与 phar 文件即可
### 使用 php-fpm > 关于如何将项目打包为 phar见项目 [php-cli-helper](https://github.com/crazywhalecc/php-cli-helper)。
采用项目参数 `--build-fpm``--build-all` 时,最后编译结果会输出一个 `./php-fpm` 的文件。 > 感谢 <https://github.com/dixyes/phpmicro> 项目提供的支持
该文件存放在 `buildroot/bin/` 目录,拷贝出来即可使用。
在正常的 Linux 发行版和 macOS 系统中,安装 php-fpm 后包管理会自动生成默认的 fpm 配置文件。 ## 自行编译
因为 php-fpm 必须指定配置文件才可启动,本项目编译的 php-fpm 不会带任何配置文件,所以需自行编写 `php-fpm.conf``pool.conf` 配置文件。
指定 `php-fpm.conf` 可以使用命令参数 `-y`,例如:`./php-fpm -y php-fpm.conf` 可以自己使用 Dockerfile 进行编译构建:
### 使用 php-embed ```bash
采用项目参数 `--build-embed``--build-all` 时,最后编译结果会输出一个 `libphp.a``php-config` 以及一系列头文件,存放在 `buildroot/`,你可以在你的其他代码中引入它们。 git clone https://github.com/crazywhalecc/static-php-cli.git
cd static-php-cli/docker
export DOCKER_BUILDKIT=1
docker build -t static-php . --build-arg USE_BACKUP_ADDRESS=no
# 新建一个用于放置构建好的二进制的文件夹
mkdir dist
# 终端会引导你进行编译安装,可选择 PHP 版本、要编译的扩展
docker run --rm -v $(pwd)/dist:/dist/ -it static-php build-php
```
如果你知道 [embed SAPI](https://github.com/php/php-src/tree/master/sapi/embed),你应该知道如何使用它。对于有可能编译用到引入其他库的问题,你可以使用 `buildroot/bin/php-config` 来获取编译时的配置。 编译之后可以使用下方命令将二进制 PHP 提取出来,用以下方式:
另外,有关如何使用此功能的高级示例,请查看[如何使用它构建 FrankenPHP 的静态版本](https://github.com/dunglas/frankenphp/blob/main/docs/static.md)。 ```bash
cd dist
file ./php
# 如果是 PHP 8.0 以上,同时会输出 micro 构建版本
file ./micro.sfx
```
## 贡献 如果你不想使用 Docker想从Alpine环境直接编译可以使用预置相同编译配置的脚本 `fast-compiler.sh`
如果缺少你需要的扩展,可发起 Issue。如果你对本项目较熟悉也欢迎为本项目发起 Pull Request。 ```bash
cd docker
# 用于切换编译的PHP版本
export VER_PHP="8.1.7"
./fast-compiler.sh
```
贡献基本原则如下: 如果要选择安装的扩展,可以修改 `docker/extensions.txt` 文件,具体规则如下:
- 文件内使用 `^` 可以表示默认不安装该扩展,`#` 开头可以编写注释
- 扩展名一律使用小写,目前默认状态下文件内所列的扩展为支持的扩展,其他扩展暂不支持,如有需求请提 Issue 添加
- 项目采用了 php-cs-fixer、phpstan 作为代码规范工具,贡献前请对更新的代码执行 `composer analyze``composer cs-fix` ## 支持的扩展表
- 涉及到其他开源库的部分应提供对应库的协议,同时对配置文件在修改后采用命令 `sort-config` 排序。有关排序的命令,见文档。 | 是否支持 | PHP 扩展名称 | 支持版本 | 备注 |
- 应遵循命名规范,例如扩展名称应采取 PHP 内注册的扩展名本身,外部库名应遵循项目本身的名称,内部逻辑的函数、类名、变量等应遵循驼峰、下划线等格式,禁止同一模块混用。 | -------- | ------------ | -------- | ------------------------------------------------------- |
- 涉及编译外部库的命令和 Patch 时应注意兼容不同操作系统。 | yes, enabled | bcmath | * | |
| yes, enabled | calendar | * | |
| yes, enabled | ctype | * | |
| yes, enabled | curl | * | 自带下载编译 curl 库 |
| yes, enabled | dom | * | |
| yes, enabled | event | >=3.0.8 | 从 BitBucket 作者仓库下载,非 pecl 版本 |
| yes, enabled | exif | * | |
| yes, enabled | filter | * | |
| yes, enabled | fileinfo | * | |
| yes, enabled | gd | * | |
| yes, enabled | hash | * | |
| yes, enabled | iconv | * | |
| yes, enabled | inotify | 3.0.0 | 从 pecl 或镜像站下载的源码 |
| yes, enabled | json | * | |
| yes, enabled | libxml | * | 自带下载编译 libxml2 库 |
| yes, enabled | mbstring | * | |
| yes, enabled | mongodb | >=1.9.1 | 未测试,从 pecl 或镜像站下载的源码 |
| | mysqli | | |
| yes, enabled | mysqlnd | * | |
| yes, enabled | openssl | * | |
| yes, enabled | pcntl | * | |
| yes, enabled | pdo | * | |
| yes, enabled | pdo_mysql | * | |
| yes, enabled | pdo_sqlite | * | |
| | pdo_pgsql | * | |
| yes, enabled | phar | * | |
| yes, enabled | posix | * | |
| yes, not enabled | protobuf | * | 默认不编译 |
| yes, enabled | readline | * | 不支持 `./php -a` |
| yes, enabled | redis | * | 从 pecl 或镜像站下载的源码 |
| yes, enabled | shmop | * | |
| yes, enabled | simplexml | * | |
| yes, enabled | soap | * | |
| yes, enabled | sockets | * | |
| yes, enabled | sqlite3 | * | |
| yes, enabled | swoole | >=4.6.6 | 使用参数 `--enable-openssl --with-openssl --with-openssl-dir=/usr`,从 pecl 或镜像站下载的源码 |
| yes, enabled | tokenizer | * | |
| yes, enabled | xml | * | |
| yes, enabled | xmlreader | * | |
| yes, enabled | xmlwriter | * | |
| yes, enabled | zip | * | 因链接库原因已关闭 `libzip` 库的 `bzip2``lzma` 支持 |
| yes, enabled | zlib | * | |
另外,添加新扩展的贡献方式,可以参考下方 `进阶` ## 自定义
- 从 Docker 运行编译会依次询问下载地址、PHP 版本、要编译的扩展、编译输出文件夹。
- 如果不想弹出终端交互框,只需按照下方给出的参数加到字符串的后面。
如果你想贡献文档内容,请到项目仓库 [crazywhalecc/static-php-cli-docs](https://github.com/crazywhalecc/static-php-cli-docs) 贡献 > `参数1`: `original` 代表使用原始地址,如果你位于中国大陆,可使用 `mirror` 加快下载
>
> `参数2`: `8.1.7` 是你要编译的 PHP 版本。
>
> `参数3`: `all` 代表你要编译所有非反选的扩展,不询问。
>
> `参数4`: `/dist/` 是你编译后输出二进制 PHP 和 micro 的文件夹
>
> 基本例子: `docker run --rm -v $(pwd)/dist:/dist/ -it static-php build-php original 8.1.7 all /dist/`
## 赞助本项目 - `docker/extensions.txt` 指定要编译安装的扩展。
- `docker/extensions.txt` 中,`^` 开头的扩展名为反选,反选的扩展将出现在编译的扩展列表中,但默认不选中。
- `docker/compile-php.sh` 中的 `php_compile_args` 函数来调整 PHP 编译参数。
- `docker/check-extensions.sh` 中的 `check_in_configure` 函数可调整 PHP 扩展编译的参数。
- `docker/config.json` 可调整要下载的扩展和依赖库版本和链接。
- `docker/fast-compiler.sh` 可以在 Alpine Linux 系统下直接运行。
你可以在 [我的个人赞助页](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md) 支持我和我的项目。 ## 目前的问题(对勾为已解决)
- [X] 不支持 event(libevent) 扩展event 扩展的 sockets 支持不能在静态编译中使用,因为静态内嵌编译暂时没办法调整扩展编译顺序,同时其本身也不支持静态编译。
- [ ] Swoole 扩展不支持 `--enable-swoole-curl`,也是因为编译顺序和加载顺序的问题。
- [X] 不支持 readline 扩展readline 扩展安装后无法正常使用 `php -a`,原因还没有弄清楚,可能是静态编译造成的 ncurses 库出现了问题。
- [X] curl/libcurl 扩展静态编译
- [X] 可自行选择不需要编译进入的扩展
- [X] php.ini 内嵌或分发
- [X] i18n国际化脚本本身和 README
## 开源协议 如果你对以上问题有解决方案,请提出 Issue 或 PR
本项目依据旧版本惯例采用 MIT License 开源,部分扩展的集成编译命令参考或修改自以下项目: 如果你对此脚本比较感兴趣,未来会在此编写脚本中涉及内容的解析和说明。
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs)(木兰宽松许可证) ## 运行示例
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli)Apache 2.0 LICENSE、SWOOLE-CLI LICENSE
因本项目的特殊性,使用项目编译过程中会使用很多其他开源项目,例如 curl、protobuf 等,它们都有各自的开源协议。 ### 静态 PHP 运行脚本
请在编译完成后,使用命令 `bin/spc dump-license` 导出项目使用项目的开源协议,并遵守对应项目的 LICENSE。
## 进阶 <img width="881" alt="未命名" src="https://user-images.githubusercontent.com/20330940/168441751-e62cb8d4-a3c8-42d9-b34e-d804b39756a1.png">
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php.dev) 贡献代码或文档。 ### micro 打包运行 Swoole
<img width="937" alt="all" src="https://user-images.githubusercontent.com/20330940/168557743-b8f92263-712f-490e-9fe0-831597741595.png">
## 原理
静态编译是一项比较多见于 Golang 的编译方式,在传统的 Linux 系统下正常的程序和库基本是动态编译链接Dynamically linked也就是说不同程序引用同样的库可以共用减少资源重复。
但是由于不少系统软件环境配置复杂,或者依赖的库版本冲突,一般使用 Docker 等容器技术可以解决这一问题。但 Docker 等容器也需要拉取镜像,体积较大,对于程序有便携需求的人(比如网络安全员做渗透测试等)需要很多程序可以像 Windows 上的绿色程序一样随处打包运行。
PHP 是最好的编程语言,它编写容易,易于部署和开发,倘若将 PHP 编译为静态的文件,并且将 Swoole 或 libevent 等库同样内嵌,那 PHP 不仅将可以编写便携的 Web 服务器,还能做很多想不到的事!
编译静态 PHP 大致分为以下几个步骤:
1. 下载 PHP 源码
2. 下载需要静态编译的额外扩展源码(如 inotify、mongodb、redis 等)
3. 将额外扩展源码放入 PHP 源码中
4. 生成 `configure` 并使用 `-static` 的 FLAG 进行生成 makefile
5. 修改 Makefile 中的编译参数,增加 `-all-static` 和去掉 dynamic 相关的参数
6. 使用 `make` 构建静态 PHP
7. 使用 `make install` 安装到指定目录,再使用 `strip` 去除符号表缩小体积
对于第二步,如果额外扩展中有依赖 Linux 的其他库(比如 curl 依赖 libcurl则需要在第二步之前编译安装对应库的静态版本比如 libxml2.a
而此处出问题最多的部分就是安装额外扩展的依赖上,很多库不支持静态编译,而互联网很难找到对对应库进行静态编译的资料。
脚本和 Dockerfile 统一采用 Alpine 的目的就是apk 包管理下有很多库提供了 `*-static` 静态版本,直接使用包管理安装就可以使用,而即使没有,也可以使用 musl-libc 进行静态编译,避免 glibc 下的 `libnss` 等无法静态编译的问题。
第二种要面对比较棘手的问题就是 PHP 扩展可能本身不支持静态编译(如 curl 扩展),有些通过绕过手段可以静态编译,但有些只能通过对扩展源码进行修改才能使其支持。
所以这个项目中涉及的脚本,最大的问题就在于对其他依赖的处理,而不是 PHP 编译本身。PHP 如果不启用任何扩展(即使用 `--disable-all`),则可以很方便地静态编译。
## 参考资料
- <https://blog.terrywh.net/post/2019/php-static-openssl/>
- <https://stackoverflow.com/a/37245653>
- <http://blog.gaoyuan.xyz/2014/04/09/statically-compile-php/>

View File

@@ -1,75 +0,0 @@
#!/usr/bin/env sh
# set error-quit, verbose, non-variable-quit
set -eu
# see what system used
__OS__=$(uname -s)
# see what arch used
__ARCH__=$(uname -m)
# format arch name
case $__ARCH__ in
arm64 | aarch64) __ARCH__=aarch64 ;;
x86_64|x64) __ARCH__=x86_64 ;;
*) ;;
esac
# format uname
case $__OS__ in
Darwin) __OS_FIXED__=macos ;;
Linux) __OS_FIXED__=linux ;;
*) echo "Current OS is not supported" && exit 1 ;;
esac
# set project dir
__DIR__=$(cd "$(dirname "$0")" && pwd)
__PROJECT__=$(cd "${__DIR__}"/../ && pwd)
# set download dir
__PHP_RUNTIME_URL__="https://dl.static-php.dev/static-php-cli/common/php-8.2.10-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
__COMPOSER_URL__="https://getcomposer.org/download/latest-stable/composer.phar"
# use china mirror
# bash bin/setup-runtime --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)
__PHP_RUNTIME_URL__="https://dl.static-php.dev/static-php-cli/common/php-8.2.10-cli-${__OS_FIXED__}-${__ARCH__}.tar.gz"
__COMPOSER_URL__="https://mirrors.aliyun.com/composer/composer.phar"
;;
esac
if ! command -v curl > /dev/null && command -v apk > /dev/null; then
apk add --no-cache curl
fi
test -d "${__PROJECT__}"/downloads || mkdir "${__PROJECT__}"/downloads
# download static php binary
test -f "${__PROJECT__}"/downloads/runtime.tar.gz || { echo "Downloading $__PHP_RUNTIME_URL__ ..." && curl -#fSL -o "${__PROJECT__}"/downloads/runtime.tar.gz "$__PHP_RUNTIME_URL__" ; }
test -f "${__DIR__}"/php || { tar -xf "${__PROJECT__}"/downloads/runtime.tar.gz -C "${__DIR__}"/ ; }
chmod +x "${__DIR__}"/php
# download composer
test -f "${__DIR__}"/composer || curl -#fSL -o "${__DIR__}"/composer "$__COMPOSER_URL__"
chmod +x "${__DIR__}"/composer
# sanity check for php and composer
"${__DIR__}"/php -v >/dev/null || { echo "Failed to run php" && exit 1; }
"${__DIR__}"/php "${__DIR__}"/composer --version >/dev/null || { echo "Failed to run composer" && exit 1; }
echo "Setup runtime OK!"
echo "runtime bin path needs to add manually by command below:"
echo ""
echo " export PATH=\"${__DIR__}:\$PATH\""
echo ""

18
bin/spc
View File

@@ -1,18 +0,0 @@
#!/usr/bin/env php
<?php
use SPC\ConsoleApplication;
use SPC\exception\ExceptionHandler;
require_once __DIR__ . '/../vendor/autoload.php';
// 防止 Micro 打包状态下不支持中文的显示(虽然这个项目目前好像没输出过中文?)
if (PHP_OS_FAMILY === 'Windows' && Phar::running()) {
exec('CHCP 65001');
}
try {
(new ConsoleApplication())->run();
} catch (Exception $e) {
ExceptionHandler::getInstance()->handle($e);
}

View File

@@ -1,112 +0,0 @@
#!/usr/bin/env sh
# This file is using docker to run commands
# Detect docker can run
if ! which docker >/dev/null; then
echo "Docker is not installed, please install docker first !"
exit 1
fi
DOCKER_EXECUTABLE="docker"
# shellcheck disable=SC2046
if [ $(id -u) -ne 0 ]; then
if ! docker info > /dev/null 2>&1; then
if [ "$SPC_USE_SUDO" != "yes" ]; then
echo "Docker command requires sudo"
# shellcheck disable=SC2039
echo -n 'To use sudo to run docker, run "export SPC_USE_SUDO=yes" and run command again'
exit 1
fi
DOCKER_EXECUTABLE="sudo docker"
fi
fi
# to check if qemu-docker run
if [ "$SPC_USE_ARCH" = "" ]; then
SPC_USE_ARCH=x86_64
fi
case $SPC_USE_ARCH in
x86_64)
ALPINE_FROM=alpine:edge
;;
aarch64)
ALPINE_FROM=multiarch/alpine:aarch64-edge
# shellcheck disable=SC2039
echo -e "\e[033m* Using different arch needs to setup qemu-static for docker !\e[0m"
$DOCKER_EXECUTABLE run --rm --privileged multiarch/qemu-user-static:register --reset > /dev/null
;;
*)
echo "Current arch is not supported to run in docker: $SPC_USE_ARCH"
exit 1
;;
esac
if [ "$SPC_USE_MIRROR" = "yes" ]; then
SPC_USE_MIRROR="RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories"
else
SPC_USE_MIRROR="RUN echo 'Using original repo'"
fi
# Detect docker env is setup
if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH; then
echo "Docker container does not exist. Building docker image ..."
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH -f- . <<EOF
FROM $ALPINE_FROM
$SPC_USE_MIRROR
RUN apk update; \
apk add --no-cache \
autoconf \
automake \
bash \
binutils \
bison \
build-base \
cmake \
curl \
file \
flex \
g++ \
gcc \
git \
jq \
libgcc \
libstdc++ \
linux-headers \
m4 \
make \
php82 \
php82-common \
php82-pcntl \
php82-phar \
php82-posix \
php82-sodium \
php82-tokenizer \
php82-dom \
php82-xml \
php82-xmlwriter \
composer \
pkgconfig \
wget \
xz ; \
ln -s /usr/bin/php82 /usr/bin/php
WORKDIR /app
ADD ./src /app/src
COPY ./composer.* /app/
ADD ./bin /app/bin
RUN composer install --no-dev --classmap-authoritative
EOF
fi
# Check if in ci (local terminal can execute with -it)
if [ -t 0 ]; then
INTERACT=-it
else
INTERACT=''
fi
# Run docker
# shellcheck disable=SC2068
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" -v "$(pwd)"/config:/app/config -v "$(pwd)"/src:/app/src -v "$(pwd)"/buildroot:/app/buildroot -v "$(pwd)"/source:/app/source -v "$(pwd)"/downloads:/app/downloads cwcc-spc-$SPC_USE_ARCH bin/spc $@

View File

@@ -1,18 +0,0 @@
{
"alias": "spc-php.phar",
"banner": false,
"blacklist": [
".github"
],
"directories": [
"config",
"src",
"vendor/psr",
"vendor/laravel/prompts",
"vendor/symfony",
"vendor/zhamao"
],
"git-commit-short": "git_commit_short",
"metadata": "ConsoleApplication::VERSION",
"output": "spc.phar"
}

View File

@@ -1,44 +0,0 @@
{
"pre-push": {
"enabled": true,
"actions": [
{
"action": "composer analyse"
}
]
},
"pre-commit": {
"enabled": true,
"actions": [
{
"action": "composer cs-fix -- --config=.php-cs-fixer.php --dry-run --diff {$STAGED_FILES|of-type:php}",
"conditions": [
{
"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileStaged\\OfType",
"args": ["php"]
}
]
}
]
},
"post-change": {
"enabled": true,
"actions": [
{
"action": "composer install",
"options": [],
"conditions": [
{
"exec": "\\CaptainHook\\App\\Hook\\Condition\\FileChanged\\Any",
"args": [
[
"composer.json",
"composer.lock"
]
]
}
]
}
]
}
}

View File

@@ -1,59 +0,0 @@
{
"name": "crazywhalecc/static-php-cli",
"description": "Build single static PHP binary, with PHP project together, with popular extensions included.",
"license": "MIT",
"authors": [
{
"name": "jerry",
"email": "admin@zhamao.me"
}
],
"require": {
"php": ">= 8.1",
"ext-mbstring": "*",
"ext-pcntl": "*",
"laravel/prompts": "^0.1.3",
"symfony/console": "^5.4 || ^6 || ^7",
"zhamao/logger": "^1.0"
},
"require-dev": {
"captainhook/captainhook": "^5.10",
"captainhook/plugin-composer": "^5.3",
"friendsofphp/php-cs-fixer": "^3.25",
"humbug/box": "^4.3",
"nunomaduro/collision": "^7.8",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.3"
},
"autoload": {
"psr-4": {
"SPC\\": "src/SPC"
},
"files": [
"src/globals/defines.php",
"src/globals/functions.php"
]
},
"autoload-dev": {
"psr-4": {
"SPC\\Tests\\": "tests/SPC"
}
},
"bin": [
"bin/spc"
],
"scripts": {
"analyse": "phpstan analyse --memory-limit 300M",
"cs-fix": "php-cs-fixer fix",
"test": "vendor/bin/phpunit tests/ --no-coverage",
"build:phar": "vendor/bin/box compile"
},
"config": {
"allow-plugins": {
"phpstan/extension-installer": true,
"captainhook/plugin-composer": true
},
"optimize-autoloader": true,
"sort-packages": true
}
}

5950
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,515 +0,0 @@
{
"apcu": {
"type": "external",
"source": "apcu"
},
"bcmath": {
"type": "builtin"
},
"bz2": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends": [
"bzip2"
]
},
"calendar": {
"type": "builtin"
},
"ctype": {
"type": "builtin"
},
"curl": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"curl"
]
},
"dba": {
"type": "builtin",
"arg-type-windows": "with"
},
"dom": {
"type": "builtin",
"arg-type": "custom",
"arg-type-windows": "with",
"lib-depends": [
"libxml2",
"zlib"
]
},
"event": {
"type": "external",
"source": "ext-event",
"arg-type": "custom",
"lib-depends": [
"libevent"
],
"ext-depends": [
"openssl"
],
"ext-suggests": [
"sockets"
]
},
"exif": {
"type": "builtin"
},
"ffi": {
"arg-type": "custom",
"type": "builtin",
"lib-depends": [
"libffi"
]
},
"fileinfo": {
"type": "builtin"
},
"filter": {
"type": "builtin"
},
"ftp": {
"type": "builtin",
"lib-suggests": [
"openssl"
]
},
"gd": {
"type": "builtin",
"arg-type": "custom",
"arg-type-windows": "with",
"lib-depends": [
"zlib",
"libpng"
],
"ext-depends": [
"zlib"
],
"lib-suggests": [
"libavif",
"libwebp",
"libjpeg",
"freetype"
]
},
"gettext": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"gettext"
]
},
"glfw": {
"type": "external",
"arg-type": "custom",
"source": "ext-glfw",
"lib-depends": [
"glfw"
]
},
"gmp": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends": [
"gmp"
]
},
"iconv": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends-windows": [
"libiconv"
]
},
"imagick": {
"type": "external",
"source": "ext-imagick",
"arg-type": "custom",
"lib-depends": [
"imagemagick"
]
},
"imap": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"imap"
],
"lib-suggests": [
"kerberos"
]
},
"inotify": {
"type": "external",
"source": "inotify"
},
"intl": {
"type": "builtin",
"cpp-extension": true,
"lib-depends": [
"icu"
]
},
"ldap": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends": [
"ldap"
],
"lib-suggests": [
"gmp",
"libsodium"
],
"ext-suggests": [
"openssl"
]
},
"mbregex": {
"type": "builtin",
"arg-type": "custom",
"ext-depends": [
"mbstring"
]
},
"mbstring": {
"type": "builtin",
"arg-type": "custom",
"lib-depends": [
"onig"
]
},
"memcache": {
"type": "external",
"source": "ext-memcache",
"arg-type": "custom",
"lib-depends": [
"zlib"
],
"ext-depends": [
"session"
]
},
"memcached": {
"type": "external",
"source": "memcached",
"arg-type": "custom",
"cpp-extension": true,
"lib-depends": [
"libmemcached"
],
"ext-depends": [
"session",
"zlib"
]
},
"mongodb": {
"type": "external",
"source": "mongodb",
"arg-type": "custom",
"lib-suggests": [
"icu",
"openssl",
"zstd",
"zlib"
]
},
"mysqli": {
"type": "builtin",
"arg-type": "with",
"ext-depends": [
"mysqlnd"
]
},
"mysqlnd": {
"type": "builtin",
"arg-type-windows": "with",
"lib-depends": [
"zlib"
]
},
"opcache": {
"type": "builtin"
},
"openssl": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"openssl"
],
"ext-depends": [
"zlib"
]
},
"pcntl": {
"type": "builtin",
"unix-only": true
},
"pdo": {
"type": "builtin"
},
"pdo_mysql": {
"type": "builtin",
"arg-type": "with",
"ext-depends": [
"pdo",
"mysqlnd"
]
},
"pdo_pgsql": {
"type": "builtin",
"arg-type": "with-prefix",
"ext-depends": [
"pdo",
"pgsql"
],
"lib-depends": [
"postgresql"
]
},
"pdo_sqlite": {
"type": "builtin",
"arg-type": "with",
"ext-depends": [
"pdo",
"sqlite3"
],
"lib-depends": [
"sqlite"
]
},
"pgsql": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends": [
"postgresql"
]
},
"phar": {
"type": "builtin",
"ext-depends": [
"zlib"
]
},
"posix": {
"type": "builtin",
"unix-only": true
},
"protobuf": {
"type": "external",
"source": "protobuf"
},
"pspell": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"aspell"
]
},
"readline": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends": [
"readline"
]
},
"redis": {
"type": "external",
"source": "redis",
"arg-type": "custom",
"ext-suggests": [
"session"
]
},
"session": {
"type": "builtin"
},
"shmop": {
"type": "builtin"
},
"simplexml": {
"type": "builtin",
"arg-type": "custom",
"arg-type-windows": "with",
"lib-depends": [
"libxml2"
]
},
"snappy": {
"type": "external",
"source": "ext-snappy",
"cpp-extension": true,
"arg-type": "custom",
"lib-depends": [
"snappy"
],
"ext-suggest": [
"apcu"
]
},
"snmp": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"net-snmp"
]
},
"soap": {
"type": "builtin",
"arg-type": "custom",
"lib-depends": [
"libxml2"
]
},
"sockets": {
"type": "builtin"
},
"sodium": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"libsodium"
]
},
"sqlite3": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends": [
"sqlite"
]
},
"ssh2": {
"type": "external",
"source": "ext-ssh2",
"arg-type": "with-prefix",
"lib-depends": [
"libssh2"
]
},
"swoole": {
"type": "external",
"source": "swoole",
"arg-type": "custom",
"cpp-extension": true,
"lib-depends": [
"openssl"
],
"ext-depends": [
"openssl"
],
"ext-suggests": [
"curl",
"pgsql"
],
"unix-only": true
},
"swow": {
"type": "external",
"source": "swow",
"arg-type": "custom",
"lib-suggests": [
"openssl",
"curl"
],
"ext-suggests": [
"openssl",
"curl"
]
},
"sysvmsg": {
"type": "builtin",
"unix-only": true
},
"sysvsem": {
"type": "builtin",
"unix-only": true
},
"sysvshm": {
"type": "builtin",
"unix-only": true
},
"tidy": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"tidy"
]
},
"tokenizer": {
"type": "builtin"
},
"xlswriter": {
"type": "external",
"source": "xlswriter",
"arg-type": "custom",
"ext-depends": [
"zlib",
"zip"
]
},
"xml": {
"type": "builtin",
"arg-type": "custom",
"arg-type-windows": "with",
"lib-depends": [
"libxml2"
]
},
"xmlreader": {
"type": "builtin",
"arg-type": "custom",
"lib-depends": [
"libxml2"
]
},
"xmlwriter": {
"type": "builtin",
"arg-type": "custom",
"lib-depends": [
"libxml2"
]
},
"xsl": {
"type": "builtin",
"arg-type": "with-prefix",
"lib-depends": [
"libxslt"
],
"ext-depends": [
"xml",
"dom"
]
},
"yaml": {
"type": "external",
"source": "yaml",
"arg-type": "with-prefix",
"lib-depends": [
"libyaml"
]
},
"zip": {
"type": "builtin",
"arg-type": "with-prefix",
"arg-type-windows": "enable",
"lib-depends": [
"libzip"
]
},
"zlib": {
"type": "builtin",
"arg-type": "with",
"arg-type-windows": "enable",
"lib-depends": [
"zlib"
]
},
"zstd": {
"type": "external",
"source": "ext-zstd",
"arg-type": "custom",
"lib-depends": [
"zstd"
]
}
}

View File

@@ -1,542 +0,0 @@
{
"brotli": {
"source": "brotli",
"static-libs-unix": [
"libbrotlidec-static.a",
"libbrotlienc-static.a",
"libbrotlicommon-static.a"
],
"static-libs-windows": [
"brotlicommon-static.lib",
"brotlienc-static.lib",
"brotlidec-static.lib"
],
"headers": [
"brotli"
]
},
"bzip2": {
"source": "bzip2",
"static-libs-unix": [
"libbz2.a"
],
"static-libs-windows": [
[
"libbz2.lib",
"libbz2_a.lib"
]
],
"headers": [
"bzlib.h"
]
},
"curl": {
"source": "curl",
"static-libs-unix": [
"libcurl.a"
],
"static-libs-windows": [
"libcurl.lib"
],
"headers": [
"curl"
],
"lib-depends-unix": [
"openssl",
"zlib"
],
"lib-suggests": [
"libssh2",
"brotli",
"nghttp2",
"zstd"
],
"lib-suggests-windows": [
"zlib",
"libssh2",
"brotli",
"nghttp2",
"zstd",
"openssl",
"idn2",
"psl"
],
"frameworks": [
"CoreFoundation",
"SystemConfiguration"
]
},
"freetype": {
"source": "freetype",
"static-libs-unix": [
"libfreetype.a"
],
"headers-unix": [
"freetype2/freetype/freetype.h",
"freetype2/ft2build.h"
],
"lib-depends": [
"zlib"
],
"lib-suggests": [
"libpng",
"bzip2",
"brotli"
]
},
"glfw": {
"source": "ext-glfw",
"static-libs-unix": [
"libglfw3.a"
],
"frameworks": [
"CoreVideo",
"OpenGL",
"Cocoa",
"IOKit"
]
},
"gmp": {
"source": "gmp",
"static-libs-unix": [
"libgmp.a"
],
"static-libs-windows": [
"libgmp.lib"
],
"headers": [
"gmp.h"
]
},
"icu": {
"source": "icu",
"static-libs-unix": [
"libicui18n.a",
"libicuio.a",
"libicuuc.a",
"libicudata.a"
]
},
"imagemagick": {
"source": "imagemagick",
"static-libs-unix": [
"libMagick++-7.Q16HDRI.a",
"libMagickCore-7.Q16HDRI.a",
"libMagickWand-7.Q16HDRI.a"
],
"lib-depends": [
"zlib",
"libpng",
"libjpeg",
"bzip2",
"libwebp",
"freetype"
],
"lib-suggests": [
"zstd",
"xz",
"libzip",
"libxml2"
]
},
"ldap": {
"source": "ldap",
"static-libs-unix": [
"liblber.a",
"libldap.a"
],
"lib-suggests": [
"openssl",
"gmp",
"libsodium"
]
},
"libavif": {
"source": "libavif",
"static-libs-unix": [
"libavif.a"
]
},
"libevent": {
"source": "libevent",
"static-libs-unix": [
"libevent.a",
"libevent_core.a",
"libevent_extra.a",
"libevent_openssl.a"
],
"lib-depends": [
"openssl"
]
},
"libffi": {
"source": "libffi",
"static-libs-unix": [
"libffi.a"
],
"static-libs-windows": [
"libffi.lib"
],
"headers-unix": [
"ffi.h",
"ffitarget.h"
],
"headers-windows": [
"ffi.h",
"fficonfig.h",
"ffitarget.h"
]
},
"libiconv": {
"source": "libiconv",
"static-libs-unix": [
"libiconv.a",
"libcharset.a"
],
"headers": [
"iconv.h",
"libcharset.h",
"localcharset.h"
]
},
"libjpeg": {
"source": "libjpeg",
"static-libs-unix": [
"libjpeg.a",
"libturbojpeg.a"
]
},
"libmcrypt": {
"source": "libmcrypt",
"static-libs-unix": [
"libmcrypt.a"
]
},
"libmemcached": {
"source": "libmemcached",
"static-libs-unix": [
"libmemcached.a",
"libmemcachedutil.a"
]
},
"libpng": {
"source": "libpng",
"static-libs-unix": [
"libpng.a"
],
"static-libs-windows": [
"libpng16_static.lib"
],
"headers-unix": [
"png.h",
"pngconf.h",
"pnglibconf.h"
],
"headers-windows": [
"png.h",
"pngconf.h"
],
"lib-depends": [
"zlib"
]
},
"libsodium": {
"source": "libsodium",
"static-libs-unix": [
"libsodium.a"
]
},
"libssh2": {
"source": "libssh2",
"static-libs-unix": [
"libssh2.a"
],
"static-libs-windows": [
"libssh2.lib"
],
"headers": [
"libssh2.h",
"libssh2_publickey.h",
"libssh2_sftp.h"
],
"lib-depends": [
"openssl"
],
"lib-suggests": [
"zlib"
]
},
"libwebp": {
"source": "libwebp",
"static-libs-unix": [
"libwebp.a",
"libwebpdecoder.a",
"libwebpdemux.a",
"libwebpmux.a",
"libsharpyuv.a"
]
},
"libxml2": {
"source": "libxml2",
"static-libs-unix": [
"libxml2.a"
],
"static-libs-windows": [
[
"libxml2s.lib",
"libxml2_a.lib"
]
],
"headers": [
"libxml2"
],
"lib-depends": [
"libiconv",
"zlib"
],
"lib-suggests": [
"xz",
"icu"
],
"lib-suggests-windows": [
"icu",
"xz",
"pthreads4w"
]
},
"libxslt": {
"source": "libxslt",
"static-libs-unix": [
"libxslt.a",
"libexslt.a"
],
"lib-depends": [
"libxml2"
]
},
"libyaml": {
"source": "libyaml",
"static-libs-unix": [
"libyaml.a"
],
"static-libs-windows": [
"yaml.lib"
],
"headers": [
"yaml.h"
]
},
"libzip": {
"source": "libzip",
"static-libs-unix": [
"libzip.a"
],
"static-libs-windows": [
[
"zip.lib",
"libzip_a.lib"
]
],
"headers": [
"zip.h",
"zipconf.h"
],
"lib-depends": [
"zlib"
],
"lib-suggests": [
"bzip2",
"xz",
"zstd",
"openssl"
]
},
"mcrypt": {
"source": "mcrypt",
"static-libs-unix": [
"libmcrypt.a"
]
},
"ncurses": {
"source": "ncurses",
"static-libs-unix": [
"libncurses.a"
]
},
"nghttp2": {
"source": "nghttp2",
"static-libs-unix": [
"libnghttp2.a"
],
"static-libs-windows": [
"nghttp2.lib"
],
"headers": [
"nghttp2"
],
"lib-depends": [
"zlib",
"openssl"
],
"lib-suggests": [
"libxml2"
]
},
"onig": {
"source": "onig",
"static-libs-unix": [
"libonig.a"
],
"static-libs-windows": [
[
"onig.lib",
"onig_a.lib"
]
],
"headers": [
"oniggnu.h",
"oniguruma.h"
]
},
"openssl": {
"source": "openssl",
"static-libs-unix": [
"libssl.a",
"libcrypto.a"
],
"static-libs-windows": [
"libssl.lib",
"libcrypto.lib"
],
"headers": [
"openssl"
],
"lib-depends": [
"zlib"
]
},
"pkg-config": {
"source": "pkg-config"
},
"postgresql": {
"source": "postgresql",
"static-libs-unix": [
"libpq.a",
"libpgport.a",
"libpgcommon.a"
],
"lib-depends": [
"libiconv",
"libxml2",
"openssl",
"zlib",
"readline"
],
"lib-suggests": [
"icu"
]
},
"pthreads4w": {
"source": "pthreads4w",
"static-libs-windows": [
"libpthreadVC3.lib"
],
"headers-windows": [
"_ptw32.h",
"pthread.h",
"sched.h",
"semaphore.h"
]
},
"readline": {
"source": "readline",
"static-libs-unix": [
"libreadline.a"
],
"lib-depends": [
"ncurses"
]
},
"snappy": {
"source": "snappy",
"static-libs-unix": [
"libsnappy.a"
],
"headers-unix": [
"snappy-c.h",
"snappy-sinksource.h",
"snappy.h",
"snappy-stubs-internal.h",
"snappy-stubs-public.h"
],
"lib-depends": [
"zlib"
]
},
"sqlite": {
"source": "sqlite",
"static-libs-unix": [
"libsqlite3.a"
],
"headers-unix": [
"sqlite3.h",
"sqlite3ext.h"
]
},
"xz": {
"source": "xz",
"static-libs-unix": [
"liblzma.a"
],
"static-libs-windows": [
[
"liblzma.lib",
"liblzma_a.lib"
]
],
"headers-unix": [
"lzma"
],
"headers-windows": [
"lzma",
"lzma.h"
],
"lib-depends": [
"libiconv"
]
},
"zlib": {
"source": "zlib",
"static-libs-unix": [
"libz.a"
],
"static-libs-windows": [
"zlib_a.lib"
],
"headers": [
"zlib.h",
"zconf.h"
]
},
"zstd": {
"source": "zstd",
"static-libs-unix": [
"libzstd.a"
],
"static-libs-windows": [
[
"zstd.lib",
"zstd_static.lib"
]
],
"headers-unix": [
"zdict.h",
"zstd.h",
"zstd_errors.h"
],
"headers-windows": [
"zstd.h",
"zstd_errors.h"
]
}
}

File diff suppressed because one or more lines are too long

89
docker/Dockerfile Executable file
View File

@@ -0,0 +1,89 @@
FROM alpine:3.16
# define script basic information
# Version of this Dockerfile
ENV SCRIPT_VERSION=1.5.1
# Download address uses backup address
ARG USE_BACKUP_ADDRESS
# (if downloading slowly, consider set it to yes)
ENV USE_BACKUP="${USE_BACKUP_ADDRESS}"
# APK repositories mirror address, if u r not in China, consider set USE_BACKUP=yes to boost
ENV LINK_APK_REPO='mirrors.ustc.edu.cn'
ENV LINK_APK_REPO_BAK='dl-cdn.alpinelinux.org'
RUN if [ "${USE_BACKUP}" = "" ]; then \
export USE_BACKUP="no" ; \
fi
RUN sed -i.backup 's/dl-cdn.alpinelinux.org/'${LINK_APK_REPO}'/g' /etc/apk/repositories ;
RUN if [ "${USE_BACKUP}" = "no" ]; then cp -f /etc/apk/repositories.backup /etc/apk/repositories; fi
RUN cat /etc/apk/repositories
# build requirements
RUN apk add bash file wget cmake gcc g++ jq autoconf git libstdc++ linux-headers make m4 libgcc binutils ncurses dialog > /dev/null
# php zlib dependencies
RUN apk add zlib-dev zlib-static > /dev/null
# php mbstring dependencies
RUN apk add oniguruma-dev > /dev/null
# php openssl dependencies
RUN apk add openssl-libs-static openssl-dev openssl > /dev/null
# php gd dependencies
RUN apk add libpng-dev libpng-static > /dev/null
# curl c-ares dependencies
RUN apk add c-ares-static c-ares-dev > /dev/null
# php event dependencies
RUN apk add libevent libevent-dev libevent-static > /dev/null
# php sqlite3 dependencies
RUN apk add sqlite sqlite-dev sqlite-libs sqlite-static > /dev/null
# php libzip dependencies
RUN apk add bzip2-dev bzip2-static bzip2 > /dev/null
# php micro ffi dependencies
RUN apk add libffi libffi-dev > /dev/null
# php gd event parent dependencies
RUN apk add zstd-static > /dev/null
# php readline dependencies
RUN apk add readline-static ncurses-static readline-dev > /dev/null
RUN apk add aria2
RUN mkdir /app
WORKDIR /app
ADD ./ /app/
# RUN chmod +x /app/*.sh
# use proxy
# ENV http_proxy=http://192.168.3.26:8015
# ENV https_proxy=http://192.168.3.26:8015
# 提前下载好,就可以跳过两步
# (容器外提前执行 下面两个命令)
RUN sh ./download-library-batch-aria2.sh
RUN sh ./download-extension-batch-aria2.sh
#ENV http_proxy=''
#ENV https_proxy=''
RUN ls -lh source/libraries
RUN ls -lh source/extensions
# quick test complie
# RUN bash ./compile-deps.sh
RUN sh ./download.sh swoole ${USE_BACKUP} && \
sh ./download.sh inotify ${USE_BACKUP} && \
sh ./download.sh mongodb ${USE_BACKUP} && \
sh ./download.sh event ${USE_BACKUP} && \
sh ./download.sh redis ${USE_BACKUP} && \
sh ./download.sh libxml2 ${USE_BACKUP} && \
sh ./download.sh xz ${USE_BACKUP} && \
sh ./download.sh curl ${USE_BACKUP} && \
sh ./download.sh libzip ${USE_BACKUP} && \
sh ./download.sh libiconv ${USE_BACKUP} && \
sh ./download-git.sh dixyes/phpmicro phpmicro ${USE_BACKUP}
RUN bash ./compile-deps.sh
RUN echo -e "#!/usr/bin/env bash\n/app/compile-php.sh \$@" > /bin/build-php && chmod +x /bin/build-php

3
docker/ac_override_1 Executable file
View File

@@ -0,0 +1,3 @@
AC_DEFUN([PHP_CHECK_LIBRARY], [
$3
])

18
docker/ac_override_2 Executable file
View File

@@ -0,0 +1,18 @@
AC_DEFUN([PHP_CHECK_LIBRARY], [
save_old_LDFLAGS=$LDFLAGS
ac_stuff="$5"
save_ext_shared=$ext_shared
ext_shared=yes
PHP_EVAL_LIBLINE([$]ac_stuff, LDFLAGS)
AC_CHECK_LIB([$1],[$2],[
LDFLAGS=$save_old_LDFLAGS
ext_shared=$save_ext_shared
$3
],[
LDFLAGS=$save_old_LDFLAGS
ext_shared=$save_ext_shared
unset ac_cv_lib_$1[]_$2
$4
])dnl
])

200
docker/check-extensions.sh Executable file
View File

@@ -0,0 +1,200 @@
#!/bin/sh
# Here are 3 steps in configuration of extensions
# before_configure
# in_configure
# after_configure
self_dir=$(cd "$(dirname "$0")";pwd)
php_dir=$(find $self_dir/source -name "php-*" -type d | tail -n1)
test -f "$self_dir/extensions_install.txt" && EXT_LIST_FILE="$self_dir/extensions_install.txt" || EXT_LIST_FILE="$self_dir/extensions.txt"
function do_copy_extension() {
ext_dir=$(find $self_dir/source -name "*$1-*" -type d | tail -n1)
mv $ext_dir $php_dir/ext/$1
if [ $? != 0 ]; then
echo "Compile error! ext: $1, ext_dir=$ext_dir"
exit 1
fi
}
function check_before_configure() {
list=$(cat "$EXT_LIST_FILE" | grep -v "^#" | grep -v "^$" | grep -v "^\^")
xml_sign="no"
for loop in $list
do
case $loop in
bcmath) ;;
calendar) ;;
ctype) ;;
exif) ;;
filter) ;;
fileinfo) ;;
gd) ;;
hash) ;;
iconv) ;;
json) ;;
mbstring) ;;
mysqlnd) ;;
openssl) ;;
pcntl) ;;
pdo) ;;
pdo_mysql) ;;
pdo_sqlite) ;;
phar) ;;
posix) ;;
protobuf)
do_copy_extension protobuf
echo '#ifndef PHP_PROTOBUF_H' >> $php_dir/ext/protobuf/php_protobuf.h && \
echo '# define PHP_PROTOBUF_H' >> $php_dir/ext/protobuf/php_protobuf.h && \
echo '#ifdef HAVE_CONFIG_H' >> $php_dir/ext/protobuf/php_protobuf.h && \
echo '# include "config.h"' >> $php_dir/ext/protobuf/php_protobuf.h && \
echo '#endif' >> $php_dir/ext/protobuf/php_protobuf.h && \
echo 'extern zend_module_entry protobuf_module_entry;' >> $php_dir/ext/protobuf/php_protobuf.h && \
echo '# define phpext_protobuf_ptr &protobuf_module_entry' >> $php_dir/ext/protobuf/php_protobuf.h && \
echo '#endif' >> $php_dir/ext/protobuf/php_protobuf.h
;;
readline)
if [ ! -d "/nom" ]; then
mkdir /nom
fi
mv /usr/lib/libreadline.so* /nom/ && \
mv /usr/lib/libncurses*.so* /nom
;;
shmop) ;;
sockets) ;;
sqlite3) ;;
tokenizer) ;;
zlib) ;;
zip) ;;
curl) cat "$self_dir/ac_override_1" "$php_dir/ext/curl/config.m4" "$self_dir/ac_override_2" > /tmp/aa && mv /tmp/aa "$php_dir/ext/curl/config.m4" ;;
dom|xml|libxml|xmlreader|xmlwriter|simplexml|soap) ;;
inotify) do_copy_extension inotify ;;
redis) do_copy_extension redis ;;
swoole) do_copy_extension swoole ;;
mongodb) do_copy_extension mongodb ;;
event) do_copy_extension event ;;
esac
done
case $1 in
8.*)
mv $self_dir/source/phpmicro $php_dir/sapi/micro && \
sed -ie 's/#include "php.h"/#include "php.h"\n#define PHP_MICRO_FAKE_CLI 1/g' $php_dir/sapi/micro/php_micro.c
;;
esac
}
function check_in_configure() {
php_configure=""
list=$(cat "$EXT_LIST_FILE" | sed 's/#.*//g' | sed 's/\^.*//g' | sed -e 's/[ ]*$//g' | grep -v "^\s*$")
for loop in $list
do
case $loop in
bcmath) php_configure="$php_configure --enable-bcmath" ;;
calendar) php_configure="$php_configure --enable-calendar" ;;
ctype) php_configure="$php_configure --enable-ctype" ;;
curl) php_configure="$php_configure --with-curl" ;;
dom) php_configure="$php_configure --enable-dom" ;;
exif) php_configure="$php_configure --enable-exif" ;;
event) php_configure="$php_configure --with-event-libevent-dir=/usr --with-event-core --with-event-extra --with-event-openssl" ;;
filter) php_configure="$php_configure --enable-filter" ;;
fileinfo) php_configure="$php_configure --enable-fileinfo" ;;
gd)
case $1 in
7.3.*|7.2.*) php_configure="$php_configure --with-gd" ;;
7.4.*|8.*) php_configure="$php_configure --enable-gd" ;;
esac
;;
hash)
case $1 in
7.3.*|7.2.*) php_configure="$php_configure --enable-hash" ;;
esac
;;
iconv) php_configure="$php_configure --with-iconv=/usr" ;;
inotify) php_configure="$php_configure --enable-inotify" ;;
json)
case $1 in
7.*) php_configure="$php_configure --enable-json" ;;
esac
;;
libxml)
case $1 in
7.3.*|7.2.*) php_configure="$php_configure --enable-libxml" ;;
7.4.*|8.*) php_configure="$php_configure --with-libxml" ;;
esac
;;
mbstring) php_configure="$php_configure --enable-mbstring" ;;
mongodb) php_configure="$php_configure --enable-mongodb" ;;
mysqlnd) php_configure="$php_configure --enable-mysqlnd" ;;
openssl) php_configure="$php_configure --with-openssl --with-openssl-dir=/usr" ;;
pcntl) php_configure="$php_configure --enable-pcntl" ;;
pdo) php_configure="$php_configure --enable-pdo" ;;
pdo_mysql) php_configure="$php_configure --with-pdo-mysql=mysqlnd" ;;
phar) php_configure="$php_configure --enable-phar" ;;
posix) php_configure="$php_configure --enable-posix" ;;
protobuf) php_configure="$php_configure --enable-protobuf" ;;
readline) php_configure="$php_configure --with-readline" ;;
redis) php_configure="$php_configure --enable-redis --disable-redis-session" ;;
shmop) php_configure="$php_configure --enable-shmop" ;;
simplexml) php_configure="$php_configure --enable-simplexml" ;;
sockets) php_configure="$php_configure --enable-sockets" ;;
soap) php_configure="$php_configure --enable-soap" ;;
sqlite3) php_configure="$php_configure --with-sqlite3" ;;
pdo_sqlite) php_configure="$php_configure --with-pdo-sqlite" ;;
swoole)
php_configure="$php_configure --enable-swoole"
have_openssl=$(echo $list | grep openssl)
if [ "$have_openssl" != "" ]; then
php_configure="$php_configure --enable-openssl --with-openssl --with-openssl-dir=/usr"
fi
have_hash=$(echo $list | grep hash)
if [ "$have_hash" = "" ]; then
case $1 in
7.3.*|7.2.*) php_configure="$php_configure --enable-hash" ;;
esac
fi
;;
tokenizer) php_configure="$php_configure --enable-tokenizer" ;;
xml) php_configure="$php_configure --enable-xml" ;;
xmlreader) php_configure="$php_configure --enable-xmlreader" ;;
xmlwriter) php_configure="$php_configure --enable-xmlwriter" ;;
zlib) php_configure="$php_configure --with-zlib" ;;
zip) php_configure="$php_configure --with-zip" ;;
*)
echo "Unsupported extension '$loop' !" >&2
exit 1
;;
esac
done
case $1 in
8.*) php_configure="$php_configure --with-ffi --enable-micro=all-static" ;;
esac
echo $php_configure
}
function check_after_configure() {
list=$(cat "$EXT_LIST_FILE" | grep -v "^#" | grep -v "^$")
for loop in $list
do
case $loop in
swoole)
sed -ie 's/swoole_clock_gettime(CLOCK_REALTIME/clock_gettime(CLOCK_REALTIME/g' "$php_dir/ext/swoole/include/swoole.h"
sed -ie 's/strcmp("cli", sapi_module.name) == 0/strcmp("cli", sapi_module.name) == 0 || strcmp("micro", sapi_module.name) == 0/g' "$php_dir/ext/swoole/ext-src/php_swoole.cc"
;;
esac
done
case $1 in
8.*) sed -ie 's/$(EXTRA_LIBS:-lresolv=-Wl,-Bstatic,-lresolv,-Bdynamic)/$(EXTRA_LIBS)/g' "$php_dir/Makefile" ;;
esac
}
function finish_compile() {
if [ -d "/nom" ]; then
mv /nom/* /usr/lib/ || echo "Empty directory"
rm -rf /nom/
fi
}
$1 $2

64
docker/compile-deps.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env bash
self_dir=$(cd "$(dirname "$0")";pwd)
function do_xml_compiler() {
cd $self_dir/source/xz-* && \
./configure --enable-static=yes && \
make -j$(cat /proc/cpuinfo | grep processor | wc -l) && \
make install && \
echo "xz compiled!" && \
cd ../libxml2-* && \
./configure --prefix=/usr --with-lzma --without-python && \
make -j$(cat /proc/cpuinfo | grep processor | wc -l) && \
make install && \
echo "libxml2 compiled!"
}
function do_libzip_compiler() {
cd $self_dir/source/libzip-* && \
mkdir build && \
cd build && \
cmake -DBUILD_SHARED_LIBS=no .. -Wno-dev -DENABLE_BZIP2=no -DENABLE_LZMA=no && \
make LDFLAGS="-llzma -lbz2" -j$(cat /proc/cpuinfo | grep processor | wc -l) && \
make install && \
echo "libzip compiled!"
}
function do_curl_compiler() {
cd $self_dir/source/curl-* && \
CC=gcc CXX=g++ CFLAGS=-fPIC CPPFLAGS=-fPIC ./configure \
--without-nghttp2 \
--with-ssl=/usr \
--with-pic=pic \
--enable-ipv6 \
--enable-shared=no \
--without-libidn2 \
--disable-ldap \
--without-libpsl \
--without-lber \
--enable-ares && \
make -j$(cat /proc/cpuinfo | grep processor | wc -l) && \
make install && \
echo "curl compiled!"
}
function do_iconv_compiler() {
cd $self_dir/source/libiconv-* && \
./configure --enable-static=yes --prefix=/usr && \
make -j$(cat /proc/cpuinfo | grep processor | wc -l) && \
make install && \
echo "libiconv compiled!"
}
if [ ! -f "$self_dir/source/.deps-compiled" ]; then
source ${self_dir}/deps-modules/libmcrypt.sh
source ${self_dir}/deps-modules/gmp.sh
do_xml_compiler && \
do_curl_compiler && \
do_libzip_compiler && \
do_iconv_compiler && \
touch "$self_dir/source/.deps-compiled"
else
echo "Skip compilation for dependencies"
fi

125
docker/compile-php.sh Executable file
View File

@@ -0,0 +1,125 @@
#!/usr/bin/env bash
self_dir=$(cd "$(dirname "$0")";pwd)
# 通过 extensions.txt 生成一个 dialog 命令
function generate_ext_dialog_cmd() {
list=$(cat "$self_dir/extensions.txt" | grep -v "^#" | grep -v "^$")
echo -n "dialog --backtitle \"static-php-cli Compile Options\" --checklist \"Please select the extension you don't want to compile.\n\nNOTE: Use <space> to select or deselect items\n\n** Default is compiling all **\" 24 60 20 " > $self_dir/.ask_cmd.sh
for loop in $list
do
case $loop in
^*)
loop=$(echo ${loop:1} | xargs)
echo -n "$loop '$loop Extension' off " >> $self_dir/.ask_cmd.sh
;;
*) echo -n "$loop '$loop Extension' on " >> $self_dir/.ask_cmd.sh ;;
esac
done
echo "2>$self_dir/extensions_install.txt" >> $self_dir/.ask_cmd.sh
}
# PHP 编译参数生成
function php_compile_args() {
_php_arg="--prefix=$self_dir/php-dist"
_php_arg="$_php_arg --disable-all"
_php_arg="$_php_arg --enable-shared=no"
_php_arg="$_php_arg --enable-static=yes"
_php_arg="$_php_arg --enable-inline-optimization"
_php_arg="$_php_arg --with-layout=GNU"
_php_arg="$_php_arg --with-pear=no"
_php_arg="$_php_arg --disable-cgi"
_php_arg="$_php_arg --disable-phpdbg"
_php_arg="$_php_arg --with-config-file-path=/etc"
_php_arg="$_php_arg $($self_dir/check-extensions.sh check_in_configure $1)"
echo $_php_arg
}
# 第一个参数用于使用镜像地址还是原地址mirror为镜像地址original为原地址
if [ "$1" = "" ]; then
dialog --backtitle "static-php-cli Compile Options" --yesno "<Yes>: Use mirror download address, mainland China users recommended.\n\n<No>: Use original address, global users recommended." 10 50
test $? == 0 && USE_BACKUP="no" || USE_BACKUP="yes"
else
test "$1" != "mirror" && USE_BACKUP="yes" || USE_BACKUP="no"
fi
# 第二个参数用于规定编译的 PHP 版本
if [ "$2" = "" ]; then
dialog --backtitle "static-php-cli Compile Options" --inputbox "Please input your PHP version to compile" 10 50 "8.1.7" 2>$self_dir/.phpver
if [ $? != 0 ]; then
clear
echo "canceled Compiling PHP." && rm -f $self_dir/.phpver
exit 1
else
VER_PHP=$(cat $self_dir/.phpver)
rm -f $self_dir/.phpver
fi
else
VER_PHP=$2
fi
# 第三个参数用于是否直接安装,如果留空则询问编译的扩展,如果填入 all则直接编译所有的扩展
if [ "$3" != "all" ]; then
generate_ext_dialog_cmd && cat $self_dir/.ask_cmd.sh && chmod +x $self_dir/.ask_cmd.sh && $self_dir/.ask_cmd.sh
if [ $? != 0 ]; then
clear
echo "canceled Compiling PHP while selecting extensions." && rm -rf $self_dir/.ask_cmd.sh
exit 1
fi
rm -f $self_dir/.ask_cmd.sh
else
cp $self_dir/extensions.txt $self_dir/extensions_install.txt
fi
# 第四个参数用于输出 PHP 和 micro 二进制文件的位置
if [ "$4" = "" ]; then
dialog --backtitle "static-php-cli Compile Options" --inputbox "Please input compiled output directory" 10 50 "/dist/" 2>$self_dir/.outdir
if [ $? != 0 ]; then
clear
echo "canceled setting output dir, compiling PHP stopped." && rm -f $self_dir/.outdir
exit 1
else
OUT_DIR=$(cat $self_dir/.outdir)
rm -f $self_dir/.outdir
fi
else
OUT_DIR=$4
fi
if [ ! -d "$OUT_DIR" ]; then
mkdir -p "$OUT_DIR"
fi
# 下载 PHP
echo "All done. Downloading PHP ..."
if [ -d "$self_dir/source/php-$VER_PHP" ]; then
rm -rf "$self_dir/source/php-$VER_PHP"
fi
$self_dir/download.sh php ${USE_BACKUP} ${VER_PHP} || { echo "Download PHP failed!" && exit 1 ; }
# 选择性编译依赖的库、移动需要安装的扩展到 PHP 目录
$self_dir/check-extensions.sh check_before_configure ${VER_PHP} || { echo "Install required library failed!" && exit 1 ; }
# 编译 PHP
echo "Compiling PHP ..."
php_dir=$(find $self_dir/source -name "php-$VER_PHP" -type d | tail -n1)
cd $php_dir && \
./buildconf --force && \
./configure LDFLAGS=-static $(php_compile_args $VER_PHP) && \
$self_dir/check-extensions.sh check_after_configure ${VER_PHP} && \
sed -ie 's/-export-dynamic//g' "Makefile" && \
sed -ie 's/-o $(SAPI_CLI_PATH)/-all-static -o $(SAPI_CLI_PATH)/g' "Makefile" && \
#sed -ie 's/$(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_MICRO_OBJS)/$(PHP_GLOBAL_OBJS:.lo=.o) $(PHP_BINARY_OBJS:.lo=.o) $(PHP_MICRO_OBJS:.lo=.o)/g' "Makefile" && \
make LDFLAGS="-ldl" -j$(cat /proc/cpuinfo | grep processor | wc -l) && \
make install-cli && \
$self_dir/check-extensions.sh finish_compile && \
strip $self_dir/php-dist/bin/php
if [ $? != 0 ]; then
exit 1
fi
# 将 PHP 和 micro 输出到指定目录
echo "Copying php binary to $OUT_DIR ..." && \
cp $self_dir/php-dist/bin/php $OUT_DIR/ && \
test -f $php_dir/sapi/micro/micro.sfx && \
echo "Copying micro.sfx binary to $OUT_DIR ..." && \
cp $php_dir/sapi/micro/micro.sfx $OUT_DIR/ || { exit 0 ; }

61
docker/config.json Executable file
View File

@@ -0,0 +1,61 @@
{
"php": {
"link": "http://mirrors.zhamao.xin/php/php-{version}.tar.gz",
"link_2": "https://www.php.net/distributions/php-{version}.tar.gz"
},
"protobuf": {
"version": "3.21.2",
"link": "http://mirrors.zhamao.xin/pecl/protobuf-{version}.tgz",
"link_2": "https://pecl.php.net/get/protobuf-{version}.tgz"
},
"swoole": {
"version": "4.8.10",
"link": "http://mirrors.zhamao.xin/pecl/swoole-{version}.tgz",
"link_2": "https://pecl.php.net/get/swoole-{version}.tgz"
},
"mongodb": {
"version": "1.13.0",
"link": "http://mirrors.zhamao.xin/pecl/mongodb-{version}.tgz",
"link_2": "https://pecl.php.net/get/mongodb-{version}.tgz"
},
"inotify": {
"version": "3.0.0",
"link": "http://mirrors.zhamao.xin/pecl/inotify-{version}.tgz",
"link_2": "https://pecl.php.net/get/inotify-{version}.tgz"
},
"event": {
"version": "3.0.8",
"link": "https://mirrors.zhamao.xin/library/php-event/event-{version}.tar.gz",
"link_2": "https://bitbucket.org/osmanov/pecl-event/get/{version}.tar.gz"
},
"redis": {
"version": "5.3.7",
"link": "http://mirrors.zhamao.xin/pecl/redis-{version}.tgz",
"link_2": "https://pecl.php.net/get/redis-{version}.tgz"
},
"libxml2": {
"version": "2.9.12",
"link": "http://mirrors.zhamao.xin/library/libxml2/libxml2-{version}.tar.gz",
"link_2": "http://xmlsoft.org/sources/libxml2-{version}.tar.gz"
},
"curl": {
"version": "7.83.1",
"link": "https://mirrors.zhamao.xin/library/curl/curl-{version}.tar.gz",
"link_2": "https://curl.haxx.se/download/curl-{version}.tar.gz"
},
"xz": {
"version": "5.2.5",
"link": "https://mirrors.zhamao.xin/library/xz/xz-{version}.tar.gz",
"link_2": "https://tukaani.org/xz/xz-{version}.tar.gz"
},
"libzip": {
"version": "1.9.2",
"link": "https://mirrors.zhamao.xin/library/libzip/libzip-{version}.tar.gz",
"link_2": "https://libzip.org/download/libzip-{version}.tar.gz"
},
"libiconv": {
"version": "1.17",
"link": "https://mirrors.zhamao.xin/library/libiconv/libiconv-{version}.tar.gz",
"link_2": "https://ftp.gnu.org/gnu/libiconv/libiconv-{version}.tar.gz"
}
}

View File

@@ -0,0 +1,32 @@
#!/bin/bash
if [ -n "$__MODULE_SH__" ]; then
return
fi
__MODULE_SH__='gmp.sh'
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
cd ${__DIR__}
# cpu 核数 前面为linux 后面为macos
cpu_nums=`nproc 2> /dev/null || sysctl -n hw.ncpu`
# cpu_nums=`grep "processor" /proc/cpuinfo | sort -u | wc -l`
function do_gmp_compiler() {
pwd
mkdir -p /app/source/builder_dir/gmp
tar --strip-components=1 -C ${__DIR__}/source/builder_dir/gmp -xf ${__DIR__}/source/libraries/gmp-6.2.1.tar.lz
cd ${__DIR__}/source/builder_dir/gmp
./configure --prefix=/usr/gmp --enable-static --disable-shared
make -j $cpu_nums
echo "gmp compiled!" && \
make install && \
echo "gmp compiled!"
return $?
}
do_gmp_compiler

View File

@@ -0,0 +1,35 @@
#!/bin/bash
if [ -n "$__MODULE_SH__" ]; then
return
fi
__MODULE_SH__='libmcrypt.sh'
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
cd ${__DIR__}
# cpu 核数 前面为linux 后面为macos
cpu_nums=`nproc 2> /dev/null || sysctl -n hw.ncpu`
# cpu_nums=`grep "processor" /proc/cpuinfo | sort -u | wc -l`
function do_libmcrypt_compiler() {
pwd
mkdir -p /app/source/builder_dir/libmcrypt
tar --strip-components=1 -C ${__DIR__}/source/builder_dir/libmcrypt -xf ${__DIR__}/source/libraries/libmcrypt-2.5.8-3.4.tar.gz
cd ${__DIR__}/source/builder_dir/libmcrypt
chmod a+x ./install-sh
sh ./configure --prefix=/usr/libmcrypt \
--enable-static=yes \
--enable-shared=no
make -j $cpu_nums
echo "libmcrypt compiled!" && \
make install && \
echo "libmcrypt compiled!"
return $?
}
do_libmcrypt_compiler

View File

@@ -0,0 +1,34 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
cd ${__DIR__}
# https://aria2.github.io/manual/en/html/aria2c.html#http-ftp-segmented-downloads
# https://aria2.github.io/manual/en/html/aria2c.html
# -with-config-file-path=/usr/local/php/etc
# -U, --user-agent
# aria2c -h
# aria2c --conf-path=/etc/aria2/aria2.conf
:<<EOF
-c, --continue [true|false]
-s, --split=<N>
-x, --max-connection-per-server=<NUM>
-k, --min-split-size=<SIZE>
-j, --max-concurrent-downloads=<N>
-i, --input-file=<FILE>
EOF
user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
test -f download_extension_urls.txt && aria2c -c -j 10 -s 10 -x 8 -k 10M --allow-overwrite=true --max-tries=30 --retry-wait=15 --user-agent=$user_agent \
-d extensions --input-file=download_extension_urls.txt
mkdir -p source/extensions
awk 'BEGIN { cmd="cp -ri extensions/* source/extensions/" ; print "n" |cmd; }'

20
docker/download-git.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
self_dir=$(cd "$(dirname "$0")";pwd)
test -d "$self_dir/source/cache/" || mkdir -p "$self_dir/source/cache"
test "$3" != "yes" && GITHUB_ADDR="https://gh.api.99988866.xyz/" || GITHUB_ADDR=""
if [ -d "$self_dir/source/cache/$2" ]; then
echo "Using cache for $2"
cp -r "$self_dir/source/cache/$2" "$self_dir/source/"
else
wget -O $self_dir/source/master.zip "$GITHUB_ADDR""https://github.com/$1/archive/master.zip" && \
cd $self_dir/source/ && \
unzip master.zip && \
mv $2-master/ cache/$2 && \
cp -r cache/$2 ./
fi
# git clone https://$GITHUB_ADDR/$1.git --depth=1 $self_dir/source/$2

View File

@@ -0,0 +1,34 @@
#!/bin/bash
set -exu
__DIR__=$(
cd "$(dirname "$0")"
pwd
)
cd ${__DIR__}
# https://aria2.github.io/manual/en/html/aria2c.html#http-ftp-segmented-downloads
# https://aria2.github.io/manual/en/html/aria2c.html
# -with-config-file-path=/usr/local/php/etc
# -U, --user-agent
# aria2c -h
# aria2c --conf-path=/etc/aria2/aria2.conf
:<<EOF
-c, --continue [true|false]
-s, --split=<N>
-x, --max-connection-per-server=<NUM>
-k, --min-split-size=<SIZE>
-j, --max-concurrent-downloads=<N>
-i, --input-file=<FILE>
EOF
user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'
test -f download_library_urls.txt && aria2c -c -j 10 -s 10 -x 8 -k 10M --allow-overwrite=true --max-tries=30 --retry-wait=15 --user-agent=$user_agent \
-d libraries --input-file=download_library_urls.txt
mkdir -p source/libraries
awk 'BEGIN { cmd="cp -ri libraries/* source/libraries/" ; print "n" |cmd; }'

60
docker/download.sh Executable file
View File

@@ -0,0 +1,60 @@
#!/bin/sh
_use_backup="$2"
SELF_DIR=$(cd "$(dirname "$0")";pwd)
if [ ! -d "source" ]; then
mkdir source
fi
if [ ! -d "source/cache" ]; then
mkdir source/cache
fi
function readconf() {
cat $SELF_DIR/config.json | jq $@ | sed 's/\"//g'
}
cd source
if [ "$_use_backup" = "yes" ]; then
_use_backup="_2"
else
_use_backup=""
fi
archive_find_tar=$(find cache/ -name "$1.*" | grep -E ".tgz" | tail -n1)
archive_find_zip=$(find cache/ -name "$1.*" | grep -E ".zip" | tail -n1)
if [ "$archive_find_tar" != "" ]; then
echo "Using cache for $1 ($archive_find_tar)"
tar -zxf "$archive_find_tar"
elif [ "$archive_find_zip" != "" ]; then
echo "Using cache for $1 ($archive_find_zip)"
unzip $archive_find_zip -d "$SELF_DIR/source" > /dev/null
else
if [ "$3" != "" ]; then
wget -q "$(readconf ".$1.link$_use_backup" | sed 's/{version}/'$3'/g')"
else
echo "Downloading $1"
wget -q "$(readconf ".$1.link$_use_backup" | sed 's/{version}/'$(readconf ".$1.version")'/g')"
fi
if [ $? == 0 ]; then
archive_file_tar=$(find . -name "*.*" -maxdepth 1 | grep -E ".tar|.gz|.tgz" | tail -n1)
archive_file_zip=$(find . -name "*.zip" -maxdepth 1 | tail -n1)
if [ "$archive_file_tar" != "" ]; then
tar -zxf $archive_file_tar && mv $archive_file_tar $SELF_DIR/source/cache/$1.tgz
elif [ "$archive_file_zip" != "" ]; then
unzip $archive_file_zip && mv $archive_file_zip $SELF_DIR/source/cache/$1.zip > /dev/null
else
find . -name "*$1*.*"
echo "Unable to find downloaded file, only support '.tar.gz', '.tgz', '.zip' file!"
exit 1
fi
else
echo "Download $1 failed! (at $?)"
exit 1
fi
fi

View File

@@ -0,0 +1,22 @@
https://pecl.php.net/get/redis-5.3.7.tgz
out=redis-5.3.7.tgz
https://pecl.php.net/get/yaml-2.2.2.tgz
out=yaml-2.2.2.tgz
https://pecl.php.net/get/imagick-3.6.0.tgz
out=imagick-3.6.0.tgz
https://pecl.php.net/get/mongodb-1.14.2.tgz
out=mongodb-1.14.2.tgz
https://pecl.php.net/get/apcu-5.1.22.tgz
out=apcu-5.1.22.tgz
https://pecl.php.net/get/ds-1.4.0.tgz
out=ds-1.4.0.tgz
https://pecl.php.net/get/inotify-3.0.0.tgz
out=inotify-3.0.0.tgz
https://pecl.php.net/get/xlswriter-1.5.2.tgz
out=xlswriter-1.5.2.tgz
https://pecl.php.net/get/zstd-0.12.1.tgz
out=zstd-0.12.1.tgz
https://pecl.php.net/get/event-3.0.8.tgz
out=event-3.0.8.tgz
https://pecl.php.net/get/mcrypt-1.0.5.tgz
out=mcrypt-1.0.5.tgz

View File

@@ -0,0 +1,4 @@
https://pecl.php.net/get/mcrypt-1.0.5.tgz
out=mcrypt-1.0.5.tgz
https://pecl.php.net/get/apcu-5.1.22.tgz
out=apcu-5.1.22.tgz

View File

@@ -0,0 +1,72 @@
https://www.openssl.org/source/openssl-1.1.1p.tar.gz
out=openssl-1.1.1p.tar.gz
https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.16.tar.gz
out=libiconv-1.16.tar.gz
https://gitlab.gnome.org/GNOME/libxml2/-/archive/v2.9.10/libxml2-v2.9.10.tar.gz
out=libxml2-v2.9.10.tar.gz
https://gitlab.gnome.org/GNOME/libxslt/-/archive/v1.1.34/libxslt-v1.1.34.tar.gz
out=libxslt-v1.1.34.tar.gz
https://github.com/google/brotli/archive/refs/tags/v1.0.9.tar.gz
out=brotli-1.0.9.tar.gz
https://c-ares.org/download/c-ares-1.19.0.tar.gz
out=c-ares-1.19.0.tar.gz
https://gmplib.org/download/gmp/gmp-6.2.1.tar.lz
out=gmp-6.2.1.tar.lz
https://mirrors.tuna.tsinghua.edu.cn/gnu/ncurses/ncurses-6.3.tar.gz https://mirrors.ustc.edu.cn/gnu/ncurses/ncurses-6.3.tar.gz https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.3.tar.gz
out=ncurses-6.3.tar.gz
https://mirrors.tuna.tsinghua.edu.cn/gnu/readline/readline-8.2.tar.gz https://mirrors.ustc.edu.cn/gnu/readline/readline-8.2.tar.gz https://ftp.gnu.org/gnu/readline/readline-8.2.tar.gz
out=readline-8.2.tar.gz
https://pyyaml.org/download/libyaml/yaml-0.2.5.tar.gz
out=yaml-0.2.5.tar.gz
https://download.libsodium.org/libsodium/releases/libsodium-1.0.18.tar.gz
out=libsodium-1.0.18.tar.gz
https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz
out=bzip2-1.0.8.tar.gz
https://udomain.dl.sourceforge.net/project/libpng/zlib/1.2.11/zlib-1.2.11.tar.gz
out=zlib-1.2.11.tar.gz
https://github.com/lz4/lz4/archive/refs/tags/v1.9.4.tar.gz
out=lz4-v1.9.4.tar.gz
https://github.com/tukaani-project/xz/releases/download/v5.4.1/xz-5.4.1.tar.gz
out=xz-5.4.1.tar.gz
https://github.com/facebook/zstd/releases/download/v1.5.2/zstd-1.5.2.tar.gz
out=zstd-1.5.2.tar.gz
https://libzip.org/download/libzip-1.9.2.tar.gz
out=libzip-1.9.2.tar.gz
https://www.sqlite.org/2021/sqlite-autoconf-3370000.tar.gz
out=sqlite-autoconf-3370000.tar.gz
https://github.com/unicode-org/icu/releases/download/release-60-3/icu4c-60_3-src.tgz
out=icu4c-60_3-src.tgz
https://codeload.github.com/kkos/oniguruma/tar.gz/refs/tags/v6.9.7
out=oniguruma-6.9.7.tar.gz
https://github.com/microsoft/mimalloc/archive/refs/tags/v2.0.7.tar.gz
out=mimalloc-2.0.7.tar.gz
https://codeload.github.com/libjpeg-turbo/libjpeg-turbo/tar.gz/refs/tags/2.1.2
out=libjpeg-turbo-2.1.2.tar.gz
https://nchc.dl.sourceforge.net/project/giflib/giflib-5.2.1.tar.gz
out=giflib-5.2.1.tar.gz
https://nchc.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.gz
out=libpng-1.6.37.tar.gz
https://codeload.github.com/webmproject/libwebp/tar.gz/refs/tags/v1.2.1
out=libwebp-1.2.1.tar.gz
https://download.savannah.gnu.org/releases/freetype/freetype-2.10.4.tar.gz
out=freetype-2.10.4.tar.gz
https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.0-62.tar.gz
out=ImageMagick-v7.1.0-62.tar.gz
https://ftp.gnu.org/gnu/libidn/libidn2-2.3.4.tar.gz
out=libidn2-2.3.4.tar.gz
https://curl.se/download/curl-7.88.0.tar.gz
out=curl-7.88.0.tar.gz
https://ftp.postgresql.org/pub/source/v15.1/postgresql-15.1.tar.gz
out=postgresql-15.1.tar.gz
https://github.com/libffi/libffi/releases/download/v3.4.4/libffi-3.4.4.tar.gz
out=libffi-3.4.4.tar.gz
https://github.com/winlibs/libmcrypt/archive/refs/tags/libmcrypt-2.5.8-3.4.tar.gz
out=libmcrypt-2.5.8-3.4.tar.gz
https://github.com/jmcnamara/libxlsxwriter/archive/refs/tags/RELEASE_1.1.5.tar.gz
out=libxlsxwriter-1.1.5.tar.gz
https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
out=libevent-2.1.12-stable.tar.gz
https://github.com/libuv/libuv/archive/refs/tags/v1.44.2.tar.gz
out=libuv-v1.44.2.tar.gz
https://github.com/php/php-src/archive/refs/tags/php-8.1.12.tar.gz
out=php-8.1.12.tar.gz

View File

@@ -0,0 +1,4 @@
https://github.com/winlibs/libmcrypt/archive/refs/tags/libmcrypt-2.5.8-3.4.tar.gz
out=libmcrypt-2.5.8-3.4.tar.gz
https://gmplib.org/download/gmp/gmp-6.2.1.tar.lz
out=gmp-6.2.1.tar.lz

44
docker/extensions.txt Executable file
View File

@@ -0,0 +1,44 @@
# Start with '#' is comments
# Start with '^' is deselecting extensions, which is not installed as default
# Each line just leave the extension name or ^ character
bcmath
calendar
ctype
curl
dom
event
exif
fileinfo
filter
gd
hash
iconv
inotify
json
libxml
mbstring
mongodb
mysqlnd
openssl
pcntl
pdo
pdo_mysql
pdo_sqlite
phar
posix
^protobuf
^readline
redis
shmop
simplexml
soap
sockets
sqlite3
swoole
tokenizer
xml
xmlreader
xmlwriter
zlib
zip

63
docker/fast-compiler.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/bin/sh
# This script needs alpine linux system.
self_dir=$(cd "$(dirname "$0")";pwd)
test "$VER_PHP" = "" && VER_PHP="8.1.7"
test "$USE_BACKUP" = "" && USE_BACKUP="no"
test "$ALL_EXTENSIONS" = "" && ALL_EXTENSIONS="all"
LINK_APK_REPO='mirrors.ustc.edu.cn'
LINK_APK_REPO_BAK='dl-cdn.alpinelinux.org'
if [ "${USE_BACKUP}" = "yes" ]; then \
echo "Using backup address..." && sleep 1s
LINK_APK_REPO=${LINK_APK_REPO_BAK}
else
echo "Using original address..." && sleep 1s
fi
sed -i 's/dl-cdn.alpinelinux.org/'${LINK_APK_REPO}'/g' /etc/apk/repositories
# build requirements
apk add bash file wget cmake gcc g++ jq autoconf git libstdc++ linux-headers make m4 libgcc binutils ncurses dialog
# php zlib dependencies
apk add zlib-dev zlib-static
# php mbstring dependencies
apk add oniguruma-dev
# php openssl dependencies
apk add openssl-libs-static openssl-dev openssl
# php gd dependencies
apk add libpng-dev libpng-static
# curl c-ares dependencies
apk add c-ares-static c-ares-dev
# php event dependencies
apk add libevent libevent-dev libevent-static
# php sqlite3 dependencies
apk add sqlite sqlite-dev sqlite-libs sqlite-static
# php libzip dependencies
apk add bzip2-dev bzip2-static bzip2
# php micro ffi dependencies
apk add libffi libffi-dev
# php gd event parent dependencies
apk add zstd-static
# php readline dependencies
apk add readline-static ncurses-static readline-dev
test "$USE_BACKUP" = "no" && PROMPT_1="mirror" || PROMPT_1="original"
$self_dir/download.sh swoole ${USE_BACKUP} && \
$self_dir/download.sh inotify ${USE_BACKUP} && \
$self_dir/download.sh mongodb ${USE_BACKUP} && \
$self_dir/download.sh event ${USE_BACKUP} && \
$self_dir/download.sh redis ${USE_BACKUP} && \
$self_dir/download.sh libxml2 ${USE_BACKUP} && \
$self_dir/download.sh xz ${USE_BACKUP} && \
$self_dir/download.sh protobuf ${USE_BACKUP} && \
$self_dir/download.sh curl ${USE_BACKUP} && \
$self_dir/download.sh libzip ${USE_BACKUP} && \
$self_dir/download.sh libiconv ${USE_BACKUP} && \
$self_dir/download-git.sh dixyes/phpmicro phpmicro ${USE_BACKUP} && \
$self_dir/compile-deps.sh && \
$self_dir/compile-php.sh $PROMPT_1 $VER_PHP $ALL_EXTENSIONS /dist/

View File

@@ -1,3 +0,0 @@
# Extension List
See: [Docs - Extensions](https://static-php.dev/en/guide/extensions.html)

69
install-runtime.sh Normal file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/env bash
function download_file() {
downloader="wget"
type wget >/dev/null 2>&1 || { downloader="curl"; }
if [ "$downloader" = "wget" ]; then
_down_prefix="O"
else
_down_prefix="o"
fi
_down_symbol=0
if [ ! -f "$2" ]; then
echo $1
$downloader "$1" -$_down_prefix "$2" >/dev/null 2>&1 && \
echo "完成!" && _down_symbol=1
else
echo "已存在!" && _down_symbol=1
fi
if [ $_down_symbol == 0 ]; then
echo "失败!请检查网络连接!"
rm -rf "$2"
return 1
fi
return 0
}
function test_composer_and_php() {
succ=$("$(pwd)/runtime/composer" -n about | grep Manage)
if [ "$succ" = "" ]; then
echo "Download PHP binary and composer failed!"
return 1
fi
return 0
}
if [ "$(uname -s)" != "Linux" ]; then
echo "Only support Linux!!!"
exit 1
fi
ZM_PHP_VERSION="7.4"
if [ "$ZM_DOWN_PHP_VERSION" != "" ]; then
ZM_PHP_VERSION="$ZM_DOWN_PHP_VERSION"
echo "Using custom PHP version: $ZM_PHP_VERSION"
fi
mkdir "$(pwd)/runtime" >/dev/null 2>&1
if [ ! -f "$(pwd)/runtime/php" ]; then
download_file "https://dl.zhamao.xin/php-bin/down.php?php_ver=$ZM_PHP_VERSION&arch=$(uname -m)" "$(pwd)/runtime/php.tar.gz"
if [ $? -ne 0 ]; then
exit 1
fi
tar -xf "$(pwd)/runtime/php.tar.gz" -C "$(pwd)/runtime/"
fi
if [ ! -f "$(pwd)/runtime/composer" ]; then
download_file "https://mirrors.aliyun.com/composer/composer.phar" "$(pwd)/runtime/composer.phar"
if [ $? -ne 0 ]; then
exit 1
fi
echo '$(dirname $0)/php $(dirname $0)/composer.phar $@' > $(pwd)/runtime/composer
chmod +x $(pwd)/runtime/composer
test_composer_and_php
fi
if [ $? -ne 0 ]; then
exit 1
fi
echo "成功下载!" && \
echo -e "PHP使用\truntime/php -v" && \
echo -e "Composer使用\truntime/composer"

View File

@@ -1,12 +0,0 @@
parameters:
reportUnmatchedIgnoredErrors: false
level: 4
paths:
- ./src/
ignoreErrors:
- '#Constant .* not found#'
- '#Unsafe usage of new static#'
- '#class Fiber#'
- '#Attribute class JetBrains\\PhpStorm\\ArrayShape does not exist#'
dynamicConstantNames:
- PHP_OS_FAMILY

View File

@@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC;
use SPC\command\BuildCliCommand;
use SPC\command\BuildLibsCommand;
use SPC\command\dev\AllExtCommand;
use SPC\command\dev\PhpVerCommand;
use SPC\command\dev\SortConfigCommand;
use SPC\command\DoctorCommand;
use SPC\command\DownloadCommand;
use SPC\command\DumpLicenseCommand;
use SPC\command\ExtractCommand;
use SPC\command\MicroCombineCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\HelpCommand;
use Symfony\Component\Console\Command\ListCommand;
/**
* static-php-cli console app entry
*/
final class ConsoleApplication extends Application
{
public const VERSION = '2.0-rc7';
public function __construct()
{
parent::__construct('static-php-cli', self::VERSION);
$this->addCommands(
[
new BuildCliCommand(),
new BuildLibsCommand(),
new DoctorCommand(),
new DownloadCommand(),
new DumpLicenseCommand(),
new ExtractCommand(),
new MicroCombineCommand(),
// Dev commands
new AllExtCommand(),
new PhpVerCommand(),
new SortConfigCommand(),
]
);
}
protected function getDefaultCommands(): array
{
return [new HelpCommand(), new ListCommand()];
}
}

View File

@@ -1,331 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourceExtractor;
use SPC\util\CustomExt;
use SPC\util\DependencyUtil;
abstract class BuilderBase
{
/** @var int Concurrency */
public int $concurrency = 1;
/** @var array<string, LibraryBase> libraries */
protected array $libs = [];
/** @var array<string, Extension> extensions */
protected array $exts = [];
/** @var bool compile libs only (just mark it) */
protected bool $libs_only = false;
/** @var array<string, mixed> compile options */
protected array $options = [];
/**
* Build libraries
*
* @param array<string> $libraries Libraries to build
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function buildLibs(array $libraries): void
{
// search all supported libs
$support_lib_list = [];
$classes = FileSystem::getClassesPsr4(
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
'SPC\\builder\\' . osfamily2dir() . '\\library'
);
foreach ($classes as $class) {
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
$support_lib_list[$class::NAME] = $class;
}
}
// if no libs specified, compile all supported libs
if ($libraries === [] && $this->isLibsOnly()) {
$libraries = array_keys($support_lib_list);
}
// pkg-config must be compiled first, whether it is specified or not
if (!in_array('pkg-config', $libraries)) {
array_unshift($libraries, 'pkg-config');
}
// append dependencies
$libraries = DependencyUtil::getLibsByDeps($libraries);
// add lib object for builder
foreach ($libraries as $library) {
// if some libs are not supported (but in config "lib.json", throw exception)
if (!isset($support_lib_list[$library])) {
throw new RuntimeException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
}
$lib = new ($support_lib_list[$library])($this);
$this->addLib($lib);
}
// calculate and check dependencies
foreach ($this->libs as $lib) {
$lib->calcDependency();
}
// extract sources
SourceExtractor::initSource(libs: $libraries);
// build all libs
foreach ($this->libs as $lib) {
match ($lib->tryBuild($this->getOption('rebuild', false))) {
BUILD_STATUS_OK => logger()->info('lib [' . $lib::NAME . '] build success'),
BUILD_STATUS_ALREADY => logger()->notice('lib [' . $lib::NAME . '] already built'),
BUILD_STATUS_FAILED => logger()->error('lib [' . $lib::NAME . '] build failed'),
default => logger()->warning('lib [' . $lib::NAME . '] build status unknown'),
};
}
}
/**
* Add library to build.
*
* @param LibraryBase $library Library object
*/
public function addLib(LibraryBase $library): void
{
$this->libs[$library::NAME] = $library;
}
/**
* Get library object by name.
*/
public function getLib(string $name): ?LibraryBase
{
return $this->libs[$name] ?? null;
}
/**
* Add extension to build.
*/
public function addExt(Extension $extension): void
{
$this->exts[$extension->getName()] = $extension;
}
/**
* Get extension object by name.
*/
public function getExt(string $name): ?Extension
{
return $this->exts[$name] ?? null;
}
/**
* Get all extension objects.
*
* @return Extension[]
*/
public function getExts(): array
{
return $this->exts;
}
/**
* Check if there is a cpp extension.
*
* @throws FileSystemException
* @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;
}
/**
* Set libs only mode.
*/
public function setLibsOnly(bool $status = true): void
{
$this->libs_only = $status;
}
/**
* Verify the list of "ext" extensions for validity and declare an Extension object to check the dependencies of the extensions.
*
* @throws FileSystemException
* @throws RuntimeException
* @throws \ReflectionException
* @throws WrongUsageException
*/
public function proveExts(array $extensions): void
{
CustomExt::loadCustomExt();
SourceExtractor::initSource(sources: ['php-src']);
if ($this->getPHPVersionID() >= 80000) {
SourceExtractor::initSource(sources: ['micro']);
}
SourceExtractor::initSource(exts: $extensions);
foreach ($extensions as $extension) {
$class = CustomExt::getExtClass($extension);
$ext = new $class($extension, $this);
$this->addExt($ext);
}
foreach ($this->exts as $ext) {
$ext->checkDependency();
}
}
/**
* Start to build PHP
*
* @param int $build_target Build target, see BUILD_TARGET_*
*/
abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE);
/**
* Generate extension enable arguments for configure.
* e.g. --enable-mbstring
*
* @throws FileSystemException
* @throws WrongUsageException
*/
public function makeExtensionArgs(): string
{
$ret = [];
foreach ($this->exts as $ext) {
$ret[] = trim($ext->getConfigureArg());
}
logger()->info('Using configure: ' . implode(' ', $ret));
return implode(' ', $ret);
}
/**
* Get libs only mode.
*/
public function isLibsOnly(): bool
{
return $this->libs_only;
}
/**
* Get PHP Version ID from php-src/main/php_version.h
*
* @throws RuntimeException
* @throws WrongUsageException
*/
public function getPHPVersionID(): int
{
if (!file_exists(SOURCE_PATH . '/php-src/main/php_version.h')) {
throw new WrongUsageException('PHP source files are not available, you need to download them first');
}
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
return intval($match[1]);
}
throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
}
/**
* Get build type name string to display.
*
* @param int $type Build target type
*/
public function getBuildTypeName(int $type): string
{
$ls = [];
if (($type & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
$ls[] = 'cli';
}
if (($type & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
$ls[] = 'micro';
}
if (($type & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
$ls[] = 'fpm';
}
if (($type & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED) {
$ls[] = 'embed';
}
return implode(', ', $ls);
}
/**
* Get builder options (maybe changed by user)
*
* @param string $key Option key
* @param mixed $default If not exists, return this value
*/
public function getOption(string $key, mixed $default = null): mixed
{
return $this->options[$key] ?? $default;
}
/**
* Get all builder options
*/
public function getOptions(): array
{
return $this->options;
}
/**
* Set builder options if not exists.
*/
public function setOptionIfNotExist(string $key, mixed $value): void
{
if (!isset($this->options[$key])) {
$this->options[$key] = $value;
}
}
/**
* Set builder options.
*/
public function setOption(string $key, mixed $value): void
{
$this->options[$key] = $value;
}
/**
* Check if all libs are downloaded.
* If not, throw exception.
*
* @throws RuntimeException
*/
protected function checkLibsSource(): void
{
$not_downloaded = [];
foreach ($this->libs as $lib) {
if (!file_exists($lib->getSourceDir())) {
$not_downloaded[] = $lib::NAME;
}
}
if ($not_downloaded !== []) {
throw new RuntimeException(
'"' . implode(', ', $not_downloaded) .
'" totally ' . count($not_downloaded) .
' source' . (count($not_downloaded) === 1 ? '' : 's') .
' not downloaded, maybe you need to "fetch" ' . (count($not_downloaded) === 1 ? 'it' : 'them') . ' first?'
);
}
}
}

View File

@@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder;
use SPC\builder\linux\LinuxBuilder;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use Symfony\Component\Console\Input\InputInterface;
/**
* 用于生成对应系统环境的 Builder 对象的类
*/
class BuilderProvider
{
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public static function makeBuilderByInput(InputInterface $input): BuilderBase
{
return match (PHP_OS_FAMILY) {
// 'Windows' => new WindowsBuilder(
// binary_sdk_dir: $input->getOption('with-sdk-binary-dir'),
// vs_ver: $input->getOption('vs-ver'),
// arch: $input->getOption('arch'),
// ),
'Darwin' => new MacOSBuilder($input->getOptions()),
'Linux' => new LinuxBuilder($input->getOptions()),
default => throw new WrongUsageException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'),
};
}
}

View File

@@ -1,224 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
class Extension
{
protected array $dependencies = [];
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function __construct(protected string $name, protected BuilderBase $builder)
{
$ext_type = Config::getExt($this->name, 'type');
$unix_only = Config::getExt($this->name, 'unix-only', false);
$windows_only = Config::getExt($this->name, 'windows-only', false);
if (PHP_OS_FAMILY !== 'Windows' && $windows_only) {
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Linux and macOS platform");
}
if (PHP_OS_FAMILY === 'Windows' && $unix_only) {
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Windows platform");
}
}
/**
* 获取开启该扩展的 PHP 编译添加的参数
*
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getConfigureArg(): string
{
$arg = $this->getEnableArg();
switch (PHP_OS_FAMILY) {
case 'Windows':
$arg = $this->getWindowsConfigureArg();
break;
case 'Darwin':
case 'Linux':
$arg .= $this->getUnixConfigureArg();
break;
}
return $arg;
}
/**
* 根据 ext 的 arg-type 获取对应开启的参数,一般都是 --enable-xxx 和 --with-xxx
*
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getEnableArg(): string
{
$_name = str_replace('_', '-', $this->name);
return match ($arg_type = Config::getExt($this->name, 'arg-type', 'enable')) {
'enable' => '--enable-' . $_name . ' ',
'with' => '--with-' . $_name . ' ',
'with-prefix' => '--with-' . $_name . '="' . BUILD_ROOT_PATH . '" ',
'none', 'custom' => '',
default => throw new WrongUsageException("argType does not accept {$arg_type}, use [enable/with/with-prefix] ."),
};
}
/**
* 导出当前扩展依赖的所有 lib 库生成的 .a 静态编译库文件,以字符串形式导出,用空格分割
*/
public function getLibFilesString(): string
{
$ret = array_map(
fn ($x) => $x->getStaticLibFiles(),
$this->getLibraryDependencies(recursive: true)
);
return implode(' ', $ret);
}
/**
* 检查下依赖就行了,作用是导入依赖给 Extension 对象,今后可以对库依赖进行选择性处理
*
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function checkDependency(): static
{
foreach (Config::getExt($this->name, 'lib-depends', []) as $name) {
$this->addLibraryDependency($name);
}
foreach (Config::getExt($this->name, 'lib-suggests', []) as $name) {
$this->addLibraryDependency($name, true);
}
foreach (Config::getExt($this->name, 'ext-depends', []) as $name) {
$this->addExtensionDependency($name);
}
foreach (Config::getExt($this->name, 'ext-suggests', []) as $name) {
$this->addExtensionDependency($name, true);
}
return $this;
}
public function getExtensionDependency(): array
{
return array_filter($this->dependencies, fn ($x) => $x instanceof Extension);
}
public function getName(): string
{
return $this->name;
}
/**
* returns extension dist name
*/
public function getDistName(): string
{
return $this->name;
}
public function getWindowsConfigureArg(): string
{
return '';
// Windows is not supported yet
}
public function getUnixConfigureArg(): string
{
return '';
}
/**
* Patch code before ./buildconf
* If you need to patch some code, overwrite this and return true
*/
public function patchBeforeBuildconf(): bool
{
return false;
}
/**
* Patch code before ./configure
* If you need to patch some code, overwrite this and return true
*/
public function patchBeforeConfigure(): bool
{
return false;
}
/**
* Patch code before make
* If you need to patch some code, overwrite this and return true
*/
public function patchBeforeMake(): bool
{
return false;
}
/**
* @throws RuntimeException
*/
protected function addLibraryDependency(string $name, bool $optional = false): void
{
$depLib = $this->builder->getLib($name);
if (!$depLib) {
if (!$optional) {
throw new RuntimeException("extension {$this->name} requires library {$name}");
}
logger()->info("enabling {$this->name} without library {$name}");
} else {
$this->dependencies[] = $depLib;
}
}
/**
* @throws RuntimeException
*/
protected function addExtensionDependency(string $name, bool $optional = false): void
{
$depExt = $this->builder->getExt($name);
if (!$depExt) {
if (!$optional) {
throw new RuntimeException("{$this->name} requires extension {$name}");
}
logger()->info("enabling {$this->name} without extension {$name}");
} else {
$this->dependencies[] = $depExt;
}
}
private function getLibraryDependencies(bool $recursive = false): array
{
$ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
if (!$recursive) {
return $ret;
}
$deps = [];
$added = 1;
while ($added !== 0) {
$added = 0;
foreach ($ret as $depName => $dep) {
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
if (!in_array($depdepName, array_keys($deps), true)) {
$deps[$depdepName] = $depdep;
++$added;
}
}
if (!in_array($depName, array_keys($deps), true)) {
$deps[$depName] = $dep;
}
}
}
return $deps;
}
}

View File

@@ -1,201 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder;
use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
abstract class LibraryBase
{
/** @var string */
public const NAME = 'unknown';
protected string $source_dir;
protected array $dependencies = [];
/**
* @throws RuntimeException
*/
public function __construct(?string $source_dir = null)
{
if (static::NAME === 'unknown') {
throw new RuntimeException('no unknown!!!!!');
}
$this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . static::NAME);
}
/**
* Get current lib source root dir.
*/
public function getSourceDir(): string
{
return $this->source_dir;
}
/**
* Get current lib dependencies.
*
* @return array<string, LibraryBase>
*/
public function getDependencies(bool $recursive = false): array
{
// 非递归情况下直接返回通过 addLibraryDependency 方法添加的依赖
if (!$recursive) {
return $this->dependencies;
}
$deps = [];
$added = 1;
while ($added !== 0) {
$added = 0;
foreach ($this->dependencies as $depName => $dep) {
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
if (!in_array($depdepName, array_keys($deps), true)) {
$deps[$depdepName] = $depdep;
++$added;
}
}
if (!in_array($depName, array_keys($deps), true)) {
$deps[$depName] = $dep;
}
}
}
return $deps;
}
/**
* Calculate dependencies for current library.
*
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function calcDependency(): void
{
// Add dependencies from the configuration file. Here, choose different metadata based on the operating system.
/*
Rules:
If it is a Windows system, try the following dependencies in order: lib-depends-windows, lib-depends-win, lib-depends.
If it is a macOS system, try the following dependencies in order: lib-depends-darwin, lib-depends-unix, lib-depends.
If it is a Linux system, try the following dependencies in order: lib-depends-linux, lib-depends-unix, lib-depends.
*/
foreach (Config::getLib(static::NAME, 'lib-depends', []) as $dep_name) {
$this->addLibraryDependency($dep_name);
}
foreach (Config::getLib(static::NAME, 'lib-suggests', []) as $dep_name) {
$this->addLibraryDependency($dep_name, true);
}
}
/**
* Get config static libs.
*
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getStaticLibs(): array
{
return Config::getLib(static::NAME, 'static-libs', []);
}
/**
* Get config headers.
*
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getHeaders(): array
{
return Config::getLib(static::NAME, 'headers', []);
}
/**
* Try to build this library, before build, we check first.
*
* BUILD_STATUS_OK if build success
* BUILD_STATUS_ALREADY if already built
* BUILD_STATUS_FAILED if build failed
*
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function tryBuild(bool $force_build = false): int
{
// force means just build
if ($force_build) {
logger()->info('Building required library [' . static::NAME . ']');
$this->patchBeforeBuild();
$this->build();
return BUILD_STATUS_OK;
}
// check if these libraries exist, if not, invoke compilation and return the result status
foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
}
// header files the same
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
}
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
if ($this instanceof MacOSLibraryBase && static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
// if all the files exist at this point, skip the compilation process
return BUILD_STATUS_ALREADY;
}
/**
* Patch before build, overwrite this and return true to patch libs.
*/
public function patchBeforeBuild(): bool
{
return false;
}
/**
* Get current builder object.
*/
abstract public function getBuilder(): BuilderBase;
/**
* Build this library.
*
* @throws RuntimeException
*/
abstract protected function build();
/**
* Add lib dependency
*
* @throws RuntimeException
*/
protected function addLibraryDependency(string $name, bool $optional = false): void
{
$dep_lib = $this->getBuilder()->getLib($name);
if ($dep_lib) {
$this->dependencies[$name] = $dep_lib;
return;
}
if (!$optional) {
throw new RuntimeException(static::NAME . " requires library {$name}");
}
logger()->debug('enabling ' . static::NAME . " without {$name}");
}
}

View File

@@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder;
interface LibraryInterface
{
public function getName(): string;
}

View File

@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('bz2')]
class bz2 extends Extension
{
/**
* @throws FileSystemException
* @throws WrongUsageException
*/
public function patchBeforeConfigure(): bool
{
$frameworks = $this->builder instanceof MacOSBuilder ? ' ' . $this->builder->getFrameworks(true) . ' ' : '';
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-lbz2/', $this->getLibFilesString() . $frameworks);
return true;
}
}

View File

@@ -1,57 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('curl')]
class curl extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeBuildconf(): bool
{
logger()->info('patching before-configure for curl checks');
$file1 = "AC_DEFUN([PHP_CHECK_LIBRARY], [\n $3\n])";
$files = FileSystem::readFile(SOURCE_PATH . '/php-src/ext/curl/config.m4');
$file2 = 'AC_DEFUN([PHP_CHECK_LIBRARY], [
save_old_LDFLAGS=$LDFLAGS
ac_stuff="$5"
save_ext_shared=$ext_shared
ext_shared=yes
PHP_EVAL_LIBLINE([$]ac_stuff, LDFLAGS)
AC_CHECK_LIB([$1],[$2],[
LDFLAGS=$save_old_LDFLAGS
ext_shared=$save_ext_shared
$3
],[
LDFLAGS=$save_old_LDFLAGS
ext_shared=$save_ext_shared
unset ac_cv_lib_$1[]_$2
$4
])dnl
])';
file_put_contents(SOURCE_PATH . '/php-src/ext/curl/config.m4', $file1 . "\n" . $files . "\n" . $file2);
return true;
}
/**
* @throws FileSystemException
* @throws WrongUsageException
*/
public function patchBeforeConfigure(): bool
{
$frameworks = $this->builder instanceof MacOSBuilder ? ' ' . $this->builder->getFrameworks(true) . ' ' : '';
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-lcurl/', $this->getLibFilesString() . $frameworks);
return true;
}
}

View File

@@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('enchant')]
class enchant extends Extension
{
public function getUnixConfigureArg(): string
{
$glibs = [
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgio-2.0.a',
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libglib-2.0.a',
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgmodule-2.0.a',
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgobject-2.0.a',
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgthread-2.0.a',
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libintl.a',
];
$arg = '--with-enchant="' . BUILD_ROOT_PATH . '"';
$arg .= ' ENCHANT2_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '/enchant-2"';
$arg .= ' ENCHANT2_LIBS="' . $this->getLibFilesString() . '"';
$arg .= ' GLIB_CFLAGS=-I"' . BUILD_INCLUDE_PATH . '"';
$arg .= ' GLIB_LIBS="' . implode(' ', $glibs) . '"';
return $arg;
}
}

View File

@@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('event')]
class event extends Extension
{
public function getUnixConfigureArg(): string
{
$arg = '--with-event-core --with-event-extra --with-event-libevent-dir=' . BUILD_ROOT_PATH;
if ($this->builder->getLib('openssl')) {
$arg .= ' --with-event-openssl=' . BUILD_ROOT_PATH;
}
if ($this->builder->getExt('sockets')) {
$arg .= ' --enable-event-sockets';
} else {
$arg .= ' --disable-event-sockets';
}
return $arg;
}
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-levent_openssl/', $this->getLibFilesString());
return true;
}
}

View File

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

View File

@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('gd')]
class gd extends Extension
{
public function getUnixConfigureArg(): string
{
$arg = '--enable-gd';
$arg .= $this->builder->getLib('freetype') ? ' --with-freetype' : '';
$arg .= $this->builder->getLib('libjpeg') ? ' --with-jpeg' : '';
$arg .= $this->builder->getLib('libwebp') ? ' --with-webp' : '';
$arg .= $this->builder->getLib('libavif') ? ' --with-avif' : '';
return $arg;
}
}

View File

@@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('glfw')]
class glfw extends Extension
{
/**
* @throws RuntimeException
*/
public function patchBeforeBuildconf(): bool
{
FileSystem::copyDir(SOURCE_PATH . '/ext-glfw', SOURCE_PATH . '/php-src/ext/glfw');
return true;
}
public function getUnixConfigureArg(): string
{
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
}
}

View File

@@ -1,23 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('iconv')]
class iconv extends Extension
{
public function patchBeforeConfigure(): bool
{
// macOS need to link iconv dynamically, we add it to extra-libs
$extra_libs = $this->builder->getOption('extra-libs', '');
if (!str_contains($extra_libs, '-liconv')) {
$extra_libs .= ' -liconv';
}
$this->builder->setOption('extra-libs', $extra_libs);
return true;
}
}

View File

@@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('imagick')]
class imagick extends Extension
{
public function patchBeforeBuildconf(): bool
{
// linux need to link library manually, we add it to extra-libs
$extra_libs = $this->builder->getOption('extra-libs', '');
if (!str_contains($extra_libs, 'libMagickCore')) {
$extra_libs .= ' /usr/lib/libMagick++-7.Q16HDRI.a /usr/lib/libMagickCore-7.Q16HDRI.a /usr/lib/libMagickWand-7.Q16HDRI.a';
}
$this->builder->setOption('extra-libs', $extra_libs);
return true;
}
public function getUnixConfigureArg(): string
{
return '--with-imagick=' . BUILD_ROOT_PATH;
}
}

View File

@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mbregex')]
class mbregex extends Extension
{
public function getDistName(): string
{
return 'mbstring';
}
public function getConfigureArg(): string
{
return '';
}
}

View File

@@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mbstring')]
class mbstring extends Extension
{
public function getUnixConfigureArg(): string
{
$arg = '--enable-mbstring';
if ($this->builder->getExt('mbregex') === null) {
$arg .= ' --disable-mbregex';
}
return $arg;
}
}

View File

@@ -1,50 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('memcache')]
class memcache extends Extension
{
public function getUnixConfigureArg(): string
{
return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH;
}
/**
* @throws FileSystemException
*/
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'if test -d $abs_srcdir/src ; then',
'if test -d $abs_srcdir/main ; then'
);
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'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
);
return true;
}
}

View File

@@ -1,18 +0,0 @@
<?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

@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mongodb')]
class mongodb extends Extension
{
public function getUnixConfigureArg(): string
{
$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

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

View File

@@ -1,25 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('openssl')]
class openssl extends Extension
{
public function patchBeforeMake(): bool
{
// patch openssl3 with php8.0 bug
if (file_exists(SOURCE_PATH . '/openssl/VERSION.dat') && $this->builder->getPHPVersionID() < 80100) {
$openssl_c = file_get_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c');
$openssl_c = preg_replace('/REGISTER_LONG_CONSTANT\s*\(\s*"OPENSSL_SSLV23_PADDING"\s*.+;/', '', $openssl_c);
file_put_contents(SOURCE_PATH . '/php-src/ext/openssl/openssl.c', $openssl_c);
return true;
}
return false;
}
}

View File

@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('pdo_sqlite')]
class pdo_sqlite extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/sqlite3_column_table_name=yes/',
'sqlite3_column_table_name=no'
);
return true;
}
}

View File

@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('pgsql')]
class pgsql extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/-lpq/',
$this->getLibFilesString()
);
return true;
}
}

View File

@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('readline')]
class readline extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/-lncurses/',
$this->getLibFilesString()
);
return true;
}
}

View File

@@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('redis')]
class redis extends Extension
{
public function getUnixConfigureArg(): string
{
$arg = '--enable-redis';
if (!$this->builder->getExt('session')) {
$arg .= ' --disable-redis-session';
} else {
$arg .= ' --enable-redis-session';
}
if ($this->builder->getLib('zstd')) {
$arg .= ' --enable-redis-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
}
return $arg;
}
}

View File

@@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('snappy')]
class snappy extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/-lsnappy/',
$this->getLibFilesString() . ($this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++')
);
return true;
}
public function getUnixConfigureArg(): string
{
return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"';
}
}

View File

@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('ssh2')]
class ssh2 extends Extension
{
/**
* @throws FileSystemException
*/
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/configure',
'/-lssh2/',
$this->getLibFilesString()
);
return true;
}
}

View File

@@ -1,23 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('swoole')]
class swoole extends Extension
{
public function getUnixConfigureArg(): string
{
$arg = '--enable-swoole';
$arg .= $this->builder->getExt('pgsql') ? ' --enable-swoole-pgsql' : ' --disable-swoole-pgsql';
$arg .= $this->builder->getLib('openssl') ? ' --enable-openssl' : ' --disable-openssl --without-openssl';
$arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
// curl hook is buggy for static php
$arg .= ' --disable-swoole-curl';
return $arg;
}
}

View File

@@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\util\CustomExt;
#[CustomExt('swow')]
class swow extends Extension
{
public function getUnixConfigureArg(): string
{
$arg = '--enable-swow';
$arg .= $this->builder->getLib('openssl') ? ' --enable-swow-ssl' : ' --disable-swow-ssl';
$arg .= $this->builder->getLib('curl') ? ' --enable-swow-curl' : ' --disable-swow-curl';
return $arg;
}
/**
* @throws RuntimeException
*/
public function patchBeforeBuildconf(): bool
{
if ($this->builder->getPHPVersionID() >= 80000 && !is_link(SOURCE_PATH . '/php-src/ext/swow')) {
if (PHP_OS_FAMILY === 'Windows') {
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && mklink /D swow swow-src\ext');
} else {
f_passthru('cd ' . SOURCE_PATH . '/php-src/ext && ln -s swow-src/ext swow');
}
return true;
}
return false;
}
}

View File

@@ -1,17 +0,0 @@
<?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

@@ -1,36 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\util\CustomExt;
#[CustomExt('xml')]
#[CustomExt('soap')]
#[CustomExt('xmlreader')]
#[CustomExt('xmlwriter')]
#[CustomExt('dom')]
#[CustomExt('simplexml')]
class xml extends Extension
{
/**
* @throws RuntimeException
*/
public function getUnixConfigureArg(): string
{
$arg = match ($this->name) {
'xml' => '--enable-xml',
'soap' => '--enable-soap',
'xmlreader' => '--enable-xmlreader',
'xmlwriter' => '--enable-xmlwriter',
'dom' => '--enable-dom',
'simplexml' => '--enable-simplexml',
default => throw new RuntimeException('Not accept non-xml extension'),
};
$arg .= ' --with-libxml="' . BUILD_ROOT_PATH . '"';
return $arg;
}
}

View File

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

View File

@@ -1,337 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux;
use SPC\builder\BuilderBase;
use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\builder\traits\UnixBuilderTrait;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
class LinuxBuilder extends BuilderBase
{
/** Unix compatible builder methods */
use UnixBuilderTrait;
/** @var string Using libc [musl,glibc] */
public string $libc;
/** @var array Tune cflags */
public array $tune_c_flags;
/** @var string pkg-config env, including PKG_CONFIG_PATH, PKG_CONFIG */
public string $pkgconf_env;
/** @var bool Micro patch phar flag */
private bool $phar_patched = false;
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function __construct(array $options = [])
{
$this->options = $options;
// ---------- set necessary options ----------
// set C Compiler (default: alpine: gcc, others: musl-gcc)
$this->setOptionIfNotExist('cc', match (SystemUtil::getOSRelease()['dist']) {
'alpine' => 'gcc',
default => 'musl-gcc'
});
// set C++ Compiler (default: g++)
$this->setOptionIfNotExist('cxx', 'g++');
// set arch (default: current)
$this->setOptionIfNotExist('arch', php_uname('m'));
$this->setOptionIfNotExist('gnu-arch', arch2gnu($this->getOption('arch')));
// ---------- set necessary compile environments ----------
// set libc
$this->libc = $this->getOption('cc', 'gcc') === 'musl-gcc' ? 'musl_wrapper' : 'musl'; // SystemUtil::selectLibc($this->cc);
// concurrency
$this->concurrency = SystemUtil::getCpuCount();
// cflags
$this->arch_c_flags = SystemUtil::getArchCFlags($this->getOption('cc'), $this->getOption('arch'));
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->getOption('cxx'), $this->getOption('arch'));
$this->tune_c_flags = SystemUtil::checkCCFlags(SystemUtil::getTuneCFlags($this->getOption('arch')), $this->getOption('cc'));
// cmake toolchain
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile(
'Linux',
$this->getOption('arch'),
$this->arch_c_flags,
$this->getOption('cc'),
$this->getOption('cxx'),
);
// pkg-config
$vars = [
'PKG_CONFIG' => BUILD_ROOT_PATH . '/bin/pkg-config',
'PKG_CONFIG_PATH' => BUILD_LIB_PATH . '/pkgconfig',
];
$this->pkgconf_env = SystemUtil::makeEnvVarString($vars);
// configure environment
$this->configure_env = SystemUtil::makeEnvVarString([
...$vars,
'CC' => $this->getOption('cc'),
'CXX' => $this->getOption('cxx'),
'PATH' => BUILD_ROOT_PATH . '/bin:' . getenv('PATH'),
]);
// cross-compile does not support yet
/*if (php_uname('m') !== $this->arch) {
$this->cross_compile_prefix = SystemUtil::getCrossCompilePrefix($this->cc, $this->arch);
logger()->info('using cross compile prefix: ' . $this->cross_compile_prefix);
$this->configure_env .= " CROSS_COMPILE='{$this->cross_compile_prefix}'";
}*/
// create pkgconfig and include dir (some libs cannot create them automatically)
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
f_mkdir(BUILD_INCLUDE_PATH, recursive: true);
}
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function makeAutoconfArgs(string $name, array $libSpecs): string
{
$ret = '';
foreach ($libSpecs as $libName => $arr) {
$lib = $this->getLib($libName);
$arr = $arr ?? [];
$disableArgs = $arr[0] ?? null;
$prefix = $arr[1] ?? null;
if ($lib instanceof LinuxLibraryBase) {
logger()->info("{$name} \033[32;1mwith\033[0;1m {$libName} support");
$ret .= $lib->makeAutoconfEnv($prefix) . ' ';
} else {
logger()->info("{$name} \033[31;1mwithout\033[0;1m {$libName} support");
$ret .= ($disableArgs ?? "--with-{$libName}=no") . ' ';
}
}
return rtrim($ret);
}
/**
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{
// ---------- Update extra-libs ----------
$extra_libs = $this->getOption('extra-libs', '');
// non-bloat linking
if (!$this->getOption('bloat', false)) {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', $this->getAllStaticLibFiles());
} else {
$extra_libs .= (empty($extra_libs) ? '' : ' ') . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", array_filter($this->getAllStaticLibFiles())));
}
// add libstdc++, some extensions or libraries need it (C++ cannot be linked statically)
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCppExtension() ? '-lstdc++ ' : '');
$this->setOption('extra-libs', $extra_libs);
$cflags = $this->arch_c_flags;
$use_lld = '';
switch ($this->libc) {
case 'musl_wrapper':
case 'glibc':
$cflags .= ' -static-libgcc -I"' . BUILD_INCLUDE_PATH . '"';
break;
case 'musl':
if (str_ends_with($this->getOption('cc'), 'clang') && SystemUtil::findCommand('lld')) {
$use_lld = '-Xcompiler -fuse-ld=lld';
}
break;
default:
throw new WrongUsageException('libc ' . $this->libc . ' is not implemented yet');
}
$envs = $this->pkgconf_env . ' ' . SystemUtil::makeEnvVarString([
'CC' => $this->getOption('cc'),
'CXX' => $this->getOption('cxx'),
'CFLAGS' => $cflags,
'LIBS' => '-ldl -lpthread',
'PATH' => BUILD_ROOT_PATH . '/bin:' . getenv('PATH'),
]);
SourcePatcher::patchBeforeBuildconf($this);
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
SourcePatcher::patchBeforeConfigure($this);
$phpVersionID = $this->getPHPVersionID();
$json_74 = $phpVersionID < 80000 ? '--enable-json ' : '';
if ($this->getOption('enable-zts', false)) {
$maxExecutionTimers = $phpVersionID >= 80100 ? '--enable-zend-max-execution-timers ' : '';
$zts = '--enable-zts --disable-zend-signals ';
} else {
$maxExecutionTimers = '';
$zts = '';
}
$enableCli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI;
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
$enableMicro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
$enableEmbed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
shell()->cd(SOURCE_PATH . '/php-src')
->exec(
'./configure ' .
'--prefix= ' .
'--with-valgrind=no ' .
'--enable-shared=no ' .
'--enable-static=yes ' .
'--disable-all ' .
'--disable-cgi ' .
'--disable-phpdbg ' .
($enableCli ? '--enable-cli ' : '--disable-cli ') .
($enableFpm ? '--enable-fpm ' : '--disable-fpm ') .
($enableEmbed ? '--enable-embed=static --disable-opcache-jit ' : '--disable-embed ') .
$json_74 .
$zts .
$maxExecutionTimers .
($enableMicro ? '--enable-micro=all-static ' : '--disable-micro ') .
$this->makeExtensionArgs() . ' ' .
$envs
);
SourcePatcher::patchBeforeMake($this);
$this->cleanMake();
if ($enableCli) {
logger()->info('building cli');
$this->buildCli($extra_libs, $use_lld);
}
if ($enableFpm) {
logger()->info('building fpm');
$this->buildFpm($extra_libs, $use_lld);
}
if ($enableMicro) {
logger()->info('building micro');
$this->buildMicro($extra_libs, $use_lld, $cflags);
}
if ($enableEmbed) {
logger()->info('building embed');
if ($enableMicro) {
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'OVERALL_TARGET =', 'OVERALL_TARGET = libphp.la');
}
$this->buildEmbed($extra_libs, $use_lld);
}
if (php_uname('m') === $this->getOption('arch')) {
$this->sanityCheck($build_target);
}
}
/**
* Build cli sapi
*
* @throws RuntimeException
* @throws FileSystemException
*/
public function buildCli(string $extra_libs, string $use_lld): void
{
$vars = SystemUtil::makeEnvVarString([
'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)),
'EXTRA_LIBS' => $extra_libs,
'EXTRA_LDFLAGS_PROGRAM' => "{$use_lld} -all-static",
]);
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make -j{$this->concurrency} {$vars} cli");
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')->exec('strip --strip-all php');
}
$this->deployBinary(BUILD_TARGET_CLI);
}
/**
* Build phpmicro sapi
*
* @throws RuntimeException
* @throws FileSystemException
*/
public function buildMicro(string $extra_libs, string $use_lld, string $cflags): void
{
if ($this->getPHPVersionID() < 80000) {
throw new RuntimeException('phpmicro only support PHP >= 8.0!');
}
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicro(['phar']);
}
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
$vars = SystemUtil::makeEnvVarString([
'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)) . $enable_fake_cli,
'EXTRA_LIBS' => $extra_libs,
'EXTRA_LDFLAGS_PROGRAM' => "{$cflags} {$use_lld} -all-static",
]);
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make -j{$this->concurrency} {$vars} micro");
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/micro')->exec('strip --strip-all micro.sfx');
}
$this->deployBinary(BUILD_TARGET_MICRO);
if ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
}
}
/**
* Build fpm sapi
*
* @throws FileSystemException
* @throws RuntimeException
*/
public function buildFpm(string $extra_libs, string $use_lld): void
{
$vars = SystemUtil::makeEnvVarString([
'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)),
'EXTRA_LIBS' => $extra_libs,
'EXTRA_LDFLAGS_PROGRAM' => "{$use_lld} -all-static",
]);
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("make -j{$this->concurrency} {$vars} fpm");
if (!$this->getOption('no-strip', false)) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm')->exec('strip --strip-all php-fpm');
}
$this->deployBinary(BUILD_TARGET_FPM);
}
public function buildEmbed(string $extra_libs, string $use_lld): void
{
$vars = SystemUtil::makeEnvVarString([
'EXTRA_CFLAGS' => '-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)),
'EXTRA_LIBS' => $extra_libs,
'EXTRA_LDFLAGS_PROGRAM' => "{$use_lld} -all-static",
]);
shell()
->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec('make INSTALL_ROOT=' . BUILD_ROOT_PATH . " -j{$this->concurrency} {$vars} install");
}
}

View File

@@ -1,207 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux;
use SPC\builder\traits\UnixSystemUtilTrait;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
class SystemUtil
{
use UnixSystemUtilTrait;
/** @noinspection PhpMissingBreakStatementInspection */
public static function getOSRelease(): array
{
$ret = [
'dist' => 'unknown',
'ver' => 'unknown',
];
switch (true) {
case file_exists('/etc/os-release'):
$lines = file('/etc/os-release');
foreach ($lines as $line) {
if (preg_match('/^ID=(.*)$/', $line, $matches)) {
$ret['dist'] = $matches[1];
}
if (preg_match('/^VERSION_ID=(.*)$/', $line, $matches)) {
$ret['ver'] = $matches[1];
}
}
$ret['dist'] = trim($ret['dist'], '"\'');
$ret['ver'] = trim($ret['ver'], '"\'');
if (strcasecmp($ret['dist'], 'centos') === 0) {
$ret['dist'] = 'redhat';
}
break;
case file_exists('/etc/centos-release'):
$lines = file('/etc/centos-release');
goto rh;
case file_exists('/etc/redhat-release'):
$lines = file('/etc/redhat-release');
rh:
foreach ($lines as $line) {
if (preg_match('/release\s+(\d+(\.\d+)*)/', $line, $matches)) {
$ret['dist'] = 'redhat';
$ret['ver'] = $matches[1];
}
}
break;
}
return $ret;
}
public static function getCpuCount(): int
{
$ncpu = 1;
if (is_file('/proc/cpuinfo')) {
$cpuinfo = file_get_contents('/proc/cpuinfo');
preg_match_all('/^processor/m', $cpuinfo, $matches);
$ncpu = count($matches[0]);
}
return $ncpu;
}
/**
* @throws RuntimeException
*/
public static function getCCType(string $cc): string
{
return match (true) {
str_ends_with($cc, 'c++'), str_ends_with($cc, 'cc'), str_ends_with($cc, 'g++'), str_ends_with($cc, 'gcc') => 'gcc',
$cc === 'clang++', $cc === 'clang', str_starts_with($cc, 'musl-clang') => 'clang',
default => throw new RuntimeException("unknown cc type: {$cc}"),
};
}
/**
* @throws RuntimeException
* @throws WrongUsageException
* @throws WrongUsageException
*/
public static function getArchCFlags(string $cc, string $arch): string
{
if (php_uname('m') === $arch) {
return '';
}
return match (static::getCCType($cc)) {
'clang' => match ($arch) {
'x86_64' => '--target=x86_64-unknown-linux',
'arm64', 'aarch64' => '--target=arm64-unknown-linux',
default => throw new WrongUsageException('unsupported arch: ' . $arch),
},
'gcc' => '',
default => throw new WrongUsageException('cc compiler ' . $cc . ' is not supported'),
};
}
/**
* @throws RuntimeException
*/
public static function getTuneCFlags(string $arch): array
{
return match ($arch) {
'x86_64' => [
'-march=corei7',
'-mtune=core-avx2',
],
'arm64', 'aarch64' => [],
default => throw new RuntimeException('unsupported arch: ' . $arch),
};
}
public static function checkCCFlags(array $flags, string $cc): array
{
return array_filter($flags, fn ($flag) => static::checkCCFlag($flag, $cc));
}
public static function checkCCFlag(string $flag, string $cc): string
{
[$ret] = shell()->execWithResult("echo | {$cc} -E -x c - {$flag} 2>/dev/null");
if ($ret != 0) {
return '';
}
return $flag;
}
/**
* @throws RuntimeException
* @noinspection PhpUnused
*/
public static function getCrossCompilePrefix(string $cc, string $arch): string
{
return match (static::getCCType($cc)) {
// guessing clang toolchains
'clang' => match ($arch) {
'x86_64' => 'x86_64-linux-gnu-',
'arm64', 'aarch64' => 'aarch64-linux-gnu-',
default => throw new RuntimeException('unsupported arch: ' . $arch),
},
// remove gcc postfix
'gcc' => str_replace('-cc', '', str_replace('-gcc', '', $cc)) . '-',
default => throw new RuntimeException('unsupported cc'),
};
}
public static function findStaticLib(string $name): ?array
{
$paths = getenv('LIBPATH');
if (!$paths) {
$paths = '/lib:/lib64:/usr/lib:/usr/lib64:/usr/local/lib:/usr/local/lib64:';
}
foreach (explode(':', $paths) as $path) {
if (file_exists("{$path}/{$name}")) {
return ["{$path}", "{$name}"];
}
}
return null;
}
/** @noinspection PhpUnused */
public static function findStaticLibs(array $names): ?array
{
$ret = [];
foreach ($names as $name) {
$path = static::findStaticLib($name);
if (!$path) {
logger()->warning("static library {$name} not found");
return null;
}
$ret[] = $path;
}
return $ret;
}
public static function findHeader(string $name): ?array
{
$paths = getenv('INCLUDEPATH');
if (!$paths) {
$paths = '/include:/usr/include:/usr/local/include';
}
foreach (explode(':', $paths) as $path) {
if (file_exists("{$path}/{$name}") || is_dir("{$path}/{$name}")) {
return ["{$path}", "{$name}"];
}
}
return null;
}
/** @noinspection PhpUnused */
public static function findHeaders(array $names): ?array
{
$ret = [];
foreach ($names as $name) {
$path = static::findHeader($name);
if (!$path) {
logger()->warning("header {$name} not found");
return null;
}
$ret[] = $path;
}
return $ret;
}
}

View File

@@ -1,88 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\builder\BuilderBase;
use SPC\builder\LibraryBase;
use SPC\builder\linux\LinuxBuilder;
use SPC\builder\traits\UnixLibraryTrait;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
abstract class LinuxLibraryBase extends LibraryBase
{
use UnixLibraryTrait;
protected array $static_libs = [];
protected array $headers;
protected array $pkgconfs;
/**
* 依赖的名字及是否可选例如curl => true代表依赖 curl 但可选
*/
protected array $dep_names;
public function __construct(protected LinuxBuilder $builder)
{
parent::__construct();
}
public function getBuilder(): BuilderBase
{
return $this->builder;
}
/**
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
public function tryBuild(bool $force_build = false): int
{
// 传入 true表明直接编译
if ($force_build) {
logger()->info('Building required library [' . static::NAME . ']');
$this->patchBeforeBuild();
$this->build();
return BUILD_STATUS_OK;
}
// 看看这些库是不是存在,如果不存在,则调用编译并返回结果状态
foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
}
// 头文件同理
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
}
// pkg-config 做特殊处理,如果是 pkg-config 就检查有没有 pkg-config 二进制
if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
// 到这里说明所有的文件都存在,就跳过编译
return BUILD_STATUS_ALREADY;
}
protected function makeFakePkgconfs(): void
{
$workspace = BUILD_ROOT_PATH;
if ($workspace === '/') {
$workspace = '';
}
foreach ($this->pkgconfs as $name => $content) {
file_put_contents(BUILD_LIB_PATH . "/pkgconfig/{$name}", "prefix={$workspace}\n" . $content);
}
}
}

View File

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

View File

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

View File

@@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class curl extends LinuxLibraryBase
{
use \SPC\builder\unix\library\curl;
public const NAME = 'curl';
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
{
$libs = parent::getStaticLibFiles($style, $recursive);
if ($this->builder->getLib('openssl')) {
$libs .= ' -ldl -lpthread';
}
return $libs;
}
}

View File

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

View File

@@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
/**
* gmp is a template library class for unix
*/
class gmp extends LinuxLibraryBase
{
use \SPC\builder\unix\library\gmp;
public const NAME = 'gmp';
}

View File

@@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class icu extends LinuxLibraryBase
{
public const NAME = 'icu';
protected function build(): void
{
$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

@@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
/**
* a template library class for unix
*/
class imagemagick extends LinuxLibraryBase
{
use \SPC\builder\unix\library\imagemagick;
public const NAME = 'imagemagick';
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,20 +0,0 @@
<?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

@@ -1,86 +0,0 @@
<?php
/**
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
*
* lwmbs is licensed under Mulan PSL v2. You can use this
* software according to the terms and conditions of the
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
*/
declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\builder\linux\SystemUtil;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
class libpng extends LinuxLibraryBase
{
public const NAME = 'libpng';
/**
* @throws FileSystemException
*/
public function patchBeforeBuild(): bool
{
FileSystem::replaceFileStr(
SOURCE_PATH . '/libpng/configure',
'-lz',
BUILD_LIB_PATH . '/libz.a'
);
if (SystemUtil::getOSRelease()['dist'] === 'alpine') {
FileSystem::replaceFileStr(
SOURCE_PATH . '/libpng/configure',
'-lm',
'/usr/lib/libm.a'
);
}
return true;
}
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public function build(): void
{
$optimizations = match ($this->builder->getOption('arch')) {
'x86_64' => '--enable-intel-sse ',
'arm64' => '--enable-arm-neon ',
default => '',
};
shell()->cd($this->source_dir)
->exec('chmod +x ./configure')
->exec('chmod +x ./install-sh')
->exec(
"{$this->builder->configure_env} ./configure " .
"--host={$this->builder->getOption('gnu-arch')}-unknown-linux " .
'--disable-shared ' .
'--enable-static ' .
'--enable-hardware-optimizations ' .
'--with-zlib-prefix="' . BUILD_ROOT_PATH . '" ' .
$optimizations .
'--prefix='
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I. -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la")
->exec('make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH)
->cd(BUILD_LIB_PATH)
->exec('ln -sf libpng16.a libpng.a');
$this->patchPkgconfPrefix(['libpng16.pc'], PKGCONF_PATCH_PREFIX);
$this->cleanLaFiles();
}
}

View File

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

View File

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

View File

@@ -1,28 +0,0 @@
<?php
/**
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
*
* lwmbs is licensed under Mulan PSL v2. You can use this
* software according to the terms and conditions of the
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
*/
declare(strict_types=1);
namespace SPC\builder\linux\library;
class libwebp extends LinuxLibraryBase
{
use \SPC\builder\unix\library\libwebp;
public const NAME = 'libwebp';
}

View File

@@ -1,47 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
class libxml2 extends LinuxLibraryBase
{
public const NAME = 'libxml2';
/**
* @throws RuntimeException
* @throws FileSystemException
*/
public function build(): void
{
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
// $enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
FileSystem::resetDir($this->source_dir . '/build');
shell()->cd($this->source_dir . '/build')
->exec(
"{$this->builder->configure_env} " . ' cmake ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DCMAKE_INSTALL_PREFIX=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DCMAKE_INSTALL_BINDIR=' . escapeshellarg(BUILD_ROOT_PATH . '/bin') . ' ' .
'-DLIBXML2_WITH_ICONV=ON ' .
'-DIconv_IS_BUILT_IN=OFF ' .
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
'-DLIBXML2_WITH_ICU=OFF ' .
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
'-DLIBXML2_WITH_PYTHON=OFF ' .
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
'-DLIBXML2_WITH_TESTS=OFF ' .
'..'
)
->exec("cmake --build . -j {$this->builder->concurrency}")
->exec('make install');
}
}

View File

@@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
/**
* gmp is a template library class for unix
*/
class libxslt extends LinuxLibraryBase
{
use \SPC\builder\unix\library\libxslt;
public const NAME = 'libxslt';
}

Some files were not shown because too many files have changed in this diff Show More