Compare commits

..

5 Commits

Author SHA1 Message Date
Marc
95bb4cb018 Merge branch 'main' into rename 2025-11-30 16:09:18 +01:00
crazywhalecc
1bbf83872f Change phpmicro base link 2025-11-26 13:28:15 +08:00
crazywhalecc
fadb1ce6c9 Rename static-php-cli to StaticPHP 2025-11-26 13:24:38 +08:00
crazywhalecc
58bf51e9c9 Next version yeah 2025-11-26 12:55:14 +08:00
crazywhalecc
b60ea8e3d6 Add maxminddb extension and libmaxminddb 2025-11-26 12:54:52 +08:00
124 changed files with 870 additions and 2846 deletions

View File

@@ -29,9 +29,6 @@ on:
description: Extensions to build (comma separated)
required: true
type: string
shared-extensions:
description: Shared extensions to build (optional, comma separated)
type: string
extra-libs:
description: Extra libraries to build (optional, comma separated)
type: string
@@ -45,22 +42,10 @@ on:
build-fpm:
description: Build fpm binary
type: boolean
build-frankenphp:
description: Build frankenphp binary (requires ZTS)
type: boolean
default: false
enable-zts:
description: Enable ZTS
type: boolean
default: false
prefer-pre-built:
description: Prefer pre-built binaries (reduce build time)
type: boolean
default: true
with-suggested-libs:
description: Build with suggested libs
type: boolean
default: false
debug:
description: Show full build logs
type: boolean
@@ -84,9 +69,6 @@ on:
description: Extensions to build (comma separated)
required: true
type: string
shared-extensions:
description: Shared extensions to build (optional, comma separated)
type: string
extra-libs:
description: Extra libraries to build (optional, comma separated)
type: string
@@ -100,22 +82,10 @@ on:
build-fpm:
description: Build fpm binary
type: boolean
build-frankenphp:
description: Build frankenphp binary (requires ZTS)
type: boolean
default: false
enable-zts:
description: Enable ZTS
type: boolean
default: false
prefer-pre-built:
description: Prefer pre-built binaries (reduce build time)
type: boolean
default: true
with-suggested-libs:
description: Include suggested libs
type: boolean
default: false
debug:
description: Show full build logs
type: boolean
@@ -174,19 +144,8 @@ jobs:
RUNS_ON="macos-15"
;;
esac
STATIC_EXTS="${{ inputs.extensions }}"
SHARED_EXTS="${{ inputs['shared-extensions'] }}"
BUILD_FRANKENPHP="${{ inputs['build-frankenphp'] }}"
ENABLE_ZTS="${{ inputs['enable-zts'] }}"
ALL_EXTS="$STATIC_EXTS"
if [ -n "$SHARED_EXTS" ]; then
ALL_EXTS="$ALL_EXTS,$SHARED_EXTS"
fi
DOWN_CMD="$DOWN_CMD --with-php=${{ inputs.php-version }} --for-extensions=$ALL_EXTS --ignore-cache-sources=php-src"
BUILD_CMD="$BUILD_CMD $STATIC_EXTS"
if [ -n "$SHARED_EXTS" ]; then
BUILD_CMD="$BUILD_CMD --build-shared=$SHARED_EXTS"
fi
DOWN_CMD="$DOWN_CMD --with-php=${{ inputs.php-version }} --for-extensions=${{ inputs.extensions }} --ignore-cache-sources=php-src"
BUILD_CMD="$BUILD_CMD ${{ inputs.extensions }}"
if [ -n "${{ inputs.extra-libs }}" ]; then
DOWN_CMD="$DOWN_CMD --for-libs=${{ inputs.extra-libs }}"
BUILD_CMD="$BUILD_CMD --with-libs=${{ inputs.extra-libs }}"
@@ -198,9 +157,6 @@ jobs:
if [ ${{ inputs.prefer-pre-built }} == true ]; then
DOWN_CMD="$DOWN_CMD --prefer-pre-built"
fi
if [ ${{ inputs.with-suggested-libs }} == true ]; then
BUILD_CMD="$BUILD_CMD --with-suggested-libs"
fi
if [ ${{ inputs.build-cli }} == true ]; then
BUILD_CMD="$BUILD_CMD --build-cli"
fi
@@ -210,12 +166,6 @@ jobs:
if [ ${{ inputs.build-fpm }} == true ]; then
BUILD_CMD="$BUILD_CMD --build-fpm"
fi
if [ "$BUILD_FRANKENPHP" = "true" ]; then
BUILD_CMD="$BUILD_CMD --build-frankenphp"
fi
if [ "$ENABLE_ZTS" = "true" ]; then
BUILD_CMD="$BUILD_CMD --enable-zts"
fi
echo 'download='"$DOWN_CMD" >> "$GITHUB_OUTPUT"
echo 'build='"$BUILD_CMD" >> "$GITHUB_OUTPUT"
echo 'run='"$RUNS_ON" >> "$GITHUB_OUTPUT"
@@ -238,27 +188,6 @@ jobs:
env:
phpts: nts
- if: ${{ inputs['build-frankenphp'] == true }}
name: "Install go-xcaddy for FrankenPHP"
run: |
case "${{ inputs.os }}" in
linux-x86_64|linux-aarch64)
./bin/spc-alpine-docker install-pkg go-xcaddy
;;
linux-x86_64-glibc|linux-aarch64-glibc)
./bin/spc-gnu-docker install-pkg go-xcaddy
;;
macos-x86_64|macos-aarch64)
composer update --no-dev --classmap-authoritative
./bin/spc doctor --auto-fix
./bin/spc install-pkg go-xcaddy
;;
*)
echo "Unsupported OS for go-xcaddy install: ${{ inputs.os }}"
exit 1
;;
esac
# Cache downloaded source
- id: cache-download
uses: actions/cache@v4
@@ -273,14 +202,6 @@ jobs:
# if: ${{ failure() }}
# uses: mxschmitt/action-tmate@v3
# Upload debug logs
- if: ${{ inputs.debug && failure() }}
name: "Upload build logs on failure"
uses: actions/upload-artifact@v4
with:
name: spc-logs-${{ inputs.php-version }}-${{ inputs.os }}
path: log/*.log
# Upload cli executable
- if: ${{ inputs.build-cli == true }}
name: "Upload PHP cli SAPI"
@@ -305,22 +226,7 @@ jobs:
name: php-fpm-${{ inputs.php-version }}-${{ inputs.os }}
path: buildroot/bin/php-fpm
# Upload frankenphp executable
- if: ${{ inputs['build-frankenphp'] == true }}
name: "Upload FrankenPHP SAPI"
uses: actions/upload-artifact@v4
with:
name: php-frankenphp-${{ inputs.php-version }}-${{ inputs.os }}
path: buildroot/bin/frankenphp
# Upload extensions metadata
- if: ${{ inputs['shared-extensions'] != '' }}
name: "Upload shared extensions"
uses: actions/upload-artifact@v4
with:
name: php-shared-ext-${{ inputs.php-version }}-${{ inputs.os }}
path: |
buildroot/modules/*.so
- uses: actions/upload-artifact@v4
name: "Upload License Files"
with:

View File

@@ -32,13 +32,10 @@ jobs:
php-version: '8.4'
extensions: curl, openssl, mbstring
ini-values: memory_limit=-1
tools: pecl, composer
- name: "Install dependencies"
run: composer install --no-progress --prefer-dist --optimize-autoloader
tools: pecl, composer, php-cs-fixer
- name: Run PHP-CS-Fixer fix
run: vendor/bin/php-cs-fixer fix --dry-run --diff --ansi
run: php-cs-fixer fix --dry-run --diff --ansi
phpstan:
runs-on: ubuntu-latest

View File

@@ -1,24 +1,24 @@
# static-php-cli
# StaticPHP
[![English readme](https://img.shields.io/badge/README-English%20%F0%9F%87%AC%F0%9F%87%A7-moccasin?style=flat-square)](README.md)
[![Chinese readme](https://img.shields.io/badge/README-%E4%B8%AD%E6%96%87%20%F0%9F%87%A8%F0%9F%87%B3-moccasin?style=flat-square)](README-zh.md)
[![English readme](https://img.shields.io/badge/README-English%20%F0%9F%87%AC%F0%9F%87%A7-moccasin?style=flat-square)](README.md)
[![Releases](https://img.shields.io/packagist/v/crazywhalecc/static-php-cli?include_prereleases&label=Release&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/releases)
[![CI](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/tests.yml?branch=main&label=Build%20Test&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
**static-php-cli** 是一个用于构建静态、独立 PHP 运行时的强大工具,支持众多流行扩展。
**StaticPHP**(原名 **static-php-cli**是一个用于构建静态、独立 PHP 运行时的强大工具,支持众多流行扩展。
## 特性
- :elephant: **支持多 PHP 版本** - 支持 PHP 8.1, 8.2, 8.3, 8.4, 8.5
- :handbag: **单文件 PHP 可执行文件** - 构建零依赖的独立 PHP
- :hamburger: **phpmicro 集成** - 构建 **[phpmicro](https://github.com/dixyes/phpmicro)** 自解压可执行文件(将 PHP 二进制文件和源代码合并为一个文件)
- :hamburger: **phpmicro 集成** - 构建 **[phpmicro](https://github.com/static-php/phpmicro)** 自解压可执行文件(将 PHP 二进制文件和源代码合并为一个文件)
- :pill: **智能环境检查器** - 自动构建环境检查器,具备自动修复功能
- :zap: **跨平台支持** - 支持 Linux、macOS、FreeBSD 和 Windows
- :wrench: **可配置补丁** - 可自定义的源代码补丁系统
- :books: **智能依赖管理** - 自动处理构建依赖
- 📦 **自包含工具** - 提供使用 [box](https://github.com/box-project/box) 构建的 `spc` 可执行文件
- :fire: **广泛的扩展支持** - 支持 75+ 流行 [扩展](https://static-php.dev/zh/guide/extensions.html)
- :fire: **广泛的扩展支持** - 支持 100+ 流行 [扩展](https://static-php.dev/zh/guide/extensions.html)
- :floppy_disk: **UPX 压缩** - 减小二进制文件大小 30-50%(仅 Linux/Windows
**单文件独立 php-cli**
@@ -33,6 +33,8 @@
### 1. 下载 spc 二进制文件
`spc` 二进制文件是 StaticPHP 项目的 CLI 工具,打包为单个可执行文件。
```bash
# Linux x86_64
curl -fsSL -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-x86_64
@@ -107,7 +109,7 @@ buildroot/bin/php-fpm -v
以下是几个具有不同扩展组合的预编译静态 PHP 二进制文件,
您可以根据需要直接下载。
| 组合名称 | 扩展数量 | 系统 | 备注 |
| 组合名称 | 扩展数量 | 系统 | 备注 |
|----------------------------------------------------------------------|----------------------------------------------------------------------------|--------------|--------------------|
| [common](https://dl.static-php.dev/static-php-cli/common/) | [30+](https://dl.static-php.dev/static-php-cli/common/README.txt) | Linux, macOS | 二进制文件大小约为 7.5MB |
| [bulk](https://dl.static-php.dev/static-php-cli/bulk/) | [50+](https://dl.static-php.dev/static-php-cli/bulk/README.txt) | Linux, macOS | 二进制文件大小约为 25MB |

View File

@@ -1,4 +1,4 @@
# static-php-cli
# StaticPHP
[![Chinese readme](https://img.shields.io/badge/README-%E4%B8%AD%E6%96%87%20%F0%9F%87%A8%F0%9F%87%B3-moccasin?style=flat-square)](README-zh.md)
[![English readme](https://img.shields.io/badge/README-English%20%F0%9F%87%AC%F0%9F%87%A7-moccasin?style=flat-square)](README.md)
@@ -6,14 +6,13 @@
[![CI](https://img.shields.io/github/actions/workflow/status/crazywhalecc/static-php-cli/tests.yml?branch=main&label=Build%20Test&style=flat-square)](https://github.com/crazywhalecc/static-php-cli/actions/workflows/tests.yml)
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
**static-php-cli** is a powerful tool designed for building static, standalone PHP runtime
with popular extensions.
**StaticPHP** (formerly **static-php-cli**) is a powerful tool designed for building static, standalone PHP runtime with popular extensions.
## Features
- :elephant: Support multiple PHP versions - PHP 8.1, 8.2, 8.3, 8.4, 8.5
- :handbag: Build single-file PHP executable with zero dependencies
- :hamburger:Build **[phpmicro](https://github.com/dixyes/phpmicro)** self-extracting executables (combines PHP binary and source code into one file)
- :hamburger:Build **[phpmicro](https://github.com/static-php/phpmicro)** self-extracting executables (combines PHP binary and source code into one file)
- :pill: Automatic build environment checker with auto-fix capabilities
- :zap: `Linux`, `macOS`, `FreeBSD`, `Windows` support
- :wrench: Configurable source code patching
@@ -34,6 +33,8 @@ with popular extensions.
### 1. Download spc binary
`spc` binary is StaticPHP CLI tool packaged as a single executable file.
```bash
# For Linux x86_64
curl -fsSL -o spc https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-x86_64
@@ -53,7 +54,7 @@ For macOS and Linux, add execute permission first:
chmod +x ./spc
```
### 2. Build Static PHP
### 2. Build standalone PHP binaries
First, create a `craft.yml` file and specify which extensions you want to include from [extension list](https://static-php.dev/en/guide/extensions.html) or [command generator](https://static-php.dev/en/guide/cli-generator.html):
@@ -79,7 +80,7 @@ Run command:
./spc craft --debug
```
### 3. Static PHP usage
### 3. Using the built binaries
Now you can copy binaries built by static-php-cli to another machine and run with no dependencies:
@@ -105,7 +106,7 @@ see <https://static-php.dev> .
If you don't want to build or want to test first, you can download example pre-compiled artifact from [Actions](https://github.com/static-php/static-php-cli-hosted/actions/workflows/build-php-bulk.yml), or from self-hosted server.
Below are several precompiled static-php binaries with different extension combinations,
Below are several precompiled statically built php binaries with different extension combinations,
which can be downloaded directly according to your needs.
| Combination | Extension Count | OS | Comment |

View File

@@ -108,7 +108,8 @@ RUN apk update; \
wget \
xz \
gettext-dev \
binutils-gold
binutils-gold \
patchelf
RUN curl -#fSL https://dl.static-php.dev/static-php-cli/bulk/php-8.4.4-cli-linux-\$(uname -m).tar.gz | tar -xz -C /usr/local/bin && \
chmod +x /usr/local/bin/php

View File

@@ -92,6 +92,11 @@ RUN echo "source scl_source enable devtoolset-10" >> /etc/bashrc
RUN source /etc/bashrc
RUN yum install -y which
RUN curl -fsSL -o patchelf.tgz https://github.com/NixOS/patchelf/releases/download/0.18.0/patchelf-0.18.0-$SPC_USE_ARCH.tar.gz && \
mkdir -p /patchelf && \
tar -xzf patchelf.tgz -C /patchelf --strip-components=1 && \
cp /patchelf/bin/patchelf /usr/bin/
RUN curl -o cmake.tgz -#fSL https://github.com/Kitware/CMake/releases/download/v3.31.4/cmake-3.31.4-linux-$SPC_USE_ARCH.tar.gz && \
mkdir /cmake && \
tar -xzf cmake.tgz -C /cmake --strip-components 1

518
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -75,10 +75,8 @@ SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime
; - musl-native: used for alpine linux, can build `musl` and `musl -dynamic` target.
; - gnu-native: used for general linux distros, can build gnu target for the installed glibc version only.
; option to specify the target, superceded by SPC_TARGET if set
; LEGACY option to specify the target
SPC_LIBC=musl
; uncomment to link libc dynamically on musl
; SPC_MUSL_DYNAMIC=true
; Recommended: specify your target here. Zig toolchain will be used.
; examples:
@@ -93,7 +91,6 @@ SPC_LIBC=musl
CC=${SPC_LINUX_DEFAULT_CC}
CXX=${SPC_LINUX_DEFAULT_CXX}
AR=${SPC_LINUX_DEFAULT_AR}
RANLIB=${SPC_LINUX_DEFAULT_RANLIB}
LD=${SPC_LINUX_DEFAULT_LD}
; default compiler flags, used in CMake toolchain file, openssl and pkg-config build
SPC_DEFAULT_C_FLAGS="-fPIC -Os"
@@ -118,10 +115,6 @@ SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fno-ident -fPIE
; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.so
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS=""
; optional, path to openssl conf. This affects where openssl will look for the default CA.
; default on Debian/Alpine: /etc/ssl, default on RHEL: /etc/pki/tls
OPENSSLDIR=""
[macos]
; build target: macho or macho (possibly we could support macho-universal in the future)
; Currently we do not support universal and cross-compilation for macOS.
@@ -149,10 +142,6 @@ SPC_CMD_PREFIX_PHP_CONFIGURE="./configure --prefix= --with-valgrind=no --enable-
SPC_CMD_VAR_PHP_EMBED_TYPE="static"
; EXTRA_CFLAGS for `configure` and `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Werror=unknown-warning-option ${SPC_DEFAULT_C_FLAGS}"
; EXTRA_LDFLAGS for `make` php, can use -release to set a soname for libphp.so
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS=""
; minimum compatible macOS version (LLVM vars, availability not guaranteed)
MACOSX_DEPLOYMENT_TARGET=12.0
[freebsd]
; compiler environments

View File

@@ -43,27 +43,6 @@
"calendar": {
"type": "builtin"
},
"clickhouse": {
"support": {
"Windows": "wip",
"BSD": "wip"
},
"type": "external",
"source": "ext-clickhouse",
"arg-type": "custom",
"cpp-extension": true,
"lib-suggests": [
"openssl"
]
},
"com_dotnet": {
"support": {
"BSD": "no",
"Linux": "no",
"Darwin": "no"
},
"type": "builtin"
},
"ctype": {
"type": "builtin"
},
@@ -76,8 +55,7 @@
],
"ext-depends-windows": [
"zlib",
"openssl",
"brotli"
"openssl"
]
},
"dba": {
@@ -87,19 +65,6 @@
"qdbm"
]
},
"decimal": {
"type": "external",
"source": "ext-decimal",
"arg-type": "custom",
"lib-depends": [
"libmpdec"
]
},
"deepclone": {
"type": "external",
"source": "deepclone",
"arg-type": "enable"
},
"dio": {
"support": {
"BSD": "wip"
@@ -162,41 +127,9 @@
"sockets"
]
},
"excimer": {
"support": {
"Windows": "wip",
"BSD": "wip"
},
"type": "external",
"source": "ext-excimer"
},
"exif": {
"type": "builtin"
},
"fastchart": {
"support": {
"Windows": "wip",
"BSD": "wip"
},
"type": "external",
"source": "ext-fastchart",
"lib-depends": [
"freetype"
],
"lib-suggests": [
"libpng",
"libjpeg",
"libwebp"
]
},
"fastjson": {
"support": {
"Windows": "wip",
"BSD": "wip"
},
"type": "external",
"source": "ext-fastjson"
},
"ffi": {
"support": {
"Linux": "partial",
@@ -287,7 +220,6 @@
"support": {
"BSD": "wip"
},
"arg-type": "with-path",
"type": "external",
"source": "ext-gmssl",
"lib-depends": [
@@ -300,14 +232,11 @@
"BSD": "wip"
},
"type": "external",
"source": "ext-grpc",
"source": "grpc",
"arg-type-unix": "enable-path",
"cpp-extension": true,
"lib-depends": [
"grpc",
"zlib",
"openssl",
"libcares"
"grpc"
]
},
"iconv": {
@@ -479,7 +408,8 @@
"ext-depends": [
"zlib",
"session"
]
],
"build-with-php": true
},
"memcached": {
"support": {
@@ -557,40 +487,6 @@
"zlib"
]
},
"mysqlnd_ed25519": {
"type": "external",
"source": "mysqlnd_ed25519",
"arg-type": "enable",
"target": [
"shared"
],
"ext-depends": [
"mysqlnd"
],
"lib-depends": [
"libsodium"
],
"lib-suggests": [
"openssl"
]
},
"mysqlnd_parsec": {
"type": "external",
"source": "mysqlnd_parsec",
"arg-type": "enable",
"target": [
"shared"
],
"ext-depends": [
"mysqlnd"
],
"lib-depends": [
"libsodium"
],
"lib-suggests": [
"openssl"
]
},
"oci8": {
"type": "wip",
"support": {
@@ -671,13 +567,6 @@
"type": "builtin",
"unix-only": true
},
"pcov": {
"type": "external",
"source": "pcov",
"target": [
"shared"
]
},
"pdo": {
"type": "builtin"
},

View File

@@ -109,7 +109,8 @@
"krb5"
],
"lib-suggests-windows": [
"brotli"
"brotli",
"zstd"
],
"frameworks": [
"CoreFoundation",
@@ -123,7 +124,7 @@
"libfastlz.a"
],
"headers": [
"fastlz.h"
"fastlz/fastlz.h"
]
},
"freetype": {
@@ -142,7 +143,9 @@
"zlib"
],
"lib-suggests": [
"libpng"
"libpng",
"bzip2",
"brotli"
]
},
"gettext": {
@@ -352,18 +355,12 @@
"static-libs-unix": [
"libaom.a"
],
"static-libs-windows": [
"aom.lib"
],
"cpp-library": true
},
"libargon2": {
"source": "libargon2",
"static-libs-unix": [
"libargon2.a"
],
"lib-suggests": [
"libsodium"
]
},
"libavif": {
@@ -373,15 +370,6 @@
],
"static-libs-windows": [
"avif.lib"
],
"lib-depends": [
"libaom"
],
"lib-suggests": [
"libwebp",
"libjpeg",
"libxml2",
"libpng"
]
},
"libcares": {
@@ -454,7 +442,6 @@
},
"libheif": {
"source": "libheif",
"cpp-library": true,
"static-libs-unix": [
"libheif.a"
],
@@ -494,7 +481,7 @@
"static-libs-windows": [
"libjpeg_a.lib"
],
"lib-depends": [
"lib-suggests-windows": [
"zlib"
]
},
@@ -529,18 +516,6 @@
"maxminddb_config.h"
]
},
"libmpdec": {
"source": "libmpdec",
"static-libs-unix": [
"libmpdec.a"
],
"static-libs-windows": [
"libmpdec_a.lib"
],
"headers": [
"mpdecimal.h"
]
},
"libmemcached": {
"source": "libmemcached",
"cpp-library": true,
@@ -775,6 +750,7 @@
"xz"
],
"lib-suggests-windows": [
"zstd",
"openssl"
]
},
@@ -874,9 +850,6 @@
},
"openssl": {
"source": "openssl",
"pkg-configs": [
"openssl"
],
"static-libs-unix": [
"libssl.a",
"libcrypto.a"
@@ -989,11 +962,6 @@
},
"unixodbc": {
"source": "unixodbc",
"pkg-configs": [
"odbc",
"odbccr",
"odbcinst"
],
"static-libs-unix": [
"libodbc.a",
"libodbccr.a",
@@ -1011,9 +979,6 @@
],
"headers": [
"wtr/watcher-c.h"
],
"frameworks": [
"CoreServices"
]
},
"xz": {
@@ -1038,9 +1003,6 @@
},
"zlib": {
"source": "zlib",
"pkg-configs": [
"zlib"
],
"static-libs-unix": [
"libz.a"
],
@@ -1054,9 +1016,6 @@
},
"zstd": {
"source": "zstd",
"pkg-configs": [
"libzstd"
],
"static-libs-unix": [
"libzstd.a"
],

View File

@@ -84,25 +84,6 @@
"path": "COPYING"
}
},
"ext-decimal": {
"type": "ghtagtar",
"repo": "php-decimal/ext-decimal",
"match": "v2\\.\\d.*",
"path": "php-src/ext/decimal",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"deepclone": {
"type": "ghtagtar",
"repo": "symfony/php-ext-deepclone",
"path": "php-src/ext/deepclone",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"dio": {
"type": "url",
"url": "https://pecl.php.net/get/dio",
@@ -124,19 +105,10 @@
}
},
"ext-brotli": {
"type": "ghtagtar",
"repo": "kjdev/php-ext-brotli",
"type": "git",
"path": "php-src/ext/brotli",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-clickhouse": {
"type": "ghtagtar",
"repo": "iliaal/php_clickhouse",
"match": "tarball/refs/tags/\\d",
"path": "php-src/ext/clickhouse",
"rev": "master",
"url": "https://github.com/kjdev/php-ext-brotli",
"license": {
"type": "file",
"path": "LICENSE"
@@ -154,41 +126,13 @@
},
"ext-event": {
"type": "url",
"url": "https://bitbucket.org/osmanov/pecl-event/get/3.1.4.tar.gz",
"url": "https://bitbucket.org/osmanov/pecl-event/get/3.0.8.tar.gz",
"path": "php-src/ext/event",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-excimer": {
"type": "url",
"url": "https://pecl.php.net/get/excimer",
"path": "php-src/ext/excimer",
"filename": "excimer.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-fastchart": {
"type": "ghtagtar",
"repo": "iliaal/fastchart",
"path": "php-src/ext/fastchart",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-fastjson": {
"type": "ghtagtar",
"repo": "iliaal/fastjson",
"path": "php-src/ext/fastjson",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ext-glfw": {
"type": "git",
"url": "https://github.com/mario-deluna/php-glfw",
@@ -207,18 +151,6 @@
"path": "LICENSE"
}
},
"ext-grpc": {
"type": "url",
"url": "https://pecl.php.net/get/grpc",
"path": "php-src/ext/grpc",
"filename": "grpc.tgz",
"license": {
"type": "file",
"path": [
"LICENSE"
]
}
},
"ext-imagick": {
"type": "url",
"url": "https://pecl.php.net/get/imagick",
@@ -273,7 +205,7 @@
},
"ext-rdkafka": {
"type": "ghtar",
"repo": "php-rdkafka/php-rdkafka",
"repo": "arnaud-lb/php-rdkafka",
"path": "php-src/ext/rdkafka",
"license": {
"type": "file",
@@ -360,9 +292,10 @@
}
},
"ext-zstd": {
"type": "ghtar",
"repo": "kjdev/php-ext-zstd",
"type": "git",
"path": "php-src/ext/zstd",
"rev": "master",
"url": "https://github.com/kjdev/php-ext-zstd",
"license": {
"type": "file",
"path": "LICENSE"
@@ -406,7 +339,7 @@
},
"gmp": {
"type": "filelist",
"url": "https://ftp.gnu.org/gnu/gmp/",
"url": "https://gmplib.org/download/gmp/",
"regex": "/href=\"(?<file>gmp-(?<version>[^\"]+)\\.tar\\.xz)\"/",
"provide-pre-built": true,
"alt": {
@@ -419,9 +352,9 @@
}
},
"gmssl": {
"type": "git",
"url": "https://github.com/guanzhi/GmSSL.git",
"rev": "master",
"type": "ghtar",
"repo": "guanzhi/GmSSL",
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -507,8 +440,10 @@
}
},
"krb5": {
"type": "url",
"url": "https://web.mit.edu/kerberos/dist/krb5/1.22/krb5-1.22.2.tar.gz",
"type": "ghtagtar",
"repo": "krb5/krb5",
"match": "krb5.+-final",
"prefer-stable": true,
"license": {
"type": "file",
"path": "NOTICE"
@@ -569,7 +504,7 @@
"libavif": {
"type": "ghtar",
"repo": "AOMediaCodec/libavif",
"provide-pre-built": false,
"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -684,7 +619,6 @@
"libjpeg": {
"type": "ghtar",
"repo": "libjpeg-turbo/libjpeg-turbo",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE.md"
@@ -726,14 +660,6 @@
"path": "LICENSE"
}
},
"libmpdec": {
"type": "url",
"url": "https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-4.0.1.tar.gz",
"license": {
"type": "file",
"path": "COPYRIGHT.txt"
}
},
"libmemcached": {
"type": "ghtagtar",
"repo": "awesomized/libmemcached",
@@ -744,10 +670,9 @@
}
},
"libpng": {
"type": "ghtagtar",
"repo": "pnggroup/libpng",
"match": "v1\\.6\\.\\d+",
"query": "?per_page=150",
"type": "git",
"url": "https://github.com/glennrp/libpng.git",
"rev": "libpng16",
"provide-pre-built": true,
"license": {
"type": "file",
@@ -755,9 +680,9 @@
}
},
"librabbitmq": {
"type": "ghtar",
"repo": "alanxz/rabbitmq-c",
"prefer-stable": true,
"type": "git",
"url": "https://github.com/alanxz/rabbitmq-c.git",
"rev": "master",
"license": {
"type": "file",
"path": "LICENSE"
@@ -774,7 +699,7 @@
"libsodium": {
"type": "ghrel",
"repo": "jedisct1/libsodium",
"match": "libsodium-(?!1\\.0\\.21)\\d+(\\.\\d+)*\\.tar\\.gz",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
@@ -846,9 +771,8 @@
]
},
"libwebp": {
"type": "ghtagtar",
"repo": "webmproject/libwebp",
"match": "v1\\.\\d+\\.\\d+$",
"type": "url",
"url": "https://github.com/webmproject/libwebp/archive/refs/tags/v1.3.2.tar.gz",
"provide-pre-built": true,
"license": {
"type": "file",
@@ -856,10 +780,8 @@
}
},
"libxml2": {
"type": "ghtagtar",
"repo": "GNOME/libxml2",
"match": "v2\\.\\d+\\.\\d+$",
"provide-pre-built": false,
"type": "url",
"url": "https://github.com/GNOME/libxml2/archive/refs/tags/v2.12.5.tar.gz",
"license": {
"type": "file",
"path": "Copyright"
@@ -946,24 +868,6 @@
"path": "LICENSE"
}
},
"mysqlnd_ed25519": {
"type": "pie",
"repo": "mariadb/mysqlnd_ed25519",
"path": "php-src/ext/mysqlnd_ed25519",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"mysqlnd_parsec": {
"type": "pie",
"repo": "mariadb/mysqlnd_parsec",
"path": "php-src/ext/mysqlnd_parsec",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"ncurses": {
"type": "filelist",
"url": "https://ftp.gnu.org/pub/gnu/ncurses/",
@@ -1026,7 +930,7 @@
"openssl": {
"type": "ghrel",
"repo": "openssl/openssl",
"match": "openssl-3.+\\.tar\\.gz",
"match": "openssl.+\\.tar\\.gz",
"prefer-stable": true,
"alt": {
"type": "filelist",
@@ -1059,15 +963,6 @@
"path": "LICENSE"
}
},
"pcov": {
"type": "url",
"url": "https://pecl.php.net/get/pcov",
"filename": "pcov.tgz",
"license": {
"type": "file",
"path": "LICENSE"
}
},
"pdo_sqlsrv": {
"type": "url",
"url": "https://pecl.php.net/get/pdo_sqlsrv",
@@ -1220,6 +1115,7 @@
"path": "php-src/ext/swoole",
"type": "ghtar",
"repo": "swoole/swoole-src",
"match": "v6\\.+",
"prefer-stable": true,
"license": {
"type": "file",
@@ -1264,8 +1160,9 @@
}
},
"xdebug": {
"type": "pie",
"repo": "xdebug/xdebug",
"type": "url",
"url": "https://pecl.php.net/get/xdebug",
"filename": "xdebug.tgz",
"license": {
"type": "file",
"path": "LICENSE"

View File

@@ -4,7 +4,7 @@ import sidebarZh from "./sidebar.zh";
// https://vitepress.dev/reference/site-config
export default {
title: "Static PHP",
title: "StaticPHP",
description: "Build single static PHP binary, with PHP project together, with popular extensions included.",
locales: {
en: {

View File

@@ -16,10 +16,8 @@ while also defining the extensions to compile.
1. Fork project.
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 static extensions. (comma separated, e.g. `bcmath,curl,mbstring`)
4. If you need shared extensions (for example `xdebug`), set `shared-extensions` (comma separated, e.g. `xdebug`).
5. If you need FrankenPHP, enable `build-frankenphp` and also enable `enable-zts`.
6. After waiting for about a period of time, enter the corresponding task and get `Artifacts`.
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.

View File

@@ -1,6 +1,6 @@
# Guide
Static php cli is a tool used to build statically compiled PHP binaries,
StaticPHP is a tool used to build statically compiled PHP binaries,
currently supporting Linux and macOS systems.
In the guide section, you will learn how to use static php cli to build standalone PHP programs.
@@ -14,12 +14,14 @@ In the guide section, you will learn how to use static php cli to build standalo
The following is the architecture support situation, where :gear: represents support for GitHub Action build,
:computer: represents support for local manual build, and empty represents temporarily not supported.
| | x86_64 | aarch64 |
|---------|-------------------|-------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: | :computer: |
| | x86_64 | aarch64 |
|---------|------------------------|------------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: (:warning:) | :computer: (:warning:) |
> Due to lack of users and testing, FreeBSD is no longer supported in latest StaticPHP project.
Current supported PHP versions for compilation:
@@ -29,17 +31,17 @@ Current supported PHP versions for compilation:
>
> :x: Not supported
| PHP Version | Status | Comment |
|-------------|--------------------|-------------------------------------------------------------------------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 7.4 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 8.0 | :warning: | PHP official has stopped maintaining 8.0, we no longer handle 8.0 related backport support |
| 8.1 | :warning: | PHP official only provides security updates for 8.1, we no longer handle 8.1 related backport support after 8.5 release |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 (beta) | :warning: | PHP 8.5 is currently in beta stage |
| PHP Version | Status | Comment |
|-------------|--------------------|--------------------------------------------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 7.4 | :x: | phpmicro and many extensions do not support 7.3, 7.4 versions |
| 8.0 | :warning: | PHP official has stopped maintaining 8.0, we no longer handle 8.0 related backport support |
| 8.1 | :warning: | PHP official only provides security updates for 8.1 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 | :heavy_check_mark: | |
> This table shows the support status of static-php-cli for building corresponding versions, not the PHP official support status for that version.

View File

@@ -549,24 +549,22 @@ otherwise it will be executed repeatedly in other events.
The following are the supported `patch_point` event names and corresponding locations:
| Event name | Event description |
|---------------------------------|----------------------------------------------------------------------------------------------------|
| before-libs-extract | Triggered before the dependent libraries extracted |
| after-libs-extract | Triggered after the compiled dependent libraries extracted |
| before-php-extract | Triggered before PHP source code extracted |
| after-php-extract | Triggered after PHP source code extracted |
| before-micro-extract | Triggered before phpmicro extract |
| after-micro-extract | Triggered after phpmicro extracted |
| before-exts-extract | Triggered before the extension (to be compiled) extracted to the PHP source directory |
| after-exts-extract | Triggered after the extension extracted to the PHP source directory |
| before-library[*name*]-build | Triggered before the library named `name` is compiled (such as `before-library[postgresql]-build`) |
| after-library[*name*]-build | Triggered after the library named `name` is compiled |
| after-shared-ext[*name*]-build | Triggered after the shared extension named `name` is compiled |
| before-shared-ext[*name*]-build | Triggered before the shared extension named `name` is compiled |
| before-php-buildconf | Triggered before compiling PHP command `./buildconf` |
| before-php-configure | Triggered before compiling PHP command `./configure` |
| before-php-make | Triggered before compiling PHP command `make` |
| before-sanity-check | Triggered after compiling PHP but before running extended checks |
| Event name | Event description |
|------------------------------|----------------------------------------------------------------------------------------------------|
| before-libs-extract | Triggered before the dependent libraries extracted |
| after-libs-extract | Triggered after the compiled dependent libraries extracted |
| before-php-extract | Triggered before PHP source code extracted |
| after-php-extract | Triggered after PHP source code extracted |
| before-micro-extract | Triggered before phpmicro extract |
| after-micro-extract | Triggered after phpmicro extracted |
| before-exts-extract | Triggered before the extension (to be compiled) extracted to the PHP source directory |
| after-exts-extract | Triggered after the extension extracted to the PHP source directory |
| before-library[*name*]-build | Triggered before the library named `name` is compiled (such as `before-library[postgresql]-build`) |
| after-library[*name*]-build | Triggered after the library named `name` is compiled |
| before-php-buildconf | Triggered before compiling PHP command `./buildconf` |
| before-php-configure | Triggered before compiling PHP command `./configure` |
| before-php-make | Triggered before compiling PHP command `make` |
| before-sanity-check | Triggered after compiling PHP but before running extended checks |
The following is a simple example of temporarily modifying the PHP source code.
Enable the CLI function to search for the `php.ini` configuration in the current working directory:

View File

@@ -3,7 +3,7 @@
layout: home
hero:
name: "Static PHP"
name: "StaticPHP"
tagline: "Build standalone PHP binary on Linux, macOS, FreeBSD, Windows, with PHP project together, with popular extensions included."
image:
src: /images/static-php_nobg.png
@@ -14,9 +14,9 @@ hero:
link: ./guide/
features:
- title: Static CLI Binary
- title: Static PHP Binary
details: You can easily compile a standalone php binary for general use. Including CLI, FPM sapi.
- title: Micro Self-Extracted Executable
- title: PHP micro Self-Extracted Executable
details: You can compile a self-extracted executable and build with your php source code.
- title: Dependency Management
details: static-php-cli comes with dependency management and supports installation of different types of PHP extensions.

View File

@@ -3,7 +3,7 @@
layout: home
hero:
name: "Static PHP"
name: "StaticPHP"
tagline: "Build standalone PHP binary on Linux, macOS, FreeBSD, Windows, with PHP project together, with popular extensions included."
image:
src: /images/static-php_nobg.png

View File

@@ -14,9 +14,7 @@ Action 构建指的是直接使用 GitHub Action 进行编译。
1. Fork 本项目。
2. 进入项目的 Actions选择 CI 开头的 Workflow根据你需要的操作系统选择
3. 选择 `Run workflow`,填入你要编译的 PHP 版本、目标类型、扩展列表。(扩展列表使用英文逗号分割,例如 `bcmath,curl,mbstring`
4. 如果需要共享扩展(例如 `xdebug`),请设置 `shared-extensions`(使用英文逗号分割,例如 `xdebug`
5. 如果需要 FrankenPHP请启用 `build-frankenphp`,同时也需要启用 `enable-zts`
6. 等待大约一段时间后,进入对应的任务中,获取 `Artifacts`
4. 等待大约一段时间后,进入对应的任务中,获取 `Artifacts`
如果你选择了 `debug`,则会在构建时输出所有日志,包括编译的日志,以供排查错误。

View File

@@ -12,12 +12,14 @@ static-php-cli 是一个用于构建静态编译的 PHP 二进制的工具,目
下面是架构支持情况,:gear: 代表支持 GitHub Action 构建,:computer: 代表支持本地构建,空 代表暂不支持。
| | x86_64 | aarch64 |
|---------|-------------------|-------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: | :computer: |
| | x86_64 | aarch64 |
|---------|------------------------|------------------------|
| macOS | :gear: :computer: | :gear: :computer: |
| Linux | :gear: :computer: | :gear: :computer: |
| Windows | :gear: :computer: | |
| FreeBSD | :computer: (:warning:) | :computer: (:warning:) |
> 由于缺乏用户和测试FreeBSD 在最新的 StaticPHP 项目中不再受支持。
当前支持编译的 PHP 版本:
@@ -27,17 +29,17 @@ static-php-cli 是一个用于构建静态编译的 PHP 二进制的工具,目
>
> :x: 不支持
| PHP Version | Status | Comment |
|-------------|--------------------|---------------------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 7.4 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 8.0 | :warning: | PHP 官方已停止 8.0 的维护,我们不再处理 8.0 相关的 backport 支持 |
| 8.1 | :warning: | PHP 官方仅对 8.1 提供安全更新,在 8.5 发布后我们不再处理 8.1 相关的 backport 支持 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 (beta) | :warning: | PHP 8.5 目前处于 beta 阶段 |
| PHP Version | Status | Comment |
|-------------|--------------------|----------------------------------------------|
| 7.2 | :x: | |
| 7.3 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 7.4 | :x: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 8.0 | :warning: | PHP 官方已停止 8.0 的维护,我们不再处理 8.0 相关的 backport 支持 |
| 8.1 | :warning: | PHP 官方仅对 8.1 提供安全更新 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |
| 8.4 | :heavy_check_mark: | |
| 8.5 | :heavy_check_mark: | |
> 这个表格的支持状态是 static-php-cli 对构建对应版本的支持情况,不是 PHP 官方对该版本的支持情况。

View File

@@ -500,8 +500,6 @@ bin/spc dev:sort-config ext
| after-exts-extract | 在要编译的扩展解压到 PHP 源码目录后触发 |
| before-library[*name*]-build | 在名称为 `name` 的库编译前触发(如 `before-library[postgresql]-build` |
| after-library[*name*]-build | 在名称为 `name` 的库编译后触发 |
| after-shared-ext[*name*]-build | 在名称为 `name` 的共享扩展编译后触发(如 `after-shared-ext[redis]-build` |
| before-shared-ext[*name*]-build | 在名称为 `name` 的共享扩展编译前触发 |
| before-php-buildconf | 在编译 PHP 命令 `./buildconf` 前触发 |
| before-php-configure | 在编译 PHP 命令 `./configure` 前触发 |
| before-php-make | 在编译 PHP 命令 `make` 前触发 |

View File

@@ -14,7 +14,6 @@ parameters:
- PHP_OS_FAMILY
excludePaths:
analyseAndScan:
- ./src/globals/ext-tests/decimal.php
- ./src/globals/ext-tests/swoole.php
- ./src/globals/ext-tests/swoole.phpt
- ./src/globals/test-extensions.php

View File

@@ -34,7 +34,7 @@ use Symfony\Component\Console\Application;
*/
final class ConsoleApplication extends Application
{
public const string VERSION = '2.8.6';
public const string VERSION = '2.7.9';
public function __construct()
{

View File

@@ -29,7 +29,7 @@ abstract class BuilderBase
/** @var array<int, string> extension names */
protected array $ext_list = [];
/** @var array<int, string> all libraries being built (resolved dep list) */
/** @var array<int, string> library names */
protected array $lib_list = [];
/** @var bool compile libs only (just mark it) */
@@ -143,7 +143,7 @@ abstract class BuilderBase
*
* @internal
*/
public function proveExts(array $static_extensions, array $shared_extensions = [], bool $skip_check_deps = false, bool $skip_extract = false, int $build_target = BUILD_TARGET_NONE): void
public function proveExts(array $static_extensions, array $shared_extensions = [], bool $skip_check_deps = false, bool $skip_extract = false): void
{
// judge ext
foreach ($static_extensions as $ext) {
@@ -171,9 +171,7 @@ abstract class BuilderBase
SourceManager::initSource(exts: [...$static_extensions, ...$shared_extensions]);
$this->emitPatchPoint('after-exts-extract');
// patch micro
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
SourcePatcher::patchMicro();
}
SourcePatcher::patchMicro();
}
foreach ([...$static_extensions, ...$shared_extensions] as $extension) {

View File

@@ -11,10 +11,8 @@ use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\GlobalEnvManager;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
class Extension
{
@@ -98,8 +96,7 @@ class Extension
fn ($x) => $x->getStaticLibFiles(),
$this->getLibraryDependencies(recursive: true)
);
$libs = implode(' ', $ret);
return deduplicate_flags($libs);
return implode(' ', $ret);
}
/**
@@ -186,6 +183,14 @@ class Extension
*/
public function patchBeforeMake(): bool
{
if (SPCTarget::getTargetOS() === 'Linux' && $this->isBuildShared() && ($objs = getenv('SPC_EXTRA_RUNTIME_OBJECTS'))) {
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/Makefile',
"/^(shared_objects_{$this->getName()}\\s*=.*)$/m",
"$1 {$objs}",
);
return true;
}
return false;
}
@@ -225,7 +230,7 @@ class Extension
if (preg_match('/^(.*_SHARED_LIBADD\s*=\s*)(.*)$/m', $makefileContent, $matches)) {
$prefix = $matches[1];
$currentLibs = trim($matches[2]);
$newLibs = clean_spaces("{$currentLibs} {$staticLibs} {$lstdcpp}");
$newLibs = trim("{$currentLibs} {$staticLibs} {$lstdcpp}");
$deduplicatedLibs = deduplicate_flags($newLibs);
FileSystem::replaceFileRegex(
@@ -235,6 +240,13 @@ class Extension
);
}
if ($objs = getenv('SPC_EXTRA_RUNTIME_OBJECTS')) {
FileSystem::replaceFileRegex(
$this->source_dir . '/Makefile',
"/^(shared_objects_{$this->getName()}\\s*=.*)$/m",
"$1 {$objs}",
);
}
return true;
}
@@ -373,9 +385,6 @@ class Extension
logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)');
return;
}
if ((string) Config::getExt($this->getName(), 'type') === 'addon') {
return;
}
logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)');
foreach ($this->dependencies as $dependency) {
if (!$dependency instanceof Extension) {
@@ -386,12 +395,13 @@ class Extension
$dependency->buildShared([...$visited, $this->getName()]);
}
}
$this->builder->emitPatchPoint('before-shared-ext[' . $this->getName() . ']-build');
if (Config::getExt($this->getName(), 'type') === 'addon') {
return;
}
match (PHP_OS_FAMILY) {
'Darwin', 'Linux' => $this->buildUnixShared(),
default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'),
};
$this->builder->emitPatchPoint('after-shared-ext[' . $this->getName() . ']-build');
} catch (SPCException $e) {
$e->bindExtensionInfo(['extension_name' => $this->getName()]);
throw $e;
@@ -442,17 +452,12 @@ class Extension
// process *.so file
$soFile = BUILD_MODULES_PATH . '/' . $this->getName() . '.so';
$soDest = $soFile;
preg_match('/-release\s+(\S*)/', getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), $matches);
if (!empty($matches[1])) {
$soDest = str_replace('.so', '-' . $matches[1] . '.so', $soFile);
}
if (!file_exists($soFile)) {
throw new ValidationException("extension {$this->getName()} build failed: {$soFile} not found", validation_module: "Extension {$this->getName()} build");
}
/** @var UnixBuilderBase $builder */
$builder = $this->builder;
$builder->deployBinary($soFile, $soDest, false);
$builder->deployBinary($soFile, $soFile, false);
}
/**
@@ -530,24 +535,14 @@ class Extension
*/
protected function getSharedExtensionEnv(): array
{
$compiler_extra = getenv('SPC_COMPILER_EXTRA') ?: '';
if (!str_contains($compiler_extra, '-lcompiler_rt') && ToolchainManager::getToolchainClass() === ZigToolchain::class) {
$compiler_extra = trim($compiler_extra . ' -lcompiler_rt');
GlobalEnvManager::putenv("SPC_COMPILER_EXTRA={$compiler_extra}");
}
$config = (new SPCConfigUtil($this->builder, ['no_php' => true]))->getExtensionConfig($this);
$config = (new SPCConfigUtil($this->builder))->getExtensionConfig($this);
[$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']);
$preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group ';
$postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group ';
$extraLd = trim((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'));
if (PHP_OS_FAMILY !== 'Darwin') {
$extraLd = trim($extraLd . ' -Wl,-Bsymbolic');
}
return [
'CFLAGS' => $config['cflags'],
'CXXFLAGS' => $config['cflags'],
'LDFLAGS' => $config['ldflags'],
'EXTRA_LDFLAGS' => $extraLd,
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
];

View File

@@ -184,18 +184,18 @@ abstract class LibraryBase
// extract first if not exists
if (!is_dir($this->source_dir)) {
$this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-extract');
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-extract');
SourceManager::initSource(libs: [static::NAME], source_only: true);
$this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-extract');
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-extract');
}
if (!$this->patched && $this->patchBeforeBuild()) {
file_put_contents($this->source_dir . '/.spc.patched', 'PATCHED!!!');
}
$this->getBuilder()->emitPatchPoint('before-library[' . static::NAME . ']-build');
$this->getBuilder()->emitPatchPoint('before-library[ ' . static::NAME . ']-build');
$this->build();
$this->installLicense();
$this->getBuilder()->emitPatchPoint('after-library[' . static::NAME . ']-build');
$this->getBuilder()->emitPatchPoint('after-library[ ' . static::NAME . ']-build');
return LIB_STATUS_OK;
}
@@ -346,46 +346,25 @@ abstract class LibraryBase
*/
protected function installLicense(): void
{
FileSystem::createDir(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName());
$source = Config::getLib($this->getName(), 'source');
FileSystem::createDir(BUILD_ROOT_PATH . "/source-licenses/{$source}");
$license_files = Config::getSource($source)['license'] ?? [];
if (is_assoc_array($license_files)) {
$license_files = [$license_files];
}
foreach ($license_files as $index => $license) {
if ($license['type'] === 'text') {
FileSystem::writeFile(BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt", $license['text']);
FileSystem::writeFile(BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt", $license['text']);
continue;
}
if ($license['type'] === 'file') {
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt");
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt");
}
}
}
protected function isLibraryInstalled(): bool
{
if ($pkg_configs = Config::getLib(static::NAME, 'pkg-configs', [])) {
$pkg_config_path = getenv('PKG_CONFIG_PATH') ?: '';
$search_paths = array_unique(array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path)));
foreach ($pkg_configs as $name) {
$found = false;
foreach ($search_paths as $path) {
if (file_exists($path . "/{$name}.pc")) {
$found = true;
break;
}
}
if (!$found) {
return false;
}
}
// allow using system dependencies if pkg_config_path is explicitly defined
if (count($search_paths) > 1) {
return true;
}
}
foreach (Config::getLib(static::NAME, 'static-libs', []) as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
return false;
@@ -396,17 +375,8 @@ abstract class LibraryBase
return false;
}
}
$pkg_config_path = getenv('PKG_CONFIG_PATH') ?: '';
$search_paths = array_filter(explode(is_unix() ? ':' : ';', $pkg_config_path));
foreach (Config::getLib(static::NAME, 'pkg-configs', []) as $name) {
$found = false;
foreach ($search_paths as $path) {
if (file_exists($path . "/{$name}.pc")) {
$found = true;
break;
}
}
if (!$found) {
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$name}.pc")) {
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('brotli')]
class brotli extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
return $this->getEnableArg($shared) . '--with-libbrotli';
}
}

View File

@@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('clickhouse')]
class clickhouse extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-clickhouse' . ($shared ? '=shared' : '');
if ($this->builder->getLib('openssl')) {
$arg .= ' --enable-clickhouse-openssl';
}
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('com_dotnet')]
class com_dotnet extends Extension
{
public function getWindowsConfigureArg(bool $shared = false): string
{
return '--enable-com-dotnet=yes';
}
}

View File

@@ -1,46 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('decimal')]
class decimal extends Extension
{
// TODO: remove this when https://github.com/php-decimal/ext-decimal/issues/92 is merged
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileStr(
$this->source_dir . '/php_decimal.c',
[
'zend_module_entry decimal_module_entry',
'ZEND_GET_MODULE(decimal)',
],
[
'zend_module_entry php_decimal_module_entry',
'ZEND_GET_MODULE(php_decimal)',
]
);
FileSystem::replaceFileStr(
$this->source_dir . '/config.w32',
'ARG_WITH("decimal", "for decimal support", "no");',
'ARG_WITH("decimal", "for decimal support", "no");' . "\n" .
'ADD_EXTENSION_DEP("decimal", "json");'
);
return true;
}
public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-decimal --with-libmpdec-path="' . BUILD_ROOT_PATH . '"';
}
public function getWindowsConfigureArg(bool $shared = false): string
{
return '--with-decimal';
}
}

View File

@@ -38,23 +38,7 @@ class event extends Extension
// Prevent event extension compile error on macOS
if ($this->builder instanceof MacOSBuilder) {
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
$patched = true;
}
return $this->patchLibeventConstPeer() || $patched;
}
public function patchBeforeSharedMake(): bool
{
$patched = parent::patchBeforeSharedMake();
return $this->patchLibeventConstPeer() || $patched;
}
private function patchLibeventConstPeer(): bool
{
$patched = false;
$file = SOURCE_PATH . '/php-src/ext/event/php8/classes/http_connection.c';
if (is_file($file) && FileSystem::replaceFileRegex($file, '/^\tchar \*address;$/m', "\tconst char *address;")) {
$patched = true;
return true;
}
return $patched;
}

View File

@@ -5,21 +5,11 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\linux\SystemUtil;
use SPC\store\SourcePatcher;
use SPC\util\CustomExt;
#[CustomExt('ffi')]
class ffi extends Extension
{
public function patchBeforeBuildconf(): bool
{
if (PHP_OS_FAMILY === 'Linux' && SystemUtil::getOSRelease()['dist'] === 'centos') {
return SourcePatcher::patchFfiCentos7FixO3strncmp();
}
return false;
}
public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-ffi' . ($shared ? '=shared' : '') . ' --enable-zend-signals';

View File

@@ -11,6 +11,7 @@ use SPC\store\FileSystem;
use SPC\util\CustomExt;
use SPC\util\GlobalEnvManager;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
#[CustomExt('grpc')]
class grpc extends Extension
@@ -20,59 +21,22 @@ class grpc extends Extension
if ($this->builder instanceof WindowsBuilder) {
throw new ValidationException('grpc extension does not support windows yet');
}
// Fix deprecated PHP API usage in call.c
FileSystem::replaceFileStr(
"{$this->source_dir}/src/php/ext/grpc/call.c",
'zend_exception_get_default(TSRMLS_C),',
'zend_ce_exception,',
);
// Fix include path conflict with pdo_sqlsrv: grpc's PHP ext dir is added to the global include path via
$grpc_php_dir = "{$this->source_dir}/src/php/ext/grpc";
if (file_exists("{$grpc_php_dir}/version.h")) {
copy("{$grpc_php_dir}/version.h", "{$grpc_php_dir}/php_grpc_version.h");
unlink("{$grpc_php_dir}/version.h");
FileSystem::replaceFileStr("{$grpc_php_dir}/php_grpc.h", '#include "version.h"', '#include "php_grpc_version.h"');
FileSystem::replaceFileStr("{$grpc_php_dir}/php_grpc.c", '#include "version.h"', '#include "php_grpc_version.h"');
if (file_exists(SOURCE_PATH . '/php-src/ext/grpc')) {
return false;
}
// soft link to the grpc source code
if (is_dir($this->source_dir . '/src/php/ext/grpc')) {
shell()->exec('ln -s ' . $this->source_dir . '/src/php/ext/grpc ' . SOURCE_PATH . '/php-src/ext/grpc');
} else {
throw new ValidationException('Cannot find grpc source code in ' . $this->source_dir . '/src/php/ext/grpc');
}
if (SPCTarget::getTargetOS() === 'Darwin') {
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/ext/grpc/config.m4',
'/GRPC_LIBDIR=.*$/m',
'GRPC_LIBDIR=' . BUILD_LIB_PATH . "\n" . 'LDFLAGS="$LDFLAGS -framework CoreFoundation"'
);
}
$config_m4 = <<<'M4'
PHP_ARG_ENABLE(grpc, [whether to enable grpc support], [AS_HELP_STRING([--enable-grpc], [Enable grpc support])])
if test "$PHP_GRPC" != "no"; then
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
GRPC_LIBDIR=@@build_lib_path@@
PHP_ADD_LIBPATH($GRPC_LIBDIR)
PHP_ADD_LIBRARY(grpc,,GRPC_SHARED_LIBADD)
LIBS="-lpthread $LIBS"
PHP_ADD_LIBRARY(pthread)
case $host in
*darwin*)
PHP_ADD_LIBRARY(c++,1,GRPC_SHARED_LIBADD)
;;
*)
PHP_ADD_LIBRARY(stdc++,1,GRPC_SHARED_LIBADD)
PHP_ADD_LIBRARY(rt,,GRPC_SHARED_LIBADD)
PHP_ADD_LIBRARY(rt)
;;
esac
PHP_NEW_EXTENSION(grpc, @grpc_c_files@, $ext_shared, , -DGRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1)
PHP_SUBST(GRPC_SHARED_LIBADD)
PHP_INSTALL_HEADERS([ext/grpc], [php_grpc.h])
fi
M4;
$replace = get_pack_replace();
// load grpc c files from src/php/ext/grpc
$c_files = glob($this->source_dir . '/src/php/ext/grpc/*.c');
$replace['@grpc_c_files@'] = implode(" \\\n ", array_map(fn ($f) => 'src/php/ext/grpc/' . basename($f), $c_files));
$config_m4 = str_replace(array_keys($replace), array_values($replace), $config_m4);
file_put_contents($this->source_dir . '/config.m4', $config_m4);
copy($this->source_dir . '/src/php/ext/grpc/php_grpc.h', $this->source_dir . '/php_grpc.h');
return true;
}
@@ -88,6 +52,7 @@ M4;
public function patchBeforeMake(): bool
{
parent::patchBeforeMake();
// add -Wno-strict-prototypes
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -Wno-strict-prototypes');
return true;
}

View File

@@ -5,8 +5,6 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\CustomExt;
#[CustomExt('imagick')]
@@ -21,9 +19,7 @@ class imagick extends Extension
protected function splitLibsIntoStaticAndShared(string $allLibs): array
{
[$static, $shared] = parent::splitLibsIntoStaticAndShared($allLibs);
if (ToolchainManager::getToolchainClass() !== ZigToolchain::class &&
(str_contains(getenv('PATH'), 'rh/devtoolset') || str_contains(getenv('PATH'), 'rh/gcc-toolset'))
) {
if (str_contains(getenv('PATH'), 'rh/devtoolset') || str_contains(getenv('PATH'), 'rh/gcc-toolset')) {
$static .= ' -l:libstdc++.a';
$shared = str_replace('-lstdc++', '', $shared);
}

View File

@@ -18,9 +18,6 @@ class memcache extends Extension
public function patchBeforeBuildconf(): bool
{
if (!$this->isBuildStatic()) {
return false;
}
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'if test -d $abs_srcdir/src ; then',
@@ -46,27 +43,4 @@ EOF
);
return true;
}
public function patchBeforeSharedConfigure(): bool
{
if (!$this->isBuildShared()) {
return false;
}
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'if test -d $abs_srcdir/main ; then',
'if test -d $abs_srcdir/src ; then',
);
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/memcache/config9.m4',
'export CPPFLAGS="$CPPFLAGS $INCLUDES -I$abs_srcdir/main"',
'export CPPFLAGS="$CPPFLAGS $INCLUDES"',
);
return true;
}
protected function getExtraEnv(): array
{
return ['CFLAGS' => '-std=c17'];
}
}

View File

@@ -5,22 +5,11 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('mongodb')]
class mongodb extends Extension
{
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/ext/mongodb/config.m4',
'/^(\s+)(src\/libmongoc\/)/m',
'$1${ac_config_dir}/$2'
);
return true;
}
public function getUnixConfigureArg(bool $shared = false): string
{
$arg = ' --enable-mongodb' . ($shared ? '=shared' : '') . ' ';
@@ -35,9 +24,4 @@ class mongodb extends Extension
$arg .= $this->builder->getLib('zlib') ? ' --with-mongodb-zlib=yes ' : ' --with-mongodb-zlib=bundled ';
return clean_spaces($arg);
}
public function getExtraEnv(): array
{
return ['CFLAGS' => '-std=c17'];
}
}

View File

@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mysqlnd_ed25519')]
class mysqlnd_ed25519 extends Extension
{
public function getConfigureArg(bool $shared = false): string
{
return '--with-mysqlnd_ed25519' . ($shared ? '=shared' : '');
}
public function getUnixConfigureArg(bool $shared = false): string
{
return $this->getConfigureArg();
}
}

View File

@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('mysqlnd_parsec')]
class mysqlnd_parsec extends Extension
{
public function getConfigureArg(bool $shared = false): string
{
return '--enable-mysqlnd_parsec' . ($shared ? '=shared' : '');
}
public function getUnixConfigureArg(bool $shared = false): string
{
return $this->getConfigureArg();
}
}

View File

@@ -58,10 +58,7 @@ class opcache extends Extension
) {
$opcache_jit = ' --disable-opcache-jit';
}
if ($phpVersionID < 80500) {
return '--enable-opcache' . ($shared ? '=shared' : '') . $opcache_jit;
}
return trim($opcache_jit);
return '--enable-opcache' . ($shared ? '=shared' : '') . $opcache_jit;
}
public function getDistName(): string

View File

@@ -24,6 +24,25 @@ class password_argon2 extends Extension
}
}
public function patchBeforeMake(): bool
{
$patched = parent::patchBeforeMake();
if ($this->builder->getLib('libsodium') !== null) {
$extraLibs = getenv('SPC_EXTRA_LIBS');
if ($extraLibs !== false) {
$extraLibs = str_replace(
[BUILD_LIB_PATH . '/libargon2.a', BUILD_LIB_PATH . '/libsodium.a'],
['', BUILD_LIB_PATH . '/libargon2.a ' . BUILD_LIB_PATH . '/libsodium.a'],
$extraLibs,
);
$extraLibs = trim(preg_replace('/\s+/', ' ', $extraLibs)); // normalize spacing
f_putenv('SPC_EXTRA_LIBS=' . $extraLibs);
return true;
}
}
return $patched;
}
public function getConfigureArg(bool $shared = false): string
{
if ($this->builder->getLib('openssl') !== null) {

View File

@@ -45,7 +45,7 @@ class pgsql extends Extension
protected function getExtraEnv(): array
{
return [
'CFLAGS' => '-std=c17 -Wno-int-conversion',
'CFLAGS' => '-Wno-int-conversion',
];
}
}

View File

@@ -45,11 +45,4 @@ class spx extends Extension
FileSystem::copy($this->source_dir . '/src/php_spx.h', $this->source_dir . '/php_spx.h');
return true;
}
public function getSharedExtensionEnv(): array
{
$env = parent::getSharedExtensionEnv();
$env['SPX_SHARED_LIBADD'] = $env['LIBS'];
return $env;
}
}

View File

@@ -33,14 +33,4 @@ class sqlsrv extends Extension
}
return false;
}
public function patchBeforeMake(): bool
{
$makefile = SOURCE_PATH . '/php-src/Makefile';
$makeContent = file_get_contents($makefile);
$makeContent = preg_replace('/^(CFLAGS_(?:PDO_)?SQLSRV=.*?)\s+\/W4\b/m', '$1', $makeContent);
$makeContent = preg_replace('/^(CFLAGS_(?:PDO_)?SQLSRV=.*?)\s+\/WX\b/m', '$1', $makeContent);
file_put_contents($makefile, $makeContent);
return true;
}
}

View File

@@ -17,7 +17,6 @@ class swoole extends Extension
public function patchBeforeMake(): bool
{
$patched = parent::patchBeforeMake();
FileSystem::replaceFileStr($this->source_dir . '/ext-src/php_swoole_private.h', 'PHP_VERSION_ID > 80500', 'PHP_VERSION_ID >= 80600');
if ($this->builder instanceof MacOSBuilder) {
// Fix swoole with event extension <util.h> conflict bug
$util_path = shell()->execWithResult('xcrun --show-sdk-path', false)[1][0] . '/usr/include/util.h';
@@ -50,16 +49,19 @@ class swoole extends Extension
// commonly used feature: coroutine-time
$arg .= ' --enable-swoole-coro-time --with-pic';
$arg .= ' --enable-swoole-ssh --enable-swoole-curl';
$arg .= $this->builder->getOption('enable-zts') ? ' --enable-swoole-thread --disable-thread-context' : ' --disable-swoole-thread --enable-thread-context';
// required features: curl, openssl (but curl hook is buggy for php 8.0)
$arg .= $this->builder->getPHPVersionID() >= 80100 ? ' --enable-swoole-curl' : ' --disable-swoole-curl';
$arg .= ' --enable-openssl';
// additional features that only require libraries
$arg .= $this->builder->getLib('libcares') ? ' --enable-cares' : '';
$arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
$arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-dir=' . BUILD_ROOT_PATH) : '';
$arg .= $this->builder->getLib('zstd') ? ' --enable-zstd' : '';
$arg .= $this->builder->getLib('liburing') && getenv('SPC_LIBC') !== 'glibc' ? ' --enable-iouring --enable-uring-socket' : '--disable-iouring';
$arg .= $this->builder->getLib('liburing') ? ' --enable-iouring' : '';
$arg .= $this->builder->getExt('sockets') ? ' --enable-sockets' : '';
// enable additional features that require the pdo extension, but conflict with pdo_* extensions
@@ -71,7 +73,6 @@ class swoole extends Extension
$config = (new SPCConfigUtil($this->builder))->getLibraryConfig($this->builder->getLib('unixodbc'));
$arg .= ' --with-swoole-odbc=unixODBC,' . BUILD_ROOT_PATH . ' SWOOLE_ODBC_LIBS="' . $config['libs'] . '"';
}
$arg .= $this->builder->getExt('ftp')?->isBuildStatic() ? ' --disable-swoole-ftp' : ' --enable-swoole-ftp';
if ($this->getExtVersion() >= '6.1.0') {
$arg .= ' --enable-swoole-stdext';

View File

@@ -7,7 +7,6 @@ namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\SourcePatcher;
use SPC\util\CustomExt;
use SPC\util\GlobalEnvManager;
#[CustomExt('xlswriter')]
class xlswriter extends Extension
@@ -29,13 +28,6 @@ class xlswriter extends Extension
public function patchBeforeMake(): bool
{
$patched = parent::patchBeforeMake();
// Remove when https://github.com/viest/php-ext-xlswriter/pull/560 is merged
if (PHP_OS_FAMILY !== 'Windows') {
GlobalEnvManager::putenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS=' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -std=gnu17');
$patched = true;
}
if (PHP_OS_FAMILY === 'Windows') {
// fix windows build with openssl extension duplicate symbol bug
SourcePatcher::patchFile('spc_fix_xlswriter_win32.patch', $this->source_dir);
@@ -48,10 +40,4 @@ class xlswriter extends Extension
}
return $patched;
}
// Remove when https://github.com/viest/php-ext-xlswriter/pull/560 is merged
protected function getExtraEnv(): array
{
return ['CFLAGS' => '-std=gnu17'];
}
}

View File

@@ -65,8 +65,6 @@ class BSDBuilder extends UnixBuilderBase
('--with-config-file-path=' . $this->getOption('with-config-file-path') . ' ') : '';
$config_file_scan_dir = $this->getOption('with-config-file-scan-dir', false) ?
('--with-config-file-scan-dir=' . $this->getOption('with-config-file-scan-dir') . ' ') : '';
$sysconfdir = $this->getOption('with-sysconfdir', false) ?
('--sysconfdir=' . $this->getOption('with-sysconfdir') . ' ') : '';
$enableCli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI;
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
@@ -91,7 +89,6 @@ class BSDBuilder extends UnixBuilderBase
($enableMicro ? '--enable-micro ' : '--disable-micro ') .
$config_file_path .
$config_file_scan_dir .
$sysconfdir .
$json_74 .
$zts .
$this->makeStaticExtensionArgs()

View File

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

View File

@@ -11,10 +11,7 @@ use SPC\store\Config;
use SPC\store\DirDiff;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\GlobalEnvManager;
use SPC\util\PgoManager;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
@@ -23,8 +20,6 @@ class LinuxBuilder extends UnixBuilderBase
/** @var bool Micro patch phar flag */
private bool $phar_patched = false;
private ?PgoManager $pgo = null;
public function __construct(array $options = [])
{
$this->options = $options;
@@ -51,8 +46,6 @@ class LinuxBuilder extends UnixBuilderBase
*/
public function buildPHP(int $build_target = BUILD_TARGET_NONE): void
{
$this->pgo = PgoManager::fromBuilder($this, $build_target);
$cflags = $this->arch_c_flags;
f_putenv('CFLAGS=' . $cflags);
@@ -72,8 +65,7 @@ class LinuxBuilder extends UnixBuilderBase
// php 8.5 contains opcache extension by default,
// if opcache_jit is enabled for 8.5 or opcache enabled,
// we need to disable undefined behavior sanitizer.
$compiler_extra = getenv('SPC_COMPILER_EXTRA') ?: '';
f_putenv('SPC_COMPILER_EXTRA=' . trim($compiler_extra . ' -fno-sanitize=undefined'));
f_putenv('SPC_COMPILER_EXTRA=-fno-sanitize=undefined');
}
if ($this->getOption('enable-zts', false)) {
@@ -88,8 +80,6 @@ class LinuxBuilder extends UnixBuilderBase
('--with-config-file-path=' . $this->getOption('with-config-file-path') . ' ') : '';
$config_file_scan_dir = $this->getOption('with-config-file-scan-dir', false) ?
('--with-config-file-scan-dir=' . $this->getOption('with-config-file-scan-dir') . ' ') : '';
$sysconfdir = $this->getOption('with-sysconfdir', false) ?
('--sysconfdir=' . $this->getOption('with-sysconfdir') . ' ') : '';
$enableCli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI;
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
@@ -127,7 +117,6 @@ class LinuxBuilder extends UnixBuilderBase
($enableCgi ? '--enable-cgi ' : '--disable-cgi ') .
$config_file_path .
$config_file_scan_dir .
$sysconfdir .
$json_74 .
$zts .
$maxExecutionTimers .
@@ -137,40 +126,35 @@ class LinuxBuilder extends UnixBuilderBase
$this->emitPatchPoint('before-php-make');
SourcePatcher::patchBeforeMake($this);
PgoManager::patchBeforeMake($this);
$this->cleanMake();
$pgo = $this->pgo;
$needsClean = false;
$sapiBuilds = [
['cli', $enableCli, true, fn () => $this->buildCli()],
['fpm', $enableFpm, true, fn () => $this->buildFpm()],
['cgi', $enableCgi, true, fn () => $this->buildCgi()],
['micro', $enableMicro, true, fn () => $this->buildMicro()],
['embed', $enableEmbed, true, function () use ($enableMicro): void {
if ($enableMicro) {
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'OVERALL_TARGET =', 'OVERALL_TARGET = libphp.la');
}
$this->buildEmbed();
}],
// frankenphp doesn't rebuild php-src; xcaddy links against the deployed libphp.so
['frankenphp', $enableFrankenphp, false, fn () => $this->buildFrankenphp()],
];
foreach ($sapiBuilds as [$sapi, $enabled, $rebuildsPhpSrc, $build]) {
if (!$enabled) {
continue;
if ($enableCli) {
logger()->info('building cli');
$this->buildCli();
}
if ($enableFpm) {
logger()->info('building fpm');
$this->buildFpm();
}
if ($enableCgi) {
logger()->info('building cgi');
$this->buildCgi();
}
if ($enableMicro) {
logger()->info('building micro');
$this->buildMicro();
}
if ($enableEmbed) {
logger()->info('building embed');
if ($enableMicro) {
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'OVERALL_TARGET =', 'OVERALL_TARGET = libphp.la');
}
if ($pgo) {
if ($needsClean && $rebuildsPhpSrc) {
$this->cleanMake();
}
$pgo->applyForSapi($sapi);
$needsClean = $needsClean || $rebuildsPhpSrc;
}
logger()->info('building ' . $sapi);
$build();
$this->buildEmbed();
}
if ($enableFrankenphp) {
logger()->info('building frankenphp');
$this->buildFrankenphp();
}
$shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
if (!empty($shared_extensions)) {
@@ -178,7 +162,7 @@ class LinuxBuilder extends UnixBuilderBase
throw new WrongUsageException(
"You're building against musl libc statically (the default on Linux), but you're trying to build shared extensions.\n" .
'Static musl libc does not implement `dlopen`, so your php binary is not able to load shared extensions.' . "\n" .
'Either use SPC_LIBC=glibc to link against glibc on a glibc OS, use SPC_TARGET="native-native-musl -dynamic" to link against musl libc dynamically using `zig cc` or use SPC_MUSL_DYNAMIC=true on alpine.'
'Either use SPC_LIBC=glibc to link against glibc on a glibc OS, or use SPC_TARGET="native-native-musl -dynamic" to link against musl libc dynamically using `zig cc`.'
);
}
logger()->info('Building shared extensions...');
@@ -282,11 +266,6 @@ class LinuxBuilder extends UnixBuilderBase
*/
protected function buildEmbed(): void
{
$compiler_extra = getenv('SPC_COMPILER_EXTRA') ?: '';
if (!str_contains($compiler_extra, '-lcompiler_rt') && ToolchainManager::getToolchainClass() === ZigToolchain::class) {
$compiler_extra = trim($compiler_extra . ' -lcompiler_rt');
GlobalEnvManager::putenv("SPC_COMPILER_EXTRA={$compiler_extra}");
}
$sharedExts = array_filter($this->exts, static fn ($ext) => $ext->isBuildShared());
$sharedExts = array_filter($sharedExts, static function ($ext) {
return Config::getExt($ext->getName(), 'build-with-php') === true;
@@ -304,14 +283,11 @@ class LinuxBuilder extends UnixBuilderBase
// process libphp.so for shared embed
$libphpSo = BUILD_LIB_PATH . '/libphp.so';
$libphpSoDest = BUILD_LIB_PATH . '/libphp.so';
if (file_exists($libphpSo)) {
// post actions: rename libphp.so to libphp-<release>.so if -release is set in LDFLAGS
$this->processLibphpSoFile($libphpSo);
// deploy libphp.so
preg_match('/-release\s+(\S*)/', getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), $matches);
if (!empty($matches[1])) {
$libphpSoDest = str_replace('.so', '-' . $matches[1] . '.so', $libphpSo);
}
$this->deployBinary($libphpSo, $libphpSoDest, false);
$this->deployBinary($libphpSo, $libphpSo, false);
}
// process shared extensions build-with-php
@@ -337,24 +313,85 @@ class LinuxBuilder extends UnixBuilderBase
*/
private function getMakeExtraVars(): array
{
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true, 'absolute_libs' => true]))->config(array_keys($this->getExts(false)), [], $this->getOption('with-suggested-exts'), $this->lib_list);
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true, 'absolute_libs' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
$static = SPCTarget::isStatic() ? '-all-static' : '';
$lib = BUILD_LIB_PATH;
$extra_ldflags = (string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS');
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared'
&& !str_contains($extra_ldflags, '-avoid-version')
&& !preg_match('/-release\s+\S+/', $extra_ldflags)) {
$extra_ldflags = trim($extra_ldflags . ' -avoid-version -module');
}
$extra_ldflags_program = trim("-L{$lib} {$static} -pie " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM'));
return array_filter([
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LIBS' => $config['libs'],
'EXTRA_LDFLAGS' => $extra_ldflags,
'EXTRA_LDFLAGS_PROGRAM' => $extra_ldflags_program,
'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'),
'EXTRA_LDFLAGS_PROGRAM' => "-L{$lib} {$static} -pie",
]);
}
private function processLibphpSoFile(string $libphpSo): void
{
$ldflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS') ?: '';
$libDir = BUILD_LIB_PATH;
$modulesDir = BUILD_MODULES_PATH;
$realLibName = 'libphp.so';
$cwd = getcwd();
if (preg_match('/-release\s+(\S+)/', $ldflags, $matches)) {
$release = $matches[1];
$realLibName = "libphp-{$release}.so";
$libphpRelease = "{$libDir}/{$realLibName}";
if (!file_exists($libphpRelease) && file_exists($libphpSo)) {
rename($libphpSo, $libphpRelease);
}
if (file_exists($libphpRelease)) {
chdir($libDir);
if (file_exists($libphpSo)) {
unlink($libphpSo);
}
symlink($realLibName, 'libphp.so');
shell()->exec(sprintf(
'patchelf --set-soname %s %s',
escapeshellarg($realLibName),
escapeshellarg($libphpRelease)
));
}
if (is_dir($modulesDir)) {
chdir($modulesDir);
foreach ($this->getExts() as $ext) {
if (!$ext->isBuildShared()) {
continue;
}
$name = $ext->getName();
$versioned = "{$name}-{$release}.so";
$unversioned = "{$name}.so";
$src = "{$modulesDir}/{$versioned}";
$dst = "{$modulesDir}/{$unversioned}";
if (is_file($src)) {
rename($src, $dst);
shell()->exec(sprintf(
'patchelf --set-soname %s %s',
escapeshellarg($unversioned),
escapeshellarg($dst)
));
}
}
}
chdir($cwd);
}
$target = "{$libDir}/{$realLibName}";
if (file_exists($target)) {
[, $output] = shell()->execWithResult('readelf -d ' . escapeshellarg($target));
$output = implode("\n", $output);
if (preg_match('/SONAME.*\[(.+)]/', $output, $sonameMatch)) {
$currentSoname = $sonameMatch[1];
if ($currentSoname !== basename($target)) {
shell()->exec(sprintf(
'patchelf --set-soname %s %s',
escapeshellarg(basename($target)),
escapeshellarg($target)
));
}
}
}
}
/**
* Patch micro.sfx after UPX compression.
* micro needs special section handling in LinuxBuilder.

View File

@@ -15,11 +15,9 @@ class icu extends LinuxLibraryBase
protected function build(): void
{
$userCxxFlags = trim((string) getenv('SPC_DEFAULT_CXX_FLAGS'));
$userLdFlags = trim((string) getenv('SPC_DEFAULT_LD_FLAGS'));
$cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -DPIC -fPIC"';
$cxxflags = "CXXFLAGS=\"-std=c++17 -DPIC -fPIC -fno-ident {$userCxxFlags}\"";
$ldflags = SPCTarget::isStatic() ? "LDFLAGS=\"-static {$userLdFlags}\"" : "LDFLAGS=\"{$userLdFlags}\"";
$cxxflags = 'CXXFLAGS="-std=c++17 -DPIC -fPIC -fno-ident"';
$ldflags = SPCTarget::isStatic() ? 'LDFLAGS="-static"' : '';
shell()->cd($this->source_dir . '/source')->initializeEnv($this)
->exec(
"{$cppflags} {$cxxflags} {$ldflags} " .

View File

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

View File

@@ -6,8 +6,6 @@ namespace SPC\builder\linux\library;
use SPC\builder\linux\SystemUtil;
use SPC\store\FileSystem;
use SPC\toolchain\GccNativeToolchain;
use SPC\toolchain\ToolchainManager;
use SPC\util\executor\UnixAutoconfExecutor;
use SPC\util\SPCTarget;
@@ -17,19 +15,26 @@ class liburing extends LinuxLibraryBase
public function patchBeforeBuild(): bool
{
if (SystemUtil::isMuslDist()) {
FileSystem::replaceFileStr($this->source_dir . '/configure', 'realpath -s', 'realpath');
return true;
if (!SystemUtil::isMuslDist()) {
return false;
}
return false;
FileSystem::replaceFileStr($this->source_dir . '/configure', 'realpath -s', 'realpath');
return true;
}
protected function build(): void
{
$use_libc = ToolchainManager::getToolchainClass() !== GccNativeToolchain::class || version_compare(SPCTarget::getLibcVersion(), '2.30', '>=');
$use_libc = SPCTarget::getLibc() !== 'glibc' || version_compare(SPCTarget::getLibcVersion(), '2.30', '>=');
$make = UnixAutoconfExecutor::create($this);
if ($use_libc) {
if (!$use_libc) {
$make->appendEnv([
'CC' => 'gcc', // libc-less version fails to compile with clang or zig
'CXX' => 'g++',
'AR' => 'ar',
'LD' => 'ld',
]);
} else {
$make->appendEnv([
'CFLAGS' => '-D_GNU_SOURCE',
]);
@@ -46,7 +51,7 @@ class liburing extends LinuxLibraryBase
$use_libc ? '--use-libc' : '',
)
->configure()
->make('library ENABLE_SHARED=0', 'install ENABLE_SHARED=0', with_clean: false);
->make('library', 'install ENABLE_SHARED=0', with_clean: false);
$this->patchPkgconfPrefix();
}

View File

@@ -21,7 +21,6 @@ declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\builder\linux\SystemUtil;
use SPC\store\FileSystem;
class openssl extends LinuxLibraryBase
@@ -52,28 +51,18 @@ class openssl extends LinuxLibraryBase
$zlib_extra = '';
}
$openssl_dir = getenv('OPENSSLDIR') ?: null;
// TODO: in v3 use the following: $openssl_dir ??= SystemUtil::getOSRelease()['dist'] === 'redhat' ? '/etc/pki/tls' : '/etc/ssl';
$openssl_dir ??= '/etc/ssl';
$ex_lib = trim($ex_lib);
// OpenSSL's Configure ignores env CFLAGS for its target template; pass our flags as extra args after the target.
$userCFlags = trim((string) getenv('SPC_DEFAULT_C_FLAGS'));
$userLdFlags = trim((string) getenv('SPC_DEFAULT_LD_FLAGS'));
$userExtraFlags = trim($userCFlags . ' ' . $userLdFlags);
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
"{$env} ./Configure no-shared {$extra} " .
'--prefix=' . BUILD_ROOT_PATH . ' ' .
'--libdir=' . BUILD_LIB_PATH . ' ' .
"--openssldir={$openssl_dir} " .
'--openssldir=/etc/ssl ' .
"{$zlib_extra}" .
'enable-pie ' .
'no-legacy ' .
'no-tests ' .
"linux-{$arch} " .
$userExtraFlags
"linux-{$arch}"
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")

View File

@@ -96,8 +96,6 @@ class MacOSBuilder extends UnixBuilderBase
('--with-config-file-path=' . $this->getOption('with-config-file-path') . ' ') : '';
$config_file_scan_dir = $this->getOption('with-config-file-scan-dir', false) ?
('--with-config-file-scan-dir=' . $this->getOption('with-config-file-scan-dir') . ' ') : '';
$sysconfdir = $this->getOption('with-sysconfdir', false) ?
('--sysconfdir=' . $this->getOption('with-sysconfdir') . ' ') : '';
$enableCli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI;
$enableFpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
@@ -131,7 +129,6 @@ class MacOSBuilder extends UnixBuilderBase
($enableCgi ? '--enable-cgi ' : '--disable-cgi ') .
$config_file_path .
$config_file_scan_dir .
$sysconfdir .
$json_74 .
$zts .
$this->makeStaticExtensionArgs() . ' ' .
@@ -296,7 +293,7 @@ class MacOSBuilder extends UnixBuilderBase
private function getMakeExtraVars(): array
{
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true]))->config(array_keys($this->getExts(false)), [], $this->getOption('with-suggested-exts'), $this->lib_list);
$config = (new SPCConfigUtil($this, ['libs_only_deps' => true]))->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
return array_filter([
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LDFLAGS_PROGRAM' => '-L' . BUILD_LIB_PATH,

View File

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

View File

@@ -34,7 +34,7 @@ trait UnixLibraryTrait
$files = array_map(fn ($x) => "{$x}.pc", $conf_pc);
}
foreach ($files as $name) {
$realpath = realpath(BUILD_LIB_PATH . '/pkgconfig/' . $name);
$realpath = realpath(BUILD_ROOT_PATH . '/lib/pkgconfig/' . $name);
if ($realpath === false) {
throw new PatchException('pkg-config prefix patcher', 'Cannot find library [' . static::NAME . '] pkgconfig file [' . $name . '] in ' . BUILD_LIB_PATH . '/pkgconfig/ !');
}

View File

@@ -50,7 +50,7 @@ trait UnixSystemUtilTrait
$defined = array_unique($defined);
sort($defined);
// export
if (SPCTarget::getTargetOS() === 'Linux' && ToolchainManager::getToolchainClass() !== ZigToolchain::class) {
if (SPCTarget::getTargetOS() === 'Linux') {
file_put_contents("{$lib_file}.dynsym", "{\n" . implode("\n", array_map(fn ($x) => " {$x};", $defined)) . "};\n");
} else {
file_put_contents("{$lib_file}.dynsym", implode("\n", $defined) . "\n");
@@ -72,8 +72,12 @@ trait UnixSystemUtilTrait
if (!is_file($symbol_file)) {
throw new SPCInternalException("The symbol file {$symbol_file} does not exist, please check if nm command is available.");
}
// macOS/zig
if (SPCTarget::getTargetOS() !== 'Linux' || ToolchainManager::getToolchainClass() === ZigToolchain::class) {
// https://github.com/ziglang/zig/issues/24662
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
return '-Wl,--export-dynamic';
}
// macOS
if (SPCTarget::getTargetOS() !== 'Linux') {
return "-Wl,-exported_symbols_list,{$symbol_file}";
}
return "-Wl,--dynamic-list={$symbol_file}";

View File

@@ -145,10 +145,11 @@ abstract class UnixBuilderBase extends BuilderBase
throw new SPCInternalException("Deploy failed. Cannot find file after copy: {$dst}");
}
if (!$this->getOption('no-strip') && !$this->getOption('pgi') && !$this->getOption('cs-pgi')) {
// extract debug info
$this->extractDebugInfo($dst);
// extra strip
// extract debug info
$this->extractDebugInfo($dst);
// strip
if (!$this->getOption('no-strip')) {
$this->stripBinary($dst);
}
@@ -229,16 +230,14 @@ abstract class UnixBuilderBase extends BuilderBase
copy(ROOT_DIR . '/src/globals/common-tests/embed.c', $sample_file_path . '/embed.c');
copy(ROOT_DIR . '/src/globals/common-tests/embed.php', $sample_file_path . '/embed.php');
$util = new SPCConfigUtil($this);
$config = $util->config(array_keys($this->getExts(false)), [], $this->getOption('with-suggested-exts'), $this->lib_list);
$config = $util->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
$lens = "{$config['cflags']} {$config['ldflags']} {$config['libs']}";
if (SPCTarget::isStatic()) {
$lens .= ' -static';
}
$dynamic_exports = '';
$embedType = 'static';
// if someone changed to EMBED_TYPE=shared, we need to add LD_LIBRARY_PATH
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
$embedType = 'shared';
if (PHP_OS_FAMILY === 'Darwin') {
$ext_path = 'DYLD_LIBRARY_PATH=' . BUILD_LIB_PATH . ':$DYLD_LIBRARY_PATH ';
} else {
@@ -257,19 +256,18 @@ abstract class UnixBuilderBase extends BuilderBase
}
}
$cc = getenv('CC');
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult("{$cc} -o embed embed.c {$lens} {$dynamic_exports}");
if ($ret !== 0) {
throw new ValidationException(
'embed failed to build. Error message: ' . implode("\n", $out),
validation_module: $embedType . ' libphp embed build sanity check'
'embed failed sanity check: build failed. Error message: ' . implode("\n", $out),
validation_module: 'static libphp.a sanity check'
);
}
[$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed');
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
throw new ValidationException(
'embed failed to run. Error message: ' . implode("\n", $output),
validation_module: $embedType . ' libphp embed run sanity check'
'embed failed sanity check: run failed. Error message: ' . implode("\n", $output),
validation_module: 'static libphp.a sanity check'
);
}
}
@@ -365,7 +363,6 @@ abstract class UnixBuilderBase extends BuilderBase
$frankenphpAppPath = $this->getOption('with-frankenphp-app');
if ($frankenphpAppPath) {
$frankenphpAppPath = trim($frankenphpAppPath, "\"'");
if (!is_dir($frankenphpAppPath)) {
throw new WrongUsageException("The path provided to --with-frankenphp-app is not a valid directory: {$frankenphpAppPath}");
}
@@ -440,7 +437,7 @@ abstract class UnixBuilderBase extends BuilderBase
$staticFlags = '-static-pie';
}
$config = (new SPCConfigUtil($this))->config(array_keys($this->getExts(false)), [], false, $this->lib_list);
$config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list);
$cflags = "{$this->arch_c_flags} {$config['cflags']} " . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS') . ' -DFRANKENPHP_VERSION=' . $frankenPhpVersion;
$libs = $config['libs'];
// Go's gcc driver doesn't automatically link against -lgcov or -lrt. Ugly, but necessary fix.
@@ -450,24 +447,20 @@ abstract class UnixBuilderBase extends BuilderBase
$cflags .= ' -Wno-error=missing-profile';
$libs .= ' -lgcov';
}
$extraLdProgram = (string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM');
$env = [...[
'CGO_ENABLED' => '1',
'CGO_CFLAGS' => clean_spaces($cflags),
'CGO_LDFLAGS' => trim("{$this->arch_ld_flags} {$staticFlags} {$config['ldflags']} {$libs} {$extraLdProgram}"),
'CGO_LDFLAGS' => "{$this->arch_ld_flags} {$staticFlags} {$config['ldflags']} {$libs}",
'XCADDY_GO_BUILD_FLAGS' => '-buildmode=pie ' .
'-ldflags \"-linkmode=external ' . $extLdFlags . ' ' .
'-X \'github.com/caddyserver/caddy/v2/modules/caddyhttp.ServerHeader=FrankenPHP Caddy\' ' .
'-X \'github.com/caddyserver/caddy/v2.CustomBinaryName=frankenphp\' ' .
'-X \'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ' .
"v{$frankenPhpVersion} PHP {$libphpVersion} Caddy'\\\" " .
"-tags={$muslTags}nobadger,nomysql,nopgx{$nobrotli}{$nowatcher}",
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
], ...GoXcaddy::getEnvironment()];
$pgo = file_exists("{$frankenphpSourceDir}/caddy/frankenphp/default.pgo") ? "--pgo {$frankenphpSourceDir}/caddy/frankenphp/default.pgo " : '';
shell()->cd(BUILD_BIN_PATH)
->setEnv($env)
->exec("xcaddy build --output frankenphp {$pgo}{$xcaddyModules}");
->exec("xcaddy build --output frankenphp {$xcaddyModules}");
$this->deploySAPIBinary(BUILD_TARGET_FRANKENPHP);
}

View File

@@ -10,8 +10,7 @@ trait bzip2
{
public function patchBeforeBuild(): bool
{
$extra = trim((string) getenv('SPC_DEFAULT_C_FLAGS'));
FileSystem::replaceFileStr($this->source_dir . '/Makefile', 'CFLAGS=-Wall', "CFLAGS={$extra} -Wall");
FileSystem::replaceFileStr($this->source_dir . '/Makefile', 'CFLAGS=-Wall', 'CFLAGS=-fPIC -Wall');
return true;
}

View File

@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
use SPC\util\executor\UnixCMakeExecutor;
trait curl
@@ -30,20 +29,11 @@ trait curl
->addConfigureArgs(
'-DBUILD_CURL_EXE=OFF',
'-DBUILD_LIBCURL_DOCS=OFF',
'-DOPENSSL_ROOT_DIR=' . BUILD_ROOT_PATH,
)
->build();
// patch pkgconf
$this->patchPkgconfPrefix(['libcurl.pc']);
// On glibc <2.28 without built-in pthreads, FindThreads sets
// INTERFACE_LINK_LIBRARIES to '-lpthread'
// curls .pc generator walks and prepends '-l' to each
// entry, resulting in -l-lpthread
FileSystem::replaceFileRegex(
BUILD_LIB_PATH . '/pkgconfig/libcurl.pc',
'/-l(-l\S+)/',
'$1'
);
shell()->cd(BUILD_LIB_PATH . '/cmake/CURL/')
->exec("sed -ie 's|\"/lib/libcurl.a\"|\"" . BUILD_LIB_PATH . "/libcurl.a\"|g' CURLTargets-release.cmake");
}

View File

@@ -10,9 +10,8 @@ trait fastlz
{
protected function build(): void
{
$extra = trim((string) getenv('SPC_DEFAULT_C_FLAGS'));
shell()->cd($this->source_dir)->initializeEnv($this)
->exec((getenv('CC') ?: 'cc') . " -c {$extra} fastlz.c -o fastlz.o")
->exec((getenv('CC') ?: 'cc') . ' -c -O3 -fPIC fastlz.c -o fastlz.o')
->exec((getenv('AR') ?: 'ar') . ' rcs libfastlz.a fastlz.o');
if (!copy($this->source_dir . '/fastlz.h', BUILD_INCLUDE_PATH . '/fastlz.h')) {

View File

@@ -13,8 +13,8 @@ trait freetype
{
$cmake = UnixCMakeExecutor::create($this)
->optionalLib('libpng', ...cmake_boolean_args('FT_DISABLE_PNG', true))
->addConfigureArgs('-DFT_DISABLE_BZIP2=ON')
->addConfigureArgs('-DFT_DISABLE_BROTLI=ON')
->optionalLib('bzip2', ...cmake_boolean_args('FT_DISABLE_BZIP2', true))
->optionalLib('brotli', ...cmake_boolean_args('FT_DISABLE_BROTLI', true))
->addConfigureArgs('-DFT_DISABLE_HARFBUZZ=ON');
// fix cmake 4.0 compatibility

View File

@@ -16,11 +16,7 @@ trait gettext
->addConfigureArgs(
'--disable-java',
'--disable-c++',
'--disable-d',
'--disable-rpath',
'--disable-modula2',
'--disable-libasprintf',
'--with-included-libintl',
'--with-included-gettext',
"--with-iconv-prefix={$this->getBuildRootPath()}",
);

View File

@@ -10,14 +10,7 @@ trait gmp
{
protected function build(): void
{
UnixAutoconfExecutor::create($this)
->appendEnv([
'CFLAGS' => '-std=c17',
])
->configure(
'--enable-fat'
)
->make();
UnixAutoconfExecutor::create($this)->configure()->make();
$this->patchPkgconfPrefix(['gmp.pc']);
}
}

View File

@@ -34,9 +34,6 @@ trait imagemagick
->addConfigureArgs(
'--disable-openmp',
'--without-x',
// implicit --with-gcc-arch
// bleeds host cpu features into built binaries
'--without-gcc-arch',
);
// special: linux-static target needs `-static`

View File

@@ -10,8 +10,7 @@ trait jbig
{
public function patchBeforeBuild(): bool
{
$extra = trim((string) getenv('SPC_DEFAULT_C_FLAGS'));
FileSystem::replaceFileStr($this->source_dir . '/Makefile', 'CFLAGS = -O2 -W -Wno-unused-result', "CFLAGS = {$extra} -W -Wno-unused-result");
FileSystem::replaceFileStr($this->source_dir . '/Makefile', 'CFLAGS = -O2 -W -Wno-unused-result', 'CFLAGS = -O2 -W -Wno-unused-result -fPIC');
return true;
}

View File

@@ -4,8 +4,6 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\executor\UnixAutoconfExecutor;
use SPC\util\SPCConfigUtil;
@@ -15,10 +13,7 @@ trait krb5
{
$origin_source_dir = $this->source_dir;
$this->source_dir .= '/src';
shell()->cd($this->source_dir)->exec('ls -lah');
if (!file_exists($this->source_dir . '/configure')) {
shell()->cd($this->source_dir)->exec('autoreconf -if');
}
shell()->cd($this->source_dir)->exec('autoreconf -if');
$libs = array_map(fn ($x) => $x->getName(), $this->getDependencies(true));
$spc = new SPCConfigUtil($this->builder, ['no_php' => true, 'libs_only_deps' => true]);
$config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs', false));
@@ -41,16 +36,12 @@ trait krb5
$extraEnv['LDFLAGS'] = '-framework Kerberos';
$args[] = 'ac_cv_func_secure_getenv=no';
}
$make = UnixAutoconfExecutor::create($this)
UnixAutoconfExecutor::create($this)
->appendEnv($extraEnv)
->optionalLib('ldap', '--with-ldap', '--without-ldap')
->optionalLib('libedit', '--with-libedit', '--without-libedit')
->configure(...$args);
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
$make->exec('find . -name Makefile -exec sed -i "s/-Werror=incompatible-pointer-types//g" {} +');
}
$make->make();
->configure(...$args)
->make();
$this->patchPkgconfPrefix([
'krb5-gssapi.pc',
'krb5.pc',

View File

@@ -4,11 +4,9 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\builder\linux\SystemUtil;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\executor\UnixCMakeExecutor;
use SPC\util\SPCTarget;
trait libaom
{
@@ -19,23 +17,9 @@ trait libaom
$new = trim($extra . ' -D_GNU_SOURCE');
f_putenv("SPC_COMPILER_EXTRA={$new}");
}
$targetCpu = SPCTarget::getTargetArch();
if (str_starts_with($targetCpu, 'aarch')) {
$targetCpu = str_replace('aarch', 'arm', $targetCpu);
}
if (!SystemUtil::findCommand('nasm') && !SystemUtil::findCommand('yasm')) {
$targetCpu = 'generic';
}
UnixCMakeExecutor::create($this)
->setBuildDir("{$this->source_dir}/builddir")
->addConfigureArgs(
"-DAOM_TARGET_CPU={$targetCpu}",
'-DCONFIG_RUNTIME_CPU_DETECT=1',
'-DENABLE_EXAMPLES=0',
'-DENABLE_TOOLS=0',
'-DENABLE_TESTS=0',
'-DENABLE_DOCS=0'
)
->addConfigureArgs('-DAOM_TARGET_CPU=generic')
->build();
f_putenv("SPC_COMPILER_EXTRA={$extra}");
$this->patchPkgconfPrefix(['aom.pc']);

View File

@@ -11,11 +11,6 @@ trait libavif
protected function build(): void
{
UnixCMakeExecutor::create($this)
->optionalLib('libaom', '-DAVIF_CODEC_AOM=SYSTEM', '-DAVIF_CODEC_AOM=OFF')
->optionalLib('libsharpyuv', '-DAVIF_LIBSHARPYUV=SYSTEM', '-DAVIF_LIBSHARPYUV=OFF')
->optionalLib('libjpeg', '-DAVIF_JPEG=SYSTEM', '-DAVIF_JPEG=OFF')
->optionalLib('libxml2', '-DAVIF_LIBXML2=SYSTEM', '-DAVIF_LIBXML2=OFF')
->optionalLib('libpng', '-DAVIF_LIBPNG=SYSTEM', '-DAVIF_LIBPNG=OFF')
->addConfigureArgs('-DAVIF_LIBYUV=OFF')
->build();
// patch pkgconfig

View File

@@ -11,11 +11,7 @@ trait libde265
protected function build(): void
{
UnixCMakeExecutor::create($this)
->addConfigureArgs(
'-DENABLE_SDL=OFF',
'-DENABLE_DECODER=OFF',
'-DHAVE_NEON=OFF',
)
->addConfigureArgs('-DENABLE_SDL=OFF')
->build();
$this->patchPkgconfPrefix(['libde265.pc']);
}

View File

@@ -11,28 +11,15 @@ trait libheif
{
public function patchBeforeBuild(): bool
{
$patched = false;
if (!str_contains(file_get_contents($this->source_dir . '/CMakeLists.txt'), 'libbrotlienc')) {
FileSystem::replaceFileStr(
$this->source_dir . '/CMakeLists.txt',
'list(APPEND REQUIRES_PRIVATE "libbrotlidec")',
'list(APPEND REQUIRES_PRIVATE "libbrotlidec")' . "\n" . ' list(APPEND REQUIRES_PRIVATE "libbrotlienc")'
);
$patched = true;
return true;
}
// libheif 1.22+ ships a C-incompatible header: `struct heif_bad_pixel`
$heif_properties = $this->source_dir . '/libheif/api/libheif/heif_properties.h';
if (file_exists($heif_properties)
&& str_contains(file_get_contents($heif_properties), 'struct heif_bad_pixel { uint32_t row; uint32_t column; };')
) {
FileSystem::replaceFileStr(
$heif_properties,
'struct heif_bad_pixel { uint32_t row; uint32_t column; };',
'typedef struct heif_bad_pixel { uint32_t row; uint32_t column; } heif_bad_pixel;'
);
$patched = true;
}
return $patched;
return false;
}
protected function build(): void

View File

@@ -14,10 +14,6 @@ trait libjpeg
->addConfigureArgs(
'-DENABLE_STATIC=ON',
'-DENABLE_SHARED=OFF',
'-DWITH_SYSTEM_ZLIB=ON',
'-DWITH_TOOLS=OFF',
'-DWITH_TESTS=OFF',
'-DWITH_SIMD=OFF',
)
->build();
// patch pkgconfig

View File

@@ -29,17 +29,13 @@ trait libjxl
);
if (ToolchainManager::getToolchainClass() === ZigToolchain::class) {
$cflags = getenv('SPC_DEFAULT_C_FLAGS') ?: getenv('CFLAGS') ?: '';
$has_avx512 = str_contains($cflags, '-mavx512') || str_contains($cflags, '-march=x86-64-v4');
if (!$has_avx512) {
$cmake->addConfigureArgs(
'-DCXX_MAVX512F_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512DQ_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512CD_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512BW_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512VL_SUPPORTED:BOOL=FALSE'
);
}
$cmake->addConfigureArgs(
'-DCXX_MAVX512F_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512DQ_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512CD_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512BW_SUPPORTED:BOOL=FALSE',
'-DCXX_MAVX512VL_SUPPORTED:BOOL=FALSE'
);
}
$cmake->build();

View File

@@ -12,13 +12,6 @@ trait liblz4
{
// disable executables
FileSystem::replaceFileStr($this->source_dir . '/programs/Makefile', 'install: lz4', "install: lz4\n\ninstallewfwef: lz4");
// zig-cc / clang -flto -c with multiple input files only produces an .o for the first source,
// leaving liblz4.a with just lz4.o. Compile sources individually so all .o files exist.
FileSystem::replaceFileStr(
$this->source_dir . '/lib/Makefile',
"liblz4.a: \$(SRCFILES)\nifeq (\$(BUILD_STATIC),yes) # can be disabled on command line\n\t@echo compiling static library\n\t\$(COMPILE.c) \$^\n\t\$(AR) rcs \$@ *.o\nendif",
"liblz4.a: \$(SRCFILES:.c=.o)\nifeq (\$(BUILD_STATIC),yes) # can be disabled on command line\n\t@echo compiling static library\n\t\$(AR) rcs \$@ \$^\nendif"
);
return true;
}
@@ -35,7 +28,7 @@ trait liblz4
$this->patchPkgconfPrefix(['liblz4.pc']);
foreach (FileSystem::scanDirFiles(BUILD_LIB_PATH . '/', false, true) as $filename) {
foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) {
if (str_starts_with($filename, 'liblz4') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) {
unlink(BUILD_ROOT_PATH . '/lib/' . $filename);
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixAutoconfExecutor;
trait libmpdec
{
protected function build(): void
{
UnixAutoconfExecutor::create($this)
->configure('--disable-cxx --disable-shared --enable-static')
->make();
}
}

View File

@@ -10,26 +10,8 @@ trait libwebp
{
protected function build(): void
{
$code = '#include <immintrin.h>
int main() { return _mm256_cvtsi256_si32(_mm256_setzero_si256()); }';
$cc = getenv('CC') ?: 'gcc';
[$ret] = shell()->execWithResult("printf '%s' '{$code}' | {$cc} -x c -mavx2 -o /dev/null - 2>&1");
$disableAvx2 = $ret !== 0 && GNU_ARCH === 'x86_64' && PHP_OS_FAMILY === 'Linux';
UnixCMakeExecutor::create($this)
->addConfigureArgs(
'-DWEBP_BUILD_EXTRAS=OFF',
'-DWEBP_BUILD_ANIM_UTILS=OFF',
'-DWEBP_BUILD_CWEBP=OFF',
'-DWEBP_BUILD_DWEBP=OFF',
'-DWEBP_BUILD_GIF2WEBP=OFF',
'-DWEBP_BUILD_IMG2WEBP=OFF',
'-DWEBP_BUILD_VWEBP=OFF',
'-DWEBP_BUILD_WEBPINFO=OFF',
'-DWEBP_BUILD_WEBPMUX=OFF',
'-DWEBP_BUILD_FUZZTEST=OFF',
$disableAvx2 ? '-DWEBP_ENABLE_SIMD=OFF' : ''
)
->addConfigureArgs('-DWEBP_BUILD_EXTRAS=ON')
->build();
// patch pkgconfig
$this->patchPkgconfPrefix(patch_option: PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR);

View File

@@ -10,29 +10,12 @@ use SPC\util\SPCTarget;
trait ncurses
{
public function patchBeforeBuild(): bool
{
// MKlib_gen.sh feeds preprocessor stdout through a sed/awk pipeline into lib_gen.c.
// zig-cc/clang leaks the "N warning(s) generated." summary onto stdout (not stderr),
// and that line ends up as invalid C in the generated source. Filter it out of the pipe.
$mklibGen = $this->source_dir . '/ncurses/base/MKlib_gen.sh';
if (!str_contains((string) file_get_contents($mklibGen), "| grep -v ' generated")) {
FileSystem::replaceFileStr(
$mklibGen,
'$preprocessor $TMP 2>/dev/null \\',
"\$preprocessor \$TMP 2>/dev/null \\\n| grep -v ' generated\\.\$' \\",
);
}
return true;
}
protected function build(): void
{
$filelist = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true);
UnixAutoconfExecutor::create($this)
->appendEnv([
'CFLAGS' => '-std=c17 -w',
'LDFLAGS' => SPCTarget::isStatic() ? '-static' : '',
])
->configure(
@@ -46,7 +29,7 @@ trait ncurses
'--without-tests',
'--without-dlsym',
'--without-debug',
'--enable-symlinks',
'-enable-symlinks',
"--bindir={$this->getBinDir()}",
"--includedir={$this->getIncludeDir()}",
"--libdir={$this->getLibDir()}",

View File

@@ -4,14 +4,29 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\store\FileSystem;
use SPC\util\PkgConfigUtil;
use SPC\util\SPCConfigUtil;
use SPC\util\SPCTarget;
trait postgresql
{
public function patchBeforeBuild(): bool
{
// fix aarch64 build on glibc 2.17 (e.g. CentOS 7)
if (SPCTarget::getLibcVersion() === '2.17' && GNU_ARCH === 'aarch64') {
try {
FileSystem::replaceFileStr("{$this->source_dir}/src/port/pg_popcount_aarch64.c", 'HWCAP_SVE', '0');
FileSystem::replaceFileStr(
"{$this->source_dir}/src/port/pg_crc32c_armv8_choose.c",
'#if defined(__linux__) && !defined(__aarch64__) && !defined(HWCAP2_CRC32)',
'#if defined(__linux__) && !defined(HWCAP_CRC32)'
);
} catch (FileSystemException) {
// allow file not-existence to make it compatible with old and new version
}
}
// skip the test on platforms where libpq infrastructure may be provided by statically-linked libraries
FileSystem::replaceFileStr("{$this->source_dir}/src/interfaces/libpq/Makefile", 'invokes exit\'; exit 1;', 'invokes exit\';');
// disable shared libs build
@@ -35,7 +50,7 @@ trait postgresql
$config = $spc->config(libraries: $libs, include_suggest_lib: $this->builder->getOption('with-suggested-libs', false));
$env_vars = [
'CFLAGS' => $config['cflags'] . ' -std=c17',
'CFLAGS' => $config['cflags'],
'CPPFLAGS' => '-DPIC',
'LDFLAGS' => $config['ldflags'],
'LIBS' => $config['libs'],
@@ -93,7 +108,8 @@ trait postgresql
// remove dynamic libs
shell()->cd($this->source_dir . '/build')
->exec("rm -rf {$this->getBuildRootPath()}/lib/*.so*")
->exec("rm -rf {$this->getBuildRootPath()}/lib/*.so.*")
->exec("rm -rf {$this->getBuildRootPath()}/lib/*.so")
->exec("rm -rf {$this->getBuildRootPath()}/lib/*.dylib");
FileSystem::replaceFileStr("{$this->getLibDir()}/pkgconfig/libpq.pc", '-lldap', '-lldap -llber');

View File

@@ -14,8 +14,6 @@ trait qdbm
{
$ac = UnixAutoconfExecutor::create($this)->configure();
FileSystem::replaceFileRegex($this->source_dir . '/Makefile', '/MYLIBS = libqdbm.a.*/m', 'MYLIBS = libqdbm.a');
$extra = trim((string) getenv('SPC_DEFAULT_C_FLAGS'));
FileSystem::replaceFileRegex($this->source_dir . '/Makefile', '/^CFLAGS = .*$/m', "CFLAGS = -Wall {$extra}");
$ac->make($this instanceof MacOSLibraryBase ? 'mac' : '');
$this->patchPkgconfPrefix(['qdbm.pc']);
}

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait unixodbc
@@ -21,15 +20,7 @@ trait unixodbc
'Linux' => '/etc',
default => throw new WrongUsageException('Unsupported OS: ' . PHP_OS_FAMILY),
};
// libltdl is incompatible with -flto (https://bugs.gentoo.org/532672)
$stripLto = static fn ($s) => preg_replace('/(^|\s)-flto(=\S+)?(?=\s|$)/', ' ', (string) $s);
$origC = $this->builder->arch_c_flags;
$origCxx = $this->builder->arch_cxx_flags;
$origLd = $this->builder->arch_ld_flags;
$this->builder->arch_c_flags = clean_spaces($stripLto($origC));
$this->builder->arch_cxx_flags = clean_spaces($stripLto($origCxx));
$this->builder->arch_ld_flags = clean_spaces($stripLto($origLd));
$make = UnixAutoconfExecutor::create($this)
UnixAutoconfExecutor::create($this)
->configure(
'--disable-debug',
'--disable-dependency-tracking',
@@ -37,27 +28,9 @@ trait unixodbc
'--with-included-ltdl',
"--sysconfdir={$sysconf_selector}",
'--enable-gui=no',
);
file_put_contents(
"{$this->source_dir}/exe/Makefile",
".PHONY: all install clean check distclean install-strip\nall install clean check distclean install-strip:\n\t@true\n",
);
$make->make();
$this->builder->arch_c_flags = $origC;
$this->builder->arch_cxx_flags = $origCxx;
$this->builder->arch_ld_flags = $origLd;
$pkgConfigs = ['odbc.pc', 'odbccr.pc', 'odbcinst.pc'];
$this->patchPkgconfPrefix($pkgConfigs);
foreach ($pkgConfigs as $file) {
FileSystem::replaceFileStr(
BUILD_LIB_PATH . "/pkgconfig/{$file}",
'$(top_build_prefix)libltdl/libltdlc.la',
''
);
}
)
->make();
$this->patchPkgconfPrefix(['odbc.pc', 'odbccr.pc', 'odbcinst.pc']);
$this->patchLaDependencyPrefix();
}
}

View File

@@ -1,36 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class brotli extends WindowsLibraryBase
{
public const NAME = 'brotli';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DBROTLI_BUILD_TOOLS=OFF ' .
'-DBROTLI_BUNDLED_MODE=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
}
}

View File

@@ -30,6 +30,7 @@ class curl extends WindowsLibraryBase
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DBUILD_STATIC_LIBS=ON ' .
'-DCURL_STATICLIB=ON ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
'-DBUILD_CURL_EXE=OFF ' . // disable curl.exe
'-DBUILD_TESTING=OFF ' . // disable tests
@@ -41,9 +42,9 @@ class curl extends WindowsLibraryBase
'-DCURL_USE_OPENSSL=OFF ' . // disable openssl due to certificate issue
'-DCURL_ENABLE_SSL=ON ' .
'-DUSE_NGHTTP2=ON ' . // enable nghttp2
'-DSHARE_LIB_OBJECT=OFF ' . // disable shared lib object
'-DCURL_USE_LIBSSH2=ON ' . // enable libssh2
'-DENABLE_IPV6=ON ' . // enable ipv6
'-DNGHTTP2_CFLAGS="/DNGHTTP2_STATICLIB" ' .
$alt
)
->execWithWrapper(
@@ -52,7 +53,5 @@ class curl extends WindowsLibraryBase
);
// move libcurl.lib to libcurl_a.lib
rename(BUILD_LIB_PATH . '\libcurl.lib', BUILD_LIB_PATH . '\libcurl_a.lib');
FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\curl\curl.h', '#ifdef CURL_STATICLIB', '#if 1');
}
}

View File

@@ -24,8 +24,6 @@ class freetype extends WindowsLibraryBase
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DFT_DISABLE_BROTLI=TRUE ' .
'-DFT_DISABLE_BZIP2=TRUE ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(

View File

@@ -12,16 +12,16 @@ class icu_static_win extends WindowsLibraryBase
protected function build(): void
{
copy("{$this->source_dir}\\lib\\icudt.lib", "{$this->getLibDir()}\\icudt.lib");
copy("{$this->source_dir}\\lib\\icuin.lib", "{$this->getLibDir()}\\icuin.lib");
copy("{$this->source_dir}\\lib\\icuio.lib", "{$this->getLibDir()}\\icuio.lib");
copy("{$this->source_dir}\\lib\\icuuc.lib", "{$this->getLibDir()}\\icuuc.lib");
copy("{$this->source_dir}\\x64-windows-static\\lib\\icudt.lib", "{$this->getLibDir()}\\icudt.lib");
copy("{$this->source_dir}\\x64-windows-static\\lib\\icuin.lib", "{$this->getLibDir()}\\icuin.lib");
copy("{$this->source_dir}\\x64-windows-static\\lib\\icuio.lib", "{$this->getLibDir()}\\icuio.lib");
copy("{$this->source_dir}\\x64-windows-static\\lib\\icuuc.lib", "{$this->getLibDir()}\\icuuc.lib");
// create libpq folder in buildroot/includes/libpq
if (!file_exists("{$this->getIncludeDir()}\\unicode")) {
mkdir("{$this->getIncludeDir()}\\unicode");
}
FileSystem::copyDir("{$this->source_dir}\\include\\unicode", "{$this->getIncludeDir()}\\unicode");
FileSystem::copyDir("{$this->source_dir}\\x64-windows-static\\include\\unicode", "{$this->getIncludeDir()}\\unicode");
}
}

View File

@@ -1,41 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libaom extends WindowsLibraryBase
{
public const NAME = 'libaom';
protected function build(): void
{
// libaom source tree contains a build/cmake/ directory with its own
// cmake modules, so we must use a different name for the build dir.
FileSystem::resetDir($this->source_dir . '\builddir');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-S . -B builddir ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DAOM_TARGET_CPU=generic ' .
'-DENABLE_DOCS=OFF ' .
'-DENABLE_EXAMPLES=OFF ' .
'-DENABLE_TESTDATA=OFF ' .
'-DENABLE_TESTS=OFF ' .
'-DENABLE_TOOLS=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build builddir --config Release --target install -j{$this->builder->concurrency}"
);
}
}

View File

@@ -28,7 +28,6 @@ class libjpeg extends WindowsLibraryBase
'-DENABLE_STATIC=ON ' .
'-DBUILD_TESTING=OFF ' .
'-DWITH_JAVA=OFF ' .
'-DWITH_SIMD=OFF ' .
'-DWITH_CRT_DLL=OFF ' .
"-DENABLE_ZLIB_COMPRESSION={$zlib} " .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '

View File

@@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
class libmpdec extends WindowsLibraryBase
{
public const NAME = 'libmpdec';
protected function build(): void
{
$makefile_dir = $this->source_dir . '\libmpdec';
$nmake = $this->builder->makeSimpleWrapper('nmake /nologo');
cmd()->cd($makefile_dir)
->exec('copy /y Makefile.vc Makefile')
->execWithWrapper($nmake, 'clean')
->execWithWrapper($nmake, 'MACHINE=x64');
// Copy static lib (rename from versioned name to libmpdec_a.lib)
$libs = glob($makefile_dir . '\libmpdec-*.lib');
foreach ($libs as $lib) {
if (!str_contains($lib, '.dll.')) {
copy($lib, BUILD_LIB_PATH . '\libmpdec_a.lib');
break;
}
}
copy($makefile_dir . '\mpdecimal.h', BUILD_INCLUDE_PATH . '\mpdecimal.h');
}
}

View File

@@ -29,16 +29,11 @@ class nghttp2 extends WindowsLibraryBase
'-DBUILD_SHARED_LIBS=OFF ' .
'-DENABLE_STATIC_CRT=ON ' .
'-DENABLE_LIB_ONLY=ON ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
'-DENABLE_STATIC_CRT=ON ' .
'-DENABLE_DOC=OFF ' .
'-DBUILD_TESTING=OFF '
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '\nghttp2\nghttp2.h', '#ifdef NGHTTP2_STATICLIB', '#if 1');
}
}

View File

@@ -29,7 +29,6 @@ class ngtcp2 extends WindowsLibraryBase
'-DBUILD_SHARED_LIBS=OFF ' .
'-DENABLE_STATIC_CRT=ON ' .
'-DENABLE_LIB_ONLY=ON ' .
'-DENABLE_OPENSSL=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(

View File

@@ -10,9 +10,9 @@ class postgresql_win extends WindowsLibraryBase
protected function build(): void
{
copy($this->source_dir . '\lib\libpq.lib', BUILD_LIB_PATH . '\libpq.lib');
copy($this->source_dir . '\lib\libpgport.lib', BUILD_LIB_PATH . '\libpgport.lib');
copy($this->source_dir . '\lib\libpgcommon.lib', BUILD_LIB_PATH . '\libpgcommon.lib');
copy($this->source_dir . '\pgsql\lib\libpq.lib', BUILD_LIB_PATH . '\libpq.lib');
copy($this->source_dir . '\pgsql\lib\libpgport.lib', BUILD_LIB_PATH . '\libpgport.lib');
copy($this->source_dir . '\pgsql\lib\libpgcommon.lib', BUILD_LIB_PATH . '\libpgcommon.lib');
// create libpq folder in buildroot/includes/libpq
if (!file_exists(BUILD_INCLUDE_PATH . '\libpq')) {
@@ -21,7 +21,7 @@ class postgresql_win extends WindowsLibraryBase
$headerFiles = ['libpq-fe.h', 'postgres_ext.h', 'pg_config_ext.h', 'libpq\libpq-fs.h'];
foreach ($headerFiles as $header) {
copy($this->source_dir . '\include\\' . $header, BUILD_INCLUDE_PATH . '\\' . $header);
copy($this->source_dir . '\pgsql\include\\' . $header, BUILD_INCLUDE_PATH . '\\' . $header);
}
}
}

View File

@@ -31,24 +31,8 @@ class zlib extends WindowsLibraryBase
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
$detect_list = [
'zlibstatic.lib',
'zs.lib',
'libzs.lib',
'libz.lib',
];
foreach ($detect_list as $item) {
if (file_exists(BUILD_LIB_PATH . '\\' . $item)) {
FileSystem::copy(BUILD_LIB_PATH . '\\' . $item, BUILD_LIB_PATH . '\zlib_a.lib');
FileSystem::copy(BUILD_LIB_PATH . '\\' . $item, BUILD_LIB_PATH . '\zlibstatic.lib');
break;
}
}
FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '\bin\zlib.dll');
FileSystem::removeFileIfExists(BUILD_LIB_PATH . '\zlib.lib');
FileSystem::removeFileIfExists(BUILD_LIB_PATH . '\libz.dll');
FileSystem::removeFileIfExists(BUILD_LIB_PATH . '\libz.lib');
FileSystem::removeFileIfExists(BUILD_LIB_PATH . '\z.lib');
FileSystem::removeFileIfExists(BUILD_LIB_PATH . '\z.dll');
copy(BUILD_LIB_PATH . '\zlibstatic.lib', BUILD_LIB_PATH . '\zlib_a.lib');
unlink(BUILD_ROOT_PATH . '\bin\zlib.dll');
unlink(BUILD_LIB_PATH . '\zlib.lib');
}
}

View File

@@ -19,7 +19,7 @@ class BuildLibsCommand extends BuildCommand
{
$this->addArgument('libraries', InputArgument::REQUIRED, 'The libraries will be compiled, comma separated');
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
$this->addOption('all', 'A', null, 'Build all libs that static-php-cli has');
$this->addOption('all', 'A', null, 'Build all libs that static-php-cli needed');
}
public function initialize(InputInterface $input, OutputInterface $output): void

View File

@@ -39,7 +39,6 @@ class BuildPHPCommand extends BuildCommand
$this->addOption('disable-opcache-jit', null, null, 'disable opcache jit');
$this->addOption('with-config-file-path', null, InputOption::VALUE_REQUIRED, 'Set the path in which to look for php.ini', $isWindows ? null : '/usr/local/etc/php');
$this->addOption('with-config-file-scan-dir', null, InputOption::VALUE_REQUIRED, 'Set the directory to scan for .ini files after reading php.ini', $isWindows ? null : '/usr/local/etc/php/conf.d');
$this->addOption('with-sysconfdir', null, InputOption::VALUE_REQUIRED, 'Set the sysconfdir (e.g. /etc/php-zts) used by configure (not available on Windows)');
$this->addOption('with-hardcoded-ini', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Patch PHP source code, inject hardcoded INI');
$this->addOption('with-micro-fake-cli', null, null, 'Let phpmicro\'s PHP_SAPI use "cli" instead of "micro"');
$this->addOption('with-suggested-libs', 'L', null, 'Build with suggested libs for selected exts and libs');
@@ -50,9 +49,6 @@ class BuildPHPCommand extends BuildCommand
$this->addOption('with-micro-logo', null, InputOption::VALUE_REQUIRED, 'Use custom .ico for micro.sfx (windows only)');
$this->addOption('enable-micro-win32', null, null, 'Enable win32 mode for phpmicro (Windows only)');
$this->addOption('with-frankenphp-app', null, InputOption::VALUE_REQUIRED, 'Path to a folder to be embedded in FrankenPHP');
$this->addOption('pgi', null, null, 'Build instrumented binaries (-fprofile-generate). Run them to collect .profraw files, then re-run with --pgo.');
$this->addOption('cs-pgi', null, null, 'Build cs-instrumented binaries (-fprofile-use=<existing.profdata> -fcs-profile-generate). Requires a prior --pgi+--pgo cycle.');
$this->addOption('pgo', null, null, 'Build optimised binaries (-fprofile-use) from .profraw collected by a previous --pgi run.');
}
public function handle(): int
@@ -181,7 +177,7 @@ class BuildPHPCommand extends BuildCommand
// compile libraries
$builder->proveLibs($libraries);
// check extensions
$builder->proveExts($static_extensions, $shared_extensions, build_target: $rule);
$builder->proveExts($static_extensions, $shared_extensions);
// validate libs and extensions
$builder->validateLibsAndExts();
@@ -214,8 +210,9 @@ class BuildPHPCommand extends BuildCommand
// clean old modules that may conflict with the new php build
FileSystem::removeDir(BUILD_MODULES_PATH);
// start to build
$builder->buildPHP($rule);
$builder->testPHP($rule);
// compile stopwatch :P

View File

@@ -10,7 +10,6 @@ use SPC\store\pkg\Zig;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\ConfigValidator;
use SPC\util\DependencyUtil;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Process\Process;
@@ -20,10 +19,6 @@ class CraftCommand extends BuildCommand
public function configure(): void
{
$this->addArgument('craft', null, 'Path to craft.yml file', WORKING_DIR . '/craft.yml');
$this->addOption('pgi', null, null, 'Forward --pgi to the inner build (instrumented binaries).');
$this->addOption('cs-pgi', null, null, 'Forward --cs-pgi to the inner build (cs-instrumented binaries).');
$this->addOption('pgo', null, null, 'Forward --pgo to the inner build (use collected profile data).');
$this->addOption('libs-only', null, null, 'Build only the libraries needed by the configured exts (skip PHP and extension build).');
}
public function handle(): int
@@ -108,38 +103,12 @@ class CraftCommand extends BuildCommand
// craft build
if ($craft['craft-options']['build']) {
if ($this->getOption('libs-only')) {
$exts = array_merge($craft['extensions'], $craft['shared-extensions'] ?? []);
$include_suggested_exts = (bool) ($craft['build-options']['with-suggested-exts'] ?? false);
$include_suggested_libs = (bool) ($craft['build-options']['with-suggested-libs'] ?? false);
[, $needed_libs] = DependencyUtil::getExtsAndLibs(
$exts,
$craft['libs'],
$include_suggested_exts,
$include_suggested_libs,
);
if ($needed_libs === []) {
$this->output->writeln('<comment>No libs needed for the configured extensions; skipping build:libs.</comment>');
} else {
$retcode = $this->runCommand('build:libs', implode(',', $needed_libs));
if ($retcode !== 0) {
$this->output->writeln('<error>craft build:libs failed</error>');
return static::FAILURE;
}
}
} else {
$args = [$static_extensions, "--with-libs={$libs}", "--build-shared={$shared_extensions}", ...array_map(fn ($x) => "--build-{$x}", $craft['sapi'])];
$this->optionsToArguments($craft['build-options'], $args);
foreach (['pgi', 'cs-pgi', 'pgo'] as $pgoFlag) {
if ($this->getOption($pgoFlag)) {
$args[] = "--{$pgoFlag}";
}
}
$retcode = $this->runCommand('build', ...$args);
if ($retcode !== 0) {
$this->output->writeln('<error>craft build failed</error>');
return static::FAILURE;
}
$args = [$static_extensions, "--with-libs={$libs}", "--build-shared={$shared_extensions}", ...array_map(fn ($x) => "--build-{$x}", $craft['sapi'])];
$this->optionsToArguments($craft['build-options'], $args);
$retcode = $this->runCommand('build', ...$args);
if ($retcode !== 0) {
$this->output->writeln('<error>craft build failed</error>');
return static::FAILURE;
}
}

View File

@@ -30,7 +30,7 @@ class DownloadCommand extends BaseCommand
$this->addArgument('sources', InputArgument::REQUIRED, 'The sources will be compiled, comma separated');
$this->addOption('shallow-clone', null, null, 'Clone shallow');
$this->addOption('with-openssl11', null, null, 'Use openssl 1.1');
$this->addOption('with-php', null, InputOption::VALUE_REQUIRED, 'version in major.minor format (default 8.5)', '8.5');
$this->addOption('with-php', null, InputOption::VALUE_REQUIRED, 'version in major.minor format (default 8.4)', '8.4');
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
$this->addOption('all', 'A', null, 'Fetch all sources that static-php-cli needed');
$this->addOption('custom-url', 'U', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Specify custom source download url, e.g "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"');

View File

@@ -20,9 +20,9 @@ class SwitchPhpVersionCommand extends BaseCommand
$this->addArgument(
'php-major-version',
InputArgument::REQUIRED,
'PHP major version (supported: 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5)',
'PHP major version (supported: 7.4, 8.0, 8.1, 8.2, 8.3, 8.4)',
null,
fn () => ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']
fn () => ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
);
$this->no_motd = true;
@@ -32,7 +32,7 @@ class SwitchPhpVersionCommand extends BaseCommand
public function handle(): int
{
$php_ver = $this->input->getArgument('php-major-version');
if (!in_array($php_ver, ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'])) {
if (!in_array($php_ver, ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4'])) {
// match x.y.z
preg_match('/^\d+\.\d+\.\d+$/', $php_ver, $matches);
if (!$matches) {

View File

@@ -74,10 +74,9 @@ class LinuxMuslCheck
SourcePatcher::patchFile('musl-1.2.5_CVE-2025-26519_0002.patch', SOURCE_PATH . "/{$musl_version_name}");
logger()->info('Installing musl wrapper');
shell()->cd(SOURCE_PATH . "/{$musl_version_name}")
->setEnv(['CC' => 'gcc', 'CXX' => 'g++', 'AR' => 'ar', 'LD' => 'ld', 'RANLIB' => 'ranlib'])
->exec('./configure --disable-gcc-wrapper')
->exec('make -j')
->exec("{$prefix}make install");
->exec('CC=gcc CXX=g++ AR=ar LD=ld ./configure --disable-gcc-wrapper')
->exec('CC=gcc CXX=g++ AR=ar LD=ld make -j')
->exec("CC=gcc CXX=g++ AR=ar LD=ld {$prefix}make install");
// TODO: add path using putenv instead of editing /etc/profile
return true;
}

View File

@@ -22,6 +22,7 @@ class LinuxToolCheckList
'bzip2', 'cmake', 'gcc',
'g++', 'patch', 'binutils-gold',
'libtoolize', 'which',
'patchelf',
];
public const TOOLS_DEBIAN = [
@@ -30,6 +31,7 @@ class LinuxToolCheckList
'tar', 'unzip', 'gzip', 'gcc', 'g++',
'bzip2', 'cmake', 'patch',
'xz', 'libtoolize', 'which',
'patchelf',
];
public const TOOLS_RHEL = [
@@ -37,7 +39,8 @@ class LinuxToolCheckList
'git', 'autoconf', 'automake',
'tar', 'unzip', 'gzip', 'gcc', 'g++',
'bzip2', 'cmake', 'patch', 'which',
'xz', 'libtool', 'gettext-devel', 'file',
'xz', 'libtool', 'gettext-devel',
'patchelf', 'file',
];
public const TOOLS_ARCH = [
@@ -109,7 +112,7 @@ class LinuxToolCheckList
public function fixBuildTools(array $distro, array $missing): bool
{
$install_cmd = match ($distro['dist']) {
'ubuntu', 'debian', 'linuxmint', 'Deepin' => 'apt-get install -y',
'ubuntu', 'debian', 'Deepin' => 'apt-get install -y',
'alpine' => 'apk add',
'redhat' => 'dnf install -y',
'centos' => 'yum install -y',

View File

@@ -97,52 +97,29 @@ class Downloader
public static function getLatestGithubTarball(string $name, array $source, string $type = 'releases'): array
{
logger()->debug("finding {$name} source from github {$type} tarball");
$source['query'] ??= '';
$data = json_decode(self::curlExec(
url: "https://api.github.com/repos/{$source['repo']}/{$type}",
hooks: [[CurlHook::class, 'setupGithubToken']],
retries: self::getRetryAttempts()
), true, 512, JSON_THROW_ON_ERROR);
// Use /releases/latest when possible: it returns the semantically latest stable
// release regardless of publish order, avoiding issues with concurrent release branches.
if ($type === 'releases' && empty($source['query']) && !($source['match'] ?? null)) {
$data = json_decode(self::curlExec(
url: "https://api.github.com/repos/{$source['repo']}/releases/latest",
hooks: [[CurlHook::class, 'setupGithubToken']],
retries: self::getRetryAttempts()
), true, 512, JSON_THROW_ON_ERROR);
if (!is_array($data) || empty($data['tarball_url'])) {
throw new DownloaderException("failed to find {$name} source");
$url = null;
foreach ($data as $rel) {
if (($rel['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) {
continue;
}
$url = $data['tarball_url'];
$version = $data['tag_name'] ?? $data['name'] ?? null;
} else {
$data = json_decode(self::curlExec(
url: "https://api.github.com/repos/{$source['repo']}/{$type}{$source['query']}",
hooks: [[CurlHook::class, 'setupGithubToken']],
retries: self::getRetryAttempts()
), true, 512, JSON_THROW_ON_ERROR);
$url = null;
$version = null;
foreach ($data as $rel) {
if (($rel['prerelease'] ?? false) === true && ($source['prefer-stable'] ?? false)) {
continue;
}
if (($rel['draft'] ?? false) === true && (($source['prefer-stable'] ?? false) || !$rel['tarball_url'])) {
continue;
}
if (!($source['match'] ?? null)) {
$url = $rel['tarball_url'] ?? null;
$version = $rel['tag_name'] ?? $rel['name'] ?? null;
break;
}
if (preg_match('|' . $source['match'] . '|', $rel['tarball_url'])) {
$url = $rel['tarball_url'];
$version = $rel['tag_name'] ?? $rel['name'] ?? null;
break;
}
if (!($source['match'] ?? null)) {
$url = $rel['tarball_url'] ?? null;
break;
}
if (!$url) {
throw new DownloaderException("failed to find {$name} source");
if (preg_match('|' . $source['match'] . '|', $rel['tarball_url'])) {
$url = $rel['tarball_url'];
break;
}
}
if (!$url) {
throw new DownloaderException("failed to find {$name} source");
}
$headers = self::curlExec(
url: $url,
method: 'HEAD',
@@ -153,7 +130,7 @@ class Downloader
if ($matches) {
$filename = $matches['filename'];
} else {
$filename = "{$name}-" . ($version ?? 'latest') . '.tar.gz';
$filename = "{$name}-" . ($type === 'releases' ? $data['tag_name'] : $data['name']) . '.tar.gz';
}
return [$url, $filename];
@@ -175,16 +152,6 @@ class Downloader
hooks: [[CurlHook::class, 'setupGithubToken']],
retries: self::getRetryAttempts()
), true);
if (($source['prefer-stable'] ?? false) === true) {
$latest = json_decode(self::curlExec(
url: "https://api.github.com/repos/{$source['repo']}/releases/latest",
hooks: [[CurlHook::class, 'setupGithubToken']],
retries: self::getRetryAttempts()
), true);
if (is_array($latest) && isset($latest['assets'])) {
array_unshift($data, $latest);
}
}
$url = null;
$filename = null;
foreach ($data as $release) {

View File

@@ -152,7 +152,7 @@ class FileSystem
$src_path = FileSystem::convertPath($from);
switch (PHP_OS_FAMILY) {
case 'Windows':
f_passthru('xcopy "' . $src_path . '" "' . $dst_path . '" /s/e/y/i');
f_passthru('xcopy "' . $src_path . '" "' . $dst_path . '" /s/e/v/y/i');
break;
case 'Linux':
case 'Darwin':
@@ -408,15 +408,15 @@ class FileSystem
continue;
}
$sub_file = self::convertPath($dir . '/' . $v);
if (is_link($sub_file) || is_file($sub_file)) {
if (!unlink($sub_file)) {
return false;
}
} elseif (is_dir($sub_file)) {
if (is_dir($sub_file)) {
# 如果是 目录 且 递推 , 则递推添加下级文件
if (!self::removeDir($sub_file)) {
return false;
}
} elseif (is_link($sub_file) || is_file($sub_file)) {
if (!unlink($sub_file)) {
return false;
}
}
}
if (is_link($dir)) {
@@ -572,44 +572,6 @@ class FileSystem
return file_put_contents($file, implode('', $lines));
}
/**
* Move file or directory, handling cross-device scenarios
* Uses rename() if possible, falls back to copy+delete for cross-device moves
*
* @param string $source Source path
* @param string $dest Destination path
*/
public static function moveFileOrDir(string $source, string $dest): void
{
$source = self::convertPath($source);
$dest = self::convertPath($dest);
// Check if source and dest are on the same device to avoid cross-device rename errors
$source_stat = @stat($source);
$dest_parent = dirname($dest);
$dest_stat = @stat($dest_parent);
// Only use rename if on same device
if ($source_stat !== false && $dest_stat !== false && $source_stat['dev'] === $dest_stat['dev']) {
if (@rename($source, $dest)) {
return;
}
}
// Fall back to copy + delete for cross-device moves or if rename failed
if (is_dir($source)) {
self::copyDir($source, $dest);
self::removeDir($source);
} else {
if (!copy($source, $dest)) {
throw new FileSystemException("Failed to copy file from {$source} to {$dest}");
}
if (!unlink($source)) {
throw new FileSystemException("Failed to remove source file: {$source}");
}
}
}
private static function extractArchive(string $filename, string $target): void
{
// Create base dir
@@ -686,6 +648,44 @@ class FileSystem
};
}
/**
* Move file or directory, handling cross-device scenarios
* Uses rename() if possible, falls back to copy+delete for cross-device moves
*
* @param string $source Source path
* @param string $dest Destination path
*/
private static function moveFileOrDir(string $source, string $dest): void
{
$source = self::convertPath($source);
$dest = self::convertPath($dest);
// Check if source and dest are on the same device to avoid cross-device rename errors
$source_stat = @stat($source);
$dest_parent = dirname($dest);
$dest_stat = @stat($dest_parent);
// Only use rename if on same device
if ($source_stat !== false && $dest_stat !== false && $source_stat['dev'] === $dest_stat['dev']) {
if (@rename($source, $dest)) {
return;
}
}
// Fall back to copy + delete for cross-device moves or if rename failed
if (is_dir($source)) {
self::copyDir($source, $dest);
self::removeDir($source);
} else {
if (!copy($source, $dest)) {
throw new FileSystemException("Failed to copy file from {$source} to {$dest}");
}
if (!unlink($source)) {
throw new FileSystemException("Failed to remove source file: {$source}");
}
}
}
/**
* Unzip file with stripping top-level directory
*/

View File

@@ -22,10 +22,9 @@ class SourcePatcher
FileSystem::addSourceExtractHook('swoole', [__CLASS__, 'patchSwoole']);
FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchPhpLibxml212']);
FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchGDWin32']);
// FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchFfiCentos7FixO3strncmp']);
FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchFfiCentos7FixO3strncmp']);
FileSystem::addSourceExtractHook('sqlsrv', [__CLASS__, 'patchSQLSRVWin32']);
FileSystem::addSourceExtractHook('pdo_sqlsrv', [__CLASS__, 'patchSQLSRVWin32']);
FileSystem::addSourceExtractHook('pdo_sqlsrv', [__CLASS__, 'patchSQLSRVPhp85']);
FileSystem::addSourceExtractHook('yaml', [__CLASS__, 'patchYamlWin32']);
FileSystem::addSourceExtractHook('libyaml', [__CLASS__, 'patchLibYaml']);
FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchImapLicense']);
@@ -95,10 +94,6 @@ class SourcePatcher
// patch php-src/build/php.m4 PKG_CHECK_MODULES -> PKG_CHECK_MODULES_STATIC
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/build/php.m4', 'PKG_CHECK_MODULES(', 'PKG_CHECK_MODULES_STATIC(');
if ($builder->getPHPVersionID() >= 80300 && $builder->getPHPVersionID() < 80400) {
self::patchFile('spc_fix_avx512_cache_before_80400.patch', SOURCE_PATH . '/php-src');
}
if ($builder->getOption('enable-micro-win32')) {
self::patchMicroWin32();
} else {
@@ -129,31 +124,6 @@ class SourcePatcher
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/have_capstone="yes"/', 'have_capstone="no"');
}
// PHP 8.2 and below: bcmath libbcmath uses K&R style C function
if (is_unix() && $builder->getPHPVersionID() < 80300) {
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/configure',
"for ac_arg in '' -std=gnu23",
"for ac_arg in '' -std=gnu17",
);
}
// strip our build-time env vars from phpinfo's "Configure Command" ('|' delimiter: PHP_BUILD_PROVIDER may contain '#')
if (is_unix()) {
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/configure',
'for var in CFLAGS CXXFLAGS CPPFLAGS LDFLAGS EXTRA_LDFLAGS_PROGRAM LIBS CC CXX; do',
'for var in CFLAGS CXXFLAGS CPPFLAGS LDFLAGS EXTRA_LDFLAGS_PROGRAM LIBS CC CXX '
. 'PKG_CONFIG PKG_CONFIG_PATH EXTENSION_DIR OPENSSL_LIBS '
. 'PHP_BUILD_SYSTEM PHP_BUILD_PROVIDER PHP_BUILD_COMPILER PHP_BUILD_ARCH; do',
);
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/configure',
'clean_configure_args=$(echo $clean_configure_args | $SED -e "s#\'$var=$val\'##")',
'clean_configure_args=$(echo $clean_configure_args | $SED -e "s|\'$var=$val\'||")',
);
}
if (file_exists(SOURCE_PATH . '/php-src/configure.ac.bak')) {
// restore configure.ac
FileSystem::restoreBackupFile(SOURCE_PATH . '/php-src/configure.ac');
@@ -346,6 +316,20 @@ class SourcePatcher
logger()->info("Library [{$lib->getName()}] patched before make");
}
}
if (str_contains((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), '-release')) {
FileSystem::replaceFileLineContainsString(
SOURCE_PATH . '/php-src/ext/standard/info.c',
'#ifdef CONFIGURE_COMMAND',
'#ifdef NO_CONFIGURE_COMMAND',
);
} else {
FileSystem::replaceFileLineContainsString(
SOURCE_PATH . '/php-src/ext/standard/info.c',
'#ifdef NO_CONFIGURE_COMMAND',
'#ifdef CONFIGURE_COMMAND',
);
}
}
public static function patchHardcodedINI(array $ini = []): bool
@@ -448,23 +432,6 @@ class SourcePatcher
return false;
}
/**
* Fix the compilation issue of pdo_sqlsrv with php 8.5
*/
public static function patchSQLSRVPhp85(): bool
{
$source_dir = SOURCE_PATH . '/php-src/ext/pdo_sqlsrv';
if (!file_exists($source_dir . '/config.m4') && is_dir($source_dir . '/source/pdo_sqlsrv')) {
FileSystem::moveFileOrDir($source_dir . '/LICENSE', $source_dir . '/source/pdo_sqlsrv/LICENSE');
FileSystem::moveFileOrDir($source_dir . '/source/shared', $source_dir . '/source/pdo_sqlsrv/shared');
FileSystem::moveFileOrDir($source_dir . '/source/pdo_sqlsrv', SOURCE_PATH . '/pdo_sqlsrv');
FileSystem::removeDir($source_dir);
FileSystem::moveFileOrDir(SOURCE_PATH . '/pdo_sqlsrv', $source_dir);
return true;
}
return false;
}
public static function patchYamlWin32(): bool
{
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/yaml/config.w32', "lib.substr(lib.length - 6, 6) == '_a.lib'", "lib.substr(lib.length - 6, 6) == '_a.lib' || 'yes' == 'yes'");
@@ -649,13 +616,7 @@ class SourcePatcher
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/gd/libgd/gdft.c', '#ifndef MSWIN32', '#ifndef _WIN32');
}
// custom config.w32, because official config.w32 is hard-coded many things
if ($ver_id >= 80500) {
$origin = file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_85.w32');
} elseif ($ver_id >= 80100) {
$origin = file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_81.w32');
} else {
$origin = file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_80.w32');
}
$origin = $ver_id >= 80100 ? file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_81.w32') : file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_80.w32');
file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32.bak', file_get_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32'));
return file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32', $origin) !== false;
}

View File

@@ -30,8 +30,8 @@ class GoXcaddy extends CustomPackage
public function fetch(string $name, bool $force = false, ?array $config = null): void
{
$pkgroot = PKG_ROOT_PATH;
$go_exec = "{$pkgroot}/go-xcaddy/bin/go";
$xcaddy_exec = "{$pkgroot}/go-xcaddy/bin/xcaddy";
$go_exec = "{$pkgroot}/{$name}/bin/go";
$xcaddy_exec = "{$pkgroot}/{$name}/bin/xcaddy";
if ($force) {
FileSystem::removeDir("{$pkgroot}/{$name}");
}
@@ -48,10 +48,10 @@ class GoXcaddy extends CustomPackage
'macos' => 'darwin',
default => throw new \InvalidArgumentException('Unsupported OS: ' . $name),
};
[$go_version] = explode("\n", Downloader::curlExec('https://go.dev/VERSION?m=text'));
$go_version = '1.25.0';
$config = [
'type' => 'url',
'url' => "https://go.dev/dl/{$go_version}.{$os}-{$arch}.tar.gz",
'url' => "https://go.dev/dl/go{$go_version}.{$os}-{$arch}.tar.gz",
];
Downloader::downloadPackage($name, $config, $force);
}
@@ -85,7 +85,7 @@ class GoXcaddy extends CustomPackage
'GOBIN' => "{$pkgroot}/go-xcaddy/bin",
'GOPATH' => "{$pkgroot}/go",
])
->exec('CGO_ENABLED=0 go install github.com/caddyserver/xcaddy/cmd/xcaddy@master');
->exec('CC=cc go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest');
}
public static function getEnvironment(): array

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