diff --git a/bin/spc-alpine-docker b/bin/spc-alpine-docker
index 28cc4939..16609b5f 100755
--- a/bin/spc-alpine-docker
+++ b/bin/spc-alpine-docker
@@ -122,6 +122,20 @@ MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot"
# shellcheck disable=SC2086
# shellcheck disable=SC2090
if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
+ echo "* Debug mode enabled, run docker in interactive mode."
+ echo "* You can use 'exit' to exit the docker container."
+ echo "* You can use 'bin/spc' like normal builds."
+ echo "*"
+ echo "* Mounted directories:"
+ echo "* ./config: $(pwd)/config"
+ echo "* ./src: $(pwd)/src"
+ echo "* ./buildroot: $(pwd)/buildroot"
+ echo "* ./source: $(pwd)/source"
+ echo "* ./dist: $(pwd)/dist"
+ echo "* ./downloads: $(pwd)/downloads"
+ echo "* ./pkgroot: $(pwd)/pkgroot"
+ echo "*"
+
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2
else
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@
diff --git a/bin/spc-gnu-docker b/bin/spc-gnu-docker
index fa84e58c..6bc7bd4a 100755
--- a/bin/spc-gnu-docker
+++ b/bin/spc-gnu-docker
@@ -12,7 +12,7 @@ DOCKER_EXECUTABLE="docker"
# shellcheck disable=SC2046
if [ $(id -u) -ne 0 ]; then
if ! docker info > /dev/null 2>&1; then
- if [ "$SPC_USE_SUDO" != "yes" ]; then
+ if [ "$SPC_USE_SUDO" != "yes" ] && [ "$SPC_DOCKER_DEBUG" != "yes" ]; then
echo "Docker command requires sudo"
# shellcheck disable=SC2039
echo -n 'To use sudo to run docker, run "export SPC_USE_SUDO=yes" and run command again'
@@ -86,7 +86,7 @@ COPY ./composer.* /app/
ADD ./bin/setup-runtime /app/bin/setup-runtime
ADD ./bin/spc /app/bin/spc
RUN /app/bin/setup-runtime
-RUN /app/bin/php /app/bin/composer install --no-dev --classmap-authoritative
+RUN /app/bin/php /app/bin/composer install --no-dev
ENV PATH="/app/bin:/cmake/bin:$PATH"
ENV SPC_LIBC=glibc
@@ -145,4 +145,23 @@ echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"'
# shellcheck disable=SC2086
# shellcheck disable=SC2090
-$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@
+
+if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
+ echo "* Debug mode enabled, run docker in interactive mode."
+ echo "* You can use 'exit' to exit the docker container."
+ echo "* You can use 'bin/spc' like normal builds."
+ echo "*"
+ echo "* Mounted directories:"
+ echo "* ./config: $(pwd)/config"
+ echo "* ./src: $(pwd)/src"
+ echo "* ./buildroot: $(pwd)/buildroot"
+ echo "* ./source: $(pwd)/source"
+ echo "* ./dist: $(pwd)/dist"
+ echo "* ./downloads: $(pwd)/downloads"
+ echo "* ./pkgroot: $(pwd)/pkgroot"
+ echo "*"
+
+ $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH
+else
+ $DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@
+fi
diff --git a/config/env.ini b/config/env.ini
index 652b0fe6..131fa07e 100644
--- a/config/env.ini
+++ b/config/env.ini
@@ -28,7 +28,6 @@
; PATH: static-php-cli will add `$BUILD_BIN_PATH` to PATH.
; PKG_CONFIG: static-php-cli will set `$BUILD_BIN_PATH/pkg-config` to PKG_CONFIG.
; PKG_CONFIG_PATH: static-php-cli will set `$BUILD_LIB_PATH/pkgconfig` to PKG_CONFIG_PATH.
-; SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS: the default optimization CFLAGS for compiling php. (if --no-strip option is set: `-g -O0`, else: `-g -Os`)
;
; * These vars are only be defined in LinuxBuilder and cannot be changed anywhere:
; SPC_LINUX_DEFAULT_CC: the default compiler for linux. (For alpine linux: `gcc`, default: `$GNU_ARCH-linux-musl-gcc`)
@@ -98,9 +97,9 @@ SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}"
; LIBS for configuring php
SPC_CMD_VAR_PHP_CONFIGURE_LIBS="-ldl -lpthread -lm"
; EXTRA_CFLAGS for `make` php
-SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS} -fno-ident -fPIE -fPIC"
+SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fno-ident -fPIE -fPIC"
; EXTRA_LIBS for `make` php
-SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS=""
+SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm"
; EXTRA_LDFLAGS_PROGRAM for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-all-static -Wl,-O1 -pie"
@@ -132,7 +131,7 @@ SPC_CMD_VAR_PHP_CONFIGURE_CPPFLAGS="-I${BUILD_INCLUDE_PATH}"
; LDFLAGS for configuring php
SPC_CMD_VAR_PHP_CONFIGURE_LDFLAGS="-L${BUILD_LIB_PATH}"
; EXTRA_CFLAGS for `make` php
-SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="${SPC_PHP_DEFAULT_OPTIMIZE_CFLAGS}"
+SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS="-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
; EXTRA_LIBS for `make` php
SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-lresolv"
; embed type for php, static (libphp.a) or shared (libphp.dylib)
diff --git a/config/ext.json b/config/ext.json
index 691be764..3d99350c 100644
--- a/config/ext.json
+++ b/config/ext.json
@@ -771,6 +771,10 @@
"Windows": "no",
"BSD": "wip"
},
+ "target": [
+ "static",
+ "shared"
+ ],
"notes": true,
"type": "external",
"source": "swoole",
@@ -919,15 +923,16 @@
},
"xdebug": {
"type": "external",
+ "source": "xdebug",
+ "target": [
+ "shared"
+ ],
"support": {
"Windows": "wip",
"BSD": "no",
- "Darwin": "no",
- "Linux": "wip"
+ "Darwin": "partial",
+ "Linux": "partial"
},
- "lib-depends": [
- "xdebug"
- ],
"notes": true
},
"xhprof": {
@@ -1042,6 +1047,10 @@
"support": {
"BSD": "wip"
},
+ "target": [
+ "static",
+ "shared"
+ ],
"type": "builtin",
"arg-type": "with-prefix",
"arg-type-windows": "enable",
diff --git a/config/lib.json b/config/lib.json
index a39409ed..cc9d4eb0 100644
--- a/config/lib.json
+++ b/config/lib.json
@@ -281,8 +281,7 @@
"headers-unix": [
"ares.h",
"ares_dns.h",
- "ares_nameser.h",
- "ares_rules.h"
+ "ares_nameser.h"
]
},
"libde265": {
@@ -751,12 +750,6 @@
"libiconv"
]
},
- "xdebug": {
- "source": "xdebug",
- "static-libs-unix": [
- "xdebug.so"
- ]
- },
"xz": {
"source": "xz",
"static-libs-unix": [
diff --git a/config/source.json b/config/source.json
index 553f0527..4a9c3cef 100644
--- a/config/source.json
+++ b/config/source.json
@@ -914,11 +914,9 @@
}
},
"xdebug": {
- "type": "ghrel",
- "repo": "xdebug/xdebug",
- "match": "Source code",
- "prefer-stable": true,
- "provide-pre-built": false,
+ "type": "url",
+ "url": "https://pecl.php.net/get/xdebug",
+ "filename": "xdebug.tgz",
"license": {
"type": "file",
"path": "LICENSE"
diff --git a/src/SPC/builder/BuilderBase.php b/src/SPC/builder/BuilderBase.php
index 0456af8b..429d950a 100644
--- a/src/SPC/builder/BuilderBase.php
+++ b/src/SPC/builder/BuilderBase.php
@@ -122,9 +122,12 @@ abstract class BuilderBase
*
* @return Extension[]
*/
- public function getExts(): array
+ public function getExts(bool $including_shared = true): array
{
- return $this->exts;
+ if ($including_shared) {
+ return $this->exts;
+ }
+ return array_filter($this->exts, fn ($ext) => !$ext->isBuildShared());
}
/**
@@ -136,7 +139,7 @@ abstract class BuilderBase
public function hasCpp(): bool
{
// judge cpp-extension
- $exts = array_keys($this->getExts());
+ $exts = array_keys($this->getExts(false));
foreach ($exts as $ext) {
if (Config::getExt($ext, 'cpp-extension', false) === true) {
return true;
@@ -170,9 +173,22 @@ abstract class BuilderBase
* @throws \Throwable|WrongUsageException
* @internal
*/
- public function proveExts(array $extensions, bool $skip_check_deps = false): void
+ public function proveExts(array $static_extensions, array $shared_extensions = [], bool $skip_check_deps = false): void
{
CustomExt::loadCustomExt();
+ // judge ext
+ foreach ($static_extensions as $ext) {
+ // if extension does not support static build, throw exception
+ if (!in_array('static', Config::getExtTarget($ext))) {
+ throw new WrongUsageException('Extension [' . $ext . '] does not support static build!');
+ }
+ }
+ foreach ($shared_extensions as $ext) {
+ // if extension does not support shared build, throw exception
+ if (!in_array('shared', Config::getExtTarget($ext)) && !in_array($ext, $shared_extensions)) {
+ throw new WrongUsageException('Extension [' . $ext . '] does not support shared build!');
+ }
+ }
$this->emitPatchPoint('before-php-extract');
SourceManager::initSource(sources: ['php-src']);
$this->emitPatchPoint('after-php-extract');
@@ -182,11 +198,18 @@ abstract class BuilderBase
$this->emitPatchPoint('after-micro-extract');
}
$this->emitPatchPoint('before-exts-extract');
- SourceManager::initSource(exts: $extensions);
+ SourceManager::initSource(exts: [...$static_extensions, ...$shared_extensions]);
$this->emitPatchPoint('after-exts-extract');
- foreach ($extensions as $extension) {
+ foreach ([...$static_extensions, ...$shared_extensions] as $extension) {
$class = CustomExt::getExtClass($extension);
+ /** @var Extension $ext */
$ext = new $class($extension, $this);
+ if (in_array($extension, $static_extensions)) {
+ $ext->setBuildStatic();
+ }
+ if (in_array($extension, $shared_extensions)) {
+ $ext->setBuildShared();
+ }
$this->addExt($ext);
}
@@ -194,10 +217,10 @@ abstract class BuilderBase
return;
}
- foreach ($this->exts as $ext) {
+ foreach ($this->getExts() as $ext) {
$ext->checkDependency();
}
- $this->ext_list = $extensions;
+ $this->ext_list = [...$static_extensions, ...$shared_extensions];
}
/**
@@ -207,6 +230,17 @@ abstract class BuilderBase
*/
abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE);
+ public function buildSharedExts(): void
+ {
+ foreach ($this->getExts() as $ext) {
+ if (!$ext->isBuildShared()) {
+ continue;
+ }
+ logger()->info('Building extension [' . $ext->getName() . '] as shared extension (' . $ext->getName() . '.so)');
+ $ext->buildShared();
+ }
+ }
+
/**
* Generate extension enable arguments for configure.
* e.g. --enable-mbstring
@@ -214,10 +248,10 @@ abstract class BuilderBase
* @throws FileSystemException
* @throws WrongUsageException
*/
- public function makeExtensionArgs(): string
+ public function makeStaticExtensionArgs(): string
{
$ret = [];
- foreach ($this->exts as $ext) {
+ foreach ($this->getExts(false) as $ext) {
logger()->info($ext->getName() . ' is using ' . $ext->getConfigureArg());
$ret[] = trim($ext->getConfigureArg());
}
@@ -396,7 +430,7 @@ abstract class BuilderBase
foreach ($this->libs as $lib) {
$lib->validate();
}
- foreach ($this->exts as $ext) {
+ foreach ($this->getExts() as $ext) {
$ext->validate();
}
}
@@ -441,7 +475,7 @@ abstract class BuilderBase
{
$php = "getExts() as $ext) {
+ foreach ($this->getExts(false) as $ext) {
$ext_name = $ext->getDistName();
if (!empty($ext_name)) {
$php .= "echo 'Running micro with {$ext_name} test' . PHP_EOL;\n";
diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php
index a7886cd8..6ada640a 100644
--- a/src/SPC/builder/Extension.php
+++ b/src/SPC/builder/Extension.php
@@ -14,6 +14,12 @@ class Extension
{
protected array $dependencies = [];
+ protected bool $build_shared = false;
+
+ protected bool $build_static = false;
+
+ protected string $source_dir;
+
/**
* @throws FileSystemException
* @throws RuntimeException
@@ -30,6 +36,18 @@ class Extension
if (PHP_OS_FAMILY === 'Windows' && $unix_only) {
throw new RuntimeException("{$ext_type} extension {$name} is not supported on Windows platform");
}
+ // set source_dir for builtin
+ if ($ext_type === 'builtin') {
+ $this->source_dir = SOURCE_PATH . '/php-src/ext/' . $this->name;
+ } else {
+ $source = Config::getExt($this->name, 'source');
+ if ($source === null) {
+ throw new RuntimeException("{$ext_type} extension {$name} source not found");
+ }
+ $source_path = Config::getSource($source)['path'] ?? null;
+ $source_path = $source_path === null ? SOURCE_PATH . '/' . $source : SOURCE_PATH . '/' . $source_path;
+ $this->source_dir = $source_path;
+ }
}
/**
@@ -132,7 +150,7 @@ class Extension
// Windows is not supported yet
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '';
}
@@ -167,6 +185,17 @@ class Extension
return false;
}
+ /**
+ * Run shared extension check when cli is enabled
+ */
+ public function runSharedExtensionCheckUnix(): void
+ {
+ [$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "extension=' . BUILD_LIB_PATH . '/' . $this->getName() . '.so" --ri ' . $this->getName());
+ if ($ret !== 0) {
+ throw new RuntimeException($this->getName() . '.so failed to load');
+ }
+ }
+
/**
* @throws RuntimeException
*/
@@ -231,6 +260,43 @@ class Extension
// do nothing, just throw wrong usage exception if not valid
}
+ /**
+ * Build shared extension
+ *
+ * @throws WrongUsageException
+ * @throws RuntimeException
+ */
+ public function buildShared(): void
+ {
+ match (PHP_OS_FAMILY) {
+ 'Darwin', 'Linux' => $this->buildUnixShared(),
+ default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'),
+ };
+ }
+
+ /**
+ * Build shared extension for Unix
+ *
+ * @throws RuntimeException
+ */
+ public function buildUnixShared(): void
+ {
+ // prepare configure args
+ shell()->cd($this->source_dir)
+ ->setEnv(['CFLAGS' => $this->builder->arch_c_flags ?? ''])
+ ->execWithEnv(BUILD_BIN_PATH . '/phpize')
+ ->execWithEnv('./configure ' . $this->getUnixConfigureArg(true) . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-shared --disable-static')
+ ->execWithEnv('make clean')
+ ->execWithEnv('make -j' . $this->builder->concurrency);
+
+ // copy shared library
+ copy($this->source_dir . '/modules/' . $this->getDistName() . '.so', BUILD_LIB_PATH . '/' . $this->getDistName() . '.so');
+ // check shared extension with php-cli
+ if (file_exists(BUILD_BIN_PATH . '/php')) {
+ $this->runSharedExtensionCheckUnix();
+ }
+ }
+
/**
* Get current extension version
*
@@ -241,6 +307,32 @@ class Extension
return null;
}
+ public function setBuildStatic(): void
+ {
+ if (!in_array('static', Config::getExtTarget($this->name))) {
+ throw new WrongUsageException("Extension [{$this->name}] does not support static build!");
+ }
+ $this->build_static = true;
+ }
+
+ public function setBuildShared(): void
+ {
+ if (!in_array('shared', Config::getExtTarget($this->name))) {
+ throw new WrongUsageException("Extension [{$this->name}] does not support shared build!");
+ }
+ $this->build_shared = true;
+ }
+
+ public function isBuildShared(): bool
+ {
+ return $this->build_shared;
+ }
+
+ public function isBuildStatic(): bool
+ {
+ return $this->build_static;
+ }
+
/**
* @throws RuntimeException
*/
diff --git a/src/SPC/builder/extension/amqp.php b/src/SPC/builder/extension/amqp.php
index d795f47d..8fbfea24 100644
--- a/src/SPC/builder/extension/amqp.php
+++ b/src/SPC/builder/extension/amqp.php
@@ -23,7 +23,7 @@ class amqp extends Extension
return false;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-amqp --with-librabbitmq-dir=' . BUILD_ROOT_PATH;
}
diff --git a/src/SPC/builder/extension/dba.php b/src/SPC/builder/extension/dba.php
index 011e4746..bd7388f3 100644
--- a/src/SPC/builder/extension/dba.php
+++ b/src/SPC/builder/extension/dba.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('dba')]
class dba extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . BUILD_ROOT_PATH) : '';
return '--enable-dba' . $qdbm;
diff --git a/src/SPC/builder/extension/enchant.php b/src/SPC/builder/extension/enchant.php
index 26578519..c3046409 100644
--- a/src/SPC/builder/extension/enchant.php
+++ b/src/SPC/builder/extension/enchant.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('enchant')]
class enchant extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$glibs = [
'/Users/jerry/project/git-project/static-php-cli/buildroot/lib/libgio-2.0.a',
diff --git a/src/SPC/builder/extension/event.php b/src/SPC/builder/extension/event.php
index a1cc7bcc..95d9aba6 100644
--- a/src/SPC/builder/extension/event.php
+++ b/src/SPC/builder/extension/event.php
@@ -13,7 +13,7 @@ use SPC\util\CustomExt;
#[CustomExt('event')]
class event extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--with-event-core --with-event-extra --with-event-libevent-dir=' . BUILD_ROOT_PATH;
if ($this->builder->getLib('openssl')) {
diff --git a/src/SPC/builder/extension/ffi.php b/src/SPC/builder/extension/ffi.php
index 6f294481..51c3efac 100644
--- a/src/SPC/builder/extension/ffi.php
+++ b/src/SPC/builder/extension/ffi.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('ffi')]
class ffi extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-ffi --enable-zend-signals';
}
diff --git a/src/SPC/builder/extension/gd.php b/src/SPC/builder/extension/gd.php
index 707a898f..f872733b 100644
--- a/src/SPC/builder/extension/gd.php
+++ b/src/SPC/builder/extension/gd.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('gd')]
class gd extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-gd';
$arg .= $this->builder->getLib('freetype') ? ' --with-freetype' : '';
diff --git a/src/SPC/builder/extension/glfw.php b/src/SPC/builder/extension/glfw.php
index c9d0c4f7..444b5d93 100644
--- a/src/SPC/builder/extension/glfw.php
+++ b/src/SPC/builder/extension/glfw.php
@@ -30,7 +30,7 @@ class glfw extends Extension
return true;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
}
diff --git a/src/SPC/builder/extension/grpc.php b/src/SPC/builder/extension/grpc.php
index a63bad9d..852f2933 100644
--- a/src/SPC/builder/extension/grpc.php
+++ b/src/SPC/builder/extension/grpc.php
@@ -44,7 +44,7 @@ class grpc extends Extension
return true;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-grpc=' . BUILD_ROOT_PATH . '/grpc GRPC_LIB_SUBDIR=' . BUILD_LIB_PATH;
}
diff --git a/src/SPC/builder/extension/imagick.php b/src/SPC/builder/extension/imagick.php
index 7becb143..c73a5f29 100644
--- a/src/SPC/builder/extension/imagick.php
+++ b/src/SPC/builder/extension/imagick.php
@@ -22,7 +22,7 @@ class imagick extends Extension
return true;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-imagick=' . BUILD_ROOT_PATH;
}
diff --git a/src/SPC/builder/extension/imap.php b/src/SPC/builder/extension/imap.php
index 3aa2c284..9cc9a87f 100644
--- a/src/SPC/builder/extension/imap.php
+++ b/src/SPC/builder/extension/imap.php
@@ -33,7 +33,7 @@ class imap extends Extension
}
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--with-imap=' . BUILD_ROOT_PATH;
if ($this->builder->getLib('openssl') !== null) {
diff --git a/src/SPC/builder/extension/memcache.php b/src/SPC/builder/extension/memcache.php
index eb3e2969..4625cae2 100644
--- a/src/SPC/builder/extension/memcache.php
+++ b/src/SPC/builder/extension/memcache.php
@@ -12,7 +12,7 @@ use SPC\util\CustomExt;
#[CustomExt('memcache')]
class memcache extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH;
}
diff --git a/src/SPC/builder/extension/memcached.php b/src/SPC/builder/extension/memcached.php
index 1ef679d9..9c433954 100644
--- a/src/SPC/builder/extension/memcached.php
+++ b/src/SPC/builder/extension/memcached.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('memcached')]
class memcached extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$rootdir = BUILD_ROOT_PATH;
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : "--with-zlib-dir={$rootdir}";
diff --git a/src/SPC/builder/extension/mongodb.php b/src/SPC/builder/extension/mongodb.php
index 2096de05..7ba1ea33 100644
--- a/src/SPC/builder/extension/mongodb.php
+++ b/src/SPC/builder/extension/mongodb.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('mongodb')]
class mongodb extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$arg = ' --enable-mongodb ';
$arg .= ' --with-mongodb-system-libs=no --with-mongodb-client-side-encryption=no ';
diff --git a/src/SPC/builder/extension/odbc.php b/src/SPC/builder/extension/odbc.php
index 6234f4e8..ac5c3e8f 100644
--- a/src/SPC/builder/extension/odbc.php
+++ b/src/SPC/builder/extension/odbc.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('odbc')]
class odbc extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-unixODBC=' . BUILD_ROOT_PATH;
}
diff --git a/src/SPC/builder/extension/opcache.php b/src/SPC/builder/extension/opcache.php
index 5276261a..5d9dda0a 100644
--- a/src/SPC/builder/extension/opcache.php
+++ b/src/SPC/builder/extension/opcache.php
@@ -42,7 +42,7 @@ class opcache extends Extension
return file_put_contents(SOURCE_PATH . '/php-src/.opcache_patched', '1') !== false;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-opcache';
}
diff --git a/src/SPC/builder/extension/openssl.php b/src/SPC/builder/extension/openssl.php
index 2576b0b2..add1aede 100644
--- a/src/SPC/builder/extension/openssl.php
+++ b/src/SPC/builder/extension/openssl.php
@@ -23,7 +23,7 @@ class openssl extends Extension
return false;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$openssl_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-openssl-dir=' . BUILD_ROOT_PATH;
return '--with-openssl=' . BUILD_ROOT_PATH . $openssl_dir;
diff --git a/src/SPC/builder/extension/pdo_odbc.php b/src/SPC/builder/extension/pdo_odbc.php
index 4ab45904..e436f381 100644
--- a/src/SPC/builder/extension/pdo_odbc.php
+++ b/src/SPC/builder/extension/pdo_odbc.php
@@ -17,7 +17,7 @@ class pdo_odbc extends Extension
return true;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-pdo-odbc=unixODBC,' . BUILD_ROOT_PATH;
}
diff --git a/src/SPC/builder/extension/pgsql.php b/src/SPC/builder/extension/pgsql.php
index 74085b21..1c63f163 100644
--- a/src/SPC/builder/extension/pgsql.php
+++ b/src/SPC/builder/extension/pgsql.php
@@ -33,7 +33,7 @@ class pgsql extends Extension
* @throws WrongUsageException
* @throws RuntimeException
*/
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
if ($this->builder->getPHPVersionID() >= 80400) {
return '--with-pgsql PGSQL_CFLAGS=-I' . BUILD_INCLUDE_PATH . ' PGSQL_LIBS="-L' . BUILD_LIB_PATH . ' -lpq -lpgport -lpgcommon"';
diff --git a/src/SPC/builder/extension/redis.php b/src/SPC/builder/extension/redis.php
index bffc768e..0b60075c 100644
--- a/src/SPC/builder/extension/redis.php
+++ b/src/SPC/builder/extension/redis.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('redis')]
class redis extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-redis';
$arg .= $this->builder->getExt('session') ? ' --enable-redis-session' : ' --disable-redis-session';
diff --git a/src/SPC/builder/extension/snappy.php b/src/SPC/builder/extension/snappy.php
index 2dc2a33a..896a9be2 100644
--- a/src/SPC/builder/extension/snappy.php
+++ b/src/SPC/builder/extension/snappy.php
@@ -26,7 +26,7 @@ class snappy extends Extension
return true;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"';
}
diff --git a/src/SPC/builder/extension/spx.php b/src/SPC/builder/extension/spx.php
index 6c2a6a19..dc341e39 100644
--- a/src/SPC/builder/extension/spx.php
+++ b/src/SPC/builder/extension/spx.php
@@ -21,7 +21,7 @@ class spx extends Extension
}
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-spx';
if ($this->builder->getExt('zlib') === null) {
diff --git a/src/SPC/builder/extension/swoole.php b/src/SPC/builder/extension/swoole.php
index 78aaf339..6ce006b9 100644
--- a/src/SPC/builder/extension/swoole.php
+++ b/src/SPC/builder/extension/swoole.php
@@ -35,7 +35,7 @@ class swoole extends Extension
return null;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
// enable swoole
$arg = '--enable-swoole';
@@ -49,7 +49,9 @@ class swoole extends Extension
// additional feature: c-ares, brotli, nghttp2 (can be disabled, but we enable it by default in config to support full network feature)
$arg .= $this->builder->getLib('libcares') ? ' --enable-cares' : '';
- $arg .= $this->builder->getLib('brotli') ? (' --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
+ if (!$shared) {
+ $arg .= $this->builder->getLib('brotli') ? (' --enable-brotli --with-brotli-dir=' . BUILD_ROOT_PATH) : '';
+ }
$arg .= $this->builder->getLib('nghttp2') ? (' --with-nghttp2-dir=' . BUILD_ROOT_PATH) : '';
// additional feature: swoole-pgsql, it should depend on lib [postgresql], but it will lack of CFLAGS etc.
diff --git a/src/SPC/builder/extension/swoole_hook_mysql.php b/src/SPC/builder/extension/swoole_hook_mysql.php
index 6d1d6828..e9684872 100644
--- a/src/SPC/builder/extension/swoole_hook_mysql.php
+++ b/src/SPC/builder/extension/swoole_hook_mysql.php
@@ -16,7 +16,7 @@ class swoole_hook_mysql extends Extension
return 'swoole';
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
// pdo_mysql doesn't need to be disabled
// enable swoole-hook-mysql will enable mysqli, pdo, pdo_mysql, we don't need to add any additional options
diff --git a/src/SPC/builder/extension/swoole_hook_pgsql.php b/src/SPC/builder/extension/swoole_hook_pgsql.php
index 08e217be..113b8eb6 100644
--- a/src/SPC/builder/extension/swoole_hook_pgsql.php
+++ b/src/SPC/builder/extension/swoole_hook_pgsql.php
@@ -25,7 +25,7 @@ class swoole_hook_pgsql extends Extension
}
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
// enable swoole pgsql hook
return '--enable-swoole-pgsql';
diff --git a/src/SPC/builder/extension/swoole_hook_sqlite.php b/src/SPC/builder/extension/swoole_hook_sqlite.php
index 5de18351..7948dd29 100644
--- a/src/SPC/builder/extension/swoole_hook_sqlite.php
+++ b/src/SPC/builder/extension/swoole_hook_sqlite.php
@@ -25,7 +25,7 @@ class swoole_hook_sqlite extends Extension
}
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
// enable swoole pgsql hook
return '--enable-swoole-sqlite';
diff --git a/src/SPC/builder/extension/xdebug.php b/src/SPC/builder/extension/xdebug.php
index c5cd901d..ed592056 100644
--- a/src/SPC/builder/extension/xdebug.php
+++ b/src/SPC/builder/extension/xdebug.php
@@ -5,7 +5,17 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
-use SPC\util\DynamicExt;
+use SPC\exception\RuntimeException;
+use SPC\util\CustomExt;
-#[DynamicExt]
-class xdebug extends Extension {}
+#[CustomExt('xdebug')]
+class xdebug extends Extension
+{
+ public function runSharedExtensionCheckUnix(): void
+ {
+ [$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "zend_extension=' . BUILD_LIB_PATH . '/xdebug.so" --ri xdebug');
+ if ($ret !== 0) {
+ throw new RuntimeException('xdebug.so failed to load.');
+ }
+ }
+}
diff --git a/src/SPC/builder/extension/xlswriter.php b/src/SPC/builder/extension/xlswriter.php
index 475a6c07..6319ce31 100644
--- a/src/SPC/builder/extension/xlswriter.php
+++ b/src/SPC/builder/extension/xlswriter.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('xlswriter')]
class xlswriter extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--with-xlswriter --enable-reader';
if ($this->builder->getLib('openssl')) {
diff --git a/src/SPC/builder/extension/xml.php b/src/SPC/builder/extension/xml.php
index 6242be6b..fc8bfc4d 100644
--- a/src/SPC/builder/extension/xml.php
+++ b/src/SPC/builder/extension/xml.php
@@ -20,7 +20,7 @@ class xml extends Extension
/**
* @throws RuntimeException
*/
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$arg = match ($this->name) {
'xml' => '--enable-xml',
diff --git a/src/SPC/builder/extension/yac.php b/src/SPC/builder/extension/yac.php
index a4152e42..bb085133 100644
--- a/src/SPC/builder/extension/yac.php
+++ b/src/SPC/builder/extension/yac.php
@@ -19,7 +19,7 @@ class yac extends Extension
return true;
}
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-yac --enable-igbinary --enable-json';
}
diff --git a/src/SPC/builder/extension/zlib.php b/src/SPC/builder/extension/zlib.php
index a9932999..86c45dbe 100644
--- a/src/SPC/builder/extension/zlib.php
+++ b/src/SPC/builder/extension/zlib.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('zlib')]
class zlib extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-zlib-dir=' . BUILD_ROOT_PATH;
return '--with-zlib' . $zlib_dir;
diff --git a/src/SPC/builder/extension/zstd.php b/src/SPC/builder/extension/zstd.php
index 13311979..3a6df602 100644
--- a/src/SPC/builder/extension/zstd.php
+++ b/src/SPC/builder/extension/zstd.php
@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('zstd')]
class zstd extends Extension
{
- public function getUnixConfigureArg(): string
+ public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
}
diff --git a/src/SPC/builder/freebsd/BSDBuilder.php b/src/SPC/builder/freebsd/BSDBuilder.php
index c1d41118..b2e246b3 100644
--- a/src/SPC/builder/freebsd/BSDBuilder.php
+++ b/src/SPC/builder/freebsd/BSDBuilder.php
@@ -118,7 +118,7 @@ class BSDBuilder extends UnixBuilderBase
$config_file_scan_dir .
$json_74 .
$zts .
- $this->makeExtensionArgs()
+ $this->makeStaticExtensionArgs()
);
$this->emitPatchPoint('before-php-make');
diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php
index cd48728f..e38714f1 100644
--- a/src/SPC/builder/linux/LinuxBuilder.php
+++ b/src/SPC/builder/linux/LinuxBuilder.php
@@ -182,7 +182,7 @@ class LinuxBuilder extends UnixBuilderBase
$json_74 .
$zts .
$maxExecutionTimers .
- $this->makeExtensionArgs() .
+ $this->makeStaticExtensionArgs() .
' ' . $envs_build_php . ' '
);
@@ -311,15 +311,7 @@ class LinuxBuilder extends UnixBuilderBase
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
- FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
- FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
- $php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
- str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
- // move mimalloc to the beginning of libs
- $php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
- // move lstdc++ to the end of libs
- $php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str);
- FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
+ $this->patchPhpScripts();
}
private function getMakeExtraVars(): array
diff --git a/src/SPC/builder/linux/library/xdebug.php b/src/SPC/builder/linux/library/xdebug.php
deleted file mode 100644
index b494bb1d..00000000
--- a/src/SPC/builder/linux/library/xdebug.php
+++ /dev/null
@@ -1,15 +0,0 @@
-makeExtensionArgs() . ' ' .
+ $this->makeStaticExtensionArgs() . ' ' .
$envs_build_php
);
@@ -300,13 +300,7 @@ class MacOSBuilder extends UnixBuilderBase
->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a')
->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o')
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o');
- FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
- FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
- $php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
- str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
- // move mimalloc to the beginning of libs
- $php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
- FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
+ $this->patchPhpScripts();
}
private function getMakeExtraVars(): array
diff --git a/src/SPC/builder/unix/UnixBuilderBase.php b/src/SPC/builder/unix/UnixBuilderBase.php
index ed07a725..4c8df333 100644
--- a/src/SPC/builder/unix/UnixBuilderBase.php
+++ b/src/SPC/builder/unix/UnixBuilderBase.php
@@ -146,7 +146,7 @@ abstract class UnixBuilderBase extends BuilderBase
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
}
- foreach ($this->exts as $ext) {
+ foreach ($this->getExts(false) as $ext) {
logger()->debug('testing ext: ' . $ext->getName());
$ext->runCliCheckUnix();
}
@@ -238,4 +238,29 @@ abstract class UnixBuilderBase extends BuilderBase
logger()->info('cleaning up');
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
}
+
+ /**
+ * Patch phpize and php-config if needed
+ * @throws FileSystemException
+ */
+ protected function patchPhpScripts(): void
+ {
+ // patch phpize
+ if (file_exists(BUILD_BIN_PATH . '/phpize')) {
+ logger()->debug('Patching phpize prefix');
+ FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
+ FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
+ }
+ // patch php-config
+ if (file_exists(BUILD_BIN_PATH . '/php-config')) {
+ logger()->debug('Patching php-config prefix and libs order');
+ $php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
+ $php_config_str = str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
+ // move mimalloc to the beginning of libs
+ $php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
+ // move lstdc++ to the end of libs
+ $php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str);
+ FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
+ }
+ }
}
diff --git a/src/SPC/builder/unix/library/libcares.php b/src/SPC/builder/unix/library/libcares.php
index 076a10c9..d99cc685 100644
--- a/src/SPC/builder/unix/library/libcares.php
+++ b/src/SPC/builder/unix/library/libcares.php
@@ -26,9 +26,9 @@ trait libcares
{
shell()->cd($this->source_dir)
->setEnv(['CFLAGS' => $this->getLibExtraCFlags(), 'LDFLAGS' => $this->getLibExtraLdFlags(), 'LIBS' => $this->getLibExtraLibs()])
- ->execWithEnv('./configure --prefix= --enable-static --disable-shared --disable-tests')
+ ->execWithEnv('./configure --prefix= --enable-static --disable-shared --disable-tests --with-pic')
->execWithEnv("make -j {$this->builder->concurrency}")
- ->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
+ ->execWithEnv('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['libcares.pc'], PKGCONF_PATCH_PREFIX);
}
diff --git a/src/SPC/builder/unix/library/xdebug.php b/src/SPC/builder/unix/library/xdebug.php
deleted file mode 100644
index 1aecb841..00000000
--- a/src/SPC/builder/unix/library/xdebug.php
+++ /dev/null
@@ -1,26 +0,0 @@
-cd($this->source_dir)
- ->exec(BUILD_BIN_PATH . '/phpize')
- ->exec('./configure --with-php-config=' . BUILD_BIN_PATH . '/php-config')
- ->exec('make clean')
- ->exec("make -j{$this->builder->concurrency}");
- copy($this->source_dir . '/modules/xdebug.so', BUILD_LIB_PATH . '/xdebug.so');
- copy($this->source_dir . '/modules/xdebug.la', BUILD_LIB_PATH . '/xdebug.la');
- }
-}
diff --git a/src/SPC/builder/windows/WindowsBuilder.php b/src/SPC/builder/windows/WindowsBuilder.php
index fb7eaa0f..7a604ca8 100644
--- a/src/SPC/builder/windows/WindowsBuilder.php
+++ b/src/SPC/builder/windows/WindowsBuilder.php
@@ -119,7 +119,7 @@ class WindowsBuilder extends BuilderBase
($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') .
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
$config_file_scan_dir .
- "{$this->makeExtensionArgs()} " .
+ "{$this->makeStaticExtensionArgs()} " .
$zts .
'"'
);
@@ -286,7 +286,7 @@ class WindowsBuilder extends BuilderBase
throw new RuntimeException('cli failed sanity check');
}
- foreach ($this->exts as $ext) {
+ foreach ($this->getExts(false) as $ext) {
logger()->debug('testing ext: ' . $ext->getName());
$ext->runCliCheckWindows();
}
diff --git a/src/SPC/command/BaseCommand.php b/src/SPC/command/BaseCommand.php
index 3688c249..a1610cae 100644
--- a/src/SPC/command/BaseCommand.php
+++ b/src/SPC/command/BaseCommand.php
@@ -165,7 +165,7 @@ abstract class BaseCommand extends Command
return SPC_EXTENSION_ALIAS[$lower];
}
return $lower;
- }, is_array($ext_list) ? $ext_list : explode(',', $ext_list));
+ }, is_array($ext_list) ? $ext_list : array_filter(explode(',', $ext_list)));
// filter internals
return array_values(array_filter($ls, function ($x) {
diff --git a/src/SPC/command/BuildPHPCommand.php b/src/SPC/command/BuildPHPCommand.php
index 3a5c17a4..4e690bed 100644
--- a/src/SPC/command/BuildPHPCommand.php
+++ b/src/SPC/command/BuildPHPCommand.php
@@ -11,7 +11,6 @@ use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourcePatcher;
use SPC\util\DependencyUtil;
-use SPC\util\DynamicExt;
use SPC\util\GlobalEnvManager;
use SPC\util\LicenseDumper;
use Symfony\Component\Console\Attribute\AsCommand;
@@ -28,6 +27,7 @@ class BuildPHPCommand extends BuildCommand
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated');
$this->addOption('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
+ $this->addOption('build-shared', 'D', InputOption::VALUE_REQUIRED, 'Shared extensions to build, comma separated', '');
$this->addOption('build-micro', null, null, 'Build micro SAPI');
$this->addOption('build-cli', null, null, 'Build cli SAPI');
$this->addOption('build-fpm', null, null, 'Build fpm SAPI (not available on Windows)');
@@ -53,13 +53,27 @@ class BuildPHPCommand extends BuildCommand
// transform string to array
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
// transform string to array
- $extensions = $this->parseExtensionList($this->getArgument('extensions'));
+ $shared_extensions = array_map('trim', array_filter(explode(',', $this->getOption('build-shared'))));
+ // transform string to array
+ $static_extensions = $this->parseExtensionList($this->getArgument('extensions'));
// parse rule with options
- $rule = $this->parseRules();
+ $rule = $this->parseRules($shared_extensions);
+
+ // check dynamic extension build env
+ // macOS must use --no-strip option
+ if (!empty($shared_extensions) && PHP_OS_FAMILY === 'Darwin' && !$this->getOption('no-strip')) {
+ $this->output->writeln('MacOS does not support dynamic extension loading with stripped binary, please use --no-strip option!');
+ return static::FAILURE;
+ }
+ // linux must build with glibc
+ if (!empty($shared_extensions) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') !== 'glibc') {
+ $this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with glibc!');
+ return static::FAILURE;
+ }
if ($rule === BUILD_TARGET_NONE) {
- $this->output->writeln('Please add at least one build target!');
+ $this->output->writeln('Please add at least one build SAPI!');
$this->output->writeln("\t--build-cli\tBuild php-cli SAPI");
$this->output->writeln("\t--build-micro\tBuild phpmicro SAPI");
$this->output->writeln("\t--build-fpm\tBuild php-fpm SAPI");
@@ -108,33 +122,22 @@ class BuildPHPCommand extends BuildCommand
$builder = BuilderProvider::makeBuilderByInput($this->input);
$include_suggest_ext = $this->getOption('with-suggested-exts');
$include_suggest_lib = $this->getOption('with-suggested-libs');
- [$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
+ [$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs(array_merge($static_extensions, $shared_extensions), $libraries, $include_suggest_ext, $include_suggest_lib);
$display_libs = array_filter($libraries, fn ($lib) => in_array(Config::getLib($lib, 'type', 'lib'), ['lib', 'package']));
- $dynamic_libs = $dynamic_exts = array_filter($extensions, function (string $ext) {
- $classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/builder/extension', 'SPC\builder\extension');
- $extension = array_find($classes, function (string $class) use ($ext) {
- $a = explode('\\', $class);
- return end($a) === $ext;
- });
- if (!$extension) {
- return false;
- }
- $reflector = new \ReflectionClass($extension);
- $attributes = $reflector->getAttributes();
- return array_find($attributes, fn ($attr) => $attr->getName() === DynamicExt::class) !== null;
- });
- $extensions = array_diff($extensions, $dynamic_exts);
- $libraries = array_diff($libraries, $dynamic_libs);
+ $display_extensions = array_map(fn ($ext) => in_array($ext, $shared_extensions) ? "*{$ext}" : $ext, $extensions);
// print info
$indent_texts = [
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
'Build SAPI' => $builder->getBuildTypeName($rule),
- 'Extensions (' . count($extensions) . ')' => implode(',', $extensions),
+ 'Extensions (' . count($extensions) . ')' => implode(',', $display_extensions),
'Libraries (' . count($libraries) . ')' => implode(',', $display_libs),
'Strip Binaries' => $builder->getOption('no-strip') ? 'no' : 'yes',
'Enable ZTS' => $builder->getOption('enable-zts') ? 'yes' : 'no',
];
+ if (!empty($shared_extensions) || ($rule & BUILD_TARGET_EMBED)) {
+ $indent_texts['Build Dev'] = 'yes';
+ }
if (!empty($this->input->getOption('with-config-file-path'))) {
$indent_texts['Config File Path'] = $this->input->getOption('with-config-file-path');
}
@@ -168,7 +171,7 @@ class BuildPHPCommand extends BuildCommand
// compile libraries
$builder->proveLibs($libraries);
// check extensions
- $builder->proveExts($extensions);
+ $builder->proveExts($static_extensions, $shared_extensions);
// validate libs and extensions
$builder->validateLibsAndExts();
@@ -199,11 +202,10 @@ class BuildPHPCommand extends BuildCommand
// start to build
$builder->buildPHP($rule);
- if ($rule & BUILD_TARGET_EMBED) {
- // build dynamic extensions
- $builder->proveLibs($dynamic_libs);
- // build or install libraries
- $builder->setupLibs();
+ // build dynamic extensions if needed
+ if (!empty($shared_extensions)) {
+ logger()->info('Building shared extensions ...');
+ $builder->buildSharedExts();
}
// compile stopwatch :P
@@ -234,13 +236,19 @@ class BuildPHPCommand extends BuildCommand
$path = FileSystem::convertPath("{$build_root_path}/bin/php-fpm");
logger()->info("Static php-fpm binary path{$fixed}: {$path}");
}
+ if (!empty($shared_extensions)) {
+ foreach ($shared_extensions as $ext) {
+ $path = FileSystem::convertPath("{$build_root_path}/lib/{$ext}.so");
+ logger()->info("Shared extension [{$ext}] path{$fixed}: {$path}");
+ }
+ }
// export metadata
file_put_contents(BUILD_ROOT_PATH . '/build-extensions.json', json_encode($extensions, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
file_put_contents(BUILD_ROOT_PATH . '/build-libraries.json', json_encode($libraries, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
// export licenses
$dumper = new LicenseDumper();
- $dumper->addExts($extensions)->addLibs($libraries)->addLibs($dynamic_libs)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license');
+ $dumper->addExts($extensions)->addLibs($libraries)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license');
$path = FileSystem::convertPath("{$build_root_path}/license/");
logger()->info("License path{$fixed}: {$path}");
return static::SUCCESS;
@@ -262,13 +270,13 @@ class BuildPHPCommand extends BuildCommand
/**
* Parse build options to rule int.
*/
- private function parseRules(): int
+ private function parseRules(array $dynamic_exts = []): int
{
$rule = BUILD_TARGET_NONE;
$rule |= ($this->getOption('build-cli') ? BUILD_TARGET_CLI : BUILD_TARGET_NONE);
$rule |= ($this->getOption('build-micro') ? BUILD_TARGET_MICRO : BUILD_TARGET_NONE);
$rule |= ($this->getOption('build-fpm') ? BUILD_TARGET_FPM : BUILD_TARGET_NONE);
- $rule |= ($this->getOption('build-embed') ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE);
+ $rule |= ($this->getOption('build-embed') || !empty($dynamic_exts) ? BUILD_TARGET_EMBED : BUILD_TARGET_NONE);
$rule |= ($this->getOption('build-all') ? BUILD_TARGET_ALL : BUILD_TARGET_NONE);
return $rule;
}
diff --git a/src/SPC/command/SPCConfigCommand.php b/src/SPC/command/SPCConfigCommand.php
index 0377ace9..d3c7a0b2 100644
--- a/src/SPC/command/SPCConfigCommand.php
+++ b/src/SPC/command/SPCConfigCommand.php
@@ -37,7 +37,7 @@ class SPCConfigCommand extends BuildCommand
$include_suggest_ext = $this->getOption('with-suggested-exts');
$include_suggest_lib = $this->getOption('with-suggested-libs');
- $util = new SPCConfigUtil(null, $this->input);
+ $util = new SPCConfigUtil();
$config = $util->config($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
if ($this->getOption('includes')) {
diff --git a/src/SPC/command/dev/ExtVerCommand.php b/src/SPC/command/dev/ExtVerCommand.php
index 0f08fa9a..3154a6bb 100644
--- a/src/SPC/command/dev/ExtVerCommand.php
+++ b/src/SPC/command/dev/ExtVerCommand.php
@@ -6,7 +6,6 @@ namespace SPC\command\dev;
use SPC\builder\BuilderProvider;
use SPC\command\BaseCommand;
-use SPC\store\Config;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -31,8 +30,7 @@ class ExtVerCommand extends BaseCommand
// Get lib object
$builder = BuilderProvider::makeBuilderByInput($this->input);
- $ext_conf = Config::getExt($this->getArgument('extension'));
- $builder->proveExts([$this->getArgument('extension')], true);
+ $builder->proveExts([$this->getArgument('extension')], [], true);
// Check whether lib is extracted
// if (!is_dir(SOURCE_PATH . '/' . $this->getArgument('library'))) {
diff --git a/src/SPC/store/Config.php b/src/SPC/store/Config.php
index 07ed2887..29455fa1 100644
--- a/src/SPC/store/Config.php
+++ b/src/SPC/store/Config.php
@@ -106,6 +106,21 @@ class Config
return self::$lib;
}
+ /**
+ * @throws WrongUsageException
+ * @throws FileSystemException
+ */
+ public static function getExtTarget(string $name): ?array
+ {
+ if (self::$ext === null) {
+ self::$ext = FileSystem::loadConfigArray('ext');
+ }
+ if (!isset(self::$ext[$name])) {
+ throw new WrongUsageException('ext [' . $name . '] is not supported yet');
+ }
+ return self::$ext[$name]['target'] ?? ['static'];
+ }
+
/**
* @throws FileSystemException
* @throws WrongUsageException
diff --git a/src/SPC/store/Downloader.php b/src/SPC/store/Downloader.php
index 5644a3c2..fbaeb7a7 100644
--- a/src/SPC/store/Downloader.php
+++ b/src/SPC/store/Downloader.php
@@ -127,10 +127,6 @@ class Downloader
if (!$match_result) {
return $release['assets'];
}
- if ($source['match'] === 'Source code') {
- $url = $release['tarball_url'];
- break;
- }
foreach ($release['assets'] as $asset) {
if (preg_match('|' . $source['match'] . '|', $asset['name'])) {
$url = $asset['browser_download_url'];
@@ -143,9 +139,6 @@ class Downloader
throw new DownloaderException("failed to find {$name} release metadata");
}
$filename = basename($url);
- if ($source['match'] === 'Source code') {
- $filename = $name . $filename . '.tar.gz';
- }
return [$url, $filename];
}
diff --git a/src/SPC/store/SourcePatcher.php b/src/SPC/store/SourcePatcher.php
index d3ffc302..2db3498e 100644
--- a/src/SPC/store/SourcePatcher.php
+++ b/src/SPC/store/SourcePatcher.php
@@ -43,7 +43,7 @@ class SourcePatcher
*/
public static function patchBeforeBuildconf(BuilderBase $builder): void
{
- foreach ($builder->getExts() as $ext) {
+ foreach ($builder->getExts(false) as $ext) {
if ($ext->patchBeforeBuildconf() === true) {
logger()->info('Extension [' . $ext->getName() . '] patched before buildconf');
}
@@ -86,7 +86,7 @@ class SourcePatcher
*/
public static function patchBeforeConfigure(BuilderBase $builder): void
{
- foreach ($builder->getExts() as $ext) {
+ foreach ($builder->getExts(false) as $ext) {
if ($ext->patchBeforeConfigure() === true) {
logger()->info('Extension [' . $ext->getName() . '] patched before configure');
}
@@ -253,7 +253,7 @@ class SourcePatcher
// }
// call extension patch before make
- foreach ($builder->getExts() as $ext) {
+ foreach ($builder->getExts(false) as $ext) {
if ($ext->patchBeforeMake() === true) {
logger()->info('Extension [' . $ext->getName() . '] patched before make');
}
diff --git a/src/SPC/util/DynamicExt.php b/src/SPC/util/DynamicExt.php
deleted file mode 100644
index d5fd549d..00000000
--- a/src/SPC/util/DynamicExt.php
+++ /dev/null
@@ -1,8 +0,0 @@
-getOption('no-strip') ? '-g -O0' : '-g -fstack-protector-strong -fpic -fpie -Os -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'));
- }
}
// Define env vars for linux
diff --git a/src/SPC/util/SPCConfigUtil.php b/src/SPC/util/SPCConfigUtil.php
index f4a121eb..7adf723b 100644
--- a/src/SPC/util/SPCConfigUtil.php
+++ b/src/SPC/util/SPCConfigUtil.php
@@ -9,14 +9,15 @@ use SPC\builder\BuilderProvider;
use SPC\builder\macos\MacOSBuilder;
use SPC\store\Config;
use Symfony\Component\Console\Input\ArgvInput;
-use Symfony\Component\Console\Input\InputInterface;
class SPCConfigUtil
{
- public function __construct(private ?BuilderBase $builder = null, ?InputInterface $input = null)
+ private ?BuilderBase $builder = null;
+
+ public function __construct(?BuilderBase $builder = null)
{
- if ($builder === null) {
- $this->builder = BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
+ if ($builder !== null) {
+ $this->builder = $builder; // BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
}
}
@@ -25,8 +26,11 @@ class SPCConfigUtil
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
ob_start();
- $this->builder->proveLibs($libraries);
- $this->builder->proveExts($extensions);
+ if ($this->builder === null) {
+ $this->builder = BuilderProvider::makeBuilderByInput(new ArgvInput());
+ $this->builder->proveLibs($libraries);
+ $this->builder->proveExts($extensions);
+ }
ob_get_clean();
$ldflags = $this->getLdflagsString();
$libs = $this->getLibsString($libraries);
@@ -47,9 +51,9 @@ class SPCConfigUtil
$libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs);
}
return [
- 'cflags' => $cflags,
- 'ldflags' => $ldflags,
- 'libs' => $libs,
+ 'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags),
+ 'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags),
+ 'libs' => trim(getenv('LIBS') . ' ' . $libs),
];
}
diff --git a/tests/SPC/builder/BuilderTest.php b/tests/SPC/builder/BuilderTest.php
index 5796f5df..17f1e799 100644
--- a/tests/SPC/builder/BuilderTest.php
+++ b/tests/SPC/builder/BuilderTest.php
@@ -72,7 +72,7 @@ class BuilderTest extends TestCase
public function testMakeExtensionArgs()
{
- $this->assertStringContainsString('--enable-mbstring', $this->builder->makeExtensionArgs());
+ $this->assertStringContainsString('--enable-mbstring', $this->builder->makeStaticExtensionArgs());
}
public function testIsLibsOnly()