Compare commits

..

30 Commits

Author SHA1 Message Date
crazywhalecc
eb00e0012f Add getLibVersion and getExtVersion method for extensions and libs 2024-06-30 23:25:58 +08:00
crazywhalecc
f645c8869a Add prefer-stable option for ghrel, ghtar, ghtagtar 2024-06-30 23:25:58 +08:00
crazywhalecc
351e391221 --ignore-cache-sources now support empty values (force all download) 2024-06-30 23:25:58 +08:00
crazywhalecc
1d78a231db Add target dir to extract hook 2024-06-30 23:25:58 +08:00
crazywhalecc
9463cf94ca Prevent constructing builder without --arch options error 2024-06-30 23:25:58 +08:00
crazywhalecc
ba127f4e00 Use extra files instead of internal patch block for libyaml 2024-06-30 23:25:58 +08:00
crazywhalecc
d4da18e869 Disable getCpuCount log 2024-06-30 23:25:58 +08:00
crazywhalecc
334a3bdf5d Add extension swow for Windows 2024-06-30 01:12:20 +08:00
crazywhalecc
a1f632e8c9 Add apcu test 2024-06-30 00:41:41 +08:00
crazywhalecc
3445a2cd58 Add extension tests 2024-06-30 00:41:41 +08:00
crazywhalecc
3100911802 Add several extensions and libs for windows
exts: bz2, sqlsrv, pdo_sqlsrv, yaml, zip, rar
libs: bzip2, libyaml, libzip, xz
2024-06-30 00:41:41 +08:00
crazywhalecc
a6236eb98c Bump version 2024-06-30 00:41:41 +08:00
crazywhalecc
c22488ec57 Add pcre as internal extension 2024-06-30 00:41:41 +08:00
Jerry Ma
0857a19c3c Increase memory_limit size (#485) 2024-06-28 12:14:36 +08:00
Jerry Ma
2a03c32bc0 Add full gd support on Windows (#484)
* Add full gd support (libjpeg, libpng, libwebp, libavif, freetype), and related patches

* cs fix

* Fix PHP 8.0 gd build
2024-06-26 20:35:11 +08:00
Jerry Ma
0b8a0504a2 Update GMP ver, using official 6.3.0 version (#483)
* Update GMP ver, using official 6.3.0 version

* Add GMP test
2024-06-26 11:30:19 +08:00
Kévin Dunglas
e9aff8f1d8 fix: error when building libtiff (#481)
* fix: error when building libtiff

* Update test-extensions.php

* Add test token

* Fix windows builds

* Fix token

* Fix token

* Test token

* Test token

* Test token

---------

Co-authored-by: Jerry Ma <jesse2061@outlook.com>
2024-06-25 12:38:38 +08:00
Jerry Ma
93cb7e9fbb Add phpmicro win32 mode support (#478)
* Add phpmicro win32 mode support

* Bump version to 2.2.4

* Add micro win32 build tests for actions

* cs-fix and update deps
2024-06-20 14:46:08 +08:00
DubbleClick
2d2607cd7f replace ext-zend-opcache with ext-opcache for spc extension list (#475)
* replace ext-zend-opcache with ext-opcache for spc extension list

* Use constant to set internal and filter extensions

---------

Co-authored-by: Marc Henderkes <m.henderkes@pc-college.de>
Co-authored-by: crazywhalecc <jesse2061@outlook.com>
2024-06-09 19:38:50 +08:00
Jerry Ma
d80406b8e0 Remove mongodb notes (#474)
* Ignore passed internal extensions

* Add tests

* Add tests

* Remove mongodb notes

* Remove mongodb notes
2024-06-06 01:17:23 +08:00
Jerry Ma
db9645641f Ignore passed internal extensions (#473)
* Ignore passed internal extensions

* Add tests

* Add tests
2024-06-05 23:20:21 +08:00
crazywhalecc
b3018af61c Fix mongodb support on macOS 2024-06-05 13:12:25 +08:00
Jerry Ma
7e6c2b4432 Fix xlswriter with openssl conflict bug (#472)
* Fix xlswriter with openssl conflict bug

* bump version to 2.2.3
2024-06-04 19:31:13 +08:00
crazywhalecc
1ae1c81f9c fix libxml2 patch for older php (limit only to 80, 81) 2024-06-04 12:40:21 +08:00
crazywhalecc
eff698cbe8 fix libxml2 patch for older php (limit only to 80, 81) 2024-06-04 12:30:46 +08:00
Jerry Ma
036e4f52b7 Prevent use building uv on 7.4 (#471)
* Prevent use building uv on 7.4

* Add swoole test

* Use github source for libcares

* Add libcares missing file patch

* Add libcares missing file patch
2024-06-04 12:24:52 +08:00
Jerry Ma
d258417afb Fix several patches & newer phpmicro support (#470)
* use upstream phpmicro

* move src/global/tests to src/global/ext-tests

* move src/global/tests to src/global/ext-tests

* prevent file_get_contents memory insufficience

* update README

* fix libxml >= 2.12 with older PHP (<=8.1) build bug

* cleanup code, support newer phpmicro

* add --no-strip and --with-upx-pack tests

* fix windows sanity check for newer phpmicro

* fix windows sanity check for newer phpmicro

* test

* test

* test

* update deps for ci
2024-06-03 23:16:15 +08:00
crazywhalecc
3057d02e37 Fix macOS --no-strip opposite bug 2024-05-31 00:13:16 +08:00
Jerry Ma
af8204fbf0 Add libxml extension wrapper for composer compatibility (#463)
* Add libxml extension wrapper for compatibility

* Add tests
2024-05-29 14:30:31 +08:00
Jerry Ma
968b3acbce Add gen-ext-docs command (#462) 2024-05-29 13:53:08 +08:00
81 changed files with 3862 additions and 1706 deletions

View File

@@ -12,6 +12,9 @@ on:
permissions:
contents: read
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
php-cs-fixer:
runs-on: ubuntu-latest
@@ -129,13 +132,6 @@ jobs:
extensions: curl, openssl, mbstring
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"
id: composer-cache
uses: actions/cache@v4
@@ -147,7 +143,7 @@ jobs:
# Cache downloaded source
- id: cache-download
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: downloads
key: php-${{ matrix.php }}-dependencies
@@ -158,14 +154,26 @@ jobs:
- name: "Run Build Tests (doctor)"
run: bin/spc doctor --auto-fix
- name: "Run Build Tests (download)"
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)" --for-libs="$(php src/globals/test-extensions.php libs)" --with-php=${{ matrix.php }} --ignore-cache-sources=php-src --debug --retry=3
- name: "Prepare UPX for Windows"
if: matrix.os == 'windows-latest'
run: |
bin/spc install-pkg upx
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $env:GITHUB_ENV
- name: "Run Build Tests (build)"
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --build-fpm --debug
- name: "Prepare UPX for Linux"
if: matrix.os == 'ubunut-latest'
run: |
bin/spc install-pkg upx
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $GITHUB_ENV
- name: "Run Build Tests (download)"
run: |
bin/spc download --for-extensions="$(php src/globals/test-extensions.php extensions)" --for-libs="$(php src/globals/test-extensions.php libs)" --with-php=${{ matrix.php }} --ignore-cache-sources=php-src --debug --retry=5
- name: "Run Build Tests (build, *nix)"
if: matrix.os != 'windows-latest'
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) $(php src/globals/test-extensions.php no_strip) $UPX_CMD --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --build-fpm --debug
- name: "Run Build Tests (build, windows)"
if: matrix.os == 'windows-latest'
run: bin/spc build "$(php src/globals/test-extensions.php extensions)" $(php src/globals/test-extensions.php zts) $(php src/globals/test-extensions.php no_strip) $env:UPX_CMD --with-libs="$(php src/globals/test-extensions.php libs)" --build-cli --build-micro --debug --enable-micro-win32

View File

@@ -15,9 +15,6 @@ jobs:
steps:
- name: "Checkout static-php-cli"
uses: actions/checkout@v4
with:
ref: main
path: static-php-cli
- name: "Checkout static-php-cli-docs"
uses: actions/checkout@v4
@@ -33,7 +30,35 @@ jobs:
git config --global user.name "GitHub Actions"
- name: "Copy Config Files"
run: cp -r static-php-cli/config/* static-php-cli-docs/docs/.vitepress/config/
run: cp -r config/* static-php-cli-docs/docs/.vitepress/config/
- name: "Install PHP for official runners"
uses: "shivammathur/setup-php@v2"
with:
coverage: none
tools: composer:v2
php-version: 8.2
ini-values: memory_limit=-1
- name: "Get Composer Cache Directory"
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: "Cache Composer dependencies"
uses: "actions/cache@v4"
with:
path: "${{ steps.composer-cache.outputs.dir }}"
key: "php-8.2-locked-composer-${{ hashFiles('**/composer.lock') }}"
restore-keys: |
php-8.2-locked-composer
- name: "Install Locked Dependencies"
run: "composer install --no-interaction --no-progress"
- name: "Generate Extension Support List"
run: |
bin/spc dev:gen-ext-docs > static-php-cli-docs/docs/extensions.md
- name: "Commit and Push Changes"
run: |

View File

@@ -74,7 +74,7 @@ static-php-cli简称 `spc`)有许多特性:
当前支持编译的 PHP 版本:
> :warning: 支持,但可能不再提供修复
> :warning: 支持,但 static-php-cli 作者可能不再提供补丁修复
>
> :heavy_check_mark: 支持
>
@@ -86,7 +86,7 @@ static-php-cli简称 `spc`)有许多特性:
| 7.3 | :warning: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 7.4 | :warning: | phpmicro 和许多扩展不支持 7.3、7.4 版本 |
| 8.0 | :heavy_check_mark: | PHP 官方已停止 8.0 的维护 |
| 8.1 | :heavy_check_mark: | |
| 8.1 | :heavy_check_mark: | PHP 官方仅对 8.1 提供安全更新 |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |

View File

@@ -82,7 +82,7 @@ Here is the supported OS and arch, where :octocat: represents support for GitHub
Currently supported PHP versions for compilation:
> :warning: supported but not maintained
> :warning: supported but not maintained by static-php-cli authors
>
> :heavy_check_mark: supported
>
@@ -94,7 +94,7 @@ Currently supported PHP versions for compilation:
| 7.3 | :warning: | phpmicro and some extensions not supported on 7.x |
| 7.4 | :warning: | phpmicro and some extensions not supported on 7.x |
| 8.0 | :heavy_check_mark: | PHP official has stopped maintenance of 8.0 |
| 8.1 | :heavy_check_mark: | |
| 8.1 | :heavy_check_mark: | PHP official has security fixes only |
| 8.2 | :heavy_check_mark: | |
| 8.3 | :heavy_check_mark: | |

358
composer.lock generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

5
config/pre-built.json Normal file
View File

@@ -0,0 +1,5 @@
{
"repo": "static-php/static-php-cli-hosted",
"match-pattern": "{name}-{arch}-{os}.tgz",
"pack-config": {}
}

View File

@@ -47,6 +47,7 @@
"type": "ghrel",
"repo": "curl/curl",
"match": "curl.+\\.tar\\.xz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -179,8 +180,12 @@
}
},
"gmp": {
"type": "ghtagtar",
"repo": "alisw/GMP",
"type": "url",
"url": "https://dl.static-php.dev/static-php-cli/deps/gmp/gmp-6.3.0.tar.xz",
"alt": {
"type": "ghtagtar",
"repo": "alisw/GMP"
},
"license": {
"type": "text",
"text": "Since version 6, GMP is distributed under the dual licenses, GNU LGPL v3 and GNU GPL v2. These licenses make the library free to use, share, and improve, and allow you to pass on the result. The GNU licenses give freedoms, but also set firm restrictions on the use with non-free programs."
@@ -190,6 +195,7 @@
"type": "ghrel",
"repo": "unicode-org/icu",
"match": "icu4c.+-src\\.tgz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -259,9 +265,15 @@
}
},
"libcares": {
"type": "filelist",
"url": "https://c-ares.org/download/",
"regex": "/href=\"\\/download\\/(?<file>c-ares-(?<version>[^\"]+)\\.tar\\.gz)\"/",
"type": "ghrel",
"repo": "c-ares/c-ares",
"match": "c-ares-.+\\.tar\\.gz",
"prefer-stable": true,
"alt": {
"type": "filelist",
"url": "https://c-ares.org/download/",
"regex": "/href=\"\\/download\\/(?<file>c-ares-(?<version>[^\"]+)\\.tar\\.gz)\"/"
},
"license": {
"type": "file",
"path": "LICENSE.md"
@@ -271,6 +283,7 @@
"type": "ghrel",
"repo": "libevent/libevent",
"match": "libevent.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -280,6 +293,7 @@
"type": "ghrel",
"repo": "libffi/libffi",
"match": "libffi.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -324,6 +338,7 @@
"type": "ghrel",
"repo": "lz4/lz4",
"match": "lz4-.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -360,6 +375,7 @@
"type": "ghrel",
"repo": "jedisct1/libsodium",
"match": "libsodium-\\d+(\\.\\d+)*\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -369,6 +385,7 @@
"type": "ghrel",
"repo": "libssh2/libssh2",
"match": "libssh2.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -435,6 +452,7 @@
"type": "ghrel",
"repo": "yaml/libyaml",
"match": "yaml-.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "License"
@@ -444,6 +462,7 @@
"type": "ghrel",
"repo": "nih-at/libzip",
"match": "libzip.+\\.tar\\.xz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -463,7 +482,7 @@
"type": "git",
"path": "php-src/sapi/micro",
"rev": "master",
"url": "https://github.com/static-php/phpmicro",
"url": "https://github.com/easysoft/phpmicro",
"license": {
"type": "file",
"path": "LICENSE"
@@ -474,6 +493,7 @@
"repo": "mongodb/mongo-php-driver",
"path": "php-src/ext/mongodb",
"match": "mongodb.+\\.tgz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -492,6 +512,7 @@
"type": "ghrel",
"repo": "nghttp2/nghttp2",
"match": "nghttp2.+\\.tar\\.xz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -501,6 +522,7 @@
"type": "ghrel",
"repo": "kkos/oniguruma",
"match": "onig-.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "COPYING"
@@ -640,6 +662,7 @@
"type": "ghtar",
"path": "php-src/ext/swoole",
"repo": "swoole/swoole-src",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"
@@ -725,6 +748,7 @@
"type": "ghrel",
"repo": "madler/zlib",
"match": "zlib.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "text",
"text": "(C) 1995-2022 Jean-loup Gailly and Mark Adler\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n\nJean-loup Gailly Mark Adler\njloup@gzip.org madler@alumni.caltech.edu"
@@ -734,6 +758,7 @@
"type": "ghrel",
"repo": "facebook/zstd",
"match": "zstd.+\\.tar\\.gz",
"prefer-stable": true,
"license": {
"type": "file",
"path": "LICENSE"

View File

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

View File

@@ -8,6 +8,9 @@ use SPC\command\BuildCliCommand;
use SPC\command\BuildLibsCommand;
use SPC\command\DeleteDownloadCommand;
use SPC\command\dev\AllExtCommand;
use SPC\command\dev\ExtVerCommand;
use SPC\command\dev\GenerateExtDocCommand;
use SPC\command\dev\LibVerCommand;
use SPC\command\dev\PhpVerCommand;
use SPC\command\dev\SortConfigCommand;
use SPC\command\DoctorCommand;
@@ -24,7 +27,7 @@ use Symfony\Component\Console\Application;
*/
final class ConsoleApplication extends Application
{
public const VERSION = '2.2.1';
public const VERSION = '2.3.0';
public function __construct()
{
@@ -47,7 +50,10 @@ final class ConsoleApplication extends Application
// Dev commands
new AllExtCommand(),
new PhpVerCommand(),
new LibVerCommand(),
new ExtVerCommand(),
new SortConfigCommand(),
new GenerateExtDocCommand(),
]
);
}

View File

@@ -9,6 +9,7 @@ use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\SourceManager;
use SPC\util\CustomExt;
@@ -160,7 +161,7 @@ abstract class BuilderBase
* @throws WrongUsageException
* @internal
*/
public function proveExts(array $extensions): void
public function proveExts(array $extensions, bool $skip_check_deps = false): void
{
CustomExt::loadCustomExt();
$this->emitPatchPoint('before-php-extract');
@@ -180,6 +181,10 @@ abstract class BuilderBase
$this->addExt($ext);
}
if ($skip_check_deps) {
return;
}
foreach ($this->exts as $ext) {
$ext->checkDependency();
}
@@ -275,6 +280,24 @@ abstract class BuilderBase
return false;
}
public function getMicroVersion(): false|string
{
$file = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/php_micro.h');
if (!file_exists($file)) {
return false;
}
$content = file_get_contents($file);
$ver = '';
preg_match('/#define PHP_MICRO_VER_MAJ (\d)/m', $content, $match);
$ver .= $match[1] . '.';
preg_match('/#define PHP_MICRO_VER_MIN (\d)/m', $content, $match);
$ver .= $match[1] . '.';
preg_match('/#define PHP_MICRO_VER_PAT (\d)/m', $content, $match);
$ver .= $match[1];
return $ver;
}
/**
* Get build type name string to display.
*
@@ -434,4 +457,29 @@ abstract class BuilderBase
$php .= "echo '[micro-test-end]';\n";
return $php;
}
protected function getMicroTestTasks(): array
{
return [
'micro_ext_test' => [
'content' => ($this->getOption('without-micro-ext-test') ? '<?php echo "[micro-test-start][micro-test-end]";' : $this->generateMicroExtTests()),
'conditions' => [
// program success
function ($ret) { return $ret === 0; },
// program returns expected output
function ($ret, $out) {
$raw_out = trim(implode('', $out));
return str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]');
},
],
],
'micro_zend_bug_test' => [
'content' => ($this->getOption('without-micro-ext-test') ? '<?php echo "hello";' : file_get_contents(ROOT_DIR . '/src/globals/common-tests/micro_zend_mm_heap_corrupted.txt')),
'conditions' => [
// program success
function ($ret) { return $ret === 0; },
],
],
];
}
}

View File

@@ -27,6 +27,8 @@ class BuilderProvider
*/
public static function makeBuilderByInput(InputInterface $input): BuilderBase
{
ini_set('memory_limit', '4G');
self::$builder = match (PHP_OS_FAMILY) {
'Windows' => new WindowsBuilder($input->getOptions()),
'Darwin' => new MacOSBuilder($input->getOptions()),

View File

@@ -170,19 +170,19 @@ class Extension
public function runCliCheckUnix(): void
{
// Run compile check if build target is cli
// If you need to run some check, overwrite this or add your assert in src/globals/tests/{extension_name}.php
// If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php
// If check failed, throw RuntimeException
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php --ri "' . $this->getDistName() . '"', false);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
}
if (file_exists(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php')) {
if (file_exists(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php')) {
// Trim additional content & escape special characters to allow inline usage
$test = str_replace(
['<?php', 'declare(strict_types=1);', "\n", '"', '$'],
['', '', '', '\"', '\$'],
file_get_contents(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php')
file_get_contents(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php')
);
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -r "' . trim($test) . '"');
@@ -201,19 +201,19 @@ class Extension
public function runCliCheckWindows(): void
{
// Run compile check if build target is cli
// If you need to run some check, overwrite this or add your assert in src/globals/tests/{extension_name}.php
// If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php
// If check failed, throw RuntimeException
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe --ri "' . $this->getDistName() . '"', false);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
}
if (file_exists(FileSystem::convertPath(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php'))) {
if (file_exists(FileSystem::convertPath(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php'))) {
// Trim additional content & escape special characters to allow inline usage
$test = str_replace(
['<?php', 'declare(strict_types=1);', "\n", '"', '$'],
['', '', '', '\"', '$'],
file_get_contents(FileSystem::convertPath(ROOT_DIR . '/src/globals/tests/' . $this->getName() . '.php'))
file_get_contents(FileSystem::convertPath(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php'))
);
[$ret] = cmd()->execWithResult(BUILD_ROOT_PATH . '/bin/php.exe -r "' . trim($test) . '"');
@@ -228,6 +228,16 @@ class Extension
// do nothing, just throw wrong usage exception if not valid
}
/**
* Get current extension version
*
* @return null|string Version string or null
*/
public function getExtVersion(): ?string
{
return null;
}
/**
* @throws RuntimeException
*/

View File

@@ -182,6 +182,16 @@ abstract class LibraryBase
// do nothing, just throw wrong usage exception if not valid
}
/**
* Get current lib version
*
* @return null|string Version string or null
*/
public function getLibVersion(): ?string
{
return null;
}
/**
* Get current builder object.
*/

View File

@@ -5,20 +5,11 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('mongodb')]
class mongodb extends Extension
{
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/mongodb/config.m4', 'if test -z "$PHP_CONFIG"; then', 'if false; then');
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/mongodb/config.m4', 'PHP_MONGODB_PHP_VERSION=`${PHP_CONFIG} --version`', 'PHP_MONGODB_PHP_VERSION=' . $this->builder->getPHPVersion());
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/mongodb/config.m4', 'PHP_MONGODB_PHP_VERSION_ID=`${PHP_CONFIG} --vernum`', 'PHP_MONGODB_PHP_VERSION_ID=' . $this->builder->getPHPVersionID());
return true;
}
public function getUnixConfigureArg(): string
{
$arg = ' --enable-mongodb ';

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('sqlsrv')]
class sqlsrv extends Extension
{
private bool $pdo_sqlsrv_patched = false;
public function patchBeforeBuildconf(): bool
{
if (PHP_OS_FAMILY === 'Windows' && $this->builder->getExt('pdo_sqlsrv') === null) {
// support sqlsrv without pdo_sqlsrv
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/sqlsrv/config.w32', 'PHP_PDO_SQLSRV', '"no"');
$this->pdo_sqlsrv_patched = true;
return true;
}
return false;
}
public function patchBeforeConfigure(): bool
{
if ($this->pdo_sqlsrv_patched) {
// revert pdo_sqlsrv patch
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/sqlsrv/config.w32', '"no" == "no"', 'PHP_PDO_SQLSRV == "no"');
return true;
}
return false;
}
}

View File

@@ -10,6 +10,18 @@ use SPC\util\CustomExt;
#[CustomExt('swoole')]
class swoole extends Extension
{
public function getExtVersion(): ?string
{
// Get version from source directory
$file = SOURCE_PATH . '/php-src/ext/swoole/include/swoole_version.h';
// Match #define SWOOLE_VERSION "5.1.3"
$pattern = '/#define SWOOLE_VERSION "(.+)"/';
if (preg_match($pattern, file_get_contents($file), $matches)) {
return $matches[1];
}
return null;
}
public function getUnixConfigureArg(): string
{
// enable swoole

View File

@@ -18,7 +18,7 @@ class swow extends Extension
}
}
public function getUnixConfigureArg(): string
public function getConfigureArg(): string
{
$arg = '--enable-swow';
$arg .= $this->builder->getLib('openssl') ? ' --enable-swow-ssl' : ' --disable-swow-ssl';

View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\util\CustomExt;
#[CustomExt('uv')]
class uv extends Extension
{
public function validate(): void
{
if ($this->builder->getPHPVersionID() < 80000 && getenv('SPC_SKIP_PHP_VERSION_CHECK') !== 'yes') {
throw new \RuntimeException('The latest uv extension requires PHP 8.0 or later');
}
}
}

View File

@@ -12,6 +12,10 @@ class xlswriter extends Extension
{
public function getUnixConfigureArg(): string
{
return '--with-xlswriter --enable-reader';
$arg = '--with-xlswriter --enable-reader';
if ($this->builder->getLib('openssl')) {
$arg .= ' --with-openssl=' . BUILD_ROOT_PATH;
}
return $arg;
}
}

View File

@@ -181,7 +181,7 @@ class BSDBuilder extends UnixBuilderBase
}
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicro(['phar']);
SourcePatcher::patchMicroPhar($this->getPHPVersionID());
}
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
@@ -202,7 +202,7 @@ class BSDBuilder extends UnixBuilderBase
$this->deployBinary(BUILD_TARGET_MICRO);
if ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
SourcePatcher::unpatchMicroPhar();
}
}

View File

@@ -149,7 +149,11 @@ class LinuxBuilder extends UnixBuilderBase
// process micro upx patch if micro sapi enabled
if ($enable_micro) {
$this->processMicroUPX();
if (version_compare($this->getMicroVersion(), '0.2.0') < 0) {
// for phpmicro 0.1.x
$this->processMicroUPXLegacy();
}
// micro latest needs do strip and upx pack later (strip, upx, cut binary manually supported)
}
shell()->cd(SOURCE_PATH . '/php-src')
@@ -236,7 +240,7 @@ class LinuxBuilder extends UnixBuilderBase
}
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicro(['phar']);
SourcePatcher::patchMicroPhar($this->getPHPVersionID());
}
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
@@ -250,10 +254,12 @@ class LinuxBuilder extends UnixBuilderBase
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("\$SPC_CMD_PREFIX_PHP_MAKE {$vars} micro");
$this->processMicroUPX();
$this->deployBinary(BUILD_TARGET_MICRO);
if ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
SourcePatcher::unpatchMicroPhar();
}
}
@@ -304,11 +310,11 @@ class LinuxBuilder extends UnixBuilderBase
}
/**
* Apply option --no-strip and --with-upx-pack for micro sapi.
* Apply option --no-strip and --with-upx-pack for micro sapi (only for phpmicro 0.1.x)
*
* @throws FileSystemException
*/
private function processMicroUPX(): void
private function processMicroUPXLegacy(): void
{
// upx pack and strip for micro
// but always restore Makefile.frag.bak first
@@ -346,4 +352,26 @@ class LinuxBuilder extends UnixBuilderBase
);
}
}
private function processMicroUPX(): void
{
if (version_compare($this->getMicroVersion(), '0.2.0') >= 0 && !$this->getOption('no-strip', false)) {
shell()->exec('strip --strip-all ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx');
if ($this->getOption('with-upx-pack')) {
// strip first
shell()->exec(getenv('UPX_EXEC') . ' --best ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx');
// cut binary with readelf
[$ret, $out] = shell()->execWithResult('readelf -l ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx | awk \'/LOAD|GNU_STACK/ {getline; print $1, $2, $3, $4, $6, $7}\'');
$out[1] = explode(' ', $out[1]);
$offset = $out[1][0];
if ($ret !== 0 || !str_starts_with($offset, '0x')) {
throw new RuntimeException('Cannot find offset in readelf output');
}
$offset = hexdec($offset);
// remove upx extra wastes
file_put_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx', substr(file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx'), 0, $offset));
}
}
}
}

View File

@@ -37,7 +37,7 @@ class MacOSBuilder extends UnixBuilderBase
$this->arch_c_flags = getenv('SPC_DEFAULT_C_FLAGS');
$this->arch_cxx_flags = getenv('SPC_DEFAULT_CXX_FLAGS');
// cmake toolchain
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->getOption('arch'), $this->arch_c_flags);
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->getOption('arch', php_uname('m')), $this->arch_c_flags);
// create pkgconfig and include dir (some libs cannot create them automatically)
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
@@ -233,7 +233,7 @@ class MacOSBuilder extends UnixBuilderBase
}
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicro(['phar']);
SourcePatcher::patchMicroPhar($this->getPHPVersionID());
}
$enable_fake_cli = $this->getOption('with-micro-fake-cli', false) ? ' -DPHP_MICRO_FAKE_CLI' : '';
@@ -241,7 +241,7 @@ class MacOSBuilder extends UnixBuilderBase
// patch fake cli for micro
$vars['EXTRA_CFLAGS'] .= $enable_fake_cli;
if (!$this->getOption('no-strip', false)) {
if ($this->getOption('no-strip', false)) {
$vars['STRIP'] = 'dsymutil -f ';
}
$vars = SystemUtil::makeEnvVarString($vars);
@@ -251,7 +251,7 @@ class MacOSBuilder extends UnixBuilderBase
$this->deployBinary(BUILD_TARGET_MICRO);
if ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
SourcePatcher::unpatchMicroPhar();
}
}

View File

@@ -20,7 +20,7 @@ class SystemUtil
*/
public static function getCpuCount(): int
{
[$ret, $output] = shell()->execWithResult('sysctl -n hw.ncpu');
[$ret, $output] = shell()->execWithResult('sysctl -n hw.ncpu', false);
if ($ret !== 0) {
throw new RuntimeException('Failed to get cpu count');
}

View File

@@ -96,7 +96,7 @@ abstract class UnixBuilderBase extends BuilderBase
$support_lib_list = [];
$classes = FileSystem::getClassesPsr4(
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
'SPC\\builder\\' . osfamily2dir() . '\\library'
'SPC\builder\\' . osfamily2dir() . '\library'
);
foreach ($classes as $class) {
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
@@ -162,22 +162,20 @@ abstract class UnixBuilderBase extends BuilderBase
// sanity check for phpmicro
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
if (file_exists(SOURCE_PATH . '/hello.exe')) {
@unlink(SOURCE_PATH . '/hello.exe');
}
file_put_contents(
SOURCE_PATH . '/hello.exe',
file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') .
($this->getOption('without-micro-ext-test') ? '<?php echo "[micro-test-start][micro-test-end]";' : $this->generateMicroExtTests())
);
chmod(SOURCE_PATH . '/hello.exe', 0755);
[$ret, $output2] = shell()->execWithResult(SOURCE_PATH . '/hello.exe');
$raw_out = trim(implode('', $output2));
$condition[0] = $ret === 0;
$condition[1] = str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]');
foreach ($condition as $k => $v) {
if (!$v) {
throw new RuntimeException("micro failed sanity check with condition[{$k}], ret[{$ret}], out[{$raw_out}]");
$test_task = $this->getMicroTestTasks();
foreach ($test_task as $task_name => $task) {
$test_file = SOURCE_PATH . '/' . $task_name . '.exe';
if (file_exists($test_file)) {
@unlink($test_file);
}
file_put_contents($test_file, file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') . $task['content']);
chmod($test_file, 0755);
[$ret, $out] = shell()->execWithResult($test_file);
foreach ($task['conditions'] as $condition => $closure) {
if (!$closure($ret, $out)) {
$raw_out = trim(implode('', $out));
throw new RuntimeException("micro failed sanity check: {$task_name}, condition [{$condition}], ret[{$ret}], out[{$raw_out}]");
}
}
}
}

View File

@@ -5,9 +5,20 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait libcares
{
public function patchBeforeBuild(): bool
{
if (!file_exists($this->source_dir . '/src/lib/thirdparty/apple/dnsinfo.h')) {
FileSystem::createDir($this->source_dir . '/src/lib/thirdparty/apple');
copy(ROOT_DIR . '/src/globals/extra/libcares_dnsinfo.h', $this->source_dir . '/src/lib/thirdparty/apple/dnsinfo.h');
return true;
}
return false;
}
/**
* @throws RuntimeException
*/

View File

@@ -15,14 +15,20 @@ trait libtiff
*/
protected function build(): void
{
shell()->cd($this->source_dir)
$shell = shell()->cd($this->source_dir)
->exec(
'./configure ' .
'--enable-static --disable-shared ' .
'--disable-cxx ' .
'--prefix='
)
->exec('make clean')
);
// TODO: Remove this check when https://gitlab.com/libtiff/libtiff/-/merge_requests/635 will be merged and released
if (file_exists($this->source_dir . '/html')) {
$shell->exec('make clean');
}
$shell
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$this->patchPkgconfPrefix(['libtiff-4.pc']);

View File

@@ -10,51 +10,27 @@ use SPC\store\FileSystem;
trait libyaml
{
public function getLibVersion(): ?string
{
// Match version from CMakeLists.txt:
// Format: set (YAML_VERSION_MAJOR 0)
// set (YAML_VERSION_MINOR 2)
// set (YAML_VERSION_PATCH 5)
$content = FileSystem::readFile($this->source_dir . '/CMakeLists.txt');
if (preg_match('/set \(YAML_VERSION_MAJOR (\d+)\)/', $content, $major)
&& preg_match('/set \(YAML_VERSION_MINOR (\d+)\)/', $content, $minor)
&& preg_match('/set \(YAML_VERSION_PATCH (\d+)\)/', $content, $patch)) {
return "{$major[1]}.{$minor[1]}.{$patch[1]}";
}
return null;
}
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
// prepare cmake/config.h.in
if (!is_file(SOURCE_PATH . '/libyaml/cmake/config.h.in')) {
f_mkdir(SOURCE_PATH . '/libyaml/cmake');
file_put_contents(
SOURCE_PATH . '/libyaml/cmake/config.h.in',
<<<'EOF'
#define YAML_VERSION_MAJOR @YAML_VERSION_MAJOR@
#define YAML_VERSION_MINOR @YAML_VERSION_MINOR@
#define YAML_VERSION_PATCH @YAML_VERSION_PATCH@
#define YAML_VERSION_STRING "@YAML_VERSION_STRING@"
EOF
);
}
// prepare yamlConfig.cmake.in
if (!is_file(SOURCE_PATH . '/libyaml/yamlConfig.cmake.in')) {
file_put_contents(
SOURCE_PATH . '/libyaml/yamlConfig.cmake.in',
<<<'EOF'
# Config file for the yaml library.
#
# It defines the following variables:
# yaml_LIBRARIES - libraries to link against
@PACKAGE_INIT@
set_and_check(yaml_TARGETS "@PACKAGE_CONFIG_DIR_CONFIG@/yamlTargets.cmake")
if(NOT yaml_TARGETS_IMPORTED)
set(yaml_TARGETS_IMPORTED 1)
include(${yaml_TARGETS})
endif()
set(yaml_LIBRARIES yaml)
EOF
);
}
[$lib, $include, $destdir] = SEPARATED_PATH;
FileSystem::resetDir($this->source_dir . '/build');

View File

@@ -90,6 +90,7 @@ class SystemUtil
$buildroot = str_replace('\\', '\\\\', BUILD_ROOT_PATH);
$toolchain = <<<CMAKE
set(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_PROCESSOR x64)
SET(CMAKE_C_FLAGS "{$cflags}")
SET(CMAKE_C_FLAGS_DEBUG "{$cflags}")
SET(CMAKE_CXX_FLAGS "{$cflags}")

View File

@@ -80,16 +80,18 @@ class WindowsBuilder extends BuilderBase
$zts = $this->zts ? '--enable-zts=yes ' : '--enable-zts=no ';
// with-upx-pack for phpmicro
$makefile = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag.w32');
if ($this->getOption('with-upx-pack', false)) {
if (!file_exists($makefile . '.originfile')) {
copy($makefile, $makefile . '.originfile');
FileSystem::replaceFileStr($makefile, '$(MICRO_SFX):', '_MICRO_UPX = ' . getenv('UPX_EXEC') . " --best $(MICRO_SFX)\n$(MICRO_SFX):");
FileSystem::replaceFileStr($makefile, '@$(_MICRO_MT)', "@$(_MICRO_MT)\n\t@$(_MICRO_UPX)");
if ($enableMicro && version_compare($this->getMicroVersion(), '0.2.0') < 0) {
$makefile = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/Makefile.frag.w32');
if ($this->getOption('with-upx-pack', false)) {
if (!file_exists($makefile . '.originfile')) {
copy($makefile, $makefile . '.originfile');
FileSystem::replaceFileStr($makefile, '$(MICRO_SFX):', '_MICRO_UPX = ' . getenv('UPX_EXEC') . " --best $(MICRO_SFX)\n$(MICRO_SFX):");
FileSystem::replaceFileStr($makefile, '@$(_MICRO_MT)', "@$(_MICRO_MT)\n\t@$(_MICRO_UPX)");
}
} elseif (file_exists($makefile . '.originfile')) {
copy($makefile . '.originfile', $makefile);
unlink($makefile . '.originfile');
}
} elseif (file_exists($makefile . '.originfile')) {
copy($makefile . '.originfile', $makefile);
unlink($makefile . '.originfile');
}
if (($logo = $this->getOption('with-micro-logo')) !== null) {
@@ -100,6 +102,8 @@ class WindowsBuilder extends BuilderBase
$micro_logo = '';
}
$micro_w32 = $this->getOption('enable-micro-win32') ? ' --enable-micro-win32=yes' : '';
cmd()->cd(SOURCE_PATH . '\php-src')
->exec(
"{$this->sdk_prefix} configure.bat --task-args \"" .
@@ -109,7 +113,7 @@ class WindowsBuilder extends BuilderBase
'--with-extra-includes=' . BUILD_INCLUDE_PATH . ' ' .
'--with-extra-libs=' . BUILD_LIB_PATH . ' ' .
($enableCli ? '--enable-cli=yes ' : '--enable-cli=no ') .
($enableMicro ? ('--enable-micro=yes ' . $micro_logo) : '--enable-micro=no ') .
($enableMicro ? ('--enable-micro=yes ' . $micro_logo . $micro_w32) : '--enable-micro=no ') .
($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
"{$this->makeExtensionArgs()} " .
$zts .
@@ -130,6 +134,8 @@ class WindowsBuilder extends BuilderBase
if ($enableMicro) {
logger()->info('building micro');
$this->buildMicro();
SourcePatcher::unpatchMicroWin32();
}
if ($enableEmbed) {
logger()->warning('Windows does not currently support embed SAPI.');
@@ -191,14 +197,14 @@ class WindowsBuilder extends BuilderBase
// phar patch for micro
if ($this->getExt('phar')) {
$this->phar_patched = true;
SourcePatcher::patchMicro(['phar']);
SourcePatcher::patchMicroPhar($this->getPHPVersionID());
}
try {
cmd()->cd(SOURCE_PATH . '\php-src')->exec("{$this->sdk_prefix} nmake_micro_wrapper.bat --task-args micro");
} finally {
if ($this->phar_patched) {
SourcePatcher::patchMicro(['phar'], true);
SourcePatcher::unpatchMicroPhar();
}
}
@@ -210,8 +216,8 @@ class WindowsBuilder extends BuilderBase
// search all supported libs
$support_lib_list = [];
$classes = FileSystem::getClassesPsr4(
ROOT_DIR . '\src\SPC\builder\\' . osfamily2dir() . '\\library',
'SPC\\builder\\' . osfamily2dir() . '\\library'
ROOT_DIR . '\src\SPC\builder\\' . osfamily2dir() . '\library',
'SPC\builder\\' . osfamily2dir() . '\library'
);
foreach ($classes as $class) {
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
@@ -283,22 +289,20 @@ class WindowsBuilder extends BuilderBase
// sanity check for phpmicro
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
if (file_exists(SOURCE_PATH . '\hello.exe')) {
@unlink(SOURCE_PATH . '\hello.exe');
}
file_put_contents(
SOURCE_PATH . '\hello.exe',
file_get_contents(BUILD_ROOT_PATH . '\bin\micro.sfx') .
($this->getOption('without-micro-ext-test') ? '<?php echo "[micro-test-start][micro-test-end]";' : $this->generateMicroExtTests())
);
chmod(SOURCE_PATH . '\hello.exe', 0755);
[$ret, $output2] = cmd()->execWithResult(SOURCE_PATH . '\hello.exe');
$raw_out = trim(implode('', $output2));
$condition[0] = $ret === 0;
$condition[1] = str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]');
foreach ($condition as $k => $v) {
if (!$v) {
throw new RuntimeException("micro failed sanity check with condition[{$k}], ret[{$ret}], out[{$raw_out}]");
$test_task = $this->getMicroTestTasks();
foreach ($test_task as $task_name => $task) {
$test_file = SOURCE_PATH . '/' . $task_name . '.exe';
if (file_exists($test_file)) {
@unlink($test_file);
}
file_put_contents($test_file, file_get_contents(BUILD_ROOT_PATH . '\bin\micro.sfx') . $task['content']);
chmod($test_file, 0755);
[$ret, $out] = cmd()->execWithResult($test_file);
foreach ($task['conditions'] as $condition => $closure) {
if (!$closure($ret, $out)) {
$raw_out = trim(implode('', $out));
throw new RuntimeException("micro failed sanity check: {$task_name}, condition [{$condition}], ret[{$ret}], out[{$raw_out}]");
}
}
}
}
@@ -320,9 +324,11 @@ class WindowsBuilder extends BuilderBase
default => throw new RuntimeException('Deployment does not accept type ' . $type),
};
// with-upx-pack for cli
if ($this->getOption('with-upx-pack', false) && $type === BUILD_TARGET_CLI) {
cmd()->exec(getenv('UPX_EXEC') . ' --best ' . escapeshellarg($src));
// with-upx-pack for cli and micro
if ($this->getOption('with-upx-pack', false)) {
if ($type === BUILD_TARGET_CLI || ($type === BUILD_TARGET_MICRO && version_compare($this->getMicroVersion(), '0.2.0') >= 0)) {
cmd()->exec(getenv('UPX_EXEC') . ' --best ' . escapeshellarg($src));
}
}
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');

View File

@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
class bzip2 extends WindowsLibraryBase
{
public const NAME = 'bzip2';
protected function build(): void
{
$nmake = $this->builder->makeSimpleWrapper('nmake /nologo /f Makefile.msc CFLAGS="-DWIN32 -MT -Ox -D_FILE_OFFSET_BITS=64 -nologo"');
cmd()->cd($this->source_dir)
->execWithWrapper($nmake, 'clean')
->execWithWrapper($nmake, 'lib');
copy($this->source_dir . '\libbz2.lib', BUILD_LIB_PATH . '\libbz2.lib');
copy($this->source_dir . '\libbz2.lib', BUILD_LIB_PATH . '\libbz2_a.lib');
copy($this->source_dir . '\bzlib.h', BUILD_INCLUDE_PATH . '\bzlib.h');
}
}

View File

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

View File

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

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libjpeg extends WindowsLibraryBase
{
public const NAME = 'libjpeg';
protected function build(): void
{
$zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DENABLE_SHARED=OFF ' .
'-DENABLE_STATIC=ON ' .
'-DBUILD_TESTING=OFF ' .
'-DWITH_JAVA=OFF ' .
'-DWITH_CRT_DLL=OFF ' .
"-DENABLE_ZLIB_COMPRESSION={$zlib} " .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
copy(BUILD_LIB_PATH . '\jpeg-static.lib', BUILD_LIB_PATH . '\libjpeg_a.lib');
}
}

View File

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

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libwebp extends WindowsLibraryBase
{
public const NAME = 'libwebp';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DWEBP_LINK_STATIC=ON ' .
'-DWEBP_BUILD_ANIM_UTILS=OFF ' .
'-DWEBP_BUILD_CWEBP=OFF ' .
'-DWEBP_BUILD_DWEBP=OFF ' .
'-DWEBP_BUILD_GIF2WEBP=OFF ' .
'-DWEBP_BUILD_IMG2WEBP=OFF ' .
'-DWEBP_BUILD_VWEBP=OFF ' .
'-DWEBP_BUILD_WEBPINFO=OFF ' .
'-DWEBP_BUILD_LIBWEBPMUX=OFF ' .
'-DWEBP_BUILD_WEBPMUX=OFF ' .
'-DWEBP_BUILD_EXTRAS=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libyaml extends WindowsLibraryBase
{
public const NAME = 'libyaml';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// check missing files: cmake\config.h.in and .\YamlConfig.cmake.in
if (!file_exists($this->source_dir . '\cmake\config.h.in')) {
FileSystem::createDir($this->source_dir . '\cmake');
copy(ROOT_DIR . '\src\globals\extra\libyaml_config.h.in', $this->source_dir . '\cmake\config.h.in');
}
if (!file_exists($this->source_dir . '\YamlConfig.cmake.in')) {
copy(ROOT_DIR . '\src\globals\extra\libyaml_YamlConfig.cmake.in', $this->source_dir . '\YamlConfig.cmake.in');
}
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DBUILD_TESTING=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
}
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class libzip extends WindowsLibraryBase
{
public const NAME = 'libzip';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
$openssl = $this->builder->getLib('openssl') ? 'ON' : 'OFF';
$zstd = $this->builder->getLib('zstd') ? 'ON' : 'OFF';
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DENABLE_BZIP2=ON ' .
'-DENABLE_LZMA=ON ' .
"-DENABLE_ZSTD={$zstd} " .
"-DENABLE_OPENSSL={$openssl} " .
'-DBUILD_TOOLS=OFF ' .
'-DBUILD_DOC=OFF ' .
'-DBUILD_EXAMPLES=OFF ' .
'-DBUILD_REGRESS=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
copy(BUILD_LIB_PATH . '\zip.lib', BUILD_LIB_PATH . '\libzip_a.lib');
}
}

View File

@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace SPC\builder\windows\library;
use SPC\store\FileSystem;
class xz extends WindowsLibraryBase
{
public const NAME = 'xz';
protected function build(): void
{
// reset cmake
FileSystem::resetDir($this->source_dir . '\build');
// start build
cmd()->cd($this->source_dir)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
'-B build ' .
'-A x64 ' .
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DBUILD_SHARED_LIBS=OFF ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' '
)
->execWithWrapper(
$this->builder->makeSimpleWrapper('cmake'),
"--build build --config Release --target install -j{$this->builder->concurrency}"
);
// copy liblzma.lib to liblzma_a.lib
copy(BUILD_LIB_PATH . '/liblzma.lib', BUILD_LIB_PATH . '/liblzma_a.lib');
// patch lzma.h
FileSystem::replaceFileStr(BUILD_INCLUDE_PATH . '/lzma.h', 'defined(LZMA_API_STATIC)', 'defined(_WIN32)');
}
}

View File

@@ -96,6 +96,8 @@ abstract class BaseCommand extends Command
});
if ($this->shouldExecute()) {
try {
// show raw argv list for logger()->debug
logger()->debug('argv: ' . implode(' ', $_SERVER['argv']));
return $this->handle();
} catch (WrongUsageException $e) {
$msg = explode("\n", $e->getMessage());
@@ -142,4 +144,31 @@ abstract class BaseCommand extends Command
logger()->error($fail_msg);
return static::FAILURE;
}
/**
* Parse extension list from string, replace alias and filter internal extensions.
*
* @param string $ext_list Extension string list, e.g. "mbstring,posix,sockets"
*/
protected function parseExtensionList(string $ext_list): array
{
// replace alias
$ls = array_map(function ($x) {
$lower = strtolower(trim($x));
if (isset(SPC_EXTENSION_ALIAS[$lower])) {
logger()->notice("Extension [{$lower}] is an alias of [" . SPC_EXTENSION_ALIAS[$lower] . '], it will be replaced.');
return SPC_EXTENSION_ALIAS[$lower];
}
return $lower;
}, explode(',', $ext_list));
// filter internals
return array_values(array_filter($ls, function ($x) {
if (in_array($x, SPC_INTERNAL_EXTENSIONS)) {
logger()->warning("Extension [{$x}] is an builtin extension, it will be ignored.");
return false;
}
return true;
}));
}
}

View File

@@ -40,6 +40,7 @@ class BuildCliCommand extends BuildCommand
$this->addOption('without-micro-ext-test', null, null, 'Disable phpmicro with extension test code');
$this->addOption('with-upx-pack', null, null, 'Compress / pack binary using UPX tool (linux/windows only)');
$this->addOption('with-micro-logo', null, InputOption::VALUE_REQUIRED, 'Use custom .ico for micro.sfx (windows only)');
$this->addOption('enable-micro-win32', null, null, 'Enable win32 mode for phpmicro (Windows only)');
}
public function handle(): int
@@ -47,7 +48,7 @@ class BuildCliCommand extends BuildCommand
// transform string to array
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('with-libs'))));
// transform string to array
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions'))));
$extensions = $this->parseExtensionList($this->getArgument('extensions'));
// parse rule with options
$rule = $this->parseRules();

View File

@@ -38,7 +38,7 @@ class DownloadCommand extends BaseCommand
$this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"');
$this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Fetch by libraries, e.g "libcares,openssl,onig"');
$this->addOption('without-suggestions', null, null, 'Do not fetch suggested sources when using --for-extensions');
$this->addOption('ignore-cache-sources', null, InputOption::VALUE_REQUIRED, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', '');
$this->addOption('ignore-cache-sources', null, InputOption::VALUE_OPTIONAL, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', '');
$this->addOption('retry', 'R', InputOption::VALUE_REQUIRED, 'Set retry time when downloading failed (default: 0)', '0');
}
@@ -68,7 +68,7 @@ class DownloadCommand extends BaseCommand
}
// mode: --for-extensions
if ($for_ext = $input->getOption('for-extensions')) {
$ext = array_map('trim', array_filter(explode(',', $for_ext)));
$ext = $this->parseExtensionList($for_ext);
$sources = $this->calculateSourcesByExt($ext, !$input->getOption('without-suggestions'));
if (PHP_OS_FAMILY !== 'Windows') {
array_unshift($sources, 'pkg-config');
@@ -147,8 +147,12 @@ class DownloadCommand extends BaseCommand
}
$chosen_sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources'))));
$force_all = empty($this->getOption('ignore-cache-sources'));
if (!$force_all) {
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources'))));
} else {
$force_list = [];
}
if ($this->getOption('all')) {
logger()->notice('Downloading with --all option will take more times to download, we recommend you to download with --for-extensions option !');
}
@@ -182,7 +186,7 @@ class DownloadCommand extends BaseCommand
Downloader::downloadSource($source, $new_config, true);
} else {
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
Downloader::downloadSource($source, Config::getSource($source), in_array($source, $force_list));
Downloader::downloadSource($source, Config::getSource($source), $force_all || in_array($source, $force_list));
}
}
$time = round(microtime(true) - START_TIME, 3);

View File

@@ -37,7 +37,7 @@ class DumpLicenseCommand extends BaseCommand
$dumper = new LicenseDumper();
if ($this->getOption('for-extensions') !== null) {
// 从参数中获取要编译的 extensions并转换为数组
$extensions = array_map('trim', array_filter(explode(',', $this->getOption('for-extensions'))));
$extensions = $this->parseExtensionList($this->getOption('for-extensions'));
// 根据提供的扩展列表获取依赖库列表并编译
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions);
$dumper->addExts($extensions);

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
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;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand('dev:ext-version', 'Returns version of extension from source directory', ['dev:ext-ver'])]
class ExtVerCommand extends BaseCommand
{
public function configure()
{
$this->addArgument('extension', InputArgument::REQUIRED, 'The library name');
}
public function initialize(InputInterface $input, OutputInterface $output): void
{
$this->no_motd = true;
parent::initialize($input, $output);
}
public function handle(): int
{
// Get lib object
$builder = BuilderProvider::makeBuilderByInput($this->input);
$ext_conf = Config::getExt($this->getArgument('extension'));
$builder->proveExts([$this->getArgument('extension')], true);
// Check whether lib is extracted
// if (!is_dir(SOURCE_PATH . '/' . $this->getArgument('library'))) {
// $this->output->writeln("<error>Library {$this->getArgument('library')} is not extracted</error>");
// return static::FAILURE;
// }
$version = $builder->getExt($this->getArgument('extension'))->getExtVersion();
if ($version === null) {
$this->output->writeln("<error>Failed to get version of extension {$this->getArgument('extension')}</error>");
return static::FAILURE;
}
$this->output->writeln("<info>{$version}</info>");
return static::SUCCESS;
}
}

View File

@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
namespace SPC\command\dev;
use SPC\command\BaseCommand;
use SPC\store\FileSystem;
use SPC\util\ConfigValidator;
use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand('dev:gen-ext-docs', 'Generate extension list markdown', [], true)]
class GenerateExtDocCommand extends BaseCommand
{
protected bool $no_motd = true;
public function handle(): int
{
// Get ext.json
$exts = json_decode(FileSystem::readFile(ROOT_DIR . '/config/ext.json'), true);
ConfigValidator::validateExts($exts);
// Markdown table needs format, we need to calculate the max length of each column
$max_name = 0;
$max_linux = 5;
$max_macos = 5;
$max_freebsd = 7;
$max_windows = 7;
$md_lines = [];
foreach ($exts as $ext_name => $ext) {
// notes is optional
$name = ($ext['notes'] ?? false) === true ? "[{$ext_name}](./extension-notes#{$ext_name})" : $ext_name;
// calculate max length
$max_name = max($max_name, strlen($name));
// linux
$linux = match ($ext['support']['Linux'] ?? 'yes') {
'wip' => '',
default => $ext['support']['Linux'] ?? 'yes',
};
$max_linux = max($max_linux, strlen($linux));
// macos
$macos = match ($ext['support']['Darwin'] ?? 'yes') {
'wip' => '',
default => $ext['support']['Darwin'] ?? 'yes',
};
$max_macos = max($max_macos, strlen($macos));
// freebsd
$freebsd = match ($ext['support']['BSD'] ?? 'yes') {
'wip' => '',
default => $ext['support']['BSD'] ?? 'yes',
};
$max_freebsd = max($max_freebsd, strlen($freebsd));
// windows
$windows = match ($ext['support']['Windows'] ?? 'yes') {
'wip' => '',
default => $ext['support']['Windows'] ?? 'yes',
};
$max_windows = max($max_windows, strlen($windows));
$md_lines[] = [
$name,
$linux,
$macos,
$freebsd,
$windows,
];
}
// generate markdown
$md = '| ' . str_pad('Extension Name', $max_name) . ' | ' . str_pad('Linux', $max_linux) . ' | ' . str_pad('macOS', $max_macos) . ' | ' . str_pad('FreeBSD', $max_freebsd) . ' | ' . str_pad('Windows', $max_windows) . ' |' . PHP_EOL;
$md .= '| ' . str_repeat('-', $max_name) . ' | ' . str_repeat('-', $max_linux) . ' | ' . str_repeat('-', $max_macos) . ' | ' . str_repeat('-', $max_freebsd) . ' | ' . str_repeat('-', $max_windows) . ' |' . PHP_EOL;
foreach ($md_lines as $line) {
$md .= '| ' . str_pad($line[0], $max_name) . ' | ' . str_pad($line[1], $max_linux) . ' | ' . str_pad($line[2], $max_macos) . ' | ' . str_pad($line[3], $max_freebsd) . ' | ' . str_pad($line[4], $max_windows) . ' |' . PHP_EOL;
}
$this->output->writeln($md);
return static::SUCCESS;
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace SPC\command\dev;
use SPC\builder\BuilderProvider;
use SPC\command\BaseCommand;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand('dev:lib-version', 'Returns version of library from source directory', ['dev:lib-ver'])]
class LibVerCommand extends BaseCommand
{
public function configure()
{
$this->addArgument('library', InputArgument::REQUIRED, 'The library name');
}
public function initialize(InputInterface $input, OutputInterface $output): void
{
$this->no_motd = true;
parent::initialize($input, $output);
}
public function handle(): int
{
// Get lib object
$builder = BuilderProvider::makeBuilderByInput($this->input);
$builder->setLibsOnly();
// check lib name exist in lib.json
try {
Config::getLib($this->getArgument('library'));
} catch (WrongUsageException $e) {
$this->output->writeln("<error>Library {$this->getArgument('library')} is not supported yet</error>");
return static::FAILURE;
}
$builder->proveLibs([$this->getArgument('library')]);
// Check whether lib is extracted
if (!is_dir(SOURCE_PATH . '/' . $this->getArgument('library'))) {
$this->output->writeln("<error>Library {$this->getArgument('library')} is not extracted</error>");
return static::FAILURE;
}
$version = $builder->getLib($this->getArgument('library'))->getLibVersion();
if ($version === null) {
$this->output->writeln("<error>Failed to get version of library {$this->getArgument('library')}</error>");
return static::FAILURE;
}
$this->output->writeln("<info>{$version}</info>");
return static::SUCCESS;
}
}

View File

@@ -70,7 +70,7 @@ final class CheckListHandler
*/
private function loadCheckList(bool $include_manual = false): array
{
foreach (FileSystem::getClassesPsr4(__DIR__ . '/item', 'SPC\\doctor\\item') as $class) {
foreach (FileSystem::getClassesPsr4(__DIR__ . '/item', 'SPC\doctor\item') as $class) {
$ref = new \ReflectionClass($class);
foreach ($ref->getMethods() as $method) {
foreach ($method->getAttributes() as $a) {

View File

@@ -16,7 +16,7 @@ use SPC\store\source\CustomSourceBase;
class Downloader
{
/**
* Get latest version from BitBucket tag
* Get latest version from BitBucket tag (type = bitbuckettag)
*
* @param string $name source name
* @param array $source source meta info: [repo]
@@ -51,7 +51,7 @@ class Downloader
}
/**
* Get latest version from GitHub tarball
* Get latest version from GitHub tarball (type = ghtar / ghtagtar)
*
* @param string $name source name
* @param array $source source meta info: [repo]
@@ -68,7 +68,16 @@ class Downloader
hooks: [[CurlHook::class, 'setupGithubToken']],
retry: intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0)
), true);
$url = $data[0]['tarball_url'];
if (($source['prefer-stable'] ?? false) === true) {
$url = $data[0]['tarball_url'];
} else {
$id = 0;
while ($data[$id]['prerelease'] === true) {
++$id;
}
$url = $data[$id]['tarball_url'] ?? null;
}
if (!$url) {
throw new DownloaderException("failed to find {$name} source");
}
@@ -106,7 +115,7 @@ class Downloader
), true);
$url = null;
foreach ($data as $release) {
if ($release['prerelease'] === true) {
if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) {
continue;
}
foreach ($release['assets'] as $asset) {
@@ -337,7 +346,7 @@ class Downloader
);
break;
case 'custom': // Custom download method, like API-based download or other
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\\store\\source');
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
foreach ($classes as $class) {
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
(new $class())->fetch($force);
@@ -437,7 +446,7 @@ class Downloader
);
break;
case 'custom': // Custom download method, like API-based download or other
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\\store\\source');
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
foreach ($classes as $class) {
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
(new $class())->fetch($force);

View File

@@ -195,7 +195,7 @@ class FileSystem
}
try {
self::extractArchive($filename, $target);
self::emitSourceExtractHook($name);
self::emitSourceExtractHook($name, $target);
} catch (RuntimeException $e) {
if (PHP_OS_FAMILY === 'Windows') {
f_passthru('rmdir /s /q ' . $target);
@@ -436,6 +436,21 @@ class FileSystem
return str_replace(array_keys($replacement), array_values($replacement), $path);
}
public static function backupFile(string $path): string
{
copy($path, $path . '.bak');
return $path . '.bak';
}
public static function restoreBackupFile(string $path): void
{
if (!file_exists($path . '.bak')) {
throw new RuntimeException('Cannot find bak file for ' . $path);
}
copy($path . '.bak', $path);
unlink($path . '.bak');
}
/**
* @throws RuntimeException
* @throws FileSystemException
@@ -503,10 +518,10 @@ class FileSystem
return file_put_contents($filename, $file);
}
private static function emitSourceExtractHook(string $name): void
private static function emitSourceExtractHook(string $name, string $target): void
{
foreach ((self::$_extract_hook[$name] ?? []) as $hook) {
if ($hook() === true) {
if ($hook($name, $target) === true) {
logger()->info('Patched source [' . $name . '] after extracted');
}
}

View File

@@ -9,6 +9,7 @@ use SPC\builder\linux\LinuxBuilder;
use SPC\builder\unix\UnixBuilderBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
class SourcePatcher
{
@@ -18,12 +19,21 @@ class SourcePatcher
FileSystem::addSourceExtractHook('micro', [SourcePatcher::class, 'patchMicro']);
FileSystem::addSourceExtractHook('openssl', [SourcePatcher::class, 'patchOpenssl11Darwin']);
FileSystem::addSourceExtractHook('swoole', [SourcePatcher::class, 'patchSwoole']);
FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchPhpLibxml212']);
FileSystem::addSourceExtractHook('php-src', [SourcePatcher::class, 'patchGDWin32']);
FileSystem::addSourceExtractHook('sqlsrv', [SourcePatcher::class, 'patchSQLSRVWin32']);
FileSystem::addSourceExtractHook('pdo_sqlsrv', [SourcePatcher::class, 'patchSQLSRVWin32']);
FileSystem::addSourceExtractHook('yaml', [SourcePatcher::class, 'patchYamlWin32']);
FileSystem::addSourceExtractHook('libyaml', [SourcePatcher::class, 'patchLibYaml']);
}
/**
* Source patcher runner before buildconf
*
* @param BuilderBase $builder Builder
* @param BuilderBase $builder Builder
* @throws FileSystemException
* @throws RuntimeException
* @throws WrongUsageException
*/
public static function patchBeforeBuildconf(BuilderBase $builder): void
{
@@ -46,6 +56,12 @@ class SourcePatcher
''
);
}
if ($builder->getOption('enable-micro-win32')) {
SourcePatcher::patchMicroWin32();
} else {
SourcePatcher::unpatchMicroWin32();
}
}
/**
@@ -69,7 +85,7 @@ class SourcePatcher
* @throws RuntimeException
* @throws FileSystemException
*/
public static function patchMicro(?array $list = null, bool $reverse = false): bool
public static function patchMicro(): bool
{
if (!file_exists(SOURCE_PATH . '/php-src/sapi/micro/php_micro.c')) {
return false;
@@ -104,7 +120,7 @@ class SourcePatcher
if (PHP_OS_FAMILY === 'Darwin') {
$default[] = 'macos_iconv';
}
$patch_list = $list ?? $default;
$patch_list = $default;
$patches = [];
$serial = ['80', '81', '82', '83', '84'];
foreach ($patch_list as $patchName) {
@@ -127,7 +143,7 @@ class SourcePatcher
f_passthru(
'cd ' . SOURCE_PATH . '/php-src && ' .
(PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . $patchesStr . ' | patch -p1 ' . ($reverse ? '-R' : '')
(PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . $patchesStr . ' | patch -p1 '
);
return true;
@@ -175,6 +191,9 @@ class SourcePatcher
return false;
}
/**
* @throws FileSystemException
*/
public static function patchSwoole(): bool
{
// swoole hook needs pdo/pdo.h
@@ -200,6 +219,11 @@ class SourcePatcher
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
}
// no asan
// if (strpos(file_get_contents(SOURCE_PATH . '/php-src/Makefile'), 'CFLAGS_CLEAN = -g') === false) {
// FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'CFLAGS_CLEAN = ', 'CFLAGS_CLEAN = -g -fsanitize=address ');
// }
// call extension patch before make
foreach ($builder->getExts() as $ext) {
if ($ext->patchBeforeMake() === true) {
@@ -268,6 +292,75 @@ class SourcePatcher
return $result;
}
/**
* @throws FileSystemException
*/
public static function patchMicroPhar(int $version_id): void
{
FileSystem::backupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c');
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/phar/phar.c',
'static zend_op_array *phar_compile_file',
"char *micro_get_filename(void);\n\nstatic zend_op_array *phar_compile_file"
);
if ($version_id < 80100) {
// PHP 8.0.x
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/phar/phar.c',
'if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {',
'if ((strstr(file_handle->filename, micro_get_filename()) || strstr(file_handle->filename, ".phar")) && !strstr(file_handle->filename, "://")) {'
);
} else {
// PHP >= 8.1
FileSystem::replaceFileStr(
SOURCE_PATH . '/php-src/ext/phar/phar.c',
'if (strstr(ZSTR_VAL(file_handle->filename), ".phar") && !strstr(ZSTR_VAL(file_handle->filename), "://")) {',
'if ((strstr(ZSTR_VAL(file_handle->filename), micro_get_filename()) || strstr(ZSTR_VAL(file_handle->filename), ".phar")) && !strstr(ZSTR_VAL(file_handle->filename), "://")) {'
);
}
}
/**
* @throws RuntimeException
*/
public static function unpatchMicroPhar(): void
{
FileSystem::restoreBackupFile(SOURCE_PATH . '/php-src/ext/phar/phar.c');
}
/**
* Fix the compilation issue of sqlsrv and pdo_sqlsrv on Windows (/sdl check is too strict and will cause Zend compilation to fail)
*
* @throws FileSystemException
*/
public static function patchSQLSRVWin32(string $source_name): bool
{
$source_name = preg_replace('/[^a-z_]/', '', $source_name);
if (file_exists(SOURCE_PATH . '/php-src/ext/' . $source_name . '/config.w32')) {
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/' . $source_name . '/config.w32', '/sdl', '');
return true;
}
return false;
}
public static function patchYamlWin32(): bool
{
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/yaml/config.w32', "lib.substr(lib.length - 6, 6) == '_a.lib'", "lib.substr(lib.length - 6, 6) == '_a.lib' || 'yes' == 'yes'");
return true;
}
public static function patchLibYaml(string $name, string $target): bool
{
if (!file_exists("{$target}\\cmake\\config.h.in")) {
FileSystem::createDir("{$target}\\cmake");
copy(ROOT_DIR . '\src\globals\extra\libyaml_config.h.in', "{$target}\\cmake\\config.h.in");
}
if (!file_exists("{$target}\\YamlConfig.cmake.in")) {
copy(ROOT_DIR . '\src\globals\extra\libyaml_YamlConfig.cmake.in', "{$target}\\YamlConfig.cmake.in");
}
return true;
}
/**
* Patch cli SAPI Makefile for Windows.
*
@@ -282,7 +375,7 @@ class SourcePatcher
$line_num = 0;
$found = false;
foreach ($lines as $v) {
if (strpos($v, '$(BUILD_DIR)\php.exe:') !== false) {
if (str_contains($v, '$(BUILD_DIR)\php.exe:')) {
$found = $line_num;
break;
}
@@ -296,6 +389,50 @@ class SourcePatcher
FileSystem::writeFile(SOURCE_PATH . '/php-src/Makefile', implode("\r\n", $lines));
}
/**
* @throws RuntimeException
*/
public static function patchPhpLibxml212(): bool
{
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
$ver_id = intval($match[1]);
if ($ver_id < 80000) {
return false;
}
if ($ver_id < 80100) {
self::patchFile('spc_fix_libxml2_12_php80.patch', SOURCE_PATH . '/php-src');
return true;
}
if ($ver_id < 80200) {
self::patchFile('spc_fix_libxml2_12_php81.patch', SOURCE_PATH . '/php-src');
return true;
}
return false;
}
return false;
}
/**
* @throws FileSystemException
*/
public static function patchGDWin32(): bool
{
$file = file_get_contents(SOURCE_PATH . '/php-src/main/php_version.h');
if (preg_match('/PHP_VERSION_ID (\d+)/', $file, $match) !== 0) {
$ver_id = intval($match[1]);
if ($ver_id < 80200) {
// see: https://github.com/php/php-src/commit/243966177e39eb71822935042c3f13fa6c5b9eed
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/gd/libgd/gdft.c', '#ifndef MSWIN32', '#ifndef _WIN32');
}
// custom config.w32, because official config.w32 is hard-coded many things
$origin = $ver_id >= 80100 ? file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_81.w32') : file_get_contents(ROOT_DIR . '/src/globals/extra/gd_config_80.w32');
file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32.bak', file_get_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32'));
return file_put_contents(SOURCE_PATH . '/php-src/ext/gd/config.w32', $origin) !== false;
}
return false;
}
/**
* Add additional `static-php-cli.version` ini value for PHP source.
*
@@ -311,4 +448,23 @@ class SourcePatcher
FileSystem::writeFile(SOURCE_PATH . '/php-src/main/main.c', $file);
}
}
/**
* @throws FileSystemException
*/
public static function patchMicroWin32(): void
{
// patch micro win32
if (!file_exists(SOURCE_PATH . '\php-src\sapi\micro\php_micro.c.win32bak')) {
copy(SOURCE_PATH . '\php-src\sapi\micro\php_micro.c', SOURCE_PATH . '\php-src\sapi\micro\php_micro.c.win32bak');
FileSystem::replaceFileStr(SOURCE_PATH . '\php-src\sapi\micro\php_micro.c', '#include "php_variables.h"', '#include "php_variables.h"' . "\n#define PHP_MICRO_WIN32_NO_CONSOLE 1");
}
}
public static function unpatchMicroWin32(): void
{
if (file_exists(SOURCE_PATH . '\php-src\sapi\micro\php_micro.c.win32bak')) {
rename(SOURCE_PATH . '\php-src\sapi\micro\php_micro.c.win32bak', SOURCE_PATH . '\php-src\sapi\micro\php_micro.c');
}
}
}

View File

@@ -23,7 +23,7 @@ class CustomExt
*/
public static function loadCustomExt(): void
{
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/builder/extension', 'SPC\\builder\\extension');
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/builder/extension', 'SPC\builder\extension');
foreach ($classes as $class) {
$reflection = new \ReflectionClass($class);
foreach ($reflection->getAttributes(CustomExt::class) as $attribute) {

View File

@@ -0,0 +1,361 @@
<?php
define('K_SP', ' ');
define('K_exclam', '!');
define('K_quotedbl', '"');
define('K_numbersign', '#');
define('K_dollar', '$');
define('K_percent', '%');
define('K_ampersand', '&');
define('K_apostrophe', "'");
define('K_parentleft', '(');
define('K_parentright', ')');
define('K_asterisk', '*');
define('K_plus', '+');
define('K_comma', ',');
define('K_minus', '-');
define('K_period', '.');
define('K_slash', '/');
define('K_0', '0');
define('K_1', '1');
define('K_2', '2');
define('K_3', '3');
define('K_4', '4');
define('K_5', '5');
define('K_6', '6');
define('K_7', '7');
define('K_8', '8');
define('K_9', '9');
define('K_colon', ':');
define('K_semicolon', ';');
define('K_less', '<');
define('K_equal', '=');
define('K_greater', '>');
define('K_question', '?');
define('K_at', '@');
define('K_A', 'A');
define('K_B', 'B');
define('K_C', 'C');
define('K_D', 'D');
define('K_E', 'E');
define('K_F', 'F');
define('K_G', 'G');
define('K_H', 'H');
define('K_I', 'I');
define('K_J', 'J');
define('K_K', 'K');
define('K_L', 'L');
define('K_M', 'M');
define('K_N', 'N');
define('K_O', 'O');
define('K_P', 'P');
define('K_Q', 'Q');
define('K_R', 'R');
define('K_S', 'S');
define('K_T', 'T');
define('K_U', 'U');
define('K_V', 'V');
define('K_W', 'W');
define('K_X', 'X');
define('K_Y', 'Y');
define('K_Z', 'Z');
define('K_bracketleft', '[');
define('K_bracketright', ']');
define('K_circum', '^');
define('K_underscore', '_');
define('K_grave', '`');
define('K_a', 'a');
define('K_b', 'b');
define('K_c', 'c');
define('K_d', 'd');
define('K_e', 'e');
define('K_f', 'f');
define('K_g', 'g');
define('K_h', 'h');
define('K_i', 'i');
define('K_j', 'j');
define('K_k', 'k');
define('K_l', 'l');
define('K_m', 'm');
define('K_n', 'n');
define('K_o', 'o');
define('K_p', 'p');
define('K_q', 'q');
define('K_r', 'r');
define('K_s', 's');
define('K_t', 't');
define('K_u', 'u');
define('K_v', 'v');
define('K_w', 'w');
define('K_x', 'x');
define('K_y', 'y');
define('K_z', 'z');
define('K_braceleft', '{');
define('K_bar', '|');
define('K_braceright', '}');
define('K_tilde', '~');
define('K_BS', '\\b');
define('K_TAB', "\t");
define('K_LF', "\n");
define('K_CR', "\r");
define('K_quoteleft', '`');
define('K_quoteright', "'");
define('K_PAUSE', 65299);
define('K_ESC', 65307);
define('K_HOME', 65360);
define('K_LEFT', 65361);
define('K_UP', 65362);
define('K_RIGHT', 65363);
define('K_DOWN', 65364);
define('K_PGUP', 65365);
define('K_PGDN', 65366);
define('K_END', 65367);
define('K_MIDDLE', 65291);
define('K_Print', 65377);
define('K_INS', 65379);
define('K_Menu', 65383);
define('K_DEL', 65535);
define('K_F1', 65470);
define('K_F2', 65471);
define('K_F3', 65472);
define('K_F4', 65473);
define('K_F5', 65474);
define('K_F6', 65475);
define('K_F7', 65476);
define('K_F8', 65477);
define('K_F9', 65478);
define('K_F10', 65479);
define('K_F11', 65480);
define('K_F12', 65481);
define('K_F13', 65482);
define('K_F14', 65483);
define('K_F15', 65484);
define('K_F16', 65485);
define('K_F17', 65486);
define('K_F18', 65487);
define('K_F19', 65488);
define('K_F20', 65489);
define('K_LSHIFT', 65505);
define('K_RSHIFT', 65506);
define('K_LCTRL', 65507);
define('K_RCTRL', 65508);
define('K_LALT', 65513);
define('K_RALT', 65514);
define('K_NUM', 65407);
define('K_SCROLL', 65300);
define('K_CAPS', 65509);
define('K_CLEAR', 65490);
define('K_HELP', 65491);
define('K_ccedilla', 231);
define('K_Ccedilla', 199);
define('K_acute', 180);
define('K_diaeresis', 168);
define('IUP_RUN', 'RUN');
define('IUP_ENGLISH', 'ENGLISH');
define('IUP_PORTUGUESE', 'PORTUGUESE');
define('IUP_SBH', 'SBH');
define('IUP_SBV', 'SBV');
define('IUP_IDLE_ACTION', 'IDLE_ACTION');
define('IUP_ACTION', 'ACTION');
define('IUP_GETFOCUS_CB', 'GETFOCUS_CB');
define('IUP_KILLFOCUS_CB', 'KILLFOCUS_CB');
define('IUP_K_ANY', 'K_ANY');
define('IUP_KEYPRESS_CB', 'KEYPRESS_CB');
define('IUP_HELP_CB', 'HELP_CB');
define('IUP_SCROLL_CB', 'SCROLL_CB');
define('IUP_RESIZE_CB', 'RESIZE_CB');
define('IUP_MOTION_CB', 'MOTION_CB');
define('IUP_BUTTON_CB', 'BUTTON_CB');
define('IUP_ENTERWINDOW_CB', 'ENTERWINDOW_CB');
define('IUP_LEAVEWINDOW_CB', 'LEAVEWINDOW_CB');
define('IUP_WHEEL_CB', 'WHEEL_CB');
define('IUP_MASK_CB', 'MASK_CB');
define('IUP_OPEN_CB', 'OPEN_CB');
define('IUP_HIGHLIGHT_CB', 'HIGHLIGHT_CB');
define('IUP_MENUCLOSE_CB', 'MENUCLOSE_CB');
define('IUP_MAP_CB', 'MAP_CB');
define('IUP_CLOSE_CB', 'CLOSE_CB');
define('IUP_SHOW_CB', 'SHOW_CB');
define('IUP_DROPFILES_CB', 'DROPFILES_CB');
define('IUP_WOM_CB', 'WOM_CB');
define('IUP_DIRECTION', 'DIRECTION');
define('IUP_ACTIVE', 'ACTIVE');
define('IUP_BGCOLOR', 'BGCOLOR');
define('IUP_FRAMECOLOR', 'FRAMECOLOR');
define('IUP_FGCOLOR', 'FGCOLOR');
define('IUP_COLOR', 'COLOR');
define('IUP_WID', 'WID');
define('IUP_SIZE', 'SIZE');
define('IUP_RASTERSIZE', 'RASTERSIZE');
define('IUP_TITLE', 'TITLE');
define('IUP_VALUE', 'VALUE');
define('IUP_VISIBLE', 'VISIBLE');
define('IUP_FONT', 'FONT');
define('IUP_TIP', 'TIP');
define('IUP_EXPAND', 'EXPAND');
define('IUP_SEPARATOR', 'SEPARATOR');
define('IUP_HOTSPOT', 'HOTSPOT');
define('IUP_HEIGHT', 'HEIGHT');
define('IUP_WIDTH', 'WIDTH');
define('IUP_KEY', 'KEY');
define('IUP_MULTIPLE', 'MULTIPLE');
define('IUP_DROPDOWN', 'DROPDOWN');
define('IUP_VISIBLE_ITEMS', 'VISIBLE_ITEMS');
define('IUP_MARGIN', 'MARGIN');
define('IUP_GAP', 'GAP');
define('IUP_ALIGNMENT', 'ALIGNMENT');
define('IUP_IMAGE', 'IMAGE');
define('IUP_IMINACTIVE', 'IMINACTIVE');
define('IUP_IMPRESS', 'IMPRESS');
define('IUP_WIN_SAVEBITS', 'WIN_SAVEBITS');
define('IUP_NC', 'NC');
define('IUP_MASK', 'MASK');
define('IUP_APPEND', 'APPEND');
define('IUP_BORDER', 'BORDER');
define('IUP_CARET', 'CARET');
define('IUP_SELECTION', 'SELECTION');
define('IUP_SELECTEDTEXT', 'SELECTEDTEXT');
define('IUP_INSERT', 'INSERT');
define('IUP_CONID', 'CONID');
define('IUP_CURSOR', 'CURSOR');
define('IUP_ICON', 'ICON');
define('IUP_MENUBOX', 'MENUBOX');
define('IUP_MINBOX', 'MINBOX');
define('IUP_MAXBOX', 'MAXBOX');
define('IUP_RESIZE', 'RESIZE');
define('IUP_MENU', 'MENU');
define('IUP_STARTFOCUS', 'STARTFOCUS');
define('IUP_PARENTDIALOG', 'PARENTDIALOG');
define('IUP_SHRINK', 'SHRINK');
define('IUP_DEFAULTENTER', 'DEFAULTENTER');
define('IUP_DEFAULTESC', 'DEFAULTESC');
define('IUP_X', 'X');
define('IUP_Y', 'Y');
define('IUP_TOOLBOX', 'TOOLBOX');
define('IUP_CONTROL', 'CONTROL');
define('IUP_READONLY', 'READONLY');
define('IUP_SCROLLBAR', 'SCROLLBAR');
define('IUP_POSY', 'POSY');
define('IUP_POSX', 'POSX');
define('IUP_DX', 'DX');
define('IUP_DY', 'DY');
define('IUP_XMAX', 'XMAX');
define('IUP_XMIN', 'XMIN');
define('IUP_YMAX', 'YMAX');
define('IUP_YMIN', 'YMIN');
define('IUP_RED', '255 0 0');
define('IUP_GREEN', '0 255 0');
define('IUP_BLUE', '0 0 255');
define('IUP_MIN', 'MIN');
define('IUP_MAX', 'MAX');
define('IUP_TIME', 'TIME');
define('IUP_DRAG', 'DRAG');
define('IUP_DROP', 'DROP');
define('IUP_REPAINT', 'REPAINT');
define('IUP_TOPMOST', 'TOPMOST');
define('IUP_CLIPCHILDREN', 'CLIPCHILDREN');
define('IUP_DIALOGTYPE', 'DIALOGTYPE');
define('IUP_FILE', 'FILE');
define('IUP_MULTIPLEFILES', 'MULTIPLEFILES');
define('IUP_FILTER', 'FILTER');
define('IUP_FILTERUSED', 'FILTERUSED');
define('IUP_FILTERINFO', 'FILTERINFO');
define('IUP_EXTFILTER', 'EXTFILTER');
define('IUP_DIRECTORY', 'DIRECTORY');
define('IUP_ALLOWNEW', 'ALLOWNEW');
define('IUP_NOOVERWRITEPROMPT', 'NOOVERWRITEPROMPT');
define('IUP_NOCHANGEDIR', 'NOCHANGEDIR');
define('IUP_FILEEXIST', 'FILEEXIST');
define('IUP_STATUS', 'STATUS');
define('IUP_LOCKLOOP', 'LOCKLOOP');
define('IUP_SYSTEM', 'SYSTEM');
define('IUP_DRIVER', 'DRIVER');
define('IUP_SCREENSIZE', 'SCREENSIZE');
define('IUP_SYSTEMLANGUAGE', 'SYSTEMLANGUAGE');
define('IUP_COMPUTERNAME', 'COMPUTERNAME');
define('IUP_USERNAME', 'USERNAME');
define('IUP_OPEN', 'OPEN');
define('IUP_SAVE', 'SAVE');
define('IUP_DIR', 'DIR');
define('IUP_HORIZONTAL', 'HORIZONTAL');
define('IUP_VERTICAL', 'VERTICAL');
define('IUP_YES', 'YES');
define('IUP_NO', 'NO');
define('IUP_ON', 'ON');
define('IUP_OFF', 'OFF');
define('IUP_ACENTER', 'ACENTER');
define('IUP_ALEFT', 'ALEFT');
define('IUP_ARIGHT', 'ARIGHT');
define('IUP_ATOP', 'ATOP');
define('IUP_ABOTTOM', 'ABOTTOM');
define('IUP_NORTH', 'NORTH');
define('IUP_SOUTH', 'SOUTH');
define('IUP_WEST', 'WEST');
define('IUP_EAST', 'EAST');
define('IUP_NE', 'NE');
define('IUP_SE', 'SE');
define('IUP_NW', 'NW');
define('IUP_SW', 'SW');
define('IUP_FULLSCREEN', 'FULLSCREEN');
define('IUP_FULL', 'FULL');
define('IUP_HALF', 'HALF');
define('IUP_THIRD', 'THIRD');
define('IUP_QUARTER', 'QUARTER');
define('IUP_EIGHTH', 'EIGHTH');
define('IUP_ARROW', 'ARROW');
define('IUP_BUSY', 'BUSY');
define('IUP_RESIZE_N', 'RESIZE_N');
define('IUP_RESIZE_S', 'RESIZE_S');
define('IUP_RESIZE_E', 'RESIZE_E');
define('IUP_RESIZE_W', 'RESIZE_W');
define('IUP_RESIZE_NE', 'RESIZE_NE');
define('IUP_RESIZE_NW', 'RESIZE_NW');
define('IUP_RESIZE_SE', 'RESIZE_SE');
define('IUP_RESIZE_SW', 'RESIZE_SW');
define('IUP_MOVE', 'MOVE');
define('IUP_HAND', 'HAND');
define('IUP_NONE', 'NONE');
define('IUP_IUP', 'IUP');
define('IUP_CROSS', 'CROSS');
define('IUP_PEN', 'PEN');
define('IUP_TEXT', 'TEXT');
define('IUP_RESIZE_C', 'RESIZE_C');
define('IUP_OPENHAND', 'OPENHAND');
define('IUP_K_exclam', 'K_exclam');
define('IUP_K_quotedbl', 'K_quotedbl');
define('IUP_K_numbersign', 'K_numbersign');
define('IUP_K_dollar', 'K_dollar');
define('IUP_K_percent', 'K_percent');
define('IUP_K_ampersand', 'K_ampersand');
define('IUP_K_quoteright', 'K_quoteright');
define('IUP_K_parentleft', 'K_parentleft');
define('IUP_K_parentright', 'K_parentright');
define('IUP_K_asterisk', 'K_asterisk');
define('IUP_K_plus', 'K_plus');
define('IUP_K_comma', 'K_comma');
define('IUP_K_minus', 'K_minus');
define('IUP_K_period', 'K_period');
define('IUP_K_slash', 'K_slash');
define('IUP_K_0', 'K_0');
define('IUP_K_1', 'K_1');
define('IUP_K_2', 'K_2');
define('IUP_K_3', 'K_3');
define('IUP_K_4', 'K_4');
define('IUP_K_5', 'K_5');
define('IUP_K_6', 'K_6');
define('IUP_K_7', 'K_7');
define('IUP_K_8', 'K_8');
define('IUP_K_9', 'K_9');
define('IUP_K_colon', 'K_colon');
define('IUP_K_semicolon', 'K_semicolon ');
define('IUP_K_less', 'K_less');
define('IUP_K_equal', 'K_equal');
define('IUP_K_greater', 'K_greater');
define('IUP_K_question', 'K_question');
define('IUP_K_at', 'K_at');
define('IUP_K_A', 'K_A');
define('IUP_K_B', 'K_B');
define('IUP_K_C', 'K_C');
define('IUP_K_D', 'K_D');
define('IUP_K_E', 'K_E');
define('IUP_K_F', 'K_F');
define('IUP_K_G', 'K_G');

View File

@@ -38,6 +38,24 @@ const DANGER_CMD = [
'rmdir',
];
// spc internal extensions
const SPC_INTERNAL_EXTENSIONS = [
'core',
'hash',
'json',
'pcre',
'reflection',
'spl',
'standard',
];
// spc extension alias
const SPC_EXTENSION_ALIAS = [
'zend opcache' => 'opcache',
'zend-opcache' => 'opcache',
'zendopcache' => 'opcache',
];
// file replace strategy
const REPLACE_FILE_STR = 1;
const REPLACE_FILE_PREG = 2;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
assert(class_exists('\\DOMDocument'));
assert(class_exists('\DOMDocument'));
$doc = new DOMDocument();
$doc->loadHtml('<html><head><meta charset="UTF-8"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body id="app">Hello</body></html>');
assert($doc->getElementById('app')->nodeValue === 'Hello');

View File

@@ -2,4 +2,4 @@
declare(strict_types=1);
assert(class_exists('\\Redis'));
assert(class_exists('\Redis'));

View File

@@ -0,0 +1,5 @@
<?php
declare(strict_types=1);
assert(class_exists('\ZipArchive'));

View File

@@ -0,0 +1,86 @@
// vim:ft=javascript
ARG_WITH("gd", "Bundled GD support", "yes");
if (PHP_GD != "no") {
// check for gd.h (required)
if (!CHECK_HEADER_ADD_INCLUDE("gd.h", "CFLAGS_GD", PHP_GD + ";ext\\gd\\libgd")) {
ERROR("gd not enabled; libraries and headers not found");
}
// zlib ext support (required)
if (!CHECK_LIB("zlib_a.lib;zlib.lib", "gd", PHP_GD)) {
ERROR("gd not enabled; zlib not enabled");
}
// libjpeg lib support
if (CHECK_LIB("libjpeg_a.lib;libjpeg.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("jpeglib.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include")) {
AC_DEFINE("HAVE_LIBJPEG", 1, "JPEG support");
AC_DEFINE("HAVE_GD_JPG", 1, "JPEG support");
}
// libpng16 lib support
if (CHECK_LIB("libpng_a.lib;libpng.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng16")) {
AC_DEFINE("HAVE_LIBPNG", 1, "PNG support");
AC_DEFINE("HAVE_GD_PNG", 1, "PNG support");
}
// freetype lib support
if (CHECK_LIB("libfreetype_a.lib;libfreetype.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("ft2build.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\freetype2;" + PHP_PHP_BUILD + "\\include\\freetype")) {
AC_DEFINE("HAVE_LIBFREETYPE", 1, "FreeType support");
AC_DEFINE("HAVE_GD_FREETYPE", 1, "FreeType support");
}
// xpm lib support
if (CHECK_LIB("libXpm_a.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("xpm.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\X11")) {
AC_DEFINE("HAVE_LIBXPM", 1, "XPM support");
AC_DEFINE("HAVE_GD_XPM", 1, "XPM support");
}
// iconv lib support
if ((CHECK_LIB("libiconv_a.lib;libiconv.lib", "gd", PHP_GD) || CHECK_LIB("iconv_a.lib;iconv.lib", "gd", PHP_GD)) &&
CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_GD", PHP_GD)) {
AC_DEFINE("HAVE_LIBICONV", 1, "Iconv support");
}
// libwebp lib support
if ((CHECK_LIB("libwebp_a.lib", "gd", PHP_GD) || CHECK_LIB("libwebp.lib", "gd", PHP_GD)) &&
CHECK_LIB("libsharpyuv.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("decode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp") &&
CHECK_HEADER_ADD_INCLUDE("encode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp")) {
AC_DEFINE("HAVE_LIBWEBP", 1, "WebP support");
AC_DEFINE("HAVE_GD_WEBP", 1, "WebP support");
}
// libavif lib is not supported on php <= 8.0
CHECK_LIB("User32.lib", "gd", PHP_GD);
CHECK_LIB("Gdi32.lib", "gd", PHP_GD);
EXTENSION("gd", "gd.c", null, "-Iext/gd/libgd");
ADD_SOURCES("ext/gd/libgd", "gd.c \
gdcache.c gdfontg.c gdfontl.c gdfontmb.c gdfonts.c gdfontt.c \
gdft.c gd_gd2.c gd_gd.c gd_gif_in.c gd_gif_out.c gdhelpers.c gd_io.c gd_io_dp.c \
gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \
gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c gd_xbm.c gd_security.c gd_transform.c \
gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c \
gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c", "gd");
AC_DEFINE('HAVE_LIBGD', 1, 'GD support');
AC_DEFINE('HAVE_GD_BUNDLED', 1, "Bundled GD");
AC_DEFINE('HAVE_GD_BMP', 1, "BMP support");
AC_DEFINE('HAVE_GD_TGA', 1, "TGA support");
ADD_FLAG("CFLAGS_GD", " \
/D PHP_GD_EXPORTS=1 \
/D HAVE_GD_GET_INTERPOLATION \
");
if (ICC_TOOLSET) {
ADD_FLAG("LDFLAGS_GD", "/nodefaultlib:libcmt");
}
PHP_INSTALL_HEADERS("", "ext/gd ext/gd/libgd");
}

View File

@@ -0,0 +1,94 @@
// vim:ft=javascript
ARG_WITH("gd", "Bundled GD support", "yes");
if (PHP_GD != "no") {
// check for gd.h (required)
if (!CHECK_HEADER_ADD_INCLUDE("gd.h", "CFLAGS_GD", PHP_GD + ";ext\\gd\\libgd")) {
ERROR("gd not enabled; libraries and headers not found");
}
// zlib ext support (required)
if (!CHECK_LIB("zlib_a.lib;zlib.lib", "gd", PHP_GD)) {
ERROR("gd not enabled; zlib not enabled");
}
// libjpeg lib support
if (CHECK_LIB("libjpeg_a.lib;libjpeg.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("jpeglib.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include")) {
AC_DEFINE("HAVE_LIBJPEG", 1, "JPEG support");
AC_DEFINE("HAVE_GD_JPG", 1, "JPEG support");
}
// libpng16 lib support
if (CHECK_LIB("libpng_a.lib;libpng.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng16")) {
AC_DEFINE("HAVE_LIBPNG", 1, "PNG support");
AC_DEFINE("HAVE_GD_PNG", 1, "PNG support");
}
// freetype lib support
if (CHECK_LIB("libfreetype_a.lib;libfreetype.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("ft2build.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\freetype2;" + PHP_PHP_BUILD + "\\include\\freetype")) {
AC_DEFINE("HAVE_LIBFREETYPE", 1, "FreeType support");
AC_DEFINE("HAVE_GD_FREETYPE", 1, "FreeType support");
}
// xpm lib support
if (CHECK_LIB("libXpm_a.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("xpm.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\X11")) {
AC_DEFINE("HAVE_LIBXPM", 1, "XPM support");
AC_DEFINE("HAVE_GD_XPM", 1, "XPM support");
}
// iconv lib support
if ((CHECK_LIB("libiconv_a.lib;libiconv.lib", "gd", PHP_GD) || CHECK_LIB("iconv_a.lib;iconv.lib", "gd", PHP_GD)) &&
CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_GD", PHP_GD)) {
AC_DEFINE("HAVE_LIBICONV", 1, "Iconv support");
}
// libwebp lib support
if ((CHECK_LIB("libwebp_a.lib", "gd", PHP_GD) || CHECK_LIB("libwebp.lib", "gd", PHP_GD)) &&
CHECK_LIB("libsharpyuv.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("decode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp") &&
CHECK_HEADER_ADD_INCLUDE("encode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp")) {
AC_DEFINE("HAVE_LIBWEBP", 1, "WebP support");
AC_DEFINE("HAVE_GD_WEBP", 1, "WebP support");
}
// libavif lib support
if (CHECK_LIB("avif_a.lib", "gd", PHP_GD) &&
CHECK_LIB("aom_a.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) {
ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBAVIF /D HAVE_GD_AVIF");
} else if (CHECK_LIB("avif.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("avif.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\avif")) {
ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBAVIF /D HAVE_GD_AVIF");
}
CHECK_LIB("User32.lib", "gd", PHP_GD);
CHECK_LIB("Gdi32.lib", "gd", PHP_GD);
EXTENSION("gd", "gd.c", null, "-Iext/gd/libgd");
ADD_SOURCES("ext/gd/libgd", "gd.c \
gdcache.c gdfontg.c gdfontl.c gdfontmb.c gdfonts.c gdfontt.c \
gdft.c gd_gd2.c gd_gd.c gd_gif_in.c gd_gif_out.c gdhelpers.c gd_io.c gd_io_dp.c \
gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \
gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c gd_xbm.c gd_security.c gd_transform.c \
gd_filter.c gd_pixelate.c gd_rotate.c gd_color_match.c gd_webp.c gd_avif.c \
gd_crop.c gd_interpolation.c gd_matrix.c gd_bmp.c gd_tga.c", "gd");
AC_DEFINE('HAVE_LIBGD', 1, 'GD support');
AC_DEFINE('HAVE_GD_BUNDLED', 1, "Bundled GD");
AC_DEFINE('HAVE_GD_BMP', 1, "BMP support");
AC_DEFINE('HAVE_GD_TGA', 1, "TGA support");
ADD_FLAG("CFLAGS_GD", " \
/D PHP_GD_EXPORTS=1 \
/D HAVE_GD_GET_INTERPOLATION \
");
if (ICC_TOOLSET) {
ADD_FLAG("LDFLAGS_GD", "/nodefaultlib:libcmt");
}
PHP_INSTALL_HEADERS("", "ext/gd ext/gd/libgd");
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2004-2006, 2008, 2009, 2011-2013, 2015-2018 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#ifndef __DNSINFO_H__
#define __DNSINFO_H__
/*
* These routines provide access to the systems DNS configuration
*/
#include <os/availability.h>
#include <sys/cdefs.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define DNSINFO_VERSION 20170629
#define DEFAULT_SEARCH_ORDER 200000 /* search order for the "default" resolver domain name */
#define DNS_PTR(type, name) \
union { \
type name; \
uint64_t _ ## name ## _p; \
}
#define DNS_VAR(type, name) \
type name
#pragma pack(4)
typedef struct {
struct in_addr address;
struct in_addr mask;
} dns_sortaddr_t;
#pragma pack()
#pragma pack(4)
typedef struct {
DNS_PTR(char *, domain); /* domain */
DNS_VAR(int32_t, n_nameserver); /* # nameserver */
DNS_PTR(struct sockaddr **, nameserver);
DNS_VAR(uint16_t, port); /* port (in host byte order) */
DNS_VAR(int32_t, n_search); /* # search */
DNS_PTR(char **, search);
DNS_VAR(int32_t, n_sortaddr); /* # sortaddr */
DNS_PTR(dns_sortaddr_t **, sortaddr);
DNS_PTR(char *, options); /* options */
DNS_VAR(uint32_t, timeout); /* timeout */
DNS_VAR(uint32_t, search_order); /* search_order */
DNS_VAR(uint32_t, if_index);
DNS_VAR(uint32_t, flags);
DNS_VAR(uint32_t, reach_flags); /* SCNetworkReachabilityFlags */
DNS_VAR(uint32_t, service_identifier);
DNS_PTR(char *, cid); /* configuration identifer */
DNS_PTR(char *, if_name); /* if_index interface name */
} dns_resolver_t;
#pragma pack()
#define DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS 0x0002 /* always requesting for A dns records in queries */
#define DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS 0x0004 /* always requesting for AAAA dns records in queries */
#define DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS \
(DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS | DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS)
#define DNS_RESOLVER_FLAGS_SCOPED 0x1000 /* configuration is for scoped questions */
#define DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC 0x2000 /* configuration is service-specific */
#define DNS_RESOLVER_FLAGS_SUPPLEMENTAL 0x4000 /* supplemental match configuration */
#pragma pack(4)
typedef struct {
DNS_VAR(int32_t, n_resolver); /* resolver configurations */
DNS_PTR(dns_resolver_t **, resolver);
DNS_VAR(int32_t, n_scoped_resolver); /* "scoped" resolver configurations */
DNS_PTR(dns_resolver_t **, scoped_resolver);
DNS_VAR(uint64_t, generation);
DNS_VAR(int32_t, n_service_specific_resolver);
DNS_PTR(dns_resolver_t **, service_specific_resolver);
DNS_VAR(uint32_t, version);
} dns_config_t;
#pragma pack()
__BEGIN_DECLS
/*
* DNS configuration access APIs
*/
const char *
dns_configuration_notify_key (void) API_AVAILABLE(macos(10.4), ios(2.0));
dns_config_t *
dns_configuration_copy (void) API_AVAILABLE(macos(10.4), ios(2.0));
void
dns_configuration_free (dns_config_t *config) API_AVAILABLE(macos(10.4), ios(2.0));
void
_dns_configuration_ack (dns_config_t *config,
const char *bundle_id) API_AVAILABLE(macos(10.8), ios(6.0));
__END_DECLS
#endif /* __DNSINFO_H__ */

View File

@@ -0,0 +1,10 @@
@PACKAGE_INIT@
set_and_check(yaml_TARGETS "@PACKAGE_CONFIG_DIR_CONFIG@/yamlTargets.cmake")
if(NOT yaml_TARGETS_IMPORTED)
set(yaml_TARGETS_IMPORTED 1)
include(${yaml_TARGETS})
endif()
set(yaml_LIBRARIES yaml)

View File

@@ -0,0 +1,4 @@
#define YAML_VERSION_MAJOR @YAML_VERSION_MAJOR@
#define YAML_VERSION_MINOR @YAML_VERSION_MINOR@
#define YAML_VERSION_PATCH @YAML_VERSION_PATCH@
#define YAML_VERSION_STRING "@YAML_VERSION_STRING@"

View File

@@ -56,7 +56,7 @@ function arch2gnu(string $arch): string
*/
function match_pattern(string $pattern, string $subject): bool
{
$pattern = str_replace(['\*', '\\\\.*'], ['.*', '\*'], preg_quote($pattern, '/'));
$pattern = str_replace(['\*', '\\\.*'], ['.*', '\*'], preg_quote($pattern, '/'));
$pattern = '/^' . $pattern . '$/i';
return preg_match($pattern, $subject) === 1;
}

View File

@@ -0,0 +1,89 @@
diff --git a/ext/dom/document.c b/ext/dom/document.c
index 02522b50..6d1b0740 100644
--- a/ext/dom/document.c
+++ b/ext/dom/document.c
@@ -23,6 +23,7 @@
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
#include "php_dom.h"
#include <libxml/SAX.h>
+#include <libxml/xmlsave.h>
#ifdef LIBXML_SCHEMAS_ENABLED
#include <libxml/relaxng.h>
#include <libxml/xmlschemas.h>
diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
index 73486ae2..59bd3d20 100644
--- a/ext/libxml/libxml.c
+++ b/ext/libxml/libxml.c
@@ -382,7 +382,7 @@ php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
if (encoding) {
char *end;
-
+
encoding += sizeof("charset=")-1;
if (*encoding == '"') {
encoding++;
@@ -481,7 +481,11 @@ static void _php_libxml_free_error(void *ptr)
xmlResetError((xmlErrorPtr) ptr);
}
-static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
+#if LIBXML_VERSION >= 21200
+static void _php_list_set_error_structure(const xmlError *error, const char *msg)
+#else
+static void _php_list_set_error_structure(xmlError *error, const char *msg)
+#endif
{
xmlError error_copy;
int ret;
@@ -732,7 +736,11 @@ PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
va_end(args);
}
+#if LIBXML_VERSION >= 21200
+PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, const xmlError *error)
+#else
PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
+#endif
{
_php_list_set_error_structure(error, NULL);
@@ -1035,11 +1043,9 @@ PHP_FUNCTION(libxml_use_internal_errors)
/* {{{ Retrieve last error from libxml */
PHP_FUNCTION(libxml_get_last_error)
{
- xmlErrorPtr error;
-
ZEND_PARSE_PARAMETERS_NONE();
- error = xmlGetLastError();
+ const xmlError *error = xmlGetLastError();
if (error) {
object_init_ex(return_value, libxmlerror_class_entry);
diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h
index d0ce7cec..02717417 100644
--- a/ext/libxml/php_libxml.h
+++ b/ext/libxml/php_libxml.h
@@ -35,6 +35,7 @@ extern zend_module_entry libxml_module_entry;
#include "zend_smart_str.h"
#include <libxml/tree.h>
+#include <libxml/parser.h>
#define LIBXML_SAVE_NOEMPTYTAG 1<<2
diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c
index e5e7f2f9..00b58b87 100644
--- a/ext/soap/php_sdl.c
+++ b/ext/soap/php_sdl.c
@@ -331,8 +331,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
sdl_restore_uri_credentials(ctx);
if (!wsdl) {
- xmlErrorPtr xmlErrorPtr = xmlGetLastError();
-
+ const xmlError *xmlErrorPtr = xmlGetLastError();
if (xmlErrorPtr) {
soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message);
} else {

View File

@@ -0,0 +1,55 @@
diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
index 3959b362..6cdfbd39 100644
--- a/ext/libxml/libxml.c
+++ b/ext/libxml/libxml.c
@@ -483,7 +483,11 @@ static void _php_libxml_free_error(void *ptr)
xmlResetError((xmlErrorPtr) ptr);
}
-static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
+#if LIBXML_VERSION >= 21200
+static void _php_list_set_error_structure(const xmlError *error, const char *msg)
+#else
+static void _php_list_set_error_structure(xmlError *error, const char *msg)
+#endif
{
xmlError error_copy;
int ret;
@@ -736,7 +740,11 @@ PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
va_end(args);
}
+#if LIBXML_VERSION >= 21200
+PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, const xmlError *error)
+#else
PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
+#endif
{
_php_list_set_error_structure(error, NULL);
@@ -1009,11 +1017,9 @@ PHP_FUNCTION(libxml_use_internal_errors)
/* {{{ Retrieve last error from libxml */
PHP_FUNCTION(libxml_get_last_error)
{
- xmlErrorPtr error;
-
ZEND_PARSE_PARAMETERS_NONE();
- error = xmlGetLastError();
+ const xmlError *error = xmlGetLastError();
if (error) {
object_init_ex(return_value, libxmlerror_class_entry);
diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c
index 651eab23..7a7ce304 100644
--- a/ext/soap/php_sdl.c
+++ b/ext/soap/php_sdl.c
@@ -332,7 +332,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
sdl_restore_uri_credentials(ctx);
if (!wsdl) {
- xmlErrorPtr xmlErrorPtr = xmlGetLastError();
+ const xmlError *xmlErrorPtr = xmlGetLastError();
if (xmlErrorPtr) {
soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message);

View File

@@ -11,12 +11,16 @@ declare(strict_types=1);
// --------------------------------- edit area ---------------------------------
$zts = true;
$zts = false;
$no_strip = false;
$upx = true;
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
$extensions = match (PHP_OS_FAMILY) {
'Linux', 'Darwin' => 'parallel',
'Windows' => 'mbstring,pdo_sqlite,mbregex,parallel',
'Linux', 'Darwin' => 'sockets',
'Windows' => 'mbstring,pdo_sqlite,mbregex,bz2,sqlsrv,pdo_sqlsrv,yaml,zip,rar,apcu,swow',
};
// If you want to test lib-suggests feature with extension, add them below (comma separated, example `libwebp,libavif`).
@@ -74,5 +78,7 @@ echo match ($argv[1]) {
'libs_cmd' => ($final_libs === '' ? '' : (' --with-libs=' . $final_libs)),
'cmd' => $final_extensions_cmd . ($final_libs === '' ? '' : (' --with-libs=' . $final_libs)),
'zts' => $zts ? '--enable-zts' : '',
'no_strip' => $no_strip ? '--no-strip' : '',
'upx' => $upx ? '--with-upx-pack' : '',
default => '',
};

View File

@@ -1,5 +0,0 @@
<?php
declare(strict_types=1);
assert(class_exists('\\ZipArchive'));

View File

@@ -94,7 +94,7 @@ class FileSystemTest extends TestCase
*/
public function testGetClassesPsr4()
{
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/builder/extension', 'SPC\\builder\\extension');
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/builder/extension', 'SPC\builder\extension');
foreach ($classes as $class) {
$this->assertIsString($class);
new \ReflectionClass($class);
@@ -185,9 +185,9 @@ class FileSystemTest extends TestCase
public function testIsRelativePath()
{
$this->assertTrue(FileSystem::isRelativePath('.'));
$this->assertTrue(FileSystem::isRelativePath('.\\sdf'));
$this->assertTrue(FileSystem::isRelativePath('.\sdf'));
if (DIRECTORY_SEPARATOR === '\\') {
$this->assertFalse(FileSystem::isRelativePath('C:\\asdasd/fwe\asd'));
$this->assertFalse(FileSystem::isRelativePath('C:\asdasd/fwe\asd'));
} else {
$this->assertFalse(FileSystem::isRelativePath('/fwefwefewf'));
}