2023-03-21 00:25:46 +08:00
< ? php
declare ( strict_types = 1 );
namespace SPC\builder\linux ;
2024-01-10 21:08:25 +08:00
use SPC\builder\unix\UnixBuilderBase ;
2025-11-06 16:24:59 +08:00
use SPC\exception\PatchException ;
2023-03-29 21:39:36 +08:00
use SPC\exception\WrongUsageException ;
2025-10-19 10:41:14 +02:00
use SPC\store\Config ;
2025-11-09 17:13:41 +08:00
use SPC\store\DirDiff ;
2023-10-01 01:32:43 +08:00
use SPC\store\FileSystem ;
2023-04-30 12:42:19 +08:00
use SPC\store\SourcePatcher ;
2024-04-07 15:52:24 +08:00
use SPC\util\GlobalEnvManager ;
2025-07-22 19:59:44 +08:00
use SPC\util\SPCConfigUtil ;
2025-07-01 16:57:56 +07:00
use SPC\util\SPCTarget ;
2023-03-21 00:25:46 +08:00
2024-01-10 21:08:25 +08:00
class LinuxBuilder extends UnixBuilderBase
2023-03-21 00:25:46 +08:00
{
2023-08-20 19:51:45 +08:00
/** @var bool Micro patch phar flag */
2023-03-21 00:25:46 +08:00
private bool $phar_patched = false ;
2023-08-20 19:51:45 +08:00
public function __construct ( array $options = [])
2023-03-21 00:25:46 +08:00
{
2023-08-20 19:51:45 +08:00
$this -> options = $options ;
2025-06-22 20:44:11 +08:00
GlobalEnvManager :: init ();
2025-06-28 16:36:05 +08:00
GlobalEnvManager :: afterInit ();
2024-04-07 16:26:21 +08:00
2023-08-20 19:51:45 +08:00
// concurrency
2025-07-04 14:39:42 +07:00
$this -> concurrency = ( int ) getenv ( 'SPC_CONCURRENCY' );
2023-08-20 19:51:45 +08:00
// cflags
2024-04-07 15:52:24 +08:00
$this -> arch_c_flags = getenv ( 'SPC_DEFAULT_C_FLAGS' );
$this -> arch_cxx_flags = getenv ( 'SPC_DEFAULT_CXX_FLAGS' );
2025-07-28 19:43:01 +07:00
$this -> arch_ld_flags = getenv ( 'SPC_DEFAULT_LD_FLAGS' );
2023-10-23 00:37:28 +08:00
2023-08-20 19:51:45 +08:00
// create pkgconfig and include dir (some libs cannot create them automatically)
2023-03-21 00:25:46 +08:00
f_mkdir ( BUILD_LIB_PATH . '/pkgconfig' , recursive : true );
f_mkdir ( BUILD_INCLUDE_PATH , recursive : true );
}
/**
2024-05-16 10:51:31 +08:00
* Build PHP from source .
*
2025-08-06 20:17:26 +08:00
* @ param int $build_target Build target , use `BUILD_TARGET_*` constants
2023-03-21 00:25:46 +08:00
*/
2023-08-20 19:51:45 +08:00
public function buildPHP ( int $build_target = BUILD_TARGET_NONE ) : void
2023-03-21 00:25:46 +08:00
{
$cflags = $this -> arch_c_flags ;
2025-03-10 00:39:20 +08:00
f_putenv ( 'CFLAGS=' . $cflags );
2023-03-21 00:25:46 +08:00
2024-01-03 15:57:05 +08:00
$this -> emitPatchPoint ( 'before-php-buildconf' );
2023-07-28 23:45:39 +08:00
SourcePatcher :: patchBeforeBuildconf ( $this );
2023-03-21 00:25:46 +08:00
2024-04-07 15:52:24 +08:00
shell () -> cd ( SOURCE_PATH . '/php-src' ) -> exec ( getenv ( 'SPC_CMD_PREFIX_PHP_BUILDCONF' ));
2023-03-21 00:25:46 +08:00
2024-01-03 15:57:05 +08:00
$this -> emitPatchPoint ( 'before-php-configure' );
2023-07-28 23:45:39 +08:00
SourcePatcher :: patchBeforeConfigure ( $this );
2023-05-10 02:04:08 +08:00
2023-08-21 12:54:36 +02:00
$phpVersionID = $this -> getPHPVersionID ();
$json_74 = $phpVersionID < 80000 ? '--enable-json ' : '' ;
2023-08-21 18:37:00 +02:00
2025-08-02 01:29:20 +08:00
$opcache_jit = ! $this -> getOption ( 'disable-opcache-jit' , false );
if ( $opcache_jit && ( $phpVersionID >= 80500 || $this -> getExt ( 'opcache' ))) {
// php 8.5 contains opcache extension by default,
// if opcache_jit is enabled for 8.5 or opcache enabled,
// we need to disable undefined behavior sanitizer.
f_putenv ( 'SPC_COMPILER_EXTRA=-fno-sanitize=undefined' );
}
2023-08-21 18:37:00 +02:00
if ( $this -> getOption ( 'enable-zts' , false )) {
$maxExecutionTimers = $phpVersionID >= 80100 ? '--enable-zend-max-execution-timers ' : '' ;
$zts = '--enable-zts --disable-zend-signals ' ;
} else {
$maxExecutionTimers = '' ;
$zts = '' ;
}
2025-08-02 01:29:20 +08:00
2024-10-12 10:41:45 +02:00
$config_file_path = $this -> getOption ( 'with-config-file-path' , false ) ?
( '--with-config-file-path=' . $this -> getOption ( 'with-config-file-path' ) . ' ' ) : '' ;
2024-10-18 14:46:00 +02:00
$config_file_scan_dir = $this -> getOption ( 'with-config-file-scan-dir' , false ) ?
( '--with-config-file-scan-dir=' . $this -> getOption ( 'with-config-file-scan-dir' ) . ' ' ) : '' ;
2024-10-12 10:41:45 +02:00
2025-06-18 11:20:05 +07:00
$enableCli = ( $build_target & BUILD_TARGET_CLI ) === BUILD_TARGET_CLI ;
$enableFpm = ( $build_target & BUILD_TARGET_FPM ) === BUILD_TARGET_FPM ;
$enableMicro = ( $build_target & BUILD_TARGET_MICRO ) === BUILD_TARGET_MICRO ;
$enableEmbed = ( $build_target & BUILD_TARGET_EMBED ) === BUILD_TARGET_EMBED ;
$enableFrankenphp = ( $build_target & BUILD_TARGET_FRANKENPHP ) === BUILD_TARGET_FRANKENPHP ;
2025-09-04 14:05:00 +08:00
$enableCgi = ( $build_target & BUILD_TARGET_CGI ) === BUILD_TARGET_CGI ;
2023-08-21 09:30:46 +02:00
2024-04-07 15:52:24 +08:00
// prepare build php envs
2025-08-03 01:12:28 +08:00
// $musl_flag = SPCTarget::getLibc() === 'musl' ? ' -D__MUSL__' : ' -U__MUSL__';
2025-07-26 11:13:29 +07:00
$php_configure_env = SystemUtil :: makeEnvVarString ([
2024-04-07 15:52:24 +08:00
'CFLAGS' => getenv ( 'SPC_CMD_VAR_PHP_CONFIGURE_CFLAGS' ),
2025-08-03 02:00:19 +08:00
'CPPFLAGS' => '-I' . BUILD_INCLUDE_PATH , // . ' -Dsomethinghere', // . $musl_flag,
2025-07-25 12:44:22 +08:00
'LDFLAGS' => '-L' . BUILD_LIB_PATH ,
2025-07-26 22:23:00 +07:00
// 'LIBS' => SPCTarget::getRuntimeLibs(), // do not pass static libraries here yet, they may contain polyfills for libc functions!
2024-04-07 15:52:24 +08:00
]);
2025-10-12 16:42:38 +08:00
$phpvars = getenv ( 'SPC_EXTRA_PHP_VARS' ) ? : '' ;
2025-03-10 16:15:47 +08:00
$embed_type = getenv ( 'SPC_CMD_VAR_PHP_EMBED_TYPE' ) ? : 'static' ;
2025-07-01 16:57:56 +07:00
if ( $embed_type !== 'static' && SPCTarget :: isStatic ()) {
throw new WrongUsageException (
'Linux does not support loading shared libraries when linking libc statically. ' .
'Change SPC_CMD_VAR_PHP_EMBED_TYPE to static.'
);
}
2025-07-27 00:59:32 +07:00
2025-09-07 10:57:44 +08:00
$this -> seekPhpSrcLogFileOnException ( fn () => shell () -> cd ( SOURCE_PATH . '/php-src' ) -> exec (
$php_configure_env . ' ' .
2025-10-08 11:48:40 +02:00
getenv ( 'SPC_CMD_PREFIX_PHP_CONFIGURE' ) . ' ' .
( $enableCli ? '--enable-cli ' : '--disable-cli ' ) .
( $enableFpm ? '--enable-fpm ' . ( $this -> getLib ( 'libacl' ) !== null ? '--with-fpm-acl ' : '' ) : '--disable-fpm ' ) .
( $enableEmbed ? " --enable-embed= { $embed_type } " : '--disable-embed ' ) .
( $enableMicro ? '--enable-micro=all-static ' : '--disable-micro ' ) .
( $enableCgi ? '--enable-cgi ' : '--disable-cgi ' ) .
$config_file_path .
$config_file_scan_dir .
$json_74 .
$zts .
$maxExecutionTimers .
2025-10-12 11:34:11 +02:00
$phpvars . ' ' .
2025-10-08 11:48:40 +02:00
$this -> makeStaticExtensionArgs () . ' '
2025-09-07 10:57:44 +08:00
));
2023-03-21 00:25:46 +08:00
2024-01-03 15:57:05 +08:00
$this -> emitPatchPoint ( 'before-php-make' );
2023-07-28 23:45:39 +08:00
SourcePatcher :: patchBeforeMake ( $this );
2023-04-30 12:42:19 +08:00
2023-03-26 22:27:51 +08:00
$this -> cleanMake ();
2023-03-21 00:25:46 +08:00
2025-06-18 11:20:05 +07:00
if ( $enableCli ) {
2023-04-23 20:31:58 +08:00
logger () -> info ( 'building cli' );
2023-10-30 22:14:47 +01:00
$this -> buildCli ();
2023-04-23 20:31:58 +08:00
}
2025-06-18 11:20:05 +07:00
if ( $enableFpm ) {
2023-04-23 20:31:58 +08:00
logger () -> info ( 'building fpm' );
2023-10-30 22:14:47 +01:00
$this -> buildFpm ();
2023-04-23 20:31:58 +08:00
}
2025-09-04 14:05:00 +08:00
if ( $enableCgi ) {
logger () -> info ( 'building cgi' );
$this -> buildCgi ();
}
2025-06-18 11:20:05 +07:00
if ( $enableMicro ) {
2023-04-23 20:31:58 +08:00
logger () -> info ( 'building micro' );
2023-10-30 22:14:47 +01:00
$this -> buildMicro ();
2023-03-21 00:25:46 +08:00
}
2025-06-18 11:20:05 +07:00
if ( $enableEmbed ) {
2023-08-21 09:30:46 +02:00
logger () -> info ( 'building embed' );
2025-06-18 11:20:05 +07:00
if ( $enableMicro ) {
2023-10-01 01:32:43 +08:00
FileSystem :: replaceFileStr ( SOURCE_PATH . '/php-src/Makefile' , 'OVERALL_TARGET =' , 'OVERALL_TARGET = libphp.la' );
}
2023-10-30 22:14:47 +01:00
$this -> buildEmbed ();
2023-08-21 09:30:46 +02:00
}
2025-09-18 09:07:18 +02:00
if ( $enableFrankenphp ) {
logger () -> info ( 'building frankenphp' );
$this -> buildFrankenphp ();
}
2025-08-29 08:45:58 +07:00
$shared_extensions = array_map ( 'trim' , array_filter ( explode ( ',' , $this -> getOption ( 'build-shared' ))));
if ( ! empty ( $shared_extensions )) {
2025-10-12 22:26:06 +02:00
if ( SPCTarget :: isStatic ()) {
2025-10-12 22:32:27 +02:00
throw new WrongUsageException (
" You're building against musl libc statically (the default on Linux), but you're trying to build shared extensions. \n " .
'Static musl libc does not implement `dlopen`, so your php binary is not able to load shared extensions.' . " \n " .
'Either use SPC_LIBC=glibc to link against glibc on a glibc OS, or use SPC_TARGET="native-native-musl -dynamic" to link against musl libc dynamically using `zig cc`.'
);
2025-10-12 22:26:06 +02:00
}
2025-10-12 22:27:38 +02:00
logger () -> info ( 'Building shared extensions...' );
2025-08-29 08:45:58 +07:00
$this -> buildSharedExts ();
}
2025-05-21 18:35:48 +07:00
}
2023-03-21 00:25:46 +08:00
2025-05-21 18:35:48 +07:00
public function testPHP ( int $build_target = BUILD_TARGET_NONE )
{
2025-03-14 18:22:50 +08:00
$this -> emitPatchPoint ( 'before-sanity-check' );
$this -> sanityCheck ( $build_target );
2023-03-21 00:25:46 +08:00
}
/**
2023-08-20 19:51:45 +08:00
* Build cli sapi
2023-03-21 00:25:46 +08:00
*/
2024-01-10 11:10:40 +08:00
protected function buildCli () : void
2023-03-21 00:25:46 +08:00
{
2025-10-08 11:48:40 +02:00
if ( $this -> getExt ( 'readline' ) && SPCTarget :: isStatic ()) {
2025-09-07 16:10:50 +08:00
SourcePatcher :: patchFile ( 'musl_static_readline.patch' , SOURCE_PATH . '/php-src' );
}
2025-10-08 11:48:40 +02:00
2024-04-07 15:52:24 +08:00
$vars = SystemUtil :: makeEnvVarString ( $this -> getMakeExtraVars ());
2025-10-08 11:48:40 +02:00
$concurrency = getenv ( 'SPC_CONCURRENCY' ) ? '-j' . getenv ( 'SPC_CONCURRENCY' ) : '' ;
2023-03-26 22:27:51 +08:00
shell () -> cd ( SOURCE_PATH . '/php-src' )
-> exec ( 'sed -i "s|//lib|/lib|g" Makefile' )
2025-10-08 11:48:40 +02:00
-> exec ( " make { $concurrency } { $vars } cli " );
2023-08-20 19:51:45 +08:00
2025-10-08 11:48:40 +02:00
if ( $this -> getExt ( 'readline' ) && SPCTarget :: isStatic ()) {
2025-09-07 16:10:50 +08:00
SourcePatcher :: patchFile ( 'musl_static_readline.patch' , SOURCE_PATH . '/php-src' , true );
}
2025-11-06 16:24:59 +08:00
$this -> deploySAPIBinary ( BUILD_TARGET_CLI );
2023-03-21 00:25:46 +08:00
}
2025-09-04 14:05:00 +08:00
protected function buildCgi () : void
{
$vars = SystemUtil :: makeEnvVarString ( $this -> getMakeExtraVars ());
2025-10-08 11:48:40 +02:00
$concurrency = getenv ( 'SPC_CONCURRENCY' ) ? '-j' . getenv ( 'SPC_CONCURRENCY' ) : '' ;
2025-09-04 14:05:00 +08:00
shell () -> cd ( SOURCE_PATH . '/php-src' )
-> exec ( 'sed -i "s|//lib|/lib|g" Makefile' )
2025-10-08 11:48:40 +02:00
-> exec ( " make { $concurrency } { $vars } cgi " );
2025-09-04 14:05:00 +08:00
2025-11-06 16:24:59 +08:00
$this -> deploySAPIBinary ( BUILD_TARGET_CGI );
2025-09-04 14:05:00 +08:00
}
2023-03-21 00:25:46 +08:00
/**
2023-08-20 19:51:45 +08:00
* Build phpmicro sapi
2023-03-21 00:25:46 +08:00
*/
2024-01-10 11:10:40 +08:00
protected function buildMicro () : void
2023-03-21 00:25:46 +08:00
{
2023-04-03 20:47:24 +08:00
if ( $this -> getPHPVersionID () < 80000 ) {
2023-10-23 00:37:28 +08:00
throw new WrongUsageException ( 'phpmicro only support PHP >= 8.0!' );
2023-04-03 20:47:24 +08:00
}
2025-10-31 16:48:21 +08:00
try {
if ( $this -> getExt ( 'phar' )) {
$this -> phar_patched = true ;
SourcePatcher :: patchMicroPhar ( $this -> getPHPVersionID ());
}
2024-04-07 15:52:24 +08:00
2025-10-31 16:48:21 +08:00
$enable_fake_cli = $this -> getOption ( 'with-micro-fake-cli' , false ) ? ' -DPHP_MICRO_FAKE_CLI' : '' ;
$vars = $this -> getMakeExtraVars ();
2023-03-21 00:25:46 +08:00
2025-10-31 16:48:21 +08:00
// patch fake cli for micro
$vars [ 'EXTRA_CFLAGS' ] .= $enable_fake_cli ;
$vars = SystemUtil :: makeEnvVarString ( $vars );
$concurrency = getenv ( 'SPC_CONCURRENCY' ) ? '-j' . getenv ( 'SPC_CONCURRENCY' ) : '' ;
2024-06-03 23:16:15 +08:00
2025-10-31 16:48:21 +08:00
shell () -> cd ( SOURCE_PATH . '/php-src' )
-> exec ( 'sed -i "s|//lib|/lib|g" Makefile' )
-> exec ( " make { $concurrency } { $vars } micro " );
2023-09-23 17:00:42 +08:00
2025-11-06 16:24:59 +08:00
// deploy micro.sfx
$dst = $this -> deploySAPIBinary ( BUILD_TARGET_MICRO );
// patch after UPX-ed micro.sfx
$this -> processUpxedMicroSfx ( $dst );
2025-10-31 16:48:21 +08:00
} finally {
if ( $this -> phar_patched ) {
SourcePatcher :: unpatchMicroPhar ();
}
2023-09-23 17:00:42 +08:00
}
2023-04-23 20:31:58 +08:00
}
/**
2023-08-20 19:51:45 +08:00
* Build fpm sapi
2023-04-23 20:31:58 +08:00
*/
2024-01-10 11:10:40 +08:00
protected function buildFpm () : void
2023-04-23 20:31:58 +08:00
{
2025-03-07 10:00:10 +01:00
$vars = SystemUtil :: makeEnvVarString ( $this -> getMakeExtraVars ());
2025-10-08 11:48:40 +02:00
$concurrency = getenv ( 'SPC_CONCURRENCY' ) ? '-j' . getenv ( 'SPC_CONCURRENCY' ) : '' ;
2023-04-23 20:31:58 +08:00
shell () -> cd ( SOURCE_PATH . '/php-src' )
-> exec ( 'sed -i "s|//lib|/lib|g" Makefile' )
2025-10-08 11:48:40 +02:00
-> exec ( " make { $concurrency } { $vars } fpm " );
2023-08-20 19:51:45 +08:00
2025-11-06 16:24:59 +08:00
$this -> deploySAPIBinary ( BUILD_TARGET_FPM );
2023-03-21 00:25:46 +08:00
}
2023-08-21 09:30:46 +02:00
2023-10-23 00:37:28 +08:00
/**
* Build embed sapi
*/
2024-01-10 11:10:40 +08:00
protected function buildEmbed () : void
2023-08-21 09:30:46 +02:00
{
2025-10-19 10:41:14 +02:00
$sharedExts = array_filter ( $this -> exts , static fn ( $ext ) => $ext -> isBuildShared ());
$sharedExts = array_filter ( $sharedExts , static function ( $ext ) {
return Config :: getExt ( $ext -> getName (), 'build-with-php' ) === true ;
});
$install_modules = $sharedExts ? 'install-modules' : '' ;
2025-11-09 17:13:41 +08:00
// detect changes in module path
$diff = new DirDiff ( BUILD_MODULES_PATH , true );
2024-04-07 15:52:24 +08:00
$vars = SystemUtil :: makeEnvVarString ( $this -> getMakeExtraVars ());
2025-10-08 11:48:40 +02:00
$concurrency = getenv ( 'SPC_CONCURRENCY' ) ? '-j' . getenv ( 'SPC_CONCURRENCY' ) : '' ;
2024-04-07 15:52:24 +08:00
shell () -> cd ( SOURCE_PATH . '/php-src' )
2023-08-21 09:30:46 +02:00
-> exec ( 'sed -i "s|//lib|/lib|g" Makefile' )
2025-05-21 13:19:51 +07:00
-> exec ( 'sed -i "s|^EXTENSION_DIR = .*|EXTENSION_DIR = /' . basename ( BUILD_MODULES_PATH ) . '|" Makefile' )
2025-10-19 10:41:14 +02:00
-> exec ( " make { $concurrency } INSTALL_ROOT= " . BUILD_ROOT_PATH . " { $vars } install-sapi { $install_modules } install-build install-headers install-programs " );
2025-06-05 13:54:17 +07:00
2025-11-06 16:24:59 +08:00
// process libphp.so for shared embed
$libphpSo = BUILD_LIB_PATH . '/libphp.so' ;
if ( file_exists ( $libphpSo )) {
// deploy libphp.so
$this -> deployBinary ( $libphpSo , $libphpSo , false );
// post actions: rename libphp.so to libphp-<release>.so if -release is set in LDFLAGS
$this -> processLibphpSoFile ( $libphpSo );
}
2025-11-09 17:13:41 +08:00
// process shared extensions build-with-php
$increment_files = $diff -> getChangedFiles ();
foreach ( $increment_files as $increment_file ) {
$this -> deployBinary ( $increment_file , $increment_file , false );
}
2025-11-06 16:24:59 +08:00
// process libphp.a for static embed
if ( getenv ( 'SPC_CMD_VAR_PHP_EMBED_TYPE' ) === 'static' ) {
$AR = getenv ( 'AR' ) ? : 'ar' ;
f_passthru ( " { $AR } -t " . BUILD_LIB_PATH . " /libphp.a | grep ' \\ .a $ ' | xargs -n1 { $AR } d " . BUILD_LIB_PATH . '/libphp.a' );
// export dynamic symbols
SystemUtil :: exportDynamicSymbols ( BUILD_LIB_PATH . '/libphp.a' );
}
// patch embed php scripts
$this -> patchPhpScripts ();
}
/**
* Return extra variables for php make command .
*/
private function getMakeExtraVars () : array
{
$config = ( new SPCConfigUtil ( $this , [ 'libs_only_deps' => true , 'absolute_libs' => true ])) -> config ( $this -> ext_list , $this -> lib_list , $this -> getOption ( 'with-suggested-exts' ), $this -> getOption ( 'with-suggested-libs' ));
$static = SPCTarget :: isStatic () ? '-all-static' : '' ;
$lib = BUILD_LIB_PATH ;
return array_filter ([
'EXTRA_CFLAGS' => getenv ( 'SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS' ),
'EXTRA_LIBS' => $config [ 'libs' ],
'EXTRA_LDFLAGS' => getenv ( 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS' ),
'EXTRA_LDFLAGS_PROGRAM' => " -L { $lib } { $static } -pie " ,
]);
}
private function processLibphpSoFile ( string $libphpSo ) : void
{
2025-07-29 11:08:53 +08:00
$ldflags = getenv ( 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS' ) ? : '' ;
2025-07-05 13:52:47 +07:00
$libDir = BUILD_LIB_PATH ;
$modulesDir = BUILD_MODULES_PATH ;
2025-06-27 22:48:15 +07:00
$realLibName = 'libphp.so' ;
2025-07-22 12:25:43 +08:00
$cwd = getcwd ();
2025-07-05 13:52:47 +07:00
2025-06-05 13:54:17 +07:00
if ( preg_match ( '/-release\s+(\S+)/' , $ldflags , $matches )) {
$release = $matches [ 1 ];
2025-07-05 13:52:47 +07:00
$realLibName = " libphp- { $release } .so " ;
$libphpRelease = " { $libDir } / { $realLibName } " ;
if ( ! file_exists ( $libphpRelease ) && file_exists ( $libphpSo )) {
rename ( $libphpSo , $libphpRelease );
2025-06-24 12:10:01 +07:00
}
if ( file_exists ( $libphpRelease )) {
2025-07-05 13:52:47 +07:00
chdir ( $libDir );
if ( file_exists ( $libphpSo )) {
unlink ( $libphpSo );
2025-06-25 14:32:00 +07:00
}
2025-06-23 15:26:39 +07:00
symlink ( $realLibName , 'libphp.so' );
2025-07-05 13:52:47 +07:00
shell () -> exec ( sprintf (
'patchelf --set-soname %s %s' ,
escapeshellarg ( $realLibName ),
escapeshellarg ( $libphpRelease )
));
2025-06-23 15:26:39 +07:00
}
2025-07-05 13:52:47 +07:00
if ( is_dir ( $modulesDir )) {
chdir ( $modulesDir );
2025-06-23 15:26:39 +07:00
foreach ( $this -> getExts () as $ext ) {
if ( ! $ext -> isBuildShared ()) {
continue ;
}
$name = $ext -> getName ();
$versioned = " { $name } - { $release } .so " ;
$unversioned = " { $name } .so " ;
2025-07-05 13:52:47 +07:00
$src = " { $modulesDir } / { $versioned } " ;
$dst = " { $modulesDir } / { $unversioned } " ;
if ( is_file ( $src )) {
rename ( $src , $dst );
shell () -> exec ( sprintf (
'patchelf --set-soname %s %s' ,
escapeshellarg ( $unversioned ),
escapeshellarg ( $dst )
));
2025-06-23 15:26:39 +07:00
}
2025-06-12 20:19:21 +07:00
}
}
2025-07-22 12:25:43 +08:00
chdir ( $cwd );
2025-07-05 13:52:47 +07:00
}
$target = " { $libDir } / { $realLibName } " ;
if ( file_exists ( $target )) {
2025-07-05 13:53:12 +07:00
[, $output ] = shell () -> execWithResult ( 'readelf -d ' . escapeshellarg ( $target ));
2025-09-18 09:07:18 +02:00
$output = implode ( " \n " , $output );
2025-07-22 12:29:41 +08:00
if ( preg_match ( '/SONAME.*\[(.+)]/' , $output , $sonameMatch )) {
2025-07-05 13:52:47 +07:00
$currentSoname = $sonameMatch [ 1 ];
if ( $currentSoname !== basename ( $target )) {
shell () -> exec ( sprintf (
'patchelf --set-soname %s %s' ,
escapeshellarg ( basename ( $target )),
escapeshellarg ( $target )
));
}
}
2025-06-05 13:54:17 +07:00
}
2025-03-24 23:50:12 +08:00
}
2025-08-02 18:07:32 +08:00
/**
2025-11-06 16:24:59 +08:00
* Patch micro . sfx after UPX compression .
* micro needs special section handling in LinuxBuilder .
* The micro . sfx does not support UPX directly , but we can remove UPX
* info segment to adapt .
* This will also make micro . sfx with upx - packed more like a malware fore antivirus
2025-08-02 18:07:32 +08:00
*/
2025-11-06 16:24:59 +08:00
private function processUpxedMicroSfx ( string $dst ) : void
2023-10-30 22:14:47 +01:00
{
2025-11-06 16:24:59 +08:00
if ( $this -> getOption ( 'with-upx-pack' ) && version_compare ( $this -> getMicroVersion (), '0.2.0' ) >= 0 ) {
// strip first
// cut binary with readelf
[ $ret , $out ] = shell () -> execWithResult ( " readelf -l { $dst } | awk '/LOAD|GNU_STACK/ { getline; print \$ 1, \$ 2, \$ 3, \$ 4, \$ 6, \$ 7}' " );
$out [ 1 ] = explode ( ' ' , $out [ 1 ]);
$offset = $out [ 1 ][ 0 ];
if ( $ret !== 0 || ! str_starts_with ( $offset , '0x' )) {
throw new PatchException ( 'phpmicro UPX patcher' , 'Cannot find offset in readelf output' );
}
$offset = hexdec ( $offset );
// remove upx extra wastes
file_put_contents ( $dst , substr ( file_get_contents ( $dst ), 0 , $offset ));
}
2023-10-30 22:14:47 +01:00
}
2023-03-21 00:25:46 +08:00
}