diff --git a/src/SPC/builder/Extension.php b/src/SPC/builder/Extension.php index 6b56f4e4..12175cee 100644 --- a/src/SPC/builder/Extension.php +++ b/src/SPC/builder/Extension.php @@ -539,11 +539,15 @@ class Extension [$staticLibs, $sharedLibs] = $this->splitLibsIntoStaticAndShared($config['libs']); $preStatic = PHP_OS_FAMILY === 'Darwin' ? '' : '-Wl,--start-group '; $postStatic = PHP_OS_FAMILY === 'Darwin' ? '' : ' -Wl,--end-group '; + $extraLd = trim((string) getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS')); + if (PHP_OS_FAMILY !== 'Darwin') { + $extraLd = trim($extraLd . ' -Wl,-Bsymbolic'); + } return [ 'CFLAGS' => $config['cflags'], 'CXXFLAGS' => $config['cflags'], 'LDFLAGS' => $config['ldflags'], - 'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'), + 'EXTRA_LDFLAGS' => $extraLd, 'LIBS' => clean_spaces("{$preStatic} {$staticLibs} {$postStatic} {$sharedLibs}"), 'LD_LIBRARY_PATH' => BUILD_LIB_PATH, ]; @@ -588,7 +592,7 @@ class Extension * of static library flags, and the second is a space-separated string * of shared library flags */ - protected function splitLibsIntoStaticAndShared(string $allLibs): array + protected function splitLibsIntoStaticAndShared(string $allLibs, array $excludeFromStatic = []): array { $staticLibString = ''; $sharedLibString = ''; @@ -598,6 +602,16 @@ class Extension if (str_starts_with($lib, BUILD_LIB_PATH . '/lib') && str_ends_with($lib, '.a')) { $staticLib = $lib; } + // Libs in $excludeFromStatic are statically linked into php-cli already and re-export their + // symbols; including them as static archives in a shared extension creates a second in-process + // copy of the same library (e.g. libssl/libcrypto), causing duplicated atexit handlers and + // shared-state corruption (NULL engine_lock at exit). Drop them here so the shared extension's + // undefined refs resolve at runtime against php-cli's exported symbols instead. + $libName = str_starts_with($lib, '-l') ? substr($lib, 2) : basename($lib, '.a'); + $libName = str_starts_with($libName, 'lib') ? substr($libName, 3) : $libName; + if (in_array($libName, $excludeFromStatic, true)) { + continue; + } if ($lib === '-lphp' || !file_exists($staticLib)) { $sharedLibString .= " {$lib}"; } else { diff --git a/src/SPC/builder/extension/opcache.php b/src/SPC/builder/extension/opcache.php index cc1dfcc1..ec7e70db 100644 --- a/src/SPC/builder/extension/opcache.php +++ b/src/SPC/builder/extension/opcache.php @@ -58,7 +58,10 @@ class opcache extends Extension ) { $opcache_jit = ' --disable-opcache-jit'; } - return '--enable-opcache' . ($shared ? '=shared' : '') . $opcache_jit; + if ($phpVersionID < 80500) { + return '--enable-opcache' . ($shared ? '=shared' : '') . $opcache_jit; + } + return trim($opcache_jit); } public function getDistName(): string diff --git a/src/SPC/builder/unix/library/liblz4.php b/src/SPC/builder/unix/library/liblz4.php index 2dc2b46f..6815fce6 100644 --- a/src/SPC/builder/unix/library/liblz4.php +++ b/src/SPC/builder/unix/library/liblz4.php @@ -12,6 +12,13 @@ trait liblz4 { // disable executables FileSystem::replaceFileStr($this->source_dir . '/programs/Makefile', 'install: lz4', "install: lz4\n\ninstallewfwef: lz4"); + // zig-cc / clang -flto -c with multiple input files only produces an .o for the first source, + // leaving liblz4.a with just lz4.o. Compile sources individually so all .o files exist. + FileSystem::replaceFileStr( + $this->source_dir . '/lib/Makefile', + "liblz4.a: \$(SRCFILES)\nifeq (\$(BUILD_STATIC),yes) # can be disabled on command line\n\t@echo compiling static library\n\t\$(COMPILE.c) \$^\n\t\$(AR) rcs \$@ *.o\nendif", + "liblz4.a: \$(SRCFILES:.c=.o)\nifeq (\$(BUILD_STATIC),yes) # can be disabled on command line\n\t@echo compiling static library\n\t\$(AR) rcs \$@ \$^\nendif" + ); return true; } @@ -28,7 +35,7 @@ trait liblz4 $this->patchPkgconfPrefix(['liblz4.pc']); - foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) { + foreach (FileSystem::scanDirFiles(BUILD_LIB_PATH . '/', false, true) as $filename) { if (str_starts_with($filename, 'liblz4') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) { unlink(BUILD_ROOT_PATH . '/lib/' . $filename); }