TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
5.8 KiB
153 lines
5.8 KiB
<?php
|
|
|
|
namespace TypePhp\Installer;
|
|
|
|
final class PhpBuildConfiguration
|
|
{
|
|
/** @return list<string> */
|
|
public static function parseShellWords(string $value): array
|
|
{
|
|
$words = [];
|
|
$word = '';
|
|
$quote = null;
|
|
$wordStarted = false;
|
|
$length = strlen($value);
|
|
|
|
for ($index = 0; $index < $length; $index++) {
|
|
$char = $value[$index];
|
|
if ($quote === null) {
|
|
if (str_contains(" \t\r\n\v\f", $char)) {
|
|
if ($wordStarted) {
|
|
$words[] = $word;
|
|
$word = '';
|
|
$wordStarted = false;
|
|
}
|
|
continue;
|
|
}
|
|
if ($char === "'" || $char === '"') {
|
|
$quote = $char;
|
|
$wordStarted = true;
|
|
continue;
|
|
}
|
|
if ($char === '\\') {
|
|
if (++$index >= $length) {
|
|
throw new \InvalidArgumentException('Incomplete escape sequence in configure options');
|
|
}
|
|
$word .= $value[$index];
|
|
$wordStarted = true;
|
|
continue;
|
|
}
|
|
$word .= $char;
|
|
$wordStarted = true;
|
|
continue;
|
|
}
|
|
|
|
if ($char === $quote) {
|
|
$quote = null;
|
|
continue;
|
|
}
|
|
if ($quote === '"' && $char === '\\' && $index + 1 < $length
|
|
&& str_contains('\"$`', $value[$index + 1])
|
|
) {
|
|
$word .= $value[++$index];
|
|
continue;
|
|
}
|
|
$word .= $char;
|
|
}
|
|
|
|
if ($quote !== null) {
|
|
throw new \InvalidArgumentException('Unterminated quote in configure options');
|
|
}
|
|
if ($wordStarted) {
|
|
$words[] = $word;
|
|
}
|
|
return $words;
|
|
}
|
|
|
|
/** @return list<string> */
|
|
public static function parsePhpConfigOptions(string $value): array
|
|
{
|
|
$options = [];
|
|
foreach (self::parseShellWords($value) as $option) {
|
|
// php-config --configure-options loses the quoting of trailing build
|
|
// assignments. Once the first assignment is reached, tokens that follow
|
|
// may be either part of its value or another assignment, so none of them
|
|
// can safely be reused as configure arguments.
|
|
if (preg_match('/^[A-Za-z_][A-Za-z0-9_]*=/', $option)) {
|
|
break;
|
|
}
|
|
$options[] = $option;
|
|
}
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* Autoconf installation directories, program name transforms and cache files.
|
|
*
|
|
* A distribution build points these outside its own --prefix (--mandir=/usr/share/man,
|
|
* --includedir=/usr/include) or renames the installed binaries (--program-suffix=8.3).
|
|
* Inheriting them makes `make install` write to system paths the user cannot own,
|
|
* and hides bin/php behind a versioned name. Autoconf derives every one of them
|
|
* from --prefix when it is absent, so dropping them keeps the private build
|
|
* entirely inside the requested prefix.
|
|
*
|
|
* The versioned name is the Debian and Ubuntu packaging scheme, not a PPA
|
|
* addition: php8.3-dev in noble-updates/main carries --program-suffix=8.3
|
|
* and --mandir=/usr/share/man, and ppa:ondrej/php repeats it per version.
|
|
*
|
|
* @var list<string>
|
|
*/
|
|
private const array PREFIX_DERIVED = [
|
|
'--exec-prefix', '--bindir', '--sbindir', '--libexecdir', '--sysconfdir',
|
|
'--sharedstatedir', '--localstatedir', '--runstatedir', '--libdir',
|
|
'--includedir', '--oldincludedir', '--datarootdir', '--datadir',
|
|
'--infodir', '--localedir', '--mandir', '--docdir', '--htmldir',
|
|
'--dvidir', '--pdfdir', '--psdir',
|
|
'--program-prefix', '--program-suffix', '--program-transform-name',
|
|
// A cache recorded for the distribution prefix answers the wrong questions
|
|
// here, and its path may not even exist on this machine.
|
|
'--cache-file', '--config-cache',
|
|
];
|
|
|
|
/**
|
|
* @param string|list<string> $configureOptions
|
|
* @return list<string>
|
|
*/
|
|
public static function derive(string|array $configureOptions, string $prefix): array
|
|
{
|
|
$replace = [
|
|
'--prefix', '--with-config-file-path', '--with-config-file-scan-dir',
|
|
'--enable-embed', '--enable-cli', '--disable-cli', '--with-libdir',
|
|
// PEAR is deprecated by PHP and PECL installation is being replaced
|
|
// by PIE. Do not inherit either form from the host PHP build.
|
|
'--with-pear', '--without-pear',
|
|
];
|
|
$drop = [
|
|
'--with-apxs', '--with-apxs2', '--enable-fpm', '--with-fpm-systemd',
|
|
...self::PREFIX_DERIVED,
|
|
];
|
|
$result = [];
|
|
$options = is_string($configureOptions) ? self::parseShellWords($configureOptions) : $configureOptions;
|
|
foreach ($options as $option) {
|
|
// Build assignments are not PHP feature configuration. Keep only long
|
|
// configure options; callers can override CFLAGS through the environment.
|
|
if (!str_starts_with($option, '--')) {
|
|
continue;
|
|
}
|
|
$name = explode('=', $option, 2)[0];
|
|
if (in_array($name, $replace, true) || in_array($name, $drop, true)) {
|
|
continue;
|
|
}
|
|
$result[] = $option;
|
|
}
|
|
return [
|
|
'--prefix=' . $prefix,
|
|
'--with-config-file-path=' . $prefix . '/lib',
|
|
'--with-config-file-scan-dir=' . $prefix . '/lib/conf.d',
|
|
'--enable-embed=shared',
|
|
'--enable-cli',
|
|
'--without-pear',
|
|
...$result,
|
|
];
|
|
}
|
|
}
|
|
|