feat(backend): 添加 C 文件编译命令构建功能

- 在 Clang 类中实现 buildCCompileCommand 方法,支持 C 文件的编译命令构建
- 为 CompilerBackend 接口添加 buildCCompileCommand 抽象方法定义
- 在 Windows 平台下自动添加 MSVC 兼容性选项
- 支持调试模式下的优化级别控制和调试符号生成
- 添加警告级别设置确保代码质量检查
- 保持 C 文件编译时不使用 C++ 特定的编译选项
pull/1/head
韩天峰 4 months ago
parent 6251d4d168
commit 51298c2d00
  1. 37
      src/Php/Backend/Clang.php
  2. 9
      src/Php/Backend/CompilerBackend.php
  3. 27
      src/Php/Backend/Gcc.php
  4. 39
      src/Php/Backend/Msvc.php
  5. 34
      src/Php/CompilerBase.php
  6. 97
      src/Php/Translator.php

@ -149,6 +149,43 @@ class Clang extends CompilerBackend
return $cmd;
}
/**
* 构建 C 文件的编译命令(不包含 C++ 特定选项)
*/
public function buildCCompileCommand(string $sourceFile, string $outputFile, array $options = []): string
{
$cmd = $this->getCompilerCommand();
// Windows 下需要 MSVC 兼容模式
if ($this->platform instanceof \PhpAot\Php\Platform\Windows) {
$cmd .= ' -fms-compatibility';
$cmd .= ' -fms-compatibility-version=19.40';
$cmd .= ' -fdelayed-template-parsing';
$cmd .= ' -fms-extensions';
}
$cmd .= ' -c';
$cmd .= ' ' . escapeshellarg($sourceFile);
$cmd .= ' -o ' . escapeshellarg($outputFile);
// 优化级别(C 文件通常使用较低的优化)
$optimizeLevel = $options['optimize'] ?? 0;
// 调试模式
if (!empty($options['debug'])) {
$cmd .= ' -O0 -g';
} else {
$cmd .= ' -O' . $optimizeLevel;
}
// 警告级别
$cmd .= ' -Wall';
// 注意:C 文件不使用 -std=c++17 等 C++ 特定选项
return $cmd;
}
public function buildLinkCommand(array $objectFiles, string $outputFile, array $options = []): string
{
$cmd = $this->getLinkerCommand();

@ -66,6 +66,15 @@ abstract class CompilerBackend
array $options = []
): string;
/**
* 构建 C 文件的编译命令(不包含 C++ 特定选项)
*/
abstract public function buildCCompileCommand(
string $sourceFile,
string $outputFile,
array $options = []
): string;
/**
* 构建完整的链接命令
*/

@ -117,6 +117,33 @@ class Gcc extends CompilerBackend
return $cmd;
}
/**
* 构建 C 文件的编译命令(不包含 C++ 特定选项)
*/
public function buildCCompileCommand(string $sourceFile, string $outputFile, array $options = []): string
{
$cmd = $this->getCompilerCommand();
$cmd .= ' -c';
$cmd .= ' ' . escapeshellarg($sourceFile);
$cmd .= ' -o ' . escapeshellarg($outputFile);
// 优化级别(C 文件通常使用较低的优化)
$optimizeLevel = $options['optimize'] ?? 0;
$cmd .= ' -O' . $optimizeLevel;
// 调试信息
if (!empty($options['debug'])) {
$cmd .= ' -g';
}
// 警告级别
$cmd .= ' -Wall';
// 注意:C 文件不使用 -std=c++17 等 C++ 特定选项
return $cmd;
}
public function buildLinkCommand(array $objectFiles, string $outputFile, array $options = []): string
{
$cmd = $this->getLinkerCommand();

@ -129,6 +129,45 @@ class Msvc extends CompilerBackend
return $cmd;
}
/**
* 构建 C 文件的编译命令(不包含 C++ 特定选项)
*/
public function buildCCompileCommand(string $sourceFile, string $outputFile, array $options = []): string
{
$cmd = $this->getCompilerCommand();
$cmd .= ' /c';
$cmd .= ' ' . escapeshellarg($sourceFile);
$cmd .= ' /Fo' . escapeshellarg($outputFile);
// 平台宏定义
$cmd .= ' /DZEND_WIN32 /DPHP_WIN32 /DZEND_DEBUG=0';
// ZTS 支持
if ($this->platform instanceof Windows && $this->platform->isZts()) {
$cmd .= ' /DZTS';
}
// 优化级别(C 文件通常使用较低的优化)
$optimizeLevel = $options['optimize'] ?? 0;
$cmd .= ' /O' . ($optimizeLevel >= 2 ? '2' : ($optimizeLevel === 0 ? 'd' : '1'));
// 警告级别
$cmd .= ' /W3';
// 禁用常见警告
$suppressedWarnings = $options['suppressed_warnings'] ?? ['4244', '4146'];
foreach ($suppressedWarnings as $code) {
$cmd .= " /wd{$code}";
}
// nologo
$cmd .= ' /nologo';
// 注意:C 文件不使用 /EHsc, /std:c++17, /MD 等 C++ 特定选项
return $cmd;
}
public function buildLinkCommand(array $objectFiles, string $outputFile, array $options = []): string
{
$cmd = $this->getLinkerCommand();

@ -381,6 +381,23 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->platform = $result['platform'];
$this->compilerBackend = $result['compiler'];
// Windows 平台:需要传递 ZTS 状态给 Platform 对象
if ($this->platform instanceof \PhpAot\Php\Platform\Windows && $this->isWindows) {
// 重新创建 Windows Platform,传递正确的 ZTS 状态
$phpSdkPath = $this->getPhpDir() . '\\SDK';
$this->platform = new \PhpAot\Php\Platform\Windows(
phpLibs: [],
isZts: $this->isPhpZts, // ✅ 传递检测到的 ZTS 状态
phpSdkPath: $phpSdkPath
);
// 重新创建 Backend,使用更新后的 Platform
$this->compilerBackend = \PhpAot\Php\Backend\CompilerFactory::createByName(
$this->cppCompiler,
$this->platform
);
}
$this->climate->info(
"Initialized new architecture: {$this->platform->getName()} + {$this->compilerBackend->getName()}"
);
@ -2468,7 +2485,7 @@ class CompilerBase extends \PhpAot\Core\Translator
// Windows: phpx.lib (无 lib 前缀)
$phpxLibPath = $this->getPhpxDir() . '\\lib\\phpx.lib';
if (file_exists($phpxLibPath)) {
$libraries[] = '"' . $phpxLibPath . '"';
$libraries[] = $phpxLibPath; // 不添加引号,由 getLibraryFlags() 统一处理
} else {
$this->error('phpx.lib not found at: ' . $phpxLibPath);
}
@ -2493,13 +2510,22 @@ class CompilerBase extends \PhpAot\Core\Translator
// extension 和 bin 模式都需要链接 PHP 库
if ($this->platform instanceof \PhpAot\Php\Platform\Windows) {
// Windows bin 模式使用已检测的库文件
// Windows: 根据构建模式选择不同的库
if ($this->buildMode === 'bin') {
// bin 模式:需要同时链接 php8ts.lib 和 php8embed.lib
// 注意:php8ts.lib 必须在 php8embed.lib 之前,因为 embed 依赖 core
// php8ts.lib 提供 PHP 核心全局符号(executor_globals, compiler_globals, sapi_globals)
if (!empty($this->windowsPhpCoreLib)) {
$libraries[] = $this->windowsPhpCoreLib; // 不添加引号
}
// php8embed.lib 提供嵌入 API
if (!empty($this->windowsPhpEmbedLib)) {
$libraries[] = '"' . $this->windowsPhpEmbedLib . '"';
$libraries[] = $this->windowsPhpEmbedLib; // 不添加引号
}
} else {
// ext 模式:只使用 php8ts.lib 或 php8.lib(PHP 扩展)
if (!empty($this->windowsPhpCoreLib)) {
$libraries[] = '"' . $this->windowsPhpCoreLib . '"';
$libraries[] = $this->windowsPhpCoreLib; // 不添加引号
}
}

@ -718,6 +718,15 @@ CODE;
return false;
}
/**
* 判断文件是否为 C++ 源文件
*/
protected function isCppFile(string $filePath): bool
{
$extension = pathinfo($filePath, PATHINFO_EXTENSION);
return in_array($extension, ['cc', 'cpp', 'cxx'], true);
}
public function compileFile(string $cppFile, string $objectFile, bool $parallel = false): void
{
if ($this->hasObjectFileCache($cppFile)) {
@ -728,58 +737,44 @@ CODE;
return;
}
// 根据平台和编译器类型构建编译命令
if ($this->isWindows()) {
// C 文件和 C++ 文件使用不同的选项
$isCppFile = (pathinfo($cppFile, PATHINFO_EXTENSION) === 'cc'
|| pathinfo($cppFile, PATHINFO_EXTENSION) === 'cpp'
|| pathinfo($cppFile, PATHINFO_EXTENSION) === 'cxx');
// Windows 下根据编译器类型选择参数格式
if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') {
// Clang on Windows 使用 GCC 风格的参数
if (!$isCppFile) {
// C 文件:在源文件前添加 -x c 标志
$cmd = $this->cppCompiler . ' -x c -c ' . $cppFile . ' -o ' . $objectFile;
} else {
$cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile;
}
} else {
// MSVC 使用 /c 和 /Fo 参数
$cmd = $this->cppCompiler . ' /c ' . $cppFile . ' /Fo' . $objectFile;
}
// 添加编译选项(C 文件不需要 /EHsc 和 /std:c++17)
if ($isCppFile) {
$this->addCompilationOption($cmd, false);
} else {
// C 文件:只添加基本选项,不添加 C++ 特定选项
// 使用 Platform 层获取包含路径
if ($this->platform !== null) {
$cmd .= ' ' . $this->parseIncludes();
}
// 添加平台宏定义(根据编译器类型选择语法)
if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') {
// Clang/GCC 风格
$cmd .= ' -DZEND_WIN32 -DPHP_WIN32 -DZEND_DEBUG=0';
if ($this->isPhpZts) {
$cmd .= ' -DZTS';
}
$cmd .= ' -O0 -Wall';
} else {
// MSVC 风格
$cmd .= ' /DZEND_WIN32 /DPHP_WIN32 /DZEND_DEBUG=0';
if ($this->isPhpZts) {
$cmd .= ' /DZTS';
}
$cmd .= ' /Od /W3 /wd4244 /wd4146 /nologo';
}
}
// 判断是否为 C++ 文件
$isCppFile = $this->isCppFile($cppFile);
// 使用 Backend 层构建编译命令
if ($isCppFile) {
// C++ 文件:使用标准的编译命令构建
$cmd = $this->compilerBackend->buildCompileCommand(
$cppFile,
$objectFile,
[
'optimize' => $this->optimizeLevel,
'debug_info' => $this->debugInfo,
'sanitize' => $this->sanitize,
'cpp_std' => $this->cxxStd,
'is_zts' => $this->isPhpZts,
'build_mode' => $this->buildMode,
'enable_profiler' => $this->enableProfiler,
'suppressed_warnings' => Constants::MSVC_SUPPRESSED_WARNINGS ?? [],
'cxxflags' => $this->cxxflags,
]
);
// 添加包含路径(通过 Platform 层)
$cmd .= ' ' . $this->parseIncludes();
} else {
// Unix/Linux/macOS GCC 编译命令
$cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile;
$this->addCompilationOption($cmd, false);
// C 文件:不能使用 C++ 特定选项(/EHsc, /std:c++17 等)
// 使用 Backend 的 buildCCompileCommand() 方法
$cmd = $this->compilerBackend->buildCCompileCommand(
$cppFile,
$objectFile,
[
'optimize' => 0,
'suppressed_warnings' => ['4244', '4146'],
]
);
// 手动添加包含路径
$cmd .= ' ' . $this->parseIncludes();
}
if (!$parallel) {

Loading…
Cancel
Save