feat(backend): 实现响应文件机制解决命令行长度限制

- 添加 createResponseFile 方法将目标文件列表写入 .rsp 文件
- 在 MSVC、GCC/Clang 编译器后端中使用 @rsp 参数替代长命令行
- 修复单元测试以验证响应文件参数生成
- 支持路径含空格时的双引号包裹处理
- 兼容 Windows 8191 字符命令行长度限制
pull/3/head
韩天峰 2 months ago
parent 7c2192ff54
commit 73e4754a49
  1. 7
      phpunit/src/Backend/BackendTest.php
  2. 22
      src/Php/Backend/CompilerBackend.php
  3. 4
      src/Php/Backend/GccLikeBackend.php
  4. 8
      src/Php/Backend/Msvc.php

@ -57,16 +57,17 @@ class BackendTest extends TestCase
{
$platform = new Windows();
$compiler = new Msvc($platform);
$cmd = $compiler->linkObjects(
['test.obj'],
'output.exe',
['C:\PHP\lib'],
['php8.lib']
);
$this->assertStringContainsString('link', $cmd);
$this->assertStringContainsString('test.obj', $cmd);
$this->assertStringContainsString('@', $cmd);
$this->assertStringContainsString('.rsp', $cmd);
$this->assertStringContainsString('/OUT:', $cmd);
$this->assertStringContainsString('output.exe', $cmd);
$this->assertStringContainsString('/LIBPATH:', $cmd);

@ -152,4 +152,26 @@ abstract class CompilerBackend
{
return $this->platform->getLibraryFlags($libraries);
}
/**
* 将目标文件列表写入 Response File,避免命令行参数过长超出 OS 限制(Windows 8191 字符)
*
* @param array $objectFiles 目标文件路径列表
* @param string $targetFile 最终输出文件路径(Response File 写入同目录)
* @return string 链接器参数,如 @build/project.rsp
*/
protected function createResponseFile(array $objectFiles, string $targetFile): string
{
$rspFile = dirname($targetFile) . DIRECTORY_SEPARATOR . basename($targetFile) . '.rsp';
$lines = [];
foreach ($objectFiles as $file) {
// 路径含空格时用双引号包裹,MSVC link.exe 和 GCC/Clang 均支持
if (str_contains($file, ' ')) {
$file = '"' . $file . '"';
}
$lines[] = $file;
}
file_put_contents($rspFile, implode("\n", $lines));
return '@' . $rspFile;
}
}

@ -125,7 +125,7 @@ abstract class GccLikeBackend extends CompilerBackend
array $flags = []
): string {
$cmd = $this->getLinkerCommand();
$cmd .= ' ' . implode(' ', array_map('escapeshellarg', $objectFiles));
$cmd .= ' ' . $this->createResponseFile($objectFiles, $outputFile);
$cmd .= ' ' . $this->getLinkerOutputFlag() . ' ' . escapeshellarg($outputFile);
if (!empty($libraryPaths)) {
@ -208,7 +208,7 @@ abstract class GccLikeBackend extends CompilerBackend
public function buildLinkCommand(array $objectFiles, string $outputFile, array $options = []): string
{
$cmd = $this->getLinkerCommand();
$cmd .= ' ' . implode(' ', array_map('escapeshellarg', $objectFiles));
$cmd .= ' ' . $this->createResponseFile($objectFiles, $outputFile);
$cmd .= ' ' . $this->getLinkerOutputFlag() . ' ' . escapeshellarg($outputFile);
if (!empty($options['library_paths'])) {

@ -72,9 +72,9 @@ class Msvc extends CompilerBackend
): string {
$cmd = $this->getLinkerCommand();
// 添加目标文件
$cmd .= ' ' . implode(' ', array_map('escapeshellarg', $objectFiles));
// 添加目标文件(通过 Response File 避免命令行过长)
$cmd .= ' ' . $this->createResponseFile($objectFiles, $outputFile);
// 输出文件
$cmd .= ' /OUT:' . escapeshellarg($outputFile);
@ -179,7 +179,7 @@ class Msvc extends CompilerBackend
public function buildLinkCommand(array $objectFiles, string $outputFile, array $options = []): string
{
$cmd = $this->getLinkerCommand();
$cmd .= ' ' . implode(' ', array_map('escapeshellarg', $objectFiles));
$cmd .= ' ' . $this->createResponseFile($objectFiles, $outputFile);
$cmd .= ' /OUT:' . escapeshellarg($outputFile);
if (!empty($options['library_paths'])) {

Loading…
Cancel
Save