Skip to content

Commit 7e2cfe2

Browse files
committed
Merge remote-tracking branch 'origin/v3-refactor/win-exts' into v3-refactor/win-exts
2 parents cd14f62 + 1d0ccde commit 7e2cfe2

3 files changed

Lines changed: 179 additions & 0 deletions

File tree

TODO.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# v3 TODO List
2+
3+
Tracking items identified during the v2 → v3 migration audit.
4+
5+
---
6+
7+
## Commands
8+
9+
- [ ] Implement `craft` command (drives full build from `craft.yml`; should be easier with v3 vendor/registry mode)
10+
- [x] Migrate `micro:combine` command (combine `micro.sfx` with PHP code + INI injection)
11+
- [ ] Implement `dump-extensions` command (extract required extensions from `composer.json` / `composer.lock`)
12+
- [ ] Design and implement v3 dev toolchain commands (WIP — needs design decision):
13+
- [ ] `dev:extensions` / equivalent listing command
14+
- [ ] `dev:php-version`, `dev:ext-version`, `dev:lib-version`
15+
- [ ] Doc generation commands (`dev:gen-ext-docs`, `dev:gen-ext-dep-docs`, `dev:gen-lib-dep-docs`) — pending v3 doc design
16+
17+
---
18+
19+
## Source Patches (SourcePatcher → Artifact migration)
20+
21+
The following v2 `SourcePatcher` hooks are not yet migrated to v3 `src/Package/Artifact/` classes:
22+
23+
- [ ] Migrate `patchSQLSRVWin32` — removes `/sdl` compile flag to prevent Zend build failure on Windows
24+
- [ ] Migrate `patchSQLSRVPhp85` — fixes `pdo_sqlsrv` directory layout for PHP 8.5
25+
- [ ] Migrate `patchYamlWin32` — patches `config.w32` `_a.lib` detection logic for the `yaml` extension
26+
- [ ] Migrate `patchImagickWith84` — applies PHP 8.4 compatibility patch for `imagick` based on version detection
27+
28+
---
29+
30+
## Extension Package Classes (Unix)
31+
32+
Extensions that had non-trivial v2 build logic and are missing a v3 `src/Package/Extension/` class:
33+
34+
- [x] `gettext` — macOS: fix `config.m4` bracket syntax for cross-version compatibility + append frameworks to linker flags (critical for macOS linking; this is a Unix-side gap, not Windows-only)
35+
36+
---
37+
38+
## Windows Extensions (Early Stage)
39+
40+
Windows extension support is still in early stage. The following extensions had Windows-specific configure args or patches in v2 and are pending v3 Windows implementation:
41+
42+
- [ ] `amqp` — Windows configure args
43+
- [ ] `com_dotnet` — Windows-only extension
44+
- [ ] `dom` — remove `dllmain.c` from `config.w32`
45+
- [ ] `ev` — fix `PHP_EV_SHARED` in `config.w32`
46+
- [ ] `gmssl` — add `CHECK_LIB("gmssl.lib")` to `config.w32`
47+
- [ ] `intl` — fix `PHP_INTL_SHARED` in `config.w32`
48+
- [ ] `lz4` — Windows configure args
49+
- [ ] `mbregex` — Windows configure args
50+
- [ ] `sqlsrv` / `pdo_sqlsrv` — complex conditional build logic (independent `sqlsrv` without `pdo_sqlsrv`)
51+
- [ ] `xml` — remove `dllmain.c` from `config.w32`; handles `soap`, `xmlreader`, `xmlwriter`, `simplexml`
52+
53+
---
54+
55+
## Documentation
56+
57+
- [ ] Write v3 user documentation (currently zero v3 docs)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace StaticPHP\Command;
6+
7+
use StaticPHP\Util\FileSystem;
8+
use Symfony\Component\Console\Attribute\AsCommand;
9+
use Symfony\Component\Console\Input\InputArgument;
10+
use Symfony\Component\Console\Input\InputOption;
11+
12+
#[AsCommand('micro:combine', 'Combine micro.sfx and php code together')]
13+
class MicroCombineCommand extends BaseCommand
14+
{
15+
public function configure(): void
16+
{
17+
$this->addArgument('file', InputArgument::REQUIRED, 'The php or phar file to be combined');
18+
$this->addOption('with-micro', 'M', InputOption::VALUE_REQUIRED, 'Customize your micro.sfx file');
19+
$this->addOption('with-ini-set', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'ini to inject into micro.sfx when combining');
20+
$this->addOption('with-ini-file', 'N', InputOption::VALUE_REQUIRED, 'ini file to inject into micro.sfx when combining');
21+
$this->addOption('output', 'O', InputOption::VALUE_REQUIRED, 'Customize your output binary file name');
22+
}
23+
24+
public function handle(): int
25+
{
26+
// 0. Initialize path variables
27+
$internal = FileSystem::convertPath(BUILD_ROOT_PATH . '/bin/micro.sfx');
28+
$micro_file = $this->getOption('with-micro');
29+
$file = $this->getArgument('file');
30+
$ini_set = $this->getOption('with-ini-set');
31+
$ini_file = $this->getOption('with-ini-file');
32+
$target_ini = [];
33+
$output = $this->getOption('output') ?? 'my-app';
34+
$ini_part = '';
35+
// 1. Make sure specified micro.sfx file exists
36+
if ($micro_file !== null && !file_exists($micro_file)) {
37+
$this->output->writeln('<error>The micro.sfx file you specified is incorrect or does not exist!</error>');
38+
return static::FAILURE;
39+
}
40+
// 2. Make sure buildroot/bin/micro.sfx exists
41+
if ($micro_file === null && !file_exists($internal)) {
42+
$this->output->writeln('<error>You haven\'t compiled micro.sfx yet, please use "build" command and "--build-micro" to compile phpmicro first!</error>');
43+
return static::FAILURE;
44+
}
45+
// 3. Use buildroot/bin/micro.sfx
46+
if ($micro_file === null) {
47+
$micro_file = $internal;
48+
}
49+
// 4. Make sure php or phar file exists
50+
if (!is_file(FileSystem::convertPath($file))) {
51+
$this->output->writeln('<error>The file to combine does not exist!</error>');
52+
return static::FAILURE;
53+
}
54+
// 5. Confirm ini files (ini-set has higher priority)
55+
if ($ini_file !== null) {
56+
// Check file exist first
57+
if (!file_exists($ini_file)) {
58+
$this->output->writeln('<error>The ini file to combine does not exist! (' . $ini_file . ')</error>');
59+
return static::FAILURE;
60+
}
61+
$arr = parse_ini_file($ini_file);
62+
if ($arr === false) {
63+
$this->output->writeln('<error>Cannot parse ini file</error>');
64+
return static::FAILURE;
65+
}
66+
$target_ini = array_merge($target_ini, $arr);
67+
}
68+
// 6. Confirm ini sets
69+
if ($ini_set !== []) {
70+
foreach ($ini_set as $item) {
71+
$arr = parse_ini_string($item);
72+
if ($arr === false) {
73+
$this->output->writeln('<error>--with-ini-set parse failed</error>');
74+
return static::FAILURE;
75+
}
76+
$target_ini = array_merge($target_ini, $arr);
77+
}
78+
}
79+
// 7. Generate ini injection parts
80+
if (!empty($target_ini)) {
81+
$ini_str = $this->encodeINI($target_ini);
82+
logger()->debug('Injecting ini parts: ' . PHP_EOL . $ini_str);
83+
$ini_part = "\xfd\xf6\x69\xe6";
84+
$ini_part .= pack('N', strlen($ini_str));
85+
$ini_part .= $ini_str;
86+
}
87+
// 8. Combine !
88+
$output = FileSystem::isRelativePath($output) ? (WORKING_DIR . '/' . $output) : $output;
89+
$file_target = file_get_contents($micro_file) . $ini_part . file_get_contents($file);
90+
if (PHP_OS_FAMILY === 'Windows' && !str_ends_with(strtolower($output), '.exe')) {
91+
$output .= '.exe';
92+
}
93+
$output = FileSystem::convertPath($output);
94+
$result = file_put_contents($output, $file_target);
95+
if ($result === false) {
96+
$this->output->writeln('<error>Combine failed.</error>');
97+
return static::FAILURE;
98+
}
99+
// 9. chmod +x
100+
chmod($output, 0755);
101+
$this->output->writeln('<info>Combine success! Binary file: ' . $output . '</info>');
102+
return static::SUCCESS;
103+
}
104+
105+
private function encodeINI(array $array): string
106+
{
107+
$res = [];
108+
foreach ($array as $key => $val) {
109+
if (is_array($val)) {
110+
$res[] = "[{$key}]";
111+
foreach ($val as $skey => $sval) {
112+
$res[] = "{$skey}=" . (is_numeric($sval) ? $sval : '"' . $sval . '"');
113+
}
114+
} else {
115+
$res[] = "{$key}=" . (is_numeric($val) ? $val : '"' . $val . '"');
116+
}
117+
}
118+
return implode("\n", $res);
119+
}
120+
}

src/StaticPHP/ConsoleApplication.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use StaticPHP\Command\DumpLicenseCommand;
2121
use StaticPHP\Command\ExtractCommand;
2222
use StaticPHP\Command\InstallPackageCommand;
23+
use StaticPHP\Command\MicroCombineCommand;
2324
use StaticPHP\Command\ResetCommand;
2425
use StaticPHP\Command\SPCConfigCommand;
2526
use StaticPHP\Package\TargetPackage;
@@ -65,6 +66,7 @@ public function __construct()
6566
new DumpLicenseCommand(),
6667
new ResetCommand(),
6768
new CheckUpdateCommand(),
69+
new MicroCombineCommand(),
6870

6971
// dev commands
7072
new ShellCommand(),

0 commit comments

Comments
 (0)