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
This commit is contained in:
Jerry Ma 2024-06-20 14:46:08 +08:00 committed by GitHub
parent 2d2607cd7f
commit 93cb7e9fbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 229 additions and 193 deletions

View File

@ -186,4 +186,4 @@ jobs:
- name: "Run Build Tests (build, windows)" - name: "Run Build Tests (build, windows)"
if: matrix.os == 'windows-latest' 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 --build-fpm --debug 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

358
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -460,7 +460,9 @@ abstract class BuilderBase
'micro_ext_test' => [ 'micro_ext_test' => [
'content' => ($this->getOption('without-micro-ext-test') ? '<?php echo "[micro-test-start][micro-test-end]";' : $this->generateMicroExtTests()), 'content' => ($this->getOption('without-micro-ext-test') ? '<?php echo "[micro-test-start][micro-test-end]";' : $this->generateMicroExtTests()),
'conditions' => [ 'conditions' => [
// program success
function ($ret) { return $ret === 0; }, function ($ret) { return $ret === 0; },
// program returns expected output
function ($ret, $out) { function ($ret, $out) {
$raw_out = trim(implode('', $out)); $raw_out = trim(implode('', $out));
return str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]'); return str_starts_with($raw_out, '[micro-test-start]') && str_ends_with($raw_out, '[micro-test-end]');
@ -470,6 +472,7 @@ abstract class BuilderBase
'micro_zend_bug_test' => [ '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')), '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' => [ 'conditions' => [
// program success
function ($ret) { return $ret === 0; }, function ($ret) { return $ret === 0; },
], ],
], ],

View File

@ -96,7 +96,7 @@ abstract class UnixBuilderBase extends BuilderBase
$support_lib_list = []; $support_lib_list = [];
$classes = FileSystem::getClassesPsr4( $classes = FileSystem::getClassesPsr4(
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library', ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
'SPC\\builder\\' . osfamily2dir() . '\\library' 'SPC\builder\\' . osfamily2dir() . '\library'
); );
foreach ($classes as $class) { foreach ($classes as $class) {
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) { if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {

View File

@ -102,6 +102,8 @@ class WindowsBuilder extends BuilderBase
$micro_logo = ''; $micro_logo = '';
} }
$micro_w32 = $this->getOption('enable-micro-win32') ? ' --enable-micro-win32=yes' : '';
cmd()->cd(SOURCE_PATH . '\php-src') cmd()->cd(SOURCE_PATH . '\php-src')
->exec( ->exec(
"{$this->sdk_prefix} configure.bat --task-args \"" . "{$this->sdk_prefix} configure.bat --task-args \"" .
@ -111,7 +113,7 @@ class WindowsBuilder extends BuilderBase
'--with-extra-includes=' . BUILD_INCLUDE_PATH . ' ' . '--with-extra-includes=' . BUILD_INCLUDE_PATH . ' ' .
'--with-extra-libs=' . BUILD_LIB_PATH . ' ' . '--with-extra-libs=' . BUILD_LIB_PATH . ' ' .
($enableCli ? '--enable-cli=yes ' : '--enable-cli=no ') . ($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 ') . ($enableEmbed ? '--enable-embed=yes ' : '--enable-embed=no ') .
"{$this->makeExtensionArgs()} " . "{$this->makeExtensionArgs()} " .
$zts . $zts .
@ -132,6 +134,8 @@ class WindowsBuilder extends BuilderBase
if ($enableMicro) { if ($enableMicro) {
logger()->info('building micro'); logger()->info('building micro');
$this->buildMicro(); $this->buildMicro();
SourcePatcher::unpatchMicroWin32();
} }
if ($enableEmbed) { if ($enableEmbed) {
logger()->warning('Windows does not currently support embed SAPI.'); logger()->warning('Windows does not currently support embed SAPI.');
@ -212,8 +216,8 @@ class WindowsBuilder extends BuilderBase
// search all supported libs // search all supported libs
$support_lib_list = []; $support_lib_list = [];
$classes = FileSystem::getClassesPsr4( $classes = FileSystem::getClassesPsr4(
ROOT_DIR . '\src\SPC\builder\\' . osfamily2dir() . '\\library', ROOT_DIR . '\src\SPC\builder\\' . osfamily2dir() . '\library',
'SPC\\builder\\' . osfamily2dir() . '\\library' 'SPC\builder\\' . osfamily2dir() . '\library'
); );
foreach ($classes as $class) { foreach ($classes as $class) {
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) { if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {

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('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-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('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 public function handle(): int

View File

@ -70,7 +70,7 @@ final class CheckListHandler
*/ */
private function loadCheckList(bool $include_manual = false): array 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); $ref = new \ReflectionClass($class);
foreach ($ref->getMethods() as $method) { foreach ($ref->getMethods() as $method) {
foreach ($method->getAttributes() as $a) { foreach ($method->getAttributes() as $a) {

View File

@ -337,7 +337,7 @@ class Downloader
); );
break; break;
case 'custom': // Custom download method, like API-based download or other 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) { foreach ($classes as $class) {
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) { if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
(new $class())->fetch($force); (new $class())->fetch($force);
@ -437,7 +437,7 @@ class Downloader
); );
break; break;
case 'custom': // Custom download method, like API-based download or other 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) { foreach ($classes as $class) {
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) { if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
(new $class())->fetch($force); (new $class())->fetch($force);

View File

@ -47,6 +47,12 @@ class SourcePatcher
'' ''
); );
} }
if ($builder->getOption('enable-micro-win32')) {
SourcePatcher::patchMicroWin32();
} else {
SourcePatcher::unpatchMicroWin32();
}
} }
/** /**
@ -368,4 +374,20 @@ class SourcePatcher
FileSystem::writeFile(SOURCE_PATH . '/php-src/main/main.c', $file); FileSystem::writeFile(SOURCE_PATH . '/php-src/main/main.c', $file);
} }
} }
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 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) { foreach ($classes as $class) {
$reflection = new \ReflectionClass($class); $reflection = new \ReflectionClass($class);
foreach ($reflection->getAttributes(CustomExt::class) as $attribute) { foreach ($reflection->getAttributes(CustomExt::class) as $attribute) {

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
assert(class_exists('\\DOMDocument')); assert(class_exists('\DOMDocument'));
$doc = new 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>'); $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'); assert($doc->getElementById('app')->nodeValue === 'Hello');

View File

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

View File

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

View File

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

View File

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