diff --git a/examples/lib-demo/cpp-src/exports.cc b/examples/lib-demo/cpp-src/exports.cc new file mode 100644 index 00000000..52128136 --- /dev/null +++ b/examples/lib-demo/cpp-src/exports.cc @@ -0,0 +1,19 @@ +#include + +#ifdef _WIN32 +#define TYPEPHP_API extern "C" __declspec(dllexport) +#else +#define TYPEPHP_API extern "C" __attribute__((visibility("default"))) +#endif + +extern "C" int php_aot_runtime_init(int argc, char **argv); + +TYPEPHP_API int typephp_lib_demo_add(int a, int b) +{ + char app_name[] = "typephp_lib_demo"; + char *argv[] = {app_name, nullptr}; + if (php_aot_runtime_init(1, argv) != 0) { + return 0; + } + return static_cast(php_demo_add(a, b)); +} diff --git a/examples/lib-demo/php-src/logic.php b/examples/lib-demo/php-src/logic.php new file mode 100644 index 00000000..cf0822e4 --- /dev/null +++ b/examples/lib-demo/php-src/logic.php @@ -0,0 +1,8 @@ +platform instanceof Windows) { return ''; } - if ((!empty($config['build_mode']) && $config['build_mode'] === 'ext') || !empty($config['pic'])) { + if ((!empty($config['build_mode']) && ($config['build_mode'] === 'ext' || $config['build_mode'] === 'lib')) || !empty($config['pic'])) { return ' -fPIC'; } return ''; @@ -108,7 +108,7 @@ class Clang extends GccLikeBackend } $flags .= ' ' . $this->platform->getCrtConfig(); - if (!empty($config['build_mode']) && $config['build_mode'] === 'ext') { + if (!empty($config['build_mode']) && ($config['build_mode'] === 'ext' || $config['build_mode'] === 'lib')) { $flags .= ' /DLL'; } return $flags; diff --git a/src/Backend/GccLikeBackend.php b/src/Backend/GccLikeBackend.php index ec6c541f..7d63f00d 100644 --- a/src/Backend/GccLikeBackend.php +++ b/src/Backend/GccLikeBackend.php @@ -53,7 +53,7 @@ abstract class GccLikeBackend extends CompilerBackend /** 获取 PIC 标志 */ protected function getPICFlag(array $config): string { - if ((!empty($config['build_mode']) && $config['build_mode'] === 'ext') || !empty($config['pic'])) { + if ((!empty($config['build_mode']) && ($config['build_mode'] === 'ext' || $config['build_mode'] === 'lib')) || !empty($config['pic'])) { return ' -fPIC'; } return ''; @@ -121,7 +121,7 @@ abstract class GccLikeBackend extends CompilerBackend { $flags = ''; - if ((!empty($config['build_mode']) && $config['build_mode'] === 'ext') || !empty($config['shared'])) { + if ((!empty($config['build_mode']) && ($config['build_mode'] === 'ext' || $config['build_mode'] === 'lib')) || !empty($config['shared'])) { $flags .= ' ' . $this->platform->getSharedLinkFlag(); if ($this->platform instanceof \TypePhp\Platform\Macos && !empty($config['install_name'])) { diff --git a/src/Backend/Msvc.php b/src/Backend/Msvc.php index baf1f6b6..9a294488 100644 --- a/src/Backend/Msvc.php +++ b/src/Backend/Msvc.php @@ -393,7 +393,7 @@ class Msvc extends CompilerBackend $cmd .= ' ' . $this->platform->getCrtConfig(); // 扩展模块选项 - if (!empty($config['build_mode']) && $config['build_mode'] === 'ext') { + if (!empty($config['build_mode']) && ($config['build_mode'] === 'ext' || $config['build_mode'] === 'lib')) { $cmd .= ' /DLL'; } diff --git a/src/CompilerBase.php b/src/CompilerBase.php index 7d525a36..25b231cd 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -177,6 +177,7 @@ class CompilerBase implements PropertyAccessContext public const string OP_NOP = "if (0) {}\n"; public const string BUILD_MODE_BIN = 'bin'; public const string BUILD_MODE_EXT = 'ext'; + public const string BUILD_MODE_LIB = 'lib'; public const string ENTRY_FUNCTION = 'main'; public const string PHPX_VENDOR_DIR = '/vendor/swoole/phpx'; protected const string PHASE_IDLE = 'idle'; @@ -523,6 +524,16 @@ class CompilerBase implements PropertyAccessContext return $this->buildMode === self::BUILD_MODE_EXT; } + public function isBuildModeLib(): bool + { + return $this->buildMode === self::BUILD_MODE_LIB; + } + + public function isBuildModeEmbed(): bool + { + return $this->isBuildModeBin() || $this->isBuildModeLib(); + } + public function getPhpDir(): string { try { @@ -2860,7 +2871,7 @@ class CompilerBase implements PropertyAccessContext // extension 和 bin 模式都需要链接 PHP 库 if ($platform instanceof Windows) { // Windows: 根据构建模式选择不同的库 - if ($this->isBuildModeBin()) { + if ($this->isBuildModeEmbed()) { // bin 模式:需要同时链接 php8ts.lib 和 php8embed.lib // 注意:php8ts.lib 必须在 php8embed.lib 之前,因为 embed 依赖 core // php8ts.lib 提供 PHP 核心全局符号(executor_globals, compiler_globals, sapi_globals) diff --git a/src/Constants.php b/src/Constants.php index 60836af3..a54fa578 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -165,7 +165,7 @@ class Constants 'mode' => [ 'longPrefix' => 'mode', 'prefix' => 'm', - 'description' => 'Build mode, -m bin(binary) or -m ext(extension), default: bin', + 'description' => 'Build mode, -m bin(binary), -m lib(shared library), or -m ext(PHP extension), default: bin', 'required' => false, 'defaultValue' => CompilerBase::BUILD_MODE_BIN, ], diff --git a/src/Platform/PlatformBase.php b/src/Platform/PlatformBase.php index f99fa60a..13e6ac05 100644 --- a/src/Platform/PlatformBase.php +++ b/src/Platform/PlatformBase.php @@ -83,7 +83,7 @@ abstract class PlatformBase */ public function getTargetExtension(string $buildMode): string { - return $buildMode === 'ext' + return ($buildMode === 'ext' || $buildMode === 'lib') ? '.so' : $this->getExecutableExtension(); } @@ -93,7 +93,7 @@ abstract class PlatformBase */ public function getBuildLibraryWarnings(string $phpDir, string $phpxDir, string $buildMode): array { - if ($buildMode !== 'bin') { + if ($buildMode !== 'bin' && $buildMode !== 'lib') { return []; } diff --git a/src/Platform/Windows.php b/src/Platform/Windows.php index ddf4adcb..f88ecc0c 100644 --- a/src/Platform/Windows.php +++ b/src/Platform/Windows.php @@ -105,7 +105,7 @@ class Windows extends PlatformBase public function getTargetExtension(string $buildMode): string { - return $buildMode === 'ext' ? '.dll' : '.exe'; + return ($buildMode === 'ext' || $buildMode === 'lib') ? '.dll' : '.exe'; } public function getDefaultCompiler(): string @@ -177,7 +177,7 @@ class Windows extends PlatformBase public function getBuildLibraryWarnings(string $phpDir, string $phpxDir, string $buildMode): array { - if ($buildMode !== 'bin') { + if ($buildMode !== 'bin' && $buildMode !== 'lib') { return []; } diff --git a/src/Preprocessor.php b/src/Preprocessor.php index 420f348d..c33a4480 100644 --- a/src/Preprocessor.php +++ b/src/Preprocessor.php @@ -88,6 +88,17 @@ class Preprocessor extends CompilerBase $ext = $this->getPlatform()->getObjectExtension(); // 保持与 cppFile 相同的路径分隔符 + $normalizedFile = str_replace('\\', '/', $cppFile); + $normalizedMiscDir = str_replace('\\', '/', $this->getPhpxDir() . '/src/misc/'); + if (str_starts_with($normalizedFile, $normalizedMiscDir)) { + $separator = $this->getPlatform()->getPathSeparator(); + $objectDir = $this->buildDir . $separator . 'phpx-misc' . $separator . $this->targetName; + if (!is_dir($objectDir)) { + mkdir($objectDir, 0777, true); + } + return $objectDir . $separator . $info['filename'] . $ext; + } + return $info['dirname'] . $this->getPlatform()->getPathSeparator() . $info['filename'] . $ext; } diff --git a/src/Translator.php b/src/Translator.php index d5963932..dd30d901 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -642,7 +642,7 @@ class Translator extends Preprocessor // shell_exec 和 define 已通过 php::fn:: 直接调用,无需动态符号表 // 根据平台检查库文件(仅在构建二进制文件时需要) - if ($this->isBuildModeBin()) { + if ($this->isBuildModeEmbed()) { foreach ($this->getPlatform()->getBuildLibraryWarnings($this->getPhpDir(), $this->getPhpxDir(), $this->buildMode) as $message) { $this->climate->warning($message['warning']); if (!empty($message['info'])) { @@ -1285,8 +1285,11 @@ CODE; $job = $this->maxJob; // embed 需要 main 函数,以及 cli 的内置函数定义 - if ($this->isBuildModeBin()) { + if ($this->isBuildModeEmbed()) { $sourceFiles[] = $this->getPhpxDir() . '/src/misc/main.cc'; + } + + if ($this->isBuildModeBin()) { $sourceFiles[] = $this->getPhpxDir() . '/src/misc/php_cli_process_title.c'; $sourceFiles[] = $this->getPhpxDir() . '/src/misc/ps_title.c'; } @@ -1575,6 +1578,11 @@ CODE; $includePaths = array_merge($includePaths, $this->userIncludePaths); } + $userDefines = $this->userDefines; + if ($this->isBuildModeLib()) { + $userDefines[] = 'PHPX_NO_MAIN=1'; + } + return [ 'include_paths' => $includePaths, 'optimize' => $this->optimizeLevel, @@ -1586,7 +1594,7 @@ CODE; 'build_mode' => $this->buildMode, 'enable_profiler' => $this->enableProfiler, 'prof_output' => $this->targetName . '.prof', - 'user_defines' => $this->userDefines, + 'user_defines' => $userDefines, 'lto' => $this->enableLto, ]; } @@ -2240,6 +2248,12 @@ CODE; $modeMap = [ 'extension' => self::BUILD_MODE_EXT, 'ext' => self::BUILD_MODE_EXT, + 'library' => self::BUILD_MODE_LIB, + 'lib' => self::BUILD_MODE_LIB, + 'shared' => self::BUILD_MODE_LIB, + 'dll' => self::BUILD_MODE_LIB, + 'dylib' => self::BUILD_MODE_LIB, + 'so' => self::BUILD_MODE_LIB, 'binary' => self::BUILD_MODE_BIN, 'bin' => self::BUILD_MODE_BIN, 'cli' => self::BUILD_MODE_BIN, diff --git a/version.txt b/version.txt index 3cf4368c..bf0a67dc 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1082 \ No newline at end of file +1084 \ No newline at end of file