diff --git a/src/StaticPHP/Package/PhpExtensionPackage.php b/src/StaticPHP/Package/PhpExtensionPackage.php index 8fb63ece..c638114d 100644 --- a/src/StaticPHP/Package/PhpExtensionPackage.php +++ b/src/StaticPHP/Package/PhpExtensionPackage.php @@ -286,7 +286,7 @@ class PhpExtensionPackage extends Package } return [ 'CFLAGS' => $config['cflags'], - 'CXXFLAGS' => $config['cflags'], + 'CXXFLAGS' => $config['cxxflags'], 'LDFLAGS' => $ldflags, 'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"), 'LD_LIBRARY_PATH' => BUILD_LIB_PATH, diff --git a/src/StaticPHP/Util/SPCConfigUtil.php b/src/StaticPHP/Util/SPCConfigUtil.php index fd2460ee..ef69f023 100644 --- a/src/StaticPHP/Util/SPCConfigUtil.php +++ b/src/StaticPHP/Util/SPCConfigUtil.php @@ -37,83 +37,12 @@ class SPCConfigUtil public function config(array $packages = [], bool $include_suggests = false): array { // if have php, make php as all extension's dependency - if (!$this->no_php) { - $dep_override = ['php' => array_filter($packages, fn ($y) => str_starts_with($y, 'ext-'))]; - } else { - $dep_override = []; - } - $resolved = DependencyResolver::resolve($packages, $dep_override, $include_suggests); - - $ldflags = $this->getLdflagsString(); - $cflags = $this->getIncludesString($resolved); - $libs = $this->getLibsString($resolved, !$this->absolute_libs); - - // additional OS-specific libraries (e.g. macOS -lresolv) - // embed - if ($extra_libs = SystemTarget::getRuntimeLibs()) { - $libs .= " {$extra_libs}"; - } - - $extra_env = getenv('SPC_EXTRA_LIBS'); - if (is_string($extra_env) && !empty($extra_env)) { - $libs .= " {$extra_env}"; - } - // package frameworks - if (SystemTarget::getTargetOS() === 'Darwin') { - $libs .= " {$this->getFrameworksString($resolved)}"; - } - // C++ - if ($this->hasCpp($resolved)) { - $target_os = SystemTarget::getTargetOS(); - if ($target_os === 'Darwin') { - $libcpp = '-lc++'; - $libs = str_replace($libcpp, '', $libs) . " {$libcpp}"; - } elseif ($target_os !== 'Windows') { - // Linux and other Unix-like systems use libstdc++ - $libcpp = '-lstdc++'; - $libs = str_replace($libcpp, '', $libs) . " {$libcpp}"; - } - // Windows (MSVC): C++ runtime is linked automatically, no explicit lib needed - } - - if ($this->libs_only_deps) { - // mimalloc must come first - if (in_array('mimalloc', $resolved) && file_exists(BUILD_LIB_PATH . '/libmimalloc.a')) { - $libs = BUILD_LIB_PATH . '/libmimalloc.a ' . str_replace([BUILD_LIB_PATH . '/libmimalloc.a', '-lmimalloc'], ['', ''], $libs); - } - return [ - 'cflags' => clean_spaces(getenv('CFLAGS') . ' ' . $cflags), - 'ldflags' => clean_spaces(getenv('LDFLAGS') . ' ' . $ldflags), - 'libs' => clean_spaces(getenv('LIBS') . ' ' . $libs), - ]; - } - - // embed - if (!$this->no_php) { - if (SystemTarget::getTargetOS() === 'Windows') { - // Windows: use php8embed.lib directly (either full path or short name) - $major = intdiv(PHP_VERSION_ID, 10000); - $php_lib = $this->absolute_libs ? BUILD_LIB_PATH . "\\php{$major}embed.lib" : "php{$major}embed.lib"; - // Windows system libs required by PHP - // Use same system libs as PHP Makefile: LIBS=kernel32.lib ole32.lib user32.lib advapi32.lib shell32.lib ws2_32.lib Dnsapi.lib psapi.lib bcrypt.lib - $libs = "{$php_lib} {$libs} kernel32.lib ole32.lib user32.lib advapi32.lib shell32.lib ws2_32.lib dnsapi.lib psapi.lib bcrypt.lib"; - } else { - $libs = "-lphp {$libs} -lc"; - } - } - - $allLibs = getenv('LIBS') . ' ' . $libs; - - // mimalloc must come first - if (in_array('mimalloc', $resolved) && file_exists(BUILD_LIB_PATH . '/libmimalloc.a')) { - $allLibs = BUILD_LIB_PATH . '/libmimalloc.a ' . str_replace([BUILD_LIB_PATH . '/libmimalloc.a', '-lmimalloc'], ['', ''], $allLibs); - } - - return [ - 'cflags' => clean_spaces(getenv('CFLAGS') . ' ' . $cflags), - 'ldflags' => clean_spaces(getenv('LDFLAGS') . ' ' . $ldflags), - 'libs' => clean_spaces($allLibs), - ]; + $dep_override = $this->no_php + ? [] + : ['php' => array_filter($packages, fn ($y) => str_starts_with($y, 'ext-'))]; + return $this->configWithResolvedPackages( + DependencyResolver::resolve($packages, $dep_override, $include_suggests) + ); } /** @@ -127,6 +56,7 @@ class SPCConfigUtil * @param array|PhpExtensionPackage $extension_packages Extension instance or list * @return array{ * cflags: string, + * cxxflags: string, * ldflags: string, * libs: string * } @@ -150,6 +80,7 @@ class SPCConfigUtil * @param array|LibraryPackage $lib Library instance or list * @return array{ * cflags: string, + * cxxflags: string, * ldflags: string, * libs: string * } @@ -180,6 +111,7 @@ class SPCConfigUtil * @param string[] $resolved_packages The full resolved package list * @return array{ * cflags: string, + * cxxflags: string, * ldflags: string, * libs: string * } @@ -192,6 +124,7 @@ class SPCConfigUtil if (empty($sub_deps)) { return [ 'cflags' => '', + 'cxxflags' => '', 'ldflags' => '', 'libs' => '', ]; @@ -212,11 +145,12 @@ class SPCConfigUtil } /** - * Get configuration using already-resolved packages (skip dependency resolution). + * Build cflags/cxxflags/ldflags/libs for an already-resolved package set (skip dependency resolution). * - * @param string[] $resolved_packages Already resolved package names in build order + * @param string[] $resolved_packages Resolved package names in build order * @return array{ * cflags: string, + * cxxflags: string, * ldflags: string, * libs: string * } @@ -224,9 +158,14 @@ class SPCConfigUtil public function configWithResolvedPackages(array $resolved_packages): array { $ldflags = $this->getLdflagsString(); - $cflags = $this->getIncludesString($resolved_packages); + $includes = $this->getIncludesString($resolved_packages); $libs = $this->getLibsString($resolved_packages, !$this->absolute_libs); + // includes (-I…) are language-agnostic — same source for cflags/cxxflags, swap only the env names + $cflags = deduplicate_flags(clean_spaces((getenv('SPC_DEFAULT_CFLAGS') ?: '') . ' ' . getenv('CFLAGS') . ' ' . $includes)); + $cxxflags = deduplicate_flags(clean_spaces((getenv('SPC_DEFAULT_CXXFLAGS') ?: '') . ' ' . getenv('CXXFLAGS') . ' ' . $includes)); + $ldflags = deduplicate_flags(clean_spaces((getenv('SPC_DEFAULT_LDFLAGS') ?: '') . ' ' . getenv('LDFLAGS') . ' ' . $ldflags)); + // additional OS-specific libraries (e.g. macOS -lresolv) if ($extra_libs = SystemTarget::getRuntimeLibs()) { $libs .= " {$extra_libs}"; @@ -262,15 +201,25 @@ class SPCConfigUtil $libs = BUILD_LIB_PATH . '/libmimalloc.a ' . str_replace([BUILD_LIB_PATH . '/libmimalloc.a', '-lmimalloc'], ['', ''], $libs); } return [ - 'cflags' => clean_spaces(getenv('CFLAGS') . ' ' . $cflags), - 'ldflags' => clean_spaces(getenv('LDFLAGS') . ' ' . $ldflags), + 'cflags' => $cflags, + 'cxxflags' => $cxxflags, + 'ldflags' => $ldflags, 'libs' => clean_spaces(getenv('LIBS') . ' ' . $libs), ]; } // embed if (!$this->no_php) { - $libs = "-lphp {$libs} -lc"; + if (SystemTarget::getTargetOS() === 'Windows') { + // Windows: use php8embed.lib directly (either full path or short name) + $major = intdiv(PHP_VERSION_ID, 10000); + $php_lib = $this->absolute_libs ? BUILD_LIB_PATH . "\\php{$major}embed.lib" : "php{$major}embed.lib"; + // Windows system libs required by PHP + // Use same system libs as PHP Makefile: LIBS=kernel32.lib ole32.lib user32.lib advapi32.lib shell32.lib ws2_32.lib Dnsapi.lib psapi.lib bcrypt.lib + $libs = "{$php_lib} {$libs} kernel32.lib ole32.lib user32.lib advapi32.lib shell32.lib ws2_32.lib dnsapi.lib psapi.lib bcrypt.lib"; + } else { + $libs = "-lphp {$libs} -lc"; + } } $allLibs = getenv('LIBS') . ' ' . $libs; @@ -281,8 +230,9 @@ class SPCConfigUtil } return [ - 'cflags' => clean_spaces(getenv('CFLAGS') . ' ' . $cflags), - 'ldflags' => clean_spaces(getenv('LDFLAGS') . ' ' . $ldflags), + 'cflags' => $cflags, + 'cxxflags' => $cxxflags, + 'ldflags' => $ldflags, 'libs' => clean_spaces($allLibs), ]; }