feat(compiler): 添加编译模式支持和目标名称配置

- 实现二进制文件和PHP扩展两种编译模式
- 添加目标名称配置功能
- 支持通过命令行参数指定编译模式
- 更新编译选项以支持不同的构建模式
- 添加main函数存在性检查确保二进制构建完整性
- 修改链接过程以支持共享库生成
- 添加示例文件array_append.php和ref.php用于测试
- 更新帮助文档和命令行参数说明
pull/1/head
韩天峰 7 months ago
parent d1c56ee5d1
commit ea77b6d746
  1. 13
      bin/compiler.php
  2. 8
      examples/array_append.php
  3. 11
      examples/ref.php
  4. 14
      src/Php/CompilerBase.php
  5. 50
      src/Php/Translator.php
  6. 12
      src/template/extension.cc.php

@ -24,11 +24,12 @@ $path = $realpath;
if (is_dir($path)) { if (is_dir($path)) {
$scanner = new FileScanner($path); $scanner = new FileScanner($path);
$list = $scanner->scan(); $list = $scanner->scan();
$targetFile = basename($path); $targetName = basename($path);
} else { } else {
$list = [$path]; $list = [$path];
$targetFile = FileScanner::getFileName($path); $targetName = FileScanner::getFileName($path);
} }
$translator->setTargetName($targetName);
$sourceFiles = []; $sourceFiles = [];
$objectFiles = []; $objectFiles = [];
@ -78,11 +79,13 @@ $translator->genExternGlobalVars($translator->getIncludeDir() . '/php_global_var
// 生成所有全局变量源文件 // 生成所有全局变量源文件
$extensionSourceFile = $translator->getBuildDir() . '/extension.cc'; $extensionSourceFile = $translator->getBuildDir() . '/extension.cc';
$translator->genExtension($extensionSourceFile); $translator->genExtension($extensionSourceFile, $targetName);
$sourceFiles[] = $extensionSourceFile; $sourceFiles[] = $extensionSourceFile;
// 添加 main.cc 文件 // 添加 main.cc 文件
$sourceFiles[] = ROOT_PATH . '/src/cpp/main.cc'; if ($translator->getBuildMode() == 'bin') {
$sourceFiles[] = ROOT_PATH . '/src/cpp/main.cc';
}
// 编译所有 C++ 文件 // 编译所有 C++ 文件
foreach ($sourceFiles as $cppFile) { foreach ($sourceFiles as $cppFile) {
@ -95,4 +98,4 @@ foreach ($sourceFiles as $cppFile) {
} }
// 连接所有目标文件,生成可执行文件 // 连接所有目标文件,生成可执行文件
$translator->compileBinary($targetFile, $objectFiles); $translator->build($objectFiles);

@ -0,0 +1,8 @@
<?php
function main()
{
$a = $b = $c = $d = 4;
$arr = [$a, $b, $c, $d];
var_dump($arr);
// var_dump($arr[] = 5);
}

@ -0,0 +1,11 @@
<?php
function main()
{
$a = [1, 2, 3];
$b = &$a;
$b[] = 5;
$c = &$b;
$c [] = 6;
var_dump($a, $b, $c);
}

@ -76,6 +76,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected array $functionCallInFile = []; protected array $functionCallInFile = [];
protected array $redoAfterDeclare = []; protected array $redoAfterDeclare = [];
protected int $optimizeLevel = 0; protected int $optimizeLevel = 0;
protected string $buildMode = 'bin';
protected int $floatPrecision = 17; protected int $floatPrecision = 17;
protected bool $debugInfo = true; protected bool $debugInfo = true;
protected bool $noLiteralStrings = false; protected bool $noLiteralStrings = false;
@ -151,6 +152,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected bool $inAssignExpr = false; protected bool $inAssignExpr = false;
protected bool $stubFile = false; protected bool $stubFile = false;
protected bool $stubFileIncluded = false; protected bool $stubFileIncluded = false;
protected bool $enableProfiler = false;
protected Parser $parser; protected Parser $parser;
public function __construct(string $rootPath) public function __construct(string $rootPath)
@ -1184,16 +1186,24 @@ class CompilerBase extends \PhpAot\Core\Translator
return $out; return $out;
} }
protected function addCompilationOption(string &$cmd): void protected function addCompilationOption(string &$cmd, bool $link): void
{ {
$cmd .= ' ' . $this->parseIncludes(); $cmd .= ' ' . $this->parseIncludes();
$cmd .= ' -O' . $this->optimizeLevel; $cmd .= ' -O' . $this->optimizeLevel;
$cmd .= ' -g'; $cmd .= ' -g';
$cmd .= ' -Wall'; $cmd .= ' -Wall';
if ($this->climate->arguments->defined('profile')) { if ($this->enableProfiler) {
$cmd .= ' -lprofiler'; $cmd .= ' -lprofiler';
$cmd .= ' -DPPROF_ON=1'; $cmd .= ' -DPPROF_ON=1';
} }
if ($this->buildMode === 'ext') {
if ($link) {
$cmd .= ' -shared';
} else {
$cmd .= ' -fPIC -D BUILD_PHP_EXTENSION=1';
}
}
} }
protected function parseBinaryOpConcat(mixed $expr): string protected function parseBinaryOpConcat(mixed $expr): string

@ -13,6 +13,7 @@ class Translator extends Preprocessor
{ {
use MagicMethodDetector; use MagicMethodDetector;
protected string $targetName = 'app';
protected bool $verbose = false; protected bool $verbose = false;
protected array $unsupportedFunctions = [ protected array $unsupportedFunctions = [
'compact', 'compact',
@ -64,13 +65,22 @@ class Translator extends Preprocessor
'required' => false, 'required' => false,
'noValue' => true, 'noValue' => true,
], ],
'mode' => [
'longPrefix' => 'mode',
'prefix' => 'm',
'description' => 'Build mode, -m bin(binary) or -m ext(extension), default: bin',
'required' => false,
'defaultValue' => 'bin',
],
]); ]);
$this->preprocessArgvAdvanced(); $this->preprocessArgvAdvanced();
$this->climate->arguments->parse(); $this->climate->arguments->parse();
$this->optimizeLevel = $this->climate->arguments->get('optimize'); $this->optimizeLevel = $this->climate->arguments->get('optimize');
$this->buildMode = $this->climate->arguments->get('mode');
// $this->noLiteralStrings = $this->climate->arguments->get('noLiteralStrings'); // $this->noLiteralStrings = $this->climate->arguments->get('noLiteralStrings');
$this->noLiteralStrings = true; $this->noLiteralStrings = true;
$this->enableProfiler = $this->climate->arguments->defined('profile');
$this->internalFunctions = array_flip(get_defined_functions()['internal']); $this->internalFunctions = array_flip(get_defined_functions()['internal']);
if ($this->climate->arguments->defined('help')) { if ($this->climate->arguments->defined('help')) {
$this->showUsage(); $this->showUsage();
@ -99,13 +109,15 @@ class Translator extends Preprocessor
$climate->tab()->out('-v, --verbose Verbose output'); $climate->tab()->out('-v, --verbose Verbose output');
$climate->tab()->out('-h, --help Show this help message'); $climate->tab()->out('-h, --help Show this help message');
$climate->tab()->out('-f, --force Force compile even if cache exists'); $climate->tab()->out('-f, --force Force compile even if cache exists');
$climate->tab()->out('-m, --mode <mode> Compilation mode, -m bin(binary) or -m ext(extension), default: bin');
$climate->tab()->out('--no-literal-strings Disable literal strings optimization'); $climate->tab()->out('--no-literal-strings Disable literal strings optimization');
$climate->br(); $climate->br();
$climate->bold('EXAMPLES:'); $climate->bold('EXAMPLES:');
$climate->tab()->out('./bin/compiler.php examples/hello.php'); $climate->tab()->out('./bin/compiler.php examples/hello.php');
$climate->tab()->out('./bin/compiler.php examples/bench.php -O2'); $climate->tab()->out('./bin/compiler.php examples/bench.php -O2');
$climate->tab()->out('./bin/compiler.php examples/bench.php -O2 -p'); $climate->tab()->out('./bin/compiler.php examples/bench.php -O2 ');
$climate->tab()->out('./bin/compiler.php examples/extension -O2 -o myapp -m ext');
$climate->tab()->out('./bin/compiler.php examples/app.php -O3 -o myapp -v'); $climate->tab()->out('./bin/compiler.php examples/app.php -O3 -o myapp -v');
$climate->br(); $climate->br();
} }
@ -170,6 +182,18 @@ class Translator extends Preprocessor
return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName(); return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName();
} }
public function setTargetName(string $name): void
{
if ($this->climate->arguments->defined('output')) {
$name = $this->climate->arguments->get('output');
}
if (!preg_match('/^[a-zA-Z0-9_]+$/', $name)) {
$this->climate->red('The target name must be a valid identifier');
exit(1);
}
$this->targetName = $name;
}
protected function getInternalCeInfo(string $ce): array protected function getInternalCeInfo(string $ce): array
{ {
return [ return [
@ -373,6 +397,12 @@ class Translator extends Preprocessor
public function genExtension(string $file): void public function genExtension(string $file): void
{ {
if ($this->buildMode == 'bin') {
if (!isset($this->nativeFunctions['main'])) {
$this->climate->red('When the build mode is a binary executable file, the `main()` function must be defined');
exit(1);
}
}
$this->localHeaders = []; $this->localHeaders = [];
$this->genClassCeList(); $this->genClassCeList();
$code = $this->render('extension.cc.php'); $code = $this->render('extension.cc.php');
@ -399,19 +429,20 @@ class Translator extends Preprocessor
return; return;
} }
$cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile; $cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile;
$this->addCompilationOption($cmd); $this->addCompilationOption($cmd, false);
$this->climate->comment($cmd); $this->climate->comment($cmd);
shell_exec($cmd); shell_exec($cmd);
} }
public function compileBinary(string $targetFile, array $objectFiles): void public function build(array $objectFiles): void
{ {
if ($this->climate->arguments->defined('output')) {
$targetFile = $this->climate->arguments->get('output');
}
$objectList = implode(' ', $objectFiles); $objectList = implode(' ', $objectFiles);
$targetFile = $this->targetName;
if ($this->buildMode == 'ext' and !str_ends_with($targetFile, '.so')) {
$targetFile .= '.so';
}
$linkCmd = $this->cppCompiler . ' ' . $objectList . ' -o ' . $targetFile . ' ' . $this->parseLdflags() . $this->parseLibs(); $linkCmd = $this->cppCompiler . ' ' . $objectList . ' -o ' . $targetFile . ' ' . $this->parseLdflags() . $this->parseLibs();
$this->addCompilationOption($linkCmd); $this->addCompilationOption($linkCmd, true);
$this->climate->comment($linkCmd); $this->climate->comment($linkCmd);
shell_exec($linkCmd); shell_exec($linkCmd);
} }
@ -569,6 +600,11 @@ class Translator extends Preprocessor
return $code; return $code;
} }
public function getBuildMode(): string
{
return $this->buildMode;
}
public function getArgInfoHeaderFile(string $stubFilenameWithoutExtension, bool $relative = false): string public function getArgInfoHeaderFile(string $stubFilenameWithoutExtension, bool $relative = false): string
{ {
$basename = basename($stubFilenameWithoutExtension); $basename = basename($stubFilenameWithoutExtension);

@ -66,7 +66,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE_END ZEND_FE_END
}; };
static PHP_MINIT_FUNCTION(app) { static PHP_MINIT_FUNCTION(<?=$this->targetName?>) {
// class/interface class entries // class/interface class entries
<?php <?php
foreach ($this->classCeList as $ce): foreach ($this->classCeList as $ce):
@ -122,11 +122,11 @@ foreach ($this->nativeConstants as $name => $constant):
<?php endforeach; ?> <?php endforeach; ?>
} }
zend_module_entry app_module_entry = { zend_module_entry <?=$this->targetName?>_module_entry = {
STANDARD_MODULE_HEADER, STANDARD_MODULE_HEADER,
"app", "<?=$this->targetName?>",
ext_functions, ext_functions,
PHP_MINIT(app), PHP_MINIT(<?=$this->targetName?>),
nullptr, nullptr,
nullptr, nullptr,
nullptr, nullptr,
@ -135,4 +135,6 @@ zend_module_entry app_module_entry = {
STANDARD_MODULE_PROPERTIES, STANDARD_MODULE_PROPERTIES,
}; };
ZEND_GET_MODULE(app); #ifdef BUILD_PHP_EXTENSION
ZEND_GET_MODULE(<?=$this->targetName?>);
#endif
Loading…
Cancel
Save