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.
249 lines
5.9 KiB
249 lines
5.9 KiB
<?php
|
|
|
|
namespace PhpAot\Php\Platform;
|
|
|
|
/**
|
|
* Linux 平台实现
|
|
*/
|
|
class Linux extends PlatformBase
|
|
{
|
|
public function getName(): string
|
|
{
|
|
return 'Linux';
|
|
}
|
|
|
|
public function isCurrent(): bool
|
|
{
|
|
return PHP_OS === 'Linux';
|
|
}
|
|
|
|
public function getIncludeFlags(array $includePaths): string
|
|
{
|
|
if (empty($includePaths)) {
|
|
return '';
|
|
}
|
|
|
|
$flags = [];
|
|
foreach ($includePaths as $path) {
|
|
$flags[] = '-I' . escapeshellarg($path);
|
|
}
|
|
|
|
return implode(' ', $flags);
|
|
}
|
|
|
|
public function getLibraryPathFlags(array $libraryPaths): string
|
|
{
|
|
if (empty($libraryPaths)) {
|
|
return '';
|
|
}
|
|
|
|
$flags = [];
|
|
foreach ($libraryPaths as $path) {
|
|
$flags[] = '-L' . escapeshellarg($path);
|
|
}
|
|
|
|
return implode(' ', $flags);
|
|
}
|
|
|
|
public function getLibraryFlags(array $libraries): string
|
|
{
|
|
if (empty($libraries)) {
|
|
return '';
|
|
}
|
|
|
|
$flags = [];
|
|
foreach ($libraries as $lib) {
|
|
// 移除 lib 前缀和 .a/.so 后缀
|
|
$libName = basename($lib);
|
|
if (str_starts_with($libName, 'lib')) {
|
|
$libName = substr($libName, 3);
|
|
}
|
|
$libName = preg_replace('/\.(a|so)$/', '', $libName);
|
|
|
|
$flags[] = '-l' . $libName;
|
|
}
|
|
|
|
return implode(' ', $flags);
|
|
}
|
|
|
|
public function getObjectExtension(): string
|
|
{
|
|
return '.o';
|
|
}
|
|
|
|
public function getExecutableExtension(): string
|
|
{
|
|
return '';
|
|
}
|
|
|
|
public function getSharedLibraryExtension(): string
|
|
{
|
|
return '.so';
|
|
}
|
|
|
|
public function getPathSeparator(): string
|
|
{
|
|
return '/';
|
|
}
|
|
|
|
public function getDefaultCompiler(): string
|
|
{
|
|
return 'g++';
|
|
}
|
|
|
|
public function getPhpDir(): string
|
|
{
|
|
$phpDir = getenv('PHP_HOME');
|
|
if ($phpDir && is_dir($phpDir)) {
|
|
return rtrim($phpDir, '\/');
|
|
}
|
|
|
|
$phpDir = shell_exec('php-config --prefix 2>/dev/null');
|
|
if (!empty($phpDir)) {
|
|
return trim($phpDir);
|
|
}
|
|
|
|
$phpExe = trim(shell_exec('which php 2>/dev/null'));
|
|
if ($phpExe && file_exists($phpExe)) {
|
|
$phpDir = dirname(dirname($phpExe));
|
|
if (is_dir($phpDir)) {
|
|
return $phpDir;
|
|
}
|
|
}
|
|
|
|
throw new \RuntimeException('The `php-config` is not found. Please install PHP development package or set PHP_HOME environment variable');
|
|
}
|
|
|
|
public function getIntegerLiteralSuffix(): string
|
|
{
|
|
return 'L';
|
|
}
|
|
|
|
/**
|
|
* 获取 RPATH 选项
|
|
*/
|
|
public function getRpathOptions(array $paths): string
|
|
{
|
|
if (empty($paths)) {
|
|
return '';
|
|
}
|
|
|
|
$rpaths = [];
|
|
foreach ($paths as $path) {
|
|
$rpaths[] = '-Wl,-rpath,' . escapeshellarg($path);
|
|
}
|
|
|
|
return implode(' ', $rpaths);
|
|
}
|
|
|
|
/**
|
|
* 获取 PIC 选项
|
|
*/
|
|
public function getPicFlag(): string
|
|
{
|
|
return '-fPIC';
|
|
}
|
|
|
|
/**
|
|
* 获取共享库链接选项
|
|
*/
|
|
public function getSharedLinkFlag(): string
|
|
{
|
|
return '-shared';
|
|
}
|
|
|
|
/**
|
|
* 构建 PHP 包含路径(使用 php-config 动态获取)
|
|
*/
|
|
public function buildPhpIncludePaths(string $phpDir): array
|
|
{
|
|
// 优先使用 php-config 获取包含路径
|
|
$phpConfigPath = $this->findPhpConfig($phpDir);
|
|
if ($phpConfigPath) {
|
|
$includes = shell_exec("{$phpConfigPath} --includes 2>/dev/null");
|
|
if ($includes) {
|
|
// 解析 -I/path 格式的路径
|
|
preg_match_all('/-I([^\s]+)/', $includes, $matches);
|
|
if (!empty($matches[1])) {
|
|
// 过滤不存在的路径并返回
|
|
return array_filter($matches[1], 'is_dir');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 回退到硬编码路径(兼容旧版本)
|
|
$paths = [
|
|
$phpDir . '/include/php',
|
|
$phpDir . '/include/php/main',
|
|
$phpDir . '/include/php/TSRM',
|
|
$phpDir . '/include/php/Zend',
|
|
$phpDir . '/include/php/ext',
|
|
];
|
|
|
|
// 过滤不存在的路径
|
|
return array_filter($paths, 'is_dir');
|
|
}
|
|
|
|
/**
|
|
* 查找 php-config 可执行文件
|
|
*/
|
|
private function findPhpConfig(string $phpDir): ?string
|
|
{
|
|
// 优先使用 PHP_DIR 指定的路径
|
|
$candidate = $phpDir . '/bin/php-config';
|
|
if (is_executable($candidate)) {
|
|
return $candidate;
|
|
}
|
|
|
|
// 回退到 PATH 中查找(通过 which 命令)
|
|
$whichResult = trim(shell_exec('which php-config 2>/dev/null'));
|
|
if ($whichResult && is_executable($whichResult)) {
|
|
return $whichResult;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 构建 PHP 库路径
|
|
*/
|
|
public function buildPhpLibPaths(string $phpDir): array
|
|
{
|
|
$paths = [];
|
|
|
|
$libPath = $phpDir . '/lib';
|
|
if (is_dir($libPath)) {
|
|
$paths[] = $libPath;
|
|
}
|
|
|
|
return $paths;
|
|
}
|
|
|
|
/**
|
|
* 检测 PHP 库文件
|
|
*/
|
|
public function detectPhpLibs(string $phpDir): array
|
|
{
|
|
$libPath = $phpDir . '/lib';
|
|
|
|
if (!is_dir($libPath)) {
|
|
throw new \RuntimeException("PHP lib directory not found: {$libPath}");
|
|
}
|
|
|
|
$embedLib = $libPath . '/libphp.so';
|
|
$staticLib = $libPath . '/libphp.a';
|
|
|
|
$hasEmbed = file_exists($embedLib);
|
|
$hasStatic = file_exists($staticLib);
|
|
|
|
if (!$hasEmbed && !$hasStatic) {
|
|
throw new \RuntimeException('Neither libphp.so nor libphp.a found');
|
|
}
|
|
|
|
return [
|
|
'embed' => $hasEmbed ? $embedLib : null,
|
|
'static' => $hasStatic ? $staticLib : null,
|
|
'is_shared' => $hasEmbed,
|
|
];
|
|
}
|
|
}
|
|
|