diff --git a/phpunit/src/Backend/BackendTest.php b/phpunit/src/Backend/BackendTest.php index 339b39b4..e35f7bdf 100644 --- a/phpunit/src/Backend/BackendTest.php +++ b/phpunit/src/Backend/BackendTest.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); diff --git a/src/Php/Backend/CompilerBackend.php b/src/Php/Backend/CompilerBackend.php index 2bdc6ec5..32ad240b 100644 --- a/src/Php/Backend/CompilerBackend.php +++ b/src/Php/Backend/CompilerBackend.php @@ -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; + } } diff --git a/src/Php/Backend/GccLikeBackend.php b/src/Php/Backend/GccLikeBackend.php index 5e0b2da0..27e6eabe 100644 --- a/src/Php/Backend/GccLikeBackend.php +++ b/src/Php/Backend/GccLikeBackend.php @@ -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'])) { diff --git a/src/Php/Backend/Msvc.php b/src/Php/Backend/Msvc.php index 2da7e8bf..817632a5 100644 --- a/src/Php/Backend/Msvc.php +++ b/src/Php/Backend/Msvc.php @@ -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'])) {