Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
656a58c
remove source dir after successful build in CI environment
henderkes Dec 18, 2025
0247458
we were installing to wrong dir if source name != lib name
henderkes Dec 18, 2025
ce44e00
@crazywhalecc how to use patch points to delete source dirs?
henderkes Dec 18, 2025
037d224
why does phpstan think this is necessary?
henderkes Dec 18, 2025
e677be7
remove
henderkes Dec 18, 2025
9e051c8
fix: check for link first before checking for is_dir
henderkes Dec 18, 2025
e1a14bb
fix implicit include
henderkes Dec 18, 2025
53f7cde
fix swoole compilation with php 8.5.1
henderkes Dec 18, 2025
6b52000
fix downloader selecting drafts
henderkes Dec 20, 2025
f7ca621
Test
crazywhalecc Dec 26, 2025
9a681a9
add mariadb mysqlnd plugins
henderkes Dec 27, 2025
09b89a3
WIP: use system libraries for grpc without building our own grpc lib
henderkes Dec 27, 2025
e952f1c
we don't even need to build grpc library for grpc extension...
henderkes Dec 27, 2025
5ef4623
grpc will fail for php 8.5, it's not updated yet
henderkes Dec 27, 2025
93a3590
factor grpc extension out to ext-grpc, keep library for now, even tho…
henderkes Dec 28, 2025
2f31226
make grpc php 8.5 compatible
henderkes Dec 28, 2025
e7a88f1
enable fat for gmp when next version releases
henderkes Dec 29, 2025
08388c0
force enable tailcall vm with zig
henderkes Dec 29, 2025
7688a55
don't get zig master branch
henderkes Dec 29, 2025
022fdb2
fix no-strip
henderkes Dec 29, 2025
a06cc32
pin libpng to released tags, not git
henderkes Dec 30, 2025
64f7a35
don't need it anymore
henderkes Jan 1, 2026
d1b1949
use OPENSSL_CONF directory for openssl default configuration
henderkes Jan 2, 2026
fff2484
postgresql doesn't build under c23
henderkes Jan 2, 2026
559a290
use little trick to order libargon2 before libsodium
henderkes Jan 2, 2026
890ff47
our memcache patch prevents shared building
henderkes Jan 3, 2026
54001ab
simplify logic a bit
henderkes Jan 3, 2026
1be353f
more concise message
henderkes Jan 3, 2026
76025b9
missing space
henderkes Jan 3, 2026
6bbb3c9
remove -release handling functionality
henderkes Jan 3, 2026
f8b0c2c
add release thing to extension build too
henderkes Jan 3, 2026
94644d3
fix
henderkes Jan 3, 2026
3a17cec
deploy extensions with -release flag too
henderkes Jan 3, 2026
34910d1
add patch point for shared ext build
henderkes Jan 4, 2026
d902e70
fix arm64 builds
henderkes Jan 16, 2026
af75ffa
suggestions, change openssldir
henderkes Jan 19, 2026
6cf4c40
Merge remote-tracking branch 'origin/main' into henderkes-patch-1
henderkes Jan 19, 2026
372760e
Update patch point docs
crazywhalecc Jan 19, 2026
b3c4502
up version
henderkes Jan 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions bin/spc-alpine-docker
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ RUN apk update; \
wget \
xz \
gettext-dev \
binutils-gold \
patchelf
binutils-gold

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
Expand Down
5 changes: 0 additions & 5 deletions bin/spc-gnu-docker
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ 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
Expand Down
428 changes: 221 additions & 207 deletions composer.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions config/env.ini
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ 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.
Expand Down
43 changes: 39 additions & 4 deletions config/ext.json
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,13 @@
"BSD": "wip"
},
"type": "external",
"source": "grpc",
"source": "ext-grpc",
"arg-type-unix": "enable-path",
"cpp-extension": true,
"lib-depends": [
"grpc"
"zlib",
"openssl",
"libcares"
]
},
"iconv": {
Expand Down Expand Up @@ -416,8 +418,7 @@
"ext-depends": [
"zlib",
"session"
],
"build-with-php": true
]
},
"memcached": {
"support": {
Expand Down Expand Up @@ -495,6 +496,40 @@
"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": {
Expand Down
3 changes: 3 additions & 0 deletions config/lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,9 @@
"source": "libargon2",
"static-libs-unix": [
"libargon2.a"
],
"lib-suggests": [
"libsodium"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it depends on libsodium?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't depend on libsodium, but because they implement a lot of the same symbols, this orders them correctly. I got rid of the patch in password_argon2.php instead as it failed with -lsodium -largon2.

Because this now suggests libsodium, meaning libsodium may contain symbols this library "relies on", SPC makes sure that libsodium comes after libargon2 everywhere. Because libargon2 implements all symbols of libsodium, no further symbols will be needed during linking and libsodium is ignored.

]
},
"libavif": {
Expand Down
45 changes: 38 additions & 7 deletions config/source.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@
"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",
Expand Down Expand Up @@ -680,19 +692,20 @@
}
},
"libpng": {
"type": "git",
"url": "https://github.com/glennrp/libpng.git",
"rev": "libpng16",
"type": "ghtagtar",
"repo": "pnggroup/libpng",
"match": "v1\\.6\\.\\d+",
"query": "?per_page=150",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary, or is it only libpng that needs this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only libpng needs this. They released a lot of v1.7 betas, so the latest 1.6 version is only on page 3.

"provide-pre-built": true,
"license": {
"type": "file",
"path": "LICENSE"
}
},
"librabbitmq": {
"type": "git",
"url": "https://github.com/alanxz/rabbitmq-c.git",
"rev": "master",
"type": "ghtar",
"repo": "alanxz/rabbitmq-c",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
Expand All @@ -709,7 +722,7 @@
"libsodium": {
"type": "ghrel",
"repo": "jedisct1/libsodium",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"match": "libsodium-(?!1\\.0\\.21)\\d+(\\.\\d+)*\\.tar\\.gz",
"prefer-stable": true,
"provide-pre-built": true,
"license": {
Expand Down Expand Up @@ -881,6 +894,24 @@
"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/",
Expand Down
34 changes: 18 additions & 16 deletions docs/en/guide/manual-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -549,22 +549,24 @@ 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 |
| 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 |
| 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 |

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:
Expand Down
2 changes: 2 additions & 0 deletions docs/zh/guide/manual-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ 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` 前触发 |
Expand Down
2 changes: 1 addition & 1 deletion src/SPC/ConsoleApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*/
final class ConsoleApplication extends Application
{
public const string VERSION = '2.7.11';
public const string VERSION = '2.8.0';

public function __construct()
{
Expand Down
16 changes: 12 additions & 4 deletions src/SPC/builder/Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@ public function buildShared(array $visited = []): void
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) {
Expand All @@ -395,13 +398,12 @@ public function buildShared(array $visited = []): void
$dependency->buildShared([...$visited, $this->getName()]);
}
}
if (Config::getExt($this->getName(), 'type') === 'addon') {
return;
}
$this->builder->emitPatchPoint('before-shared-ext[' . $this->getName() . ']-build');
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;
Expand Down Expand Up @@ -452,12 +454,17 @@ public function buildUnixShared(): void

// 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, $soFile, false);
$builder->deployBinary($soFile, $soDest, false);
}

/**
Expand Down Expand Up @@ -543,6 +550,7 @@ protected function getSharedExtensionEnv(): array
'CFLAGS' => $config['cflags'],
'CXXFLAGS' => $config['cflags'],
'LDFLAGS' => $config['ldflags'],
'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'),
'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"),
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
];
Expand Down
25 changes: 17 additions & 8 deletions src/SPC/builder/LibraryBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,18 @@ public function tryBuild(bool $force_build = false): int

// 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;
}

Expand Down Expand Up @@ -346,19 +346,19 @@ protected function getSnakeCaseName(): string
*/
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/' . $this->getName() . "/{$index}.txt", $license['text']);
FileSystem::writeFile(BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt", $license['text']);
continue;
}
if ($license['type'] === 'file') {
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . '/source-licenses/' . $this->getName() . "/{$index}.txt");
copy($this->source_dir . '/' . $license['path'], BUILD_ROOT_PATH . "/source-licenses/{$source}/{$index}.txt");
}
}
}
Expand All @@ -375,8 +375,17 @@ protected function isLibraryInstalled(): bool
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) {
if (!file_exists(BUILD_LIB_PATH . "/pkgconfig/{$name}.pc")) {
$found = false;
foreach ($search_paths as $path) {
if (file_exists($path . "/{$name}.pc")) {
$found = true;
break;
}
}
if (!$found) {
return false;
}
}
Expand Down
16 changes: 6 additions & 10 deletions src/SPC/builder/extension/grpc.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,14 @@ public function patchBeforeBuildconf(): bool
if ($this->builder instanceof WindowsBuilder) {
throw new ValidationException('grpc extension does not support windows yet');
}
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');
}
FileSystem::replaceFileStr(
$this->source_dir . '/src/php/ext/grpc/call.c',
'zend_exception_get_default(TSRMLS_C),',
'zend_ce_exception,',
);
if (SPCTarget::getTargetOS() === 'Darwin') {
FileSystem::replaceFileRegex(
SOURCE_PATH . '/php-src/ext/grpc/config.m4',
$this->source_dir . '/config.m4',
'/GRPC_LIBDIR=.*$/m',
'GRPC_LIBDIR=' . BUILD_LIB_PATH . "\n" . 'LDFLAGS="$LDFLAGS -framework CoreFoundation"'
);
Expand Down
Loading
Loading