From f3944a5259b1e29815a79bc5615509df82e8f760 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 13 Jan 2026 11:39:57 +0800 Subject: [PATCH] =?UTF-8?q?refactor(compiler):=20=E9=87=8D=E6=9E=84PHP?= =?UTF-8?q?=E5=88=B0C++=E7=BC=96=E8=AF=91=E5=99=A8=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改编译流程,添加对象文件路径管理功能 - 实现缓存检查机制,跳过已存在的编译文件 - 重命名MethodDef中的def属性为functionDef - 提取表达式类型转换逻辑到独立方法convertExprFromType - 添加扩展模板文件extension.cc.php,使用模板渲染替代手动代码生成 - 修改main.cc文件结构,使用模块注册方式替代函数注册 - 更新编译参数,添加-Wall编译选项 - 实现方法调用参数传递的动态构建机制 - 优化全局变量初始化和清理函数的实现 --- bin/compiler.php | 9 ++- src/Php/CompilerBase.php | 28 +++++--- src/Php/MethodDef.php | 11 +-- src/Php/Translator.php | 129 ++++++++++++---------------------- src/cpp/main.cc | 30 +++----- src/template/extension.cc.php | 120 +++++++++++++++++++++++++++++++ 6 files changed, 203 insertions(+), 124 deletions(-) create mode 100644 src/template/extension.cc.php diff --git a/bin/compiler.php b/bin/compiler.php index ba9b950e..04bb440d 100755 --- a/bin/compiler.php +++ b/bin/compiler.php @@ -34,6 +34,11 @@ $objectFiles = []; // 分析 PHP 文件,预处理 foreach ($list as $k => $file) { +// if ($translator->hasCache($file)) { +// echo " skip: " . $file . ", cache exists\n"; +// unset($list[$k]); +// continue; +// } if (FileScanner::isPhpFile($file)) { try { $translator->prepare($file); @@ -83,8 +88,8 @@ $sourceFiles[] = ROOT_PATH . '/src/cpp/main.cc'; // 编译所有 C++ 文件 foreach ($sourceFiles as $cppFile) { - $translator->compileFile($cppFile); - $objectFile = $cppFile . '.o'; + $objectFile = $translator->getObjectFile($cppFile); + $translator->compileFile($cppFile, $objectFile); if (!is_file($objectFile)) { throw new Exception("compile error"); } diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 8fd7666f..c14162d9 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -1046,9 +1046,10 @@ class CompilerBase extends \PhpAot\Core\Translator protected function addCompilationOption(string &$cmd): void { - $cmd .= $this->parseIncludes(); + $cmd .= ' ' . $this->parseIncludes(); $cmd .= ' -O' . $this->optimizeLevel; $cmd .= ' -g'; + $cmd .= ' -Wall'; if ($this->climate->arguments->defined('profile')) { $cmd .= ' -lprofiler'; $cmd .= ' -DPPROF_ON=1'; @@ -2131,19 +2132,24 @@ class CompilerBase extends \PhpAot\Core\Translator } } + protected function convertExprFromType(string $type, string $expr): string + { + if ($type === self::TYPE_FLOAT) { + return $this->convertFloatExpr($expr); + } + if ($type === self::TYPE_INT) { + return $this->convertIntExpr($expr); + } + if ($type === self::TYPE_BOOL) { + return $this->convertBoolExpr($expr); + } + return $expr; + } + protected function convertVarType($var, $expr): string { if ($this->hasVar($var)) { - $type = $this->getVarType($var); - if ($type === self::TYPE_FLOAT) { - return $this->convertFloatExpr($expr); - } - if ($type === self::TYPE_INT) { - return $this->convertIntExpr($expr); - } - if ($type === self::TYPE_BOOL) { - return $this->convertBoolExpr($expr); - } + return $this->convertExprFromType($this->getVarType($var), $expr); } return $expr; } diff --git a/src/Php/MethodDef.php b/src/Php/MethodDef.php index 8a82a14d..900c7826 100644 --- a/src/Php/MethodDef.php +++ b/src/Php/MethodDef.php @@ -6,22 +6,17 @@ class MethodDef { public int $flags; public string $name; - public FunctionDef $def; + public FunctionDef $functionDef; public function __construct(int $flags, string $name, FunctionDef $def) { $this->flags = $flags; $this->name = $name; - $this->def = $def; - } - - public function getFlags(): int - { - return $this->flags; + $this->functionDef = $def; } public function getReturnType(): string { - return $this->def->returnType; + return $this->functionDef->returnType; } } diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 598998b9..ae541cd1 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -88,6 +88,18 @@ class Translator extends Preprocessor $climate->br(); } + public function getCppFile(string $file): string + { + $info = pathinfo($file); + return $this->buildDir . '/' . $this->removeCommonPrefix($this->buildDir, $info['dirname'] . '/' . $info['filename'] . '.cc'); + } + + public function getObjectFile(string $cppFile): string + { + $info = pathinfo($cppFile); + return $info['dirname'] . '/' . $info['filename'] . '.o'; + } + public function convert(string $file): string { $phpCode = $this->loadFile($file); @@ -96,8 +108,7 @@ class Translator extends Preprocessor while (true) { try { $cppCode = $this->doConvert($phpCode); - $info = pathinfo($file); - $cppFile = $this->buildDir . '/' . $this->removeCommonPrefix($this->buildDir, $info['dirname'] . '/' . $info['filename'] . '.cc'); + $cppFile = $this->getCppFile($file); $this->save($cppCode, $cppFile); return $cppFile; } catch (RedoException $e) { @@ -111,6 +122,17 @@ class Translator extends Preprocessor return self::PREFIX . 'register_class_' . $name; } + public function hasCache(string $file): bool + { + $cppFile = $this->getCppFile($file); + $objectFile = $this->getObjectFile($cppFile); + if ((file_exists($cppFile) and filemtime($cppFile) > filemtime($file)) + and (file_exists($objectFile) and filemtime($objectFile) > filemtime($cppFile))) { + return true; + } + return false; + } + protected function getClassCe(ClassDef $classDef): string { return self::PREFIX . 'class_entry_' . $classDef->getNamespacedName(); @@ -209,93 +231,24 @@ class Translator extends Preprocessor $this->writeFile($file, $code); } + private function render(string $template): string + { + ob_start(); + include __DIR__ . '/../template/' . $template; + return ob_get_clean(); + } + public function genGlobalVars(string $file): void { $this->localHeaders = []; - $code = $this->genIncludeHeaderFiles(); - $lines = []; - // 全局变量只能是 var 类型 - foreach ($this->globalVars as $name => $type) { - $lines[] = self::TYPE_VAR . ' ' . $name . ';'; - } - // 类定义 - $lines[] = $this->getIndent() . '// class entries'; - foreach ($this->classes as $classDef) { - $lines[] = $this->getIndent() . 'zend_class_entry *' . $this->getClassCe($classDef) . ';'; - } - foreach ($this->classes as $classDef) { - $name = $classDef->getNamespacedName(); - if ($classDef->extends) { - $parentCe = 'zend_class_entry *parent_ce'; - } else { - $parentCe = ''; - } - $lines[] = 'extern zend_class_entry *' . $this->getRegisterClassFunction($name) . '(' . $parentCe . ');'; - } - $code .= implode(PHP_EOL, $lines) . PHP_EOL; - - $code .= PHP_EOL; - $literalStringsCount = count($this->literalStrings); - $code .= 'php::Var ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '] = {' . PHP_EOL; - $this->indentLevel++; - $code .= $this->getIndent() . '// literal strings' . PHP_EOL; - foreach ($this->literalStrings as $str => $index) { - $code .= $this->getIndent() . 'php::String{ZEND_STRL("' . $this->escapeString($str) . '"), true},' . PHP_EOL; - } - $this->indentLevel--; - $code .= '};' . PHP_EOL; - - // 生成常量表 - $this->indentLevel++; - foreach ($this->nativeConstants as $name => $constant) { - $code .= $constant->type . ' ' . $name . ';' . PHP_EOL; - } - $this->indentLevel--; - - $code .= PHP_EOL; - $this->indentLevel++; - $lines = []; - $lines[] = $this->getIndent() . '// constants'; - foreach ($this->nativeConstants as $name => $constant) { - $lines[] = $this->getIndent() . $name . ' = ' . $constant->value . ';'; - $lines[] = $this->getIndent() . 'php::define("' . $name . '", ' . $name . ');'; - } - $lines[] = $this->getIndent() . '// global vars'; - foreach ($this->globalVars as $name => $type) { - $lines[] = $this->getIndent() . $name . ' = php::global("' . $name . '");'; - } - $lines[] = $this->getIndent() . '// class entries'; - foreach ($this->classes as $classDef) { - $name = $classDef->getNamespacedName(); - $parentCe = $this->getParentClassCe($classDef); - $lines[] = $this->getIndent() . $this->getClassCe($classDef) . ' = ' . $this->getRegisterClassFunction($name) . '(' . $parentCe . ');'; - } - $this->indentLevel--; - $code .= $this->genFunction(self::PREFIX . 'init_global_vars', 'void', [], $lines); - - // 销毁全局变量 - $code .= PHP_EOL; - $this->indentLevel++; - $lines = []; - foreach ($this->globalVars as $name => $type) { - $lines[] = $this->getIndent() . $name . '.unset();'; - } - foreach ($this->nativeConstants as $name => $constant) { - if ($constant->type !== self::TYPE_VAR) { - continue; - } - $lines[] = $this->getIndent() . $name . '.unset();'; - } - $this->indentLevel--; - $code .= $this->genFunction(self::PREFIX . 'unset_global_vars', 'void', [], $lines); - + $code = $this->render('extension.cc.php'); $this->writeFile($file, $code); $this->formatCppCode($file); } - public function compileFile($file): void + public function compileFile(string $file, string $objectFile): void { - $cmd = $this->cppCompiler . ' -c ' . $file . ' -o ' . $file . '.o '; + $cmd = $this->cppCompiler . ' -c ' . $file . ' -o ' . $objectFile; $this->addCompilationOption($cmd); $this->climate->comment($cmd); shell_exec($cmd); @@ -475,11 +428,19 @@ class Translator extends Preprocessor $cppCode .= $this->getIndent() . self::TYPE_OBJECT . ' this_(&execute_data->This);' . PHP_EOL; $fn = self::PREFIX . $this->getNativeMethodName($classDef, $methodDef); + $callParams = ''; + foreach ($methodDef->functionDef->argInfoList as $k => $argInfo) { + $expr = $this->convertExprFromType($argInfo->type, 'ZEND_CALL_ARG(EG(current_execute_data), ' . ($k + 1) . ')'); + $cppCode .= $this->getIndent() . $argInfo->type . ' arg_' . $argInfo->name . ' = ' . $expr . ';' . PHP_EOL; + $callParams .= 'arg_' . $argInfo->name . ','; + } + $callParams = $methodDef->functionDef->argInfoList ? 'this_, ' . rtrim($callParams, ',') : 'this_'; + if ($methodDef->getReturnType() !== self::TYPE_VOID) { - $cppCode .= $this->getIndent() . 'auto retval = ' . $fn . '(this_);' . PHP_EOL; + $cppCode .= $this->getIndent() . 'auto retval = ' . $fn . '(' . $callParams . ');' . PHP_EOL; $cppCode .= $this->getIndent() . 'php::move(retval, return_value);' . PHP_EOL; } else { - $cppCode .= $this->getIndent() . $fn . '(this_);' . PHP_EOL; + $cppCode .= $this->getIndent() . $fn . '(' . $callParams . ');' . PHP_EOL; } $cppCode .= '}' . PHP_EOL . PHP_EOL; @@ -500,7 +461,7 @@ class Translator extends Preprocessor $param = ''; } $cppCode .= 'zend_class_entry *' . $this->getRegisterClassFunction($name) . '(' . $parentName . ') {' . PHP_EOL; - $cppCode .= $this->getIndent() . 'return ' . $this->getRegisterClassFunction($name) . '(' . $param . ');' . PHP_EOL; + $cppCode .= $this->getIndent() . 'return register_class_' . $name . '(' . $param . ');' . PHP_EOL; $cppCode .= '}' . PHP_EOL . PHP_EOL; $methods = $classDef->methods; diff --git a/src/cpp/main.cc b/src/cpp/main.cc index 3278c9be..f9aaa84d 100644 --- a/src/cpp/main.cc +++ b/src/cpp/main.cc @@ -4,25 +4,14 @@ #endif #include -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_void, 0, 0, IS_VOID, 0) -ZEND_END_ARG_INFO() - -void php_main(); - extern php::Var argc; extern php::Var argv; -extern void php_init_global_vars(); -extern void php_unset_global_vars(); - -static ZEND_FUNCTION(main) { - php_main(); -} - -static const zend_function_entry ext_functions[] = { - ZEND_FE(main, arginfo_void) - ZEND_FE_END -}; +extern void php_app_init(); +extern void php_app_clean(); +BEGIN_EXTERN_C() +extern zend_module_entry *get_module(); +END_EXTERN_C() static void throw_exception(zend_object *ex) { zend_bailout(); @@ -31,14 +20,17 @@ static void throw_exception(zend_object *ex) { int main(int cpp_argc, char **cpp_argv) { php_embed_init(cpp_argc, cpp_argv); zend_throw_exception_hook = throw_exception; - zend_register_functions(nullptr, ext_functions, nullptr, 0); + + if (zend_register_module_ex(get_module(), MODULE_TEMPORARY) == NULL) { + zend_error(E_ERROR, "Failed to register module"); + } int rc = 0; #if PPROF_ON ProfilerStart("myapp.prof"); #endif zend_first_try { - php_init_global_vars(); + php_app_init(); php::eval("main();"); } zend_catch { @@ -52,7 +44,7 @@ int main(int cpp_argc, char **cpp_argv) { #if PPROF_ON ProfilerStop(); #endif - php_unset_global_vars(); + php_app_clean(); php::request_shutdown(); php_embed_shutdown(); diff --git a/src/template/extension.cc.php b/src/template/extension.cc.php new file mode 100644 index 00000000..3cf9ceb7 --- /dev/null +++ b/src/template/extension.cc.php @@ -0,0 +1,120 @@ +genIncludeHeaderFiles(); +?> + +// global vars +globalVars as $name => $type): +?> + ; + + +// class entries +classes as $classDef) : +?> +zend_class_entry * getClassCe($classDef) ?>; + + +// class register functions +classes as $classDef): + $name = $classDef->getNamespacedName(); + $parentCe = $classDef->extends ? 'zend_class_entry *parent_ce' : ''; +?> +extern zend_class_entry *getRegisterClassFunction($name) ?>(); + + +// literal strings +php::Var [] = { +literalStrings as $str => $index): +?> + php::String{ZEND_STRL("escapeString($str)?>"), true}, + +}; + +// constants +nativeConstants as $name => $constant): +?> +type?> ; + + +static ZEND_FUNCTION(main) { + php_main(); +} + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_void, 0, 0, IS_VOID, 0) +ZEND_END_ARG_INFO() + +static const zend_function_entry ext_functions[] = { + ZEND_FE(main, arginfo_void) + ZEND_FE_END +}; + +static PHP_MINIT_FUNCTION(app) { +classes as $classDef): + $name = $classDef->getNamespacedName(); + $parentCe = $this->getParentClassCe($classDef); + $fn = $this->getRegisterClassFunction($name); +?> + getClassCe($classDef)?> = (); + + + return SUCCESS; +} + +void php_app_init() { + // register constants +nativeConstants as $name => $constant): +?> + = value ?>; + php::define("", ); + + + // global vars +globalVars as $name => $type): +?> + = php::global(""); + +} + +void php_app_clean() { +globalVars as $name => $type) : +?> + .unset(); + +nativeConstants as $name => $constant): + if ($constant->type !== Translator::TYPE_VAR) { + continue; + } +?> + .unset(); + +} + +static zend_module_entry app_module_entry = { + STANDARD_MODULE_HEADER, + "app", + ext_functions, + PHP_MINIT(app), + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + STANDARD_MODULE_PROPERTIES, +}; + +ZEND_GET_MODULE(app);