fix(backend): ensure response file cleanup and improve link error handling

- Add cleanupResponseFile call after successful builds in BackendTest
- Implement proper exception handling for link failures with TestError
- Add test case for response file cleanup when linking fails
- Replace php_aot_static_int_ref with typephp_static_int_ref in assertions
- Refactor Translator to always clean up response files in finally block
- Improve error reporting for both link failures and missing target files
- Update FunctionTest return type declaration and method implementation
pull/16/head
韩天峰 2 months ago
parent 0c2939738e
commit 35795be037
  1. 37
      phpunit/src/Backend/BackendTest.php
  2. 4
      phpunit/src/FunctionTest.php
  3. 8
      phpunit/src/NativePropertyTest.php
  4. 39
      src/Translator.php

@ -10,6 +10,8 @@ use TypePhp\Backend\Msvc;
use TypePhp\Backend\Gcc;
use TypePhp\Backend\Clang;
use TypePhp\Backend\CompilerFactory;
use TypePhp\CompilerTest;
use TypePhp\Exception\TestError;
class BackendTest extends TestCase
{
@ -104,6 +106,7 @@ class BackendTest extends TestCase
$this->assertStringContainsString('/OUT:', $cmd);
$this->assertStringContainsString('output.exe', $cmd);
$this->assertStringContainsString('/LIBPATH:', $cmd);
$compiler->cleanupResponseFile();
}
/**
@ -183,6 +186,7 @@ class BackendTest extends TestCase
$this->assertStringContainsString('/DEBUG', $cmd);
$this->assertStringContainsString('/NODEFAULTLIB:LIBCMT', $cmd);
$this->assertStringContainsString('/nologo', $cmd);
$compiler->cleanupResponseFile();
}
/**
@ -352,6 +356,39 @@ class BackendTest extends TestCase
$this->assertStringContainsString('-shared', $cmd);
$this->assertStringContainsString('-lphpx', $cmd);
$this->assertStringContainsString('-lphp', $cmd);
$compiler->cleanupResponseFile();
}
public function testBuildCleansResponseFileWhenLinkFails(): void
{
$dir = $this->createTemporaryDirectory('backend_link_failure');
$target = $dir . '/app';
$backend = new Gcc(new Linux(), 'false');
$compiler = new class(ROOT_PATH, $target, $backend) extends CompilerTest {
public function __construct(
string $rootPath,
private readonly string $testTarget,
\TypePhp\Backend\CompilerBackend $backend
) {
parent::__construct($rootPath);
$this->forTest = true;
$this->compilerBackend = $backend;
}
protected function getTargetFileName(): string
{
return $this->testTarget;
}
};
try {
$compiler->build([$dir . '/missing.o']);
$this->fail('The failing linker command should abort the build');
} catch (TestError $e) {
$this->assertStringContainsString('link failed', $e->getMessage());
}
$this->assertFileDoesNotExist($target . '.rsp');
}
public function testResponseFileArgumentIsEscapedForPathsWithSpaces(): void

@ -2,9 +2,9 @@
class FunctionTest extends \BaseTest
{
public function testReturnRef()
public function testReturnRef(): void
{
$this->exec('The return type of the function `test` cannot be a reference type', 'function-return-ref.php');
$this->compile('function-return-ref.php');
}
public function testNativeCallUnknownNamedArgument()

@ -51,9 +51,9 @@ class NativePropertyTest extends \BaseTest
}
$code = file_get_contents($outputFile);
$this->assertStringContainsString('php_aot_static_int_ref(this_.attr(', $code);
$this->assertStringContainsString('php_aot_static_int_ref(box.attr(', $code);
$this->assertSame(2, substr_count($code, 'php_aot_static_int_ref('));
$this->assertStringContainsString('typephp_static_int_ref(this_.attr(', $code);
$this->assertStringContainsString('typephp_static_int_ref(box.attr(', $code);
$this->assertSame(2, substr_count($code, 'typephp_static_int_ref('));
$this->assertStringNotContainsString('this_.attr(php_get_prop(0, _literal_strings[0], 0, _literal_strings[1]), true) +=', $code);
$this->assertStringNotContainsString('box.attr(php_get_prop(0, _literal_strings[0], 0, _literal_strings[1]), true) +=', $code);
}
@ -67,7 +67,7 @@ class NativePropertyTest extends \BaseTest
}
$code = file_get_contents($outputFile);
$this->assertStringContainsString('php_aot_static_int_ref(this_.attr(', $code);
$this->assertStringContainsString('typephp_static_int_ref(this_.attr(', $code);
$this->assertStringContainsString('&= (~php::toInt(php::constant(', $code);
}

@ -1750,32 +1750,35 @@ CODE;
}
}
$linkCmd = $this->buildLinkCommand($objectFiles, $targetFile);
$this->climate->comment($linkCmd);
$backend = $this->getCompilerBackend();
$buildError = null;
try {
$linkCmd = $this->buildLinkCommand($objectFiles, $targetFile);
$this->climate->comment($linkCmd);
// 执行链接并捕获输出
exec($linkCmd . ' 2>&1', $output, $ret);
// 执行链接并捕获输出
exec($linkCmd . ' 2>&1', $output, $ret);
// 显示输出(如果有)
if (!empty($output)) {
foreach ($output as $line) {
$this->climate->out($line);
// 显示输出(如果有)
if (!empty($output)) {
foreach ($output as $line) {
$this->climate->out($line);
}
}
}
// 检查链接是否成功
if ($ret !== 0) {
$this->error('link failed: ' . $targetFile);
if ($ret !== 0) {
$buildError = 'link failed: ' . $targetFile;
} elseif (!file_exists($targetFile)) {
$buildError = 'target file not generated: ' . $targetFile;
}
} finally {
$backend->cleanupResponseFile();
}
// 验证目标文件是否生成
if (!file_exists($targetFile)) {
$this->error('target file not generated: ' . $targetFile);
if ($buildError !== null) {
$this->error($buildError);
}
// 删除 Response File 临时文件
$this->getCompilerBackend()->cleanupResponseFile();
$this->climate->green('Build successful: ' . $targetFile);
return $targetFile;

Loading…
Cancel
Save