Compare commits

..

26 Commits

Author SHA1 Message Date
crazywhalecc
645e2a9fc2 update to beta 3 2024-02-17 00:37:09 +08:00
crazywhalecc
d59b8457c6 update composer 2024-02-17 00:33:23 +08:00
crazywhalecc
a2d1262cbf update composer.lock 2024-02-17 00:25:25 +08:00
Jerry Ma
2f9a1e8601 Update release-build.yml 2024-02-17 00:09:46 +08:00
Jerry Ma
b239f60fe4 Update release-build.yml 2024-02-17 00:09:32 +08:00
Jerry Ma
983521e225 Update release-build.yml 2024-02-17 00:07:30 +08:00
Jerry Ma
aeed04a5ec Update release-build.yml 2024-02-17 00:04:02 +08:00
Jerry Ma
be2394b39b Merge pull request #329 from crazywhalecc/suggest-cmd
add with-suggested-libs and with-suggested-exts
2024-02-16 19:36:54 +08:00
crazywhalecc
158298b96c Merge branch 'main' into suggest-cmd
# Conflicts:
#	src/globals/test-extensions.php
2024-02-16 18:58:11 +08:00
crazywhalecc
ffa84f8b91 remove unused exts 2024-02-16 18:57:44 +08:00
crazywhalecc
0954ddcc96 refactor some terminal outputs 2024-02-16 18:57:32 +08:00
crazywhalecc
d9bd96af71 add dependency util tests 2024-02-16 18:57:12 +08:00
crazywhalecc
2649dcd05c add BuilderBase::getPHPVersionFromArchive 2024-02-16 18:56:59 +08:00
crazywhalecc
939db75268 refactor DependencyUtil, use for-libs and for-sources instead of by 2024-02-16 18:56:33 +08:00
Jerry Ma
9777c9aa93 Fix openpty bug for linux (#337)
* fix openpty bug for linux

* add event test

* add download retry for download command

* use test token

* use test token

* use test token

* use test token

* re-fix this bug
2024-02-14 00:49:58 +08:00
Viktor Szépe
b8d8461e61 Fix badges in README (#333)
* Fix badges in README

* Remove Discord badge

* Fix badges in README-zh
2024-02-12 19:59:51 +08:00
Viktor Szépe
b977543c72 Update README.md 2024-02-12 19:12:43 +08:00
Viktor Szépe
4d87cd11cc Update README-zh.md 2024-02-12 19:12:43 +08:00
Viktor Szépe
957daf0547 Update README.md 2024-02-12 19:12:43 +08:00
Viktor Szépe
3dae904122 Update README-zh.md 2024-02-12 19:12:43 +08:00
Viktor Szépe
e835196972 Add language badges to README 2024-02-12 19:12:43 +08:00
crazywhalecc
52ed0e2cee add glibtoolize check for macos 2024-02-07 01:19:54 +08:00
crazywhalecc
1e898d271d add with-suggested-libs and with-suggested-exts 2024-02-06 16:06:09 +08:00
crazywhalecc
39754cde59 add micro patcher for php84 2024-02-06 15:56:47 +08:00
Peter Kokot
a6f7b938e1 Fix PHP version ID 2024-02-05 20:05:54 +08:00
Peter Kokot
0ad501af9a Patch for PHP >= 8.4
FIBER_ASSEMBLER and FIBER_ASM_ARCH Makefile variables in Windows build
system PHP 8.4 have been removed in favor of the PHP_ASSEMBLER and
FIBER_ASM_ABI.
2024-02-05 20:05:54 +08:00
24 changed files with 955 additions and 609 deletions

View File

@@ -15,14 +15,15 @@ jobs:
strategy: strategy:
matrix: matrix:
php-version: php-version:
- "8.1" - "8.2"
micro-version: micro-version:
- "8.1.26" - "8.2.16"
operating-system: operating-system:
- "linux-x86_64" - "linux-x86_64"
- "macos-x86_64" - "macos-x86_64"
- "linux-aarch64" - "linux-aarch64"
- "macos-aarch64" - "macos-aarch64"
- "windows-x64"
steps: steps:
- name: "Checkout" - name: "Checkout"
uses: "actions/checkout@v4" uses: "actions/checkout@v4"
@@ -59,25 +60,45 @@ jobs:
- name: "Download minimal combination" - name: "Download minimal combination"
run: | run: |
curl https://dl.static-php.dev/static-php-cli/minimal/php-${{ matrix.micro-version }}-micro-${{ matrix.operating-system }}.tar.gz -o tmp.tgz if [ "${{ matrix.operating-system }}" = "windows-x64" ]; then
tar -zxvf tmp.tgz curl https://dl.static-php.dev/static-php-cli/windows/spc-min/php-${{ matrix.micro-version }}-micro-win.zip -o tmp.zip
unzip tmp.zip
else
curl https://dl.static-php.dev/static-php-cli/minimal/php-${{ matrix.micro-version }}-micro-${{ matrix.operating-system }}.tar.gz -o tmp.tgz
tar -zxvf tmp.tgz
fi
- name: "Generate Executable" - name: "Generate Executable"
run: | run: |
cat micro.sfx spc.phar > spc if [ "${{ matrix.operating-system }}" = "windows-x64" ]; then
chmod +x spc cat micro.sfx spc.phar > spc.exe
else
cat micro.sfx spc.phar > spc
chmod +x spc
fi
- name: "Archive Executable" - name: "Archive Executable"
run: | run: |
tar -czf spc-${{ matrix.operating-system }}.tar.gz spc if [ "${{ matrix.operating-system }}" != "windows-x64" ]; then
echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV tar -czf spc-${{ matrix.operating-system }}.tar.gz spc
echo "OS=${{ matrix.operating-system }}" >> $GITHUB_ENV echo "filename=spc-${{ matrix.operating-system }}.tar.gz" >> $GITHUB_ENV
if [ "${{ matrix.operating-system }}" == "linux-x86_64" ]; then echo "OS=${{ matrix.operating-system }}" >> $GITHUB_ENV
./spc dev:extensions if [ "${{ matrix.operating-system }}" == "linux-x86_64" ]; then
./spc dev:extensions
fi
else
echo "filename=spc-${{ matrix.operating-system }}.exe" >> $GITHUB_ENV
echo "OS=${{ matrix.operating-system }}" >> $GITHUB_ENV
fi fi
- name: "Copy file" - name: "Copy file"
run: "mkdir dist/ && cp ${{ env.filename }} dist/ && cp spc dist/spc-$OS" run: |
if [ "${{ matrix.operating-system }}" != "windows-x64" ]; then
mkdir dist/ && cp ${{ env.filename }} dist/ && cp spc dist/spc-$OS
else
mkdir dist/ && cp spc.exe dist/${{ env.filename }}
echo "SUFFIX=.exe" >> $GITHUB_ENV
fi
- name: upload binaries to release - name: upload binaries to release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
@@ -100,5 +121,5 @@ jobs:
- name: "Upload Artifact" - name: "Upload Artifact"
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
path: spc path: spc${{ env.SUFFIX }}
name: spc-${{ matrix.operating-system }} name: spc-${{ matrix.operating-system }}${{ env.SUFFIX }}

View File

@@ -129,6 +129,13 @@ jobs:
extensions: curl, openssl, mbstring extensions: curl, openssl, mbstring
ini-values: memory_limit=-1 ini-values: memory_limit=-1
- name: "Use test token if exists"
if: matrix.os != 'windows-latest'
run: |
if [ "${{ secrets.TEST_GH_TOKEN }}" != "" ]; then
echo "GITHUB_TOKEN=${{ secrets.TEST_GH_TOKEN }}" >> $GITHUB_ENV
fi
- name: "Cache Composer packages" - name: "Cache Composer packages"
id: composer-cache id: composer-cache
uses: actions/cache@v3 uses: actions/cache@v3
@@ -152,7 +159,12 @@ jobs:
run: bin/spc doctor --auto-fix run: bin/spc doctor --auto-fix
- name: "Run Build Tests (download)" - name: "Run Build Tests (download)"
run: bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --with-php=${{ matrix.php }} --debug uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: 3
retry_on: error
command: bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --with-php=${{ matrix.php }} --debug
- name: "Run Build Tests (build)" - name: "Run Build Tests (build)"
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php libs_cmd) --build-cli --build-micro --build-fpm --debug run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php libs_cmd) --build-cli --build-micro --build-fpm --debug

View File

@@ -1,10 +1,11 @@
# static-php-cli # static-php-cli
[![Version](https://img.shields.io/packagist/v/crazywhalecc/static-php-cli?include_prereleases&label=Release&style=flat-square)]() [![English readme](https://img.shields.io/badge/README-English%20%F0%9F%87%AC%F0%9F%87%A7-moccasin?style=flat-square)](README.md)
[![](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) [![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)
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]() [![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)
[![](https://img.shields.io/badge/Extension%20Counter-75+-yellow.svg?style=flat-square)]([https://static-php.dev/](https://static-php.dev/en/guide/extensions.html)) [![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)
[![](https://dcbadge.vercel.app/api/server/RNpegEYW?style=flat-square&compact=true&theme=default-inverted)](https://discord.gg/RNpegEYW) [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
[![Extensions](https://img.shields.io/badge/Extension%20Counter-75+-yellow.svg?style=flat-square)](https://static-php.dev/zh/guide/extensions.html)
**static-php-cli**是一个用于静态编译、构建 PHP 解释器的工具,支持众多流行扩展。 **static-php-cli**是一个用于静态编译、构建 PHP 解释器的工具,支持众多流行扩展。
@@ -12,9 +13,6 @@
**static-php-cli**也支持将 PHP 代码和 PHP 运行时打包为一个文件并运行。 **static-php-cli**也支持将 PHP 代码和 PHP 运行时打包为一个文件并运行。
- [README - English](./README.md)
- [README - 中文](./README-zh.md)
## 特性 ## 特性
static-php-cli简称 `spc`)有许多特性: static-php-cli简称 `spc`)有许多特性:

View File

@@ -1,10 +1,11 @@
# static-php-cli # static-php-cli
[![Version](https://img.shields.io/packagist/v/crazywhalecc/static-php-cli?include_prereleases&label=Release&style=flat-square)]() [![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)
[![](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) [![English readme](https://img.shields.io/badge/README-English%20%F0%9F%87%AC%F0%9F%87%A7-moccasin?style=flat-square)](README.md)
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)]() [![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)
[![](https://img.shields.io/badge/Extension%20Counter-75+-yellow.svg?style=flat-square)]([https://static-php.dev/](https://static-php.dev/en/guide/extensions.html)) [![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)
[![](https://dcbadge.vercel.app/api/server/RNpegEYW?style=flat-square&compact=true&theme=default-inverted)](https://discord.gg/RNpegEYW) [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://github.com/crazywhalecc/static-php-cli/blob/main/LICENSE)
[![Extensions](https://img.shields.io/badge/Extension%20Counter-75+-yellow.svg?style=flat-square)](https://static-php.dev/en/guide/extensions.html)
**static-php-cli** is a powerful tool designed for building static, standalone PHP runtime **static-php-cli** is a powerful tool designed for building static, standalone PHP runtime
with popular extensions. with popular extensions.
@@ -14,9 +15,6 @@ Static PHP built by **static-php-cli** supports `cli`, `fpm`, `embed` and `micro
**static-php-cli** also has the ability to package PHP projects **static-php-cli** also has the ability to package PHP projects
along with the PHP interpreter into one single executable file. along with the PHP interpreter into one single executable file.
- [README - English](./README.md)
- [README - 中文](./README-zh.md)
## Features ## Features
static-php-cli (you can call it `spc`) has a lot of features: static-php-cli (you can call it `spc`) has a lot of features:

View File

@@ -14,6 +14,5 @@
"vendor/zhamao" "vendor/zhamao"
], ],
"git-commit-short": "git_commit_short", "git-commit-short": "git_commit_short",
"metadata": "ConsoleApplication::VERSION",
"output": "spc.phar" "output": "spc.phar"
} }

View File

@@ -19,10 +19,10 @@
"captainhook/captainhook": "^5.10", "captainhook/captainhook": "^5.10",
"captainhook/plugin-composer": "^5.3", "captainhook/plugin-composer": "^5.3",
"friendsofphp/php-cs-fixer": "^3.25", "friendsofphp/php-cs-fixer": "^3.25",
"humbug/box": "^4.3", "humbug/box": "^4.5",
"nunomaduro/collision": "^7.8", "nunomaduro/collision": "^7.8",
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.3" "phpunit/phpunit": "^10.3 || ^9"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

940
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -93,13 +93,6 @@
"freetype" "freetype"
] ]
}, },
"gettext": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"gettext"
]
},
"glfw": { "glfw": {
"type": "external", "type": "external",
"arg-type": "custom", "arg-type": "custom",
@@ -313,13 +306,6 @@
"type": "external", "type": "external",
"source": "protobuf" "source": "protobuf"
}, },
"pspell": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"aspell"
]
},
"rar": { "rar": {
"type": "external", "type": "external",
"source": "rar", "source": "rar",
@@ -371,13 +357,6 @@
"apcu" "apcu"
] ]
}, },
"snmp": {
"type": "builtin",
"arg-type": "with",
"lib-depends": [
"net-snmp"
]
},
"soap": { "soap": {
"type": "builtin", "type": "builtin",
"arg-type": "custom", "arg-type": "custom",

View File

@@ -23,7 +23,7 @@ use Symfony\Component\Console\Command\ListCommand;
*/ */
final class ConsoleApplication extends Application final class ConsoleApplication extends Application
{ {
public const VERSION = '2.1.0-beta.2'; public const VERSION = '2.1.0-beta.3';
public function __construct() public function __construct()
{ {

View File

@@ -231,6 +231,30 @@ abstract class BuilderBase
throw new RuntimeException('PHP version file format is malformed, please remove it and download again'); throw new RuntimeException('PHP version file format is malformed, please remove it and download again');
} }
/**
* Get PHP version from archive file name.
*
* @param null|string $file php-*.*.*.tar.gz filename, read from lockfile if empty
*/
public function getPHPVersionFromArchive(?string $file = null): false|string
{
if ($file === null) {
$lock = file_exists(DOWNLOAD_PATH . '/.lock.json') ? file_get_contents(DOWNLOAD_PATH . '/.lock.json') : false;
if ($lock === false) {
return false;
}
$lock = json_decode($lock, true);
$file = $lock['php-src']['filename'] ?? null;
if ($file === null) {
return false;
}
}
if (preg_match('/php-(\d+\.\d+\.\d+)/', $file, $match)) {
return $match[1];
}
return false;
}
/** /**
* Get build type name string to display. * Get build type name string to display.
* *

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension; namespace SPC\builder\extension;
use SPC\builder\Extension; use SPC\builder\Extension;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\util\CustomExt; use SPC\util\CustomExt;
@@ -34,4 +35,16 @@ class event extends Extension
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-levent_openssl/', $this->getLibFilesString()); FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-levent_openssl/', $this->getLibFilesString());
return true; return true;
} }
/**
* @throws FileSystemException
*/
public function patchBeforeMake(): bool
{
// 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', '');
}
return true;
}
} }

View File

@@ -107,7 +107,7 @@ abstract class UnixBuilderBase extends BuilderBase
// if no libs specified, compile all supported libs // if no libs specified, compile all supported libs
if ($sorted_libraries === [] && $this->isLibsOnly()) { if ($sorted_libraries === [] && $this->isLibsOnly()) {
$libraries = array_keys($support_lib_list); $libraries = array_keys($support_lib_list);
$sorted_libraries = DependencyUtil::getLibsByDeps($libraries); $sorted_libraries = DependencyUtil::getLibs($libraries);
} }
// pkg-config must be compiled first, whether it is specified or not // pkg-config must be compiled first, whether it is specified or not

View File

@@ -150,6 +150,8 @@ class WindowsBuilder extends BuilderBase
$makefile = FileSystem::readFile(SOURCE_PATH . '\php-src\Makefile'); $makefile = FileSystem::readFile(SOURCE_PATH . '\php-src\Makefile');
if ($this->getPHPVersionID() >= 80200 && str_contains($makefile, 'FIBER_ASM_ARCH')) { if ($this->getPHPVersionID() >= 80200 && str_contains($makefile, 'FIBER_ASM_ARCH')) {
$makefile .= "\r\n" . '$(MICRO_SFX): $(BUILD_DIR)\Zend\jump_$(FIBER_ASM_ARCH)_ms_pe_masm.obj $(BUILD_DIR)\Zend\make_$(FIBER_ASM_ARCH)_ms_pe_masm.obj' . "\r\n\r\n"; $makefile .= "\r\n" . '$(MICRO_SFX): $(BUILD_DIR)\Zend\jump_$(FIBER_ASM_ARCH)_ms_pe_masm.obj $(BUILD_DIR)\Zend\make_$(FIBER_ASM_ARCH)_ms_pe_masm.obj' . "\r\n\r\n";
} elseif ($this->getPHPVersionID() >= 80400 && str_contains($makefile, 'FIBER_ASM_ABI')) {
$makefile .= "\r\n" . '$(MICRO_SFX): $(BUILD_DIR)\Zend\jump_$(FIBER_ASM_ABI).obj $(BUILD_DIR)\Zend\make_$(FIBER_ASM_ABI).obj' . "\r\n\r\n";
} }
FileSystem::writeFile(SOURCE_PATH . '\php-src\Makefile', $makefile); FileSystem::writeFile(SOURCE_PATH . '\php-src\Makefile', $makefile);
@@ -190,7 +192,7 @@ class WindowsBuilder extends BuilderBase
// if no libs specified, compile all supported libs // if no libs specified, compile all supported libs
if ($sorted_libraries === [] && $this->isLibsOnly()) { if ($sorted_libraries === [] && $this->isLibsOnly()) {
$libraries = array_keys($support_lib_list); $libraries = array_keys($support_lib_list);
$sorted_libraries = DependencyUtil::getLibsByDeps($libraries); $sorted_libraries = DependencyUtil::getLibs($libraries);
} }
// add lib object for builder // add lib object for builder

View File

@@ -23,11 +23,11 @@ class BuildCliCommand extends BuildCommand
{ {
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extensions will be compiled, comma separated'); $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('with-libs', null, InputOption::VALUE_REQUIRED, 'add additional libraries, comma separated', '');
$this->addOption('build-micro', null, null, 'build micro'); $this->addOption('build-micro', null, null, 'Build micro SAPI');
$this->addOption('build-cli', null, null, 'build cli'); $this->addOption('build-cli', null, null, 'Build cli SAPI');
$this->addOption('build-fpm', null, null, 'build fpm'); $this->addOption('build-fpm', null, null, 'Build fpm SAPI');
$this->addOption('build-embed', null, null, 'build embed'); $this->addOption('build-embed', null, null, 'Build embed SAPI');
$this->addOption('build-all', null, null, 'build cli, micro, fpm, embed'); $this->addOption('build-all', null, null, 'Build all SAPI');
$this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions'); $this->addOption('no-strip', null, null, 'build without strip, in order to debug and load external extensions');
$this->addOption('enable-zts', null, null, 'enable ZTS support'); $this->addOption('enable-zts', null, null, 'enable ZTS support');
$this->addOption('disable-opcache-jit', null, null, 'disable opcache jit'); $this->addOption('disable-opcache-jit', null, null, 'disable opcache jit');
@@ -61,8 +61,9 @@ class BuildCliCommand extends BuildCommand
try { try {
// create builder // create builder
$builder = BuilderProvider::makeBuilderByInput($this->input); $builder = BuilderProvider::makeBuilderByInput($this->input);
// calculate dependencies $include_suggest_ext = $this->getOption('with-suggested-exts');
[$extensions, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps($extensions, $libraries); $include_suggest_lib = $this->getOption('with-suggested-libs');
[$extensions, $libraries, $not_included] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
// print info // print info
$indent_texts = [ $indent_texts = [
@@ -76,12 +77,23 @@ class BuildCliCommand extends BuildCommand
if (!empty($this->input->getOption('with-hardcoded-ini'))) { if (!empty($this->input->getOption('with-hardcoded-ini'))) {
$indent_texts['Hardcoded INI'] = $this->input->getOption('with-hardcoded-ini'); $indent_texts['Hardcoded INI'] = $this->input->getOption('with-hardcoded-ini');
} }
$this->printFormatInfo($indent_texts); if ($this->input->getOption('disable-opcache-jit')) {
$indent_texts['Opcache JIT'] = 'disabled';
}
try {
$ver = $builder->getPHPVersion();
$indent_texts['PHP Version'] = $ver;
} catch (\Throwable) {
if (($ver = $builder->getPHPVersionFromArchive()) !== false) {
$indent_texts['PHP Version'] = $ver;
}
}
if (!empty($not_included)) { if (!empty($not_included)) {
logger()->warning('Some extensions will be enabled due to dependencies: ' . implode(',', $not_included)); $indent_texts['Extra Exts (' . count($not_included) . ')'] = implode(', ', $not_included);
} }
logger()->info('Build will start after 2s ...'); $this->printFormatInfo($indent_texts);
logger()->notice('Build will start after 2s ...');
sleep(2); sleep(2);
if ($this->input->getOption('with-clean')) { if ($this->input->getOption('with-clean')) {

View File

@@ -60,7 +60,7 @@ class BuildLibsCommand extends BuildCommand
// 只编译 library 的情况下,标记 // 只编译 library 的情况下,标记
$builder->setLibsOnly(); $builder->setLibsOnly();
// 编译和检查库完整 // 编译和检查库完整
$libraries = DependencyUtil::getLibsByDeps($libraries); $libraries = DependencyUtil::getLibs($libraries);
$builder->buildLibs($libraries); $builder->buildLibs($libraries);
$time = round(microtime(true) - START_TIME, 3); $time = round(microtime(true) - START_TIME, 3);

View File

@@ -214,7 +214,7 @@ class DownloadCommand extends BaseCommand
*/ */
private function calculateSourcesByExt(array $extensions, bool $include_suggests = true): array private function calculateSourcesByExt(array $extensions, bool $include_suggests = true): array
{ {
[$extensions, $libraries] = $include_suggests ? DependencyUtil::getAllExtLibsByDeps($extensions) : DependencyUtil::getExtLibsByDeps($extensions); [$extensions, $libraries] = $include_suggests ? DependencyUtil::getExtsAndLibs($extensions, [], true, true) : DependencyUtil::getExtsAndLibs($extensions);
$sources = []; $sources = [];
foreach ($extensions as $extension) { foreach ($extensions as $extension) {
if (Config::getExt($extension, 'type') === 'external') { if (Config::getExt($extension, 'type') === 'external') {

View File

@@ -22,8 +22,8 @@ class DumpLicenseCommand extends BaseCommand
{ {
$this->addOption('for-extensions', null, InputOption::VALUE_REQUIRED, 'Dump by extensions and related libraries', null); $this->addOption('for-extensions', null, InputOption::VALUE_REQUIRED, 'Dump by extensions and related libraries', null);
$this->addOption('without-php', null, InputOption::VALUE_NONE, 'Dump without php-src'); $this->addOption('without-php', null, InputOption::VALUE_NONE, 'Dump without php-src');
$this->addOption('by-libs', null, InputOption::VALUE_REQUIRED, 'Dump by libraries', null); $this->addOption('for-libs', null, InputOption::VALUE_REQUIRED, 'Dump by libraries', null);
$this->addOption('by-sources', null, InputOption::VALUE_REQUIRED, 'Dump by original sources (source.json)', null); $this->addOption('for-sources', null, InputOption::VALUE_REQUIRED, 'Dump by original sources (source.json)', null);
$this->addOption('dump-dir', null, InputOption::VALUE_REQUIRED, 'Change dump directory', BUILD_ROOT_PATH . '/license'); $this->addOption('dump-dir', null, InputOption::VALUE_REQUIRED, 'Change dump directory', BUILD_ROOT_PATH . '/license');
} }
@@ -39,7 +39,7 @@ class DumpLicenseCommand extends BaseCommand
// 从参数中获取要编译的 extensions并转换为数组 // 从参数中获取要编译的 extensions并转换为数组
$extensions = array_map('trim', array_filter(explode(',', $this->getOption('for-extensions')))); $extensions = array_map('trim', array_filter(explode(',', $this->getOption('for-extensions'))));
// 根据提供的扩展列表获取依赖库列表并编译 // 根据提供的扩展列表获取依赖库列表并编译
[$extensions, $libraries] = DependencyUtil::getExtLibsByDeps($extensions); [$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions);
$dumper->addExts($extensions); $dumper->addExts($extensions);
$dumper->addLibs($libraries); $dumper->addLibs($libraries);
if (!$this->getOption('without-php')) { if (!$this->getOption('without-php')) {
@@ -52,22 +52,22 @@ class DumpLicenseCommand extends BaseCommand
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir')); $this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
return static::SUCCESS; return static::SUCCESS;
} }
if ($this->getOption('by-libs') !== null) { if ($this->getOption('for-libs') !== null) {
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('by-libs')))); $libraries = array_map('trim', array_filter(explode(',', $this->getOption('for-libs'))));
$libraries = DependencyUtil::getLibsByDeps($libraries); $libraries = DependencyUtil::getLibs($libraries);
$dumper->addLibs($libraries); $dumper->addLibs($libraries);
$dumper->dump($this->getOption('dump-dir')); $dumper->dump($this->getOption('dump-dir'));
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir')); $this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
return static::SUCCESS; return static::SUCCESS;
} }
if ($this->getOption('by-sources') !== null) { if ($this->getOption('for-sources') !== null) {
$sources = array_map('trim', array_filter(explode(',', $this->getOption('by-sources')))); $sources = array_map('trim', array_filter(explode(',', $this->getOption('for-sources'))));
$dumper->addSources($sources); $dumper->addSources($sources);
$dumper->dump($this->getOption('dump-dir')); $dumper->dump($this->getOption('dump-dir'));
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir')); $this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
return static::SUCCESS; return static::SUCCESS;
} }
$this->output->writeln('You must use one of "--for-extensions=", "--by-libs=", "--by-sources=" to dump'); $this->output->writeln('You must use one of "--for-extensions=", "--for-libs=", "--for-sources=" to dump');
return static::FAILURE; return static::FAILURE;
} }
} }

View File

@@ -15,8 +15,6 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Style\SymfonyStyle;
use function Laravel\Prompts\table;
#[AsCommand('dev:extensions', 'Helper command that lists available extension details', ['list-ext'])] #[AsCommand('dev:extensions', 'Helper command that lists available extension details', ['list-ext'])]
class AllExtCommand extends BaseCommand class AllExtCommand extends BaseCommand
{ {
@@ -61,7 +59,7 @@ class AllExtCommand extends BaseCommand
} }
try { try {
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]); [, $libraries, $not_included] = DependencyUtil::getExtsAndLibs([$extension]);
} catch (WrongUsageException) { } catch (WrongUsageException) {
$libraries = $not_included = []; $libraries = $not_included = [];
} }
@@ -88,7 +86,8 @@ class AllExtCommand extends BaseCommand
if ($data === []) { if ($data === []) {
$style->warning('Unknown extension selected: ' . implode(',', $extensions)); $style->warning('Unknown extension selected: ' . implode(',', $extensions));
} else { } else {
table($columns, $data); $func = PHP_OS_FAMILY === 'Windows' ? [$style, 'table'] : '\Laravel\Prompts\table';
call_user_func($func, $columns, $data);
} }
return static::SUCCESS; return static::SUCCESS;

View File

@@ -31,6 +31,7 @@ class MacOSToolCheckList
'gzip', 'gzip',
'bzip2', 'bzip2',
'cmake', 'cmake',
'glibtoolize',
]; ];
#[AsCheckItem('if homebrew has installed', limit_os: 'Darwin', level: 998)] #[AsCheckItem('if homebrew has installed', limit_os: 'Darwin', level: 998)]
@@ -72,8 +73,14 @@ class MacOSToolCheckList
#[AsFixItem('build-tools')] #[AsFixItem('build-tools')]
public function fixBuildTools(array $missing): bool public function fixBuildTools(array $missing): bool
{ {
$replacement = [
'glibtoolize' => 'libtool',
];
foreach ($missing as $cmd) { foreach ($missing as $cmd) {
try { try {
if (isset($replacement[$cmd])) {
$cmd = $replacement[$cmd];
}
shell(true)->exec('brew install --formula ' . escapeshellarg($cmd)); shell(true)->exec('brew install --formula ' . escapeshellarg($cmd));
} catch (RuntimeException) { } catch (RuntimeException) {
return false; return false;

View File

@@ -227,8 +227,12 @@ class FileSystem
{ {
$dir = self::convertPath($dir); $dir = self::convertPath($dir);
// 不是目录不扫,直接 false 处理 // 不是目录不扫,直接 false 处理
if (!file_exists($dir)) {
logger()->debug('Scan dir failed, no such file or directory.');
return false;
}
if (!is_dir($dir)) { if (!is_dir($dir)) {
logger()->warning('Scan dir failed, no such directory.'); logger()->warning('Scan dir failed, not directory.');
return false; return false;
} }
logger()->debug('scanning directory ' . $dir); logger()->debug('scanning directory ' . $dir);
@@ -317,8 +321,12 @@ class FileSystem
$dir = FileSystem::convertPath($dir); $dir = FileSystem::convertPath($dir);
logger()->debug('Removing path recursively: "' . $dir . '"'); logger()->debug('Removing path recursively: "' . $dir . '"');
// 不是目录不扫,直接 false 处理 // 不是目录不扫,直接 false 处理
if (!file_exists($dir)) {
logger()->debug('Scan dir failed, no such file or directory.');
return false;
}
if (!is_dir($dir)) { if (!is_dir($dir)) {
logger()->warning('Scan dir failed, no such directory.'); logger()->warning('Scan dir failed, not directory.');
return false; return false;
} }
logger()->debug('scanning directory ' . $dir); logger()->debug('scanning directory ' . $dir);

View File

@@ -106,7 +106,7 @@ class SourcePatcher
} }
$patch_list = $list ?? $default; $patch_list = $list ?? $default;
$patches = []; $patches = [];
$serial = ['80', '81', '82', '83']; $serial = ['80', '81', '82', '83', '84'];
foreach ($patch_list as $patchName) { foreach ($patch_list as $patchName) {
if (file_exists(SOURCE_PATH . "/php-src/sapi/micro/patches/{$patchName}.patch")) { if (file_exists(SOURCE_PATH . "/php-src/sapi/micro/patches/{$patchName}.patch")) {
$patches[] = "sapi/micro/patches/{$patchName}.patch"; $patches[] = "sapi/micro/patches/{$patchName}.patch";
@@ -197,7 +197,6 @@ class SourcePatcher
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', ''); FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', '');
} }
if ($builder instanceof UnixBuilderBase) { if ($builder instanceof UnixBuilderBase) {
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', ''); FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
} }

View File

@@ -5,90 +5,164 @@ declare(strict_types=1);
namespace SPC\util; namespace SPC\util;
use SPC\exception\FileSystemException; use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\store\Config; use SPC\store\Config;
/** /**
* 依赖处理工具类,包含处理扩展、库的依赖列表顺序等 * Dependency processing tool class, including processing extensions, library dependency list order, etc.
*/ */
class DependencyUtil class DependencyUtil
{ {
/** /**
* Obtain the dependent lib list according to the required ext list, and sort according to the dependency * Convert platform extensions to library dependencies and suggestions.
* *
* @param array $exts extensions list
* @param array $additional_libs List of additional libraries to add to activate the extra library features triggered by lib-suggests
* @return array Returns an array containing three arrays, [extensions, libraries, not included extensions]
* @throws WrongUsageException * @throws WrongUsageException
* @throws RuntimeException
* @throws FileSystemException * @throws FileSystemException
*/ */
public static function getExtLibsByDeps(array $exts, array $additional_libs = []): array public static function platExtToLibs(): array
{ {
$sorted = []; $exts = Config::getExts();
$visited = []; $libs = Config::getLibs();
$not_included_exts = []; $dep_list = [];
foreach ($exts as $ext) { foreach ($exts as $ext_name => $ext) {
if (!isset($visited[$ext])) { // convert ext-depends value to ext@xxx
self::visitExtDeps($ext, $visited, $sorted); $ext_depends = Config::getExt($ext_name, 'ext-depends', []);
} $ext_depends = array_map(fn ($x) => "ext@{$x}", $ext_depends);
// convert ext-suggests value to ext@xxx
$ext_suggests = Config::getExt($ext_name, 'ext-suggests', []);
$ext_suggests = array_map(fn ($x) => "ext@{$x}", $ext_suggests);
// merge ext-depends with lib-depends
$lib_depends = Config::getExt($ext_name, 'lib-depends', []);
$depends = array_merge($ext_depends, $lib_depends);
// merge ext-suggests with lib-suggests
$lib_suggests = Config::getExt($ext_name, 'lib-suggests', []);
$suggests = array_merge($ext_suggests, $lib_suggests);
$dep_list["ext@{$ext_name}"] = [
'depends' => $depends,
'suggests' => $suggests,
];
} }
$sorted_suggests = []; foreach ($libs as $lib_name => $lib) {
$visited_suggests = []; $dep_list[$lib_name] = [
$final = []; 'depends' => Config::getLib($lib_name, 'lib-depends', []),
foreach ($exts as $ext) { 'suggests' => Config::getLib($lib_name, 'lib-suggests', []),
if (!isset($visited_suggests[$ext])) { ];
self::visitExtAllDeps($ext, $visited_suggests, $sorted_suggests);
}
} }
foreach ($sorted_suggests as $suggest) { // here is an array that only contains dependency map
if (in_array($suggest, $sorted)) { return $dep_list;
$final[] = $suggest;
}
}
$libs = $additional_libs;
foreach ($final as $ext) {
if (!in_array($ext, $exts)) {
$not_included_exts[] = $ext;
}
foreach (Config::getExt($ext, 'lib-depends', []) as $lib) {
if (!in_array($lib, $libs)) {
$libs[] = $lib;
}
}
}
return [$final, self::getLibsByDeps($libs), $not_included_exts];
} }
/** /**
* 根据 lib 库的依赖关系进行一个排序,同时返回多出来的依赖列表
*
* @param array $libs 要排序的 libs 列表
* @return array 排序后的列表
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException * @throws WrongUsageException
* @throws FileSystemException
*/ */
public static function getLibsByDeps(array $libs): array public static function getLibs(array $libs, bool $include_suggested_libs = false): array
{ {
$sorted = []; $dep_list = self::platExtToLibs();
$visited = [];
// 遍历所有 if ($include_suggested_libs) {
foreach ($libs as $lib) { foreach ($dep_list as $name => $obj) {
if (!isset($visited[$lib])) { foreach ($obj['suggests'] as $id => $suggest) {
self::visitLibDeps($lib, $visited, $sorted); if (!str_starts_with($suggest, 'ext@')) {
$dep_list[$name]['depends'][] = $suggest;
array_splice($dep_list[$name]['suggests'], $id, 1);
}
}
} }
} }
$final = self::doVisitPlat($libs, $dep_list);
$libs_final = [];
foreach ($final as $item) {
if (!str_starts_with($item, 'ext@')) {
$libs_final[] = $item;
}
}
return $libs_final;
}
/**
* @throws FileSystemException|WrongUsageException
*/
public static function getExtsAndLibs(array $exts, array $additional_libs = [], bool $include_suggested_exts = false, bool $include_suggested_libs = false): array
{
$dep_list = self::platExtToLibs();
// include suggested extensions
if ($include_suggested_exts) {
// check every deps suggests contains ext@
foreach ($dep_list as $name => $obj) {
foreach ($obj['suggests'] as $id => $suggest) {
if (str_starts_with($suggest, 'ext@')) {
$dep_list[$name]['depends'][] = $suggest;
array_splice($dep_list[$name]['suggests'], $id, 1);
}
}
}
}
// include suggested libraries
if ($include_suggested_libs) {
// check every deps suggests
foreach ($dep_list as $name => $obj) {
foreach ($obj['suggests'] as $id => $suggest) {
if (!str_starts_with($suggest, 'ext@')) {
$dep_list[$name]['depends'][] = $suggest;
array_splice($dep_list[$name]['suggests'], $id, 1);
}
}
}
}
// convert ext_name to ext@ext_name
$origin_exts = $exts;
$exts = array_map(fn ($x) => "ext@{$x}", $exts);
$exts = array_merge($exts, $additional_libs);
$final = self::doVisitPlat($exts, $dep_list);
// revert array
$exts_final = [];
$libs_final = [];
$not_included_final = [];
foreach ($final as $item) {
if (str_starts_with($item, 'ext@')) {
$tmp = substr($item, 4);
if (!in_array($tmp, $origin_exts)) {
$not_included_final[] = $tmp;
}
$exts_final[] = $tmp;
} else {
$libs_final[] = $item;
}
}
return [$exts_final, $libs_final, $not_included_final];
}
/**
* @throws WrongUsageException
*/
private static function doVisitPlat(array $deps, array $dep_list): array
{
// default: get extension exts and libs sorted by dep_list
$sorted = [];
$visited = [];
foreach ($deps as $ext_name) {
if (!isset($dep_list[$ext_name])) {
$ext_name = str_starts_with($ext_name, 'ext@') ? ('Extension [' . substr($ext_name, 4) . ']') : ('Library [' . $ext_name . ']');
throw new WrongUsageException("{$ext_name} not exist !");
}
if (!isset($visited[$ext_name])) {
self::visitPlatDeps($ext_name, $dep_list, $visited, $sorted);
}
}
$sorted_suggests = []; $sorted_suggests = [];
$visited_suggests = []; $visited_suggests = [];
$final = []; $final = [];
foreach ($libs as $lib) { foreach ($deps as $ext_name) {
if (!isset($visited_suggests[$lib])) { if (!isset($visited_suggests[$ext_name])) {
self::visitLibAllDeps($lib, $visited_suggests, $sorted_suggests); self::visitPlatAllDeps($ext_name, $dep_list, $visited_suggests, $sorted_suggests);
} }
} }
foreach ($sorted_suggests as $suggest) { foreach ($sorted_suggests as $suggest) {
@@ -99,49 +173,7 @@ class DependencyUtil
return $final; return $final;
} }
public static function getAllExtLibsByDeps(array $exts): array private static function visitPlatAllDeps(string $lib_name, array $dep_list, array &$visited, array &$sorted): void
{
$sorted = [];
$visited = [];
$not_included_exts = [];
foreach ($exts as $ext) {
if (!isset($visited[$ext])) {
self::visitExtAllDeps($ext, $visited, $sorted);
}
}
$libs = [];
foreach ($sorted as $ext) {
if (!in_array($ext, $exts)) {
$not_included_exts[] = $ext;
}
foreach (array_merge(Config::getExt($ext, 'lib-depends', []), Config::getExt($ext, 'lib-suggests', [])) as $dep) {
if (!in_array($dep, $libs)) {
$libs[] = $dep;
}
}
}
return [$sorted, self::getAllLibsByDeps($libs), $not_included_exts];
}
public static function getAllLibsByDeps(array $libs): array
{
$sorted = [];
$visited = [];
foreach ($libs as $lib) {
if (!isset($visited[$lib])) {
self::visitLibAllDeps($lib, $visited, $sorted);
}
}
return $sorted;
}
/**
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
private static function visitLibAllDeps(string $lib_name, array &$visited, array &$sorted): void
{ {
// 如果已经识别到了,那就不管 // 如果已经识别到了,那就不管
if (isset($visited[$lib_name])) { if (isset($visited[$lib_name])) {
@@ -149,37 +181,13 @@ class DependencyUtil
} }
$visited[$lib_name] = true; $visited[$lib_name] = true;
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常) // 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
foreach (array_merge(Config::getLib($lib_name, 'lib-depends', []), Config::getLib($lib_name, 'lib-suggests', [])) as $dep) { foreach (array_merge($dep_list[$lib_name]['depends'], $dep_list[$lib_name]['suggests']) as $dep) {
self::visitLibDeps($dep, $visited, $sorted); self::visitPlatAllDeps($dep, $dep_list, $visited, $sorted);
} }
$sorted[] = $lib_name; $sorted[] = $lib_name;
} }
/** private static function visitPlatDeps(string $lib_name, array $dep_list, array &$visited, array &$sorted): void
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
private static function visitExtAllDeps(string $ext_name, array &$visited, array &$sorted): void
{
// 如果已经识别到了,那就不管
if (isset($visited[$ext_name])) {
return;
}
$visited[$ext_name] = true;
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
foreach (array_merge(Config::getExt($ext_name, 'ext-depends', []), Config::getExt($ext_name, 'ext-suggests', [])) as $dep) {
self::visitExtDeps($dep, $visited, $sorted);
}
$sorted[] = $ext_name;
}
/**
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
private static function visitLibDeps(string $lib_name, array &$visited, array &$sorted): void
{ {
// 如果已经识别到了,那就不管 // 如果已经识别到了,那就不管
if (isset($visited[$lib_name])) { if (isset($visited[$lib_name])) {
@@ -187,26 +195,9 @@ class DependencyUtil
} }
$visited[$lib_name] = true; $visited[$lib_name] = true;
// 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常) // 遍历该依赖的所有依赖(此处的 getLib 如果检测到当前库不存在的话,会抛出异常)
foreach (Config::getLib($lib_name, 'lib-depends', []) as $dep) { foreach ($dep_list[$lib_name]['depends'] as $dep) {
self::visitLibDeps($dep, $visited, $sorted); self::visitPlatDeps($dep, $dep_list, $visited, $sorted);
} }
$sorted[] = $lib_name; $sorted[] = $lib_name;
} }
/**
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
*/
private static function visitExtDeps(string $ext_name, array &$visited, array &$sorted): void
{
if (isset($visited[$ext_name])) {
return;
}
$visited[$ext_name] = true;
foreach (Config::getExt($ext_name, 'ext-depends', []) as $dep) {
self::visitExtDeps($dep, $visited, $sorted);
}
$sorted[] = $ext_name;
}
} }

View File

@@ -13,8 +13,8 @@ declare(strict_types=1);
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`). // If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) { $extensions = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'calendar,ctype,curl,dom,fileinfo,filter,gd,iconv,imagick,mbregex,mbstring,mysqli,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,rar,redis,session,simplexml,soap,sockets,sqlite3,swoole,swoole-hook-mysql,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib', 'Linux', 'Darwin' => '',
'Windows' => 'mbstring,openssl', 'Windows' => 'mbstring',
}; };
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`). // If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
@@ -27,7 +27,7 @@ $with_libs = match (PHP_OS_FAMILY) {
// You can use `common`, `bulk`, `minimal` or `none`. // You can use `common`, `bulk`, `minimal` or `none`.
// note: combination is only available for *nix platform. Windows must use `none` combination // note: combination is only available for *nix platform. Windows must use `none` combination
$base_combination = match (PHP_OS_FAMILY) { $base_combination = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'none', 'Linux', 'Darwin' => 'common',
'Windows' => 'none', 'Windows' => 'none',
}; };

View File

@@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
namespace SPC\Tests\util;
use PHPUnit\Framework\TestCase;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\util\DependencyUtil;
/**
* @internal
*/
final class DependencyUtilTest extends TestCase
{
public function testGetExtLibsByDeps(): void
{
// example
Config::$source = [
'test1' => [
'type' => 'url',
'url' => 'https://pecl.php.net/get/APCu',
'filename' => 'apcu.tgz',
'license' => [
'type' => 'file',
'path' => 'LICENSE',
],
],
];
Config::$lib = [
'libaaa' => [
'source' => 'test1',
'static-libs' => ['libaaa.a'],
'lib-depends' => ['libbbb', 'libccc'],
'lib-suggests' => ['libeee'],
],
'libbbb' => [
'source' => 'test1',
'static-libs' => ['libbbb.a'],
'lib-suggests' => ['libccc'],
],
'libccc' => [
'source' => 'test1',
'static-libs' => ['libccc.a'],
],
'libeee' => [
'source' => 'test1',
'static-libs' => ['libeee.a'],
'lib-suggests' => ['libfff'],
],
'libfff' => [
'source' => 'test1',
'static-libs' => ['libfff.a'],
],
];
Config::$ext = [
'ext-a' => [
'type' => 'builtin',
'lib-depends' => ['libaaa'],
'ext-suggests' => ['ext-b'],
],
'ext-b' => [
'type' => 'builtin',
'lib-depends' => ['libeee'],
],
];
// test getExtLibsByDeps (notmal test with ext-depends and lib-depends)
[$exts, $libs, $not_included] = DependencyUtil::getExtsAndLibs(['ext-a'], include_suggested_exts: true);
$this->assertContains('libbbb', $libs);
$this->assertContains('libccc', $libs);
$this->assertContains('ext-b', $exts);
$this->assertContains('ext-b', $not_included);
// test dep order
$this->assertIsInt($b = array_search('libbbb', $libs));
$this->assertIsInt($c = array_search('libccc', $libs));
$this->assertIsInt($a = array_search('libaaa', $libs));
// libbbb, libaaa
$this->assertTrue($b < $a);
$this->assertTrue($c < $a);
$this->assertTrue($c < $b);
}
public function testNotExistExtException(): void
{
$this->expectException(WrongUsageException::class);
DependencyUtil::getExtsAndLibs(['sdsd']);
}
}