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-08-06 20:17:26 +08:00
use SPC\exception\PatchException ;
2023-03-29 21:39:36 +08:00
use SPC\exception\WrongUsageException ;
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-07-05 12:01:52 +07:00
if ( ! $this -> getOption ( 'no-strip' , false )) {
2025-07-05 13:52:47 +07:00
shell () -> cd ( SOURCE_PATH . '/php-src/sapi/cli' ) -> exec ( 'strip --strip-unneeded php' );
2025-07-05 12:01:52 +07:00
}
2024-02-19 15:29:43 +08:00
if ( $this -> getOption ( 'with-upx-pack' )) {
2024-02-19 12:17:03 +08:00
shell () -> cd ( SOURCE_PATH . '/php-src/sapi/cli' )
2024-04-07 15:52:24 +08:00
-> exec ( getenv ( 'UPX_EXEC' ) . ' --best php' );
2023-08-20 19:51:45 +08:00
}
2023-03-26 22:27:51 +08:00
2023-04-23 20:31:58 +08:00
$this -> deployBinary ( 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
if ( ! $this -> getOption ( 'no-strip' , false )) {
shell () -> cd ( SOURCE_PATH . '/php-src/sapi/cgi' ) -> exec ( 'strip --strip-unneeded php-cgi' );
}
if ( $this -> getOption ( 'with-upx-pack' )) {
shell () -> cd ( SOURCE_PATH . '/php-src/sapi/cgi' )
-> exec ( getenv ( 'UPX_EXEC' ) . ' --best php-cgi' );
}
$this -> deployBinary ( BUILD_TARGET_CGI );
}
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
}
2023-03-21 00:25:46 +08:00
if ( $this -> getExt ( 'phar' )) {
$this -> phar_patched = true ;
2024-06-03 23:16:15 +08:00
SourcePatcher :: patchMicroPhar ( $this -> getPHPVersionID ());
2023-03-21 00:25:46 +08:00
}
2024-04-07 15:52:24 +08:00
$enable_fake_cli = $this -> getOption ( 'with-micro-fake-cli' , false ) ? ' -DPHP_MICRO_FAKE_CLI' : '' ;
$vars = $this -> getMakeExtraVars ();
// patch fake cli for micro
$vars [ 'EXTRA_CFLAGS' ] .= $enable_fake_cli ;
$vars = SystemUtil :: makeEnvVarString ( $vars );
2025-10-08 11:48:40 +02:00
$concurrency = getenv ( 'SPC_CONCURRENCY' ) ? '-j' . getenv ( 'SPC_CONCURRENCY' ) : '' ;
2024-04-07 15:52:24 +08:00
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 } micro " );
2023-03-21 00:25:46 +08:00
2024-06-03 23:16:15 +08:00
$this -> processMicroUPX ();
2023-04-23 20:31:58 +08:00
$this -> deployBinary ( BUILD_TARGET_MICRO );
2023-09-23 17:00:42 +08:00
if ( $this -> phar_patched ) {
2024-06-03 23:16:15 +08:00
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-07-05 12:01:52 +07:00
if ( ! $this -> getOption ( 'no-strip' , false )) {
2025-07-05 13:52:47 +07:00
shell () -> cd ( SOURCE_PATH . '/php-src/sapi/fpm' ) -> exec ( 'strip --strip-unneeded php-fpm' );
2025-07-05 12:01:52 +07:00
}
2024-02-19 15:29:43 +08:00
if ( $this -> getOption ( 'with-upx-pack' )) {
2024-02-19 12:17:03 +08:00
shell () -> cd ( SOURCE_PATH . '/php-src/sapi/fpm' )
2024-04-07 15:52:24 +08:00
-> exec ( getenv ( 'UPX_EXEC' ) . ' --best php-fpm' );
2023-08-20 19:51:45 +08:00
}
2023-04-23 20:31:58 +08:00
$this -> deployBinary ( 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
{
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-18 11:08:55 +02:00
-> exec ( " make { $concurrency } INSTALL_ROOT= " . BUILD_ROOT_PATH . " { $vars } install-sapi install-build install-headers install-programs " );
2025-06-05 13:54:17 +07:00
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 ;
$libphpSo = " { $libDir } /libphp.so " ;
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-07-05 13:52:47 +07:00
2025-07-26 13:48:22 +07:00
if ( getenv ( 'SPC_CMD_VAR_PHP_EMBED_TYPE' ) === 'static' ) {
2025-07-27 00:59:32 +07:00
$AR = getenv ( 'AR' ) ? : 'ar' ;
2025-07-27 01:10:21 +07:00
f_passthru ( " { $AR } -t " . BUILD_LIB_PATH . " /libphp.a | grep ' \\ .a $ ' | xargs -n1 { $AR } d " . BUILD_LIB_PATH . '/libphp.a' );
2025-08-31 14:24:28 +08:00
// export dynamic symbols
SystemUtil :: exportDynamicSymbols ( BUILD_LIB_PATH . '/libphp.a' );
2025-07-26 13:48:22 +07:00
}
2025-06-27 22:48:15 +07:00
if ( ! $this -> getOption ( 'no-strip' , false ) && file_exists ( BUILD_LIB_PATH . '/' . $realLibName )) {
2025-07-05 13:52:47 +07:00
shell () -> cd ( BUILD_LIB_PATH ) -> exec ( " strip --strip-unneeded { $realLibName } " );
2025-06-27 22:01:37 +07:00
}
2025-03-24 23:50:12 +08:00
$this -> patchPhpScripts ();
}
2025-08-02 18:07:32 +08:00
/**
* Return extra variables for php make command .
*/
2024-04-07 15:52:24 +08:00
private function getMakeExtraVars () : array
2023-10-30 22:14:47 +01:00
{
2025-07-22 19:59:44 +08:00
$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' ));
2025-07-25 12:44:22 +08:00
$static = SPCTarget :: isStatic () ? '-all-static' : '' ;
$lib = BUILD_LIB_PATH ;
2025-06-24 23:07:17 +07:00
return [
2024-04-07 15:52:24 +08:00
'EXTRA_CFLAGS' => getenv ( 'SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS' ),
2025-07-25 09:59:24 +07:00
'EXTRA_LIBS' => $config [ 'libs' ],
2025-06-05 13:54:17 +07:00
'EXTRA_LDFLAGS' => getenv ( 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS' ),
2025-07-25 12:44:22 +08:00
'EXTRA_LDFLAGS_PROGRAM' => " -L { $lib } { $static } -pie " ,
2023-10-30 22:14:47 +01:00
];
}
2024-05-16 10:51:31 +08:00
/**
2025-07-22 12:29:41 +08:00
* Strip micro . sfx for Linux .
* 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 : (
2024-05-16 10:51:31 +08:00
*/
2024-06-03 23:16:15 +08:00
private function processMicroUPX () : void
{
if ( version_compare ( $this -> getMicroVersion (), '0.2.0' ) >= 0 && ! $this -> getOption ( 'no-strip' , false )) {
2025-07-05 13:52:47 +07:00
shell () -> exec ( 'strip --strip-unneeded ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx' );
2024-06-03 23:16:15 +08:00
if ( $this -> getOption ( 'with-upx-pack' )) {
// strip first
shell () -> exec ( getenv ( 'UPX_EXEC' ) . ' --best ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx' );
// cut binary with readelf
[ $ret , $out ] = shell () -> execWithResult ( 'readelf -l ' . SOURCE_PATH . '/php-src/sapi/micro/micro.sfx | 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' )) {
2025-08-06 20:43:23 +08:00
throw new PatchException ( 'phpmicro UPX patcher' , 'Cannot find offset in readelf output' );
2024-06-03 23:16:15 +08:00
}
$offset = hexdec ( $offset );
// remove upx extra wastes
file_put_contents ( SOURCE_PATH . '/php-src/sapi/micro/micro.sfx' , substr ( file_get_contents ( SOURCE_PATH . '/php-src/sapi/micro/micro.sfx' ), 0 , $offset ));
}
}
}
2023-03-21 00:25:46 +08:00
}