diff --git a/src/Build/NativeBuildConfigurationTrait.php b/src/Build/NativeBuildConfigurationTrait.php index dc28d40c..aa3d1ae0 100644 --- a/src/Build/NativeBuildConfigurationTrait.php +++ b/src/Build/NativeBuildConfigurationTrait.php @@ -11,8 +11,45 @@ use TypePhp\Platform\Windows; trait NativeBuildConfigurationTrait { + /** + * Resolve the fully-static SDK directory (phpx/full-static/sdk). + * + * Fully-static builds are self-contained: the SDK bundles libphp.a and + * libphpx.a plus every required header, so neither PHP_HOME nor php-config + * is consulted. Returns null when fully-static mode is disabled. + */ + protected function getFullStaticSdkDir(): ?string + { + if (!$this->fullStatic) { + return null; + } + $sdkDir = $this->getPhpxDir() . '/full-static/sdk'; + if (!is_dir($sdkDir)) { + $this->error( + '--full-static requires the bundled SDK at phpx/full-static/sdk; not found at: ' . $sdkDir + ); + } + return $sdkDir; + } + protected function getIncludePaths(): array { + $sdkDir = $this->getFullStaticSdkDir(); + if ($sdkDir !== null) { + return [ + $sdkDir . '/include/phpx', + $sdkDir . '/include', + $sdkDir . '/include/php', + $sdkDir . '/include/php/main', + $sdkDir . '/include/php/Zend', + $sdkDir . '/include/php/TSRM', + $sdkDir . '/include/php/ext', + $sdkDir . '/include/php/ext/date/lib', + $this->getBuildDir() . '/include', + $this->getPhpxDir() . '/src/misc', + ]; + } + $platform = $this->getPlatform(); $includePaths = [ $this->getPhpxDir() . '/include', @@ -38,6 +75,11 @@ trait NativeBuildConfigurationTrait protected function getLibraryPaths(): array { + $sdkDir = $this->getFullStaticSdkDir(); + if ($sdkDir !== null) { + return [$sdkDir . '/lib']; + } + $platform = $this->getPlatform(); $libraryPaths = [ $this->getPhpxDir() . '/lib', @@ -61,6 +103,17 @@ trait NativeBuildConfigurationTrait */ protected function getLibraries(): array { + $sdkDir = $this->getFullStaticSdkDir(); + if ($sdkDir !== null) { + // Fully-static: both archives are self-contained. libphpx.a comes + // first because it references symbols resolved by libphp.a; no + // -lgmp/-lgmpxx/-lmpfr or system libc is needed. + return [ + $sdkDir . '/lib/libphpx.a', + $sdkDir . '/lib/libphp.a', + ]; + } + $platform = $this->getPlatform(); $libraries = []; @@ -126,6 +179,12 @@ trait NativeBuildConfigurationTrait */ protected function findPhpxLibrary(): ?string { + $sdkDir = $this->getFullStaticSdkDir(); + if ($sdkDir !== null) { + $phpxStaticPath = $sdkDir . '/lib/libphpx.a'; + return is_file($phpxStaticPath) ? $phpxStaticPath : null; + } + $platform = $this->getPlatform(); if ($platform instanceof Windows) { diff --git a/src/CompilerBase.php b/src/CompilerBase.php index 1042e21f..a0375752 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -413,6 +413,7 @@ class CompilerBase implements PropertyAccessContext protected array $userIncludePaths = []; // --include-path / -I: user-provided C++ include dirs protected array $userDefines = []; // --define / -D: user-provided preprocessor macros protected bool $enableLto = false; // --lto: enable Link Time Optimization (-flto) + protected bool $fullStatic = false; // --full-static: link against the bundled fully-static SDK protected string $file; protected string $dir; diff --git a/src/Metadata/Constants.php b/src/Metadata/Constants.php index 0e796950..5d527e75 100644 --- a/src/Metadata/Constants.php +++ b/src/Metadata/Constants.php @@ -302,6 +302,12 @@ class Constants 'required' => false, 'multiple' => true, ], + 'full-static' => [ + 'longPrefix' => 'full-static', + 'description' => 'Enable fully-static linking using the bundled SDK (phpx/full-static/sdk)', + 'required' => false, + 'noValue' => true, + ], ]; /** diff --git a/src/Translator.php b/src/Translator.php index 6c585d76..20dc04e7 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -218,6 +218,16 @@ class Translator extends Preprocessor ? $this->platform->getDefaultCompiler() : CompilerFactory::detectCompilerName($this->platform); + // --full-static: the bundled libphp.a/libphpx.a are built by clang. + // gcc and clang compute TLS offsets differently (gcc's layout differs + // by 64 bytes here), which corrupts thread-local variables at runtime, + // so fully-static builds must use a real Linux clang (PHPX_CC/CXX take + // precedence; otherwise fall back to clang) to keep the toolchain consistent. + if ($this->climate->arguments->defined('full-static')) { + $this->fullStatic = true; + $this->cppCompiler = getenv('PHPX_CC') ?: (getenv('CXX') ?: 'clang'); + } + if ($this->platform instanceof Windows) { $libInfo = $this->platform->detectPhpLibs($this->getPhpDir()); $this->windowsPhpEmbedLib = $libInfo['embed'];