Merge branch 'main' into feat/intl-win

This commit is contained in:
Marc
2025-06-25 10:28:45 +07:00
committed by GitHub
164 changed files with 3374 additions and 1744 deletions

View File

@@ -33,7 +33,7 @@ use Symfony\Component\Console\Application;
*/
final class ConsoleApplication extends Application
{
public const VERSION = '2.5.2';
public const VERSION = '2.6.1';
public function __construct()
{

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace SPC\builder;
use PharIo\FileSystem\File;
use SPC\exception\ExceptionHandler;
use SPC\exception\FileSystemException;
use SPC\exception\InterruptException;
@@ -11,6 +12,7 @@ use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\store\LockFile;
use SPC\store\SourceManager;
use SPC\util\CustomExt;
@@ -127,7 +129,7 @@ abstract class BuilderBase
if ($including_shared) {
return $this->exts;
}
return array_filter($this->exts, fn ($ext) => !$ext->isBuildShared());
return array_filter($this->exts, fn ($ext) => $ext->isBuildStatic());
}
/**
@@ -233,15 +235,41 @@ abstract class BuilderBase
*/
abstract public function buildPHP(int $build_target = BUILD_TARGET_NONE);
/**
* Test PHP
*/
abstract public function testPHP(int $build_target = BUILD_TARGET_NONE);
/**
* @throws WrongUsageException
* @throws RuntimeException
* @throws FileSystemException
*/
public function buildSharedExts(): void
{
foreach ($this->getExts() as $ext) {
if (!$ext->isBuildShared()) {
continue;
$lines = file(BUILD_BIN_PATH . '/php-config');
$extension_dir_line = null;
foreach ($lines as $key => $value) {
if (str_starts_with($value, 'extension_dir=')) {
$lines[$key] = 'extension_dir="' . BUILD_MODULES_PATH . '"' . PHP_EOL;
$extension_dir_line = $value;
break;
}
logger()->info('Building extension [' . $ext->getName() . '] as shared extension (' . $ext->getName() . '.so)');
$ext->buildShared();
}
file_put_contents(BUILD_BIN_PATH . '/php-config', implode('', $lines));
FileSystem::createDir(BUILD_MODULES_PATH);
try {
foreach ($this->getExts() as $ext) {
if (!$ext->isBuildShared()) {
continue;
}
$ext->buildShared();
}
} catch (RuntimeException $e) {
FileSystem::replaceFileLineContainsString(BUILD_BIN_PATH . '/php-config', 'extension_dir=', $extension_dir_line);
throw $e;
}
FileSystem::replaceFileLineContainsString(BUILD_BIN_PATH . '/php-config', 'extension_dir=', $extension_dir_line);
}
/**
@@ -254,9 +282,21 @@ abstract class BuilderBase
public function makeStaticExtensionArgs(): string
{
$ret = [];
foreach ($this->getExts(false) as $ext) {
logger()->info($ext->getName() . ' is using ' . $ext->getConfigureArg());
$ret[] = trim($ext->getConfigureArg());
foreach ($this->getExts() as $ext) {
$arg = $ext->getConfigureArg();
if ($ext->isBuildShared() && !$ext->isBuildStatic()) {
if (
(Config::getExt($ext->getName(), 'type') === 'builtin' &&
!file_exists(SOURCE_PATH . '/php-src/ext/' . $ext->getName() . '/config.m4')) ||
Config::getExt($ext->getName(), 'build-with-php') === true
) {
$arg = $ext->getConfigureArg(true);
} else {
continue;
}
}
logger()->info($ext->getName() . ' is using ' . $arg);
$ret[] = trim($arg);
}
logger()->debug('Using configure: ' . implode(' ', $ret));
return implode(' ', $ret);
@@ -311,15 +351,11 @@ abstract class BuilderBase
public function getPHPVersionFromArchive(?string $file = null): false|string
{
if ($file === null) {
$lock = file_exists(DOWNLOAD_PATH . '/.lock.json') ? file_get_contents(DOWNLOAD_PATH . '/.lock.json') : false;
if ($lock === false) {
return false;
}
$lock = json_decode($lock, true);
$file = $lock['php-src']['filename'] ?? null;
if ($file === null) {
$lock = LockFile::get('php-src');
if ($lock === null) {
return false;
}
$file = LockFile::getLockFullPath($lock);
}
if (preg_match('/php-(\d+\.\d+\.\d+(?:RC\d+)?)\.tar\.(?:gz|bz2|xz)/', $file, $match)) {
return $match[1];
@@ -365,6 +401,9 @@ abstract class BuilderBase
if (($type & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED) {
$ls[] = 'embed';
}
if (($type & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP) {
$ls[] = 'frankenphp';
}
return implode(', ', $ls);
}
@@ -471,6 +510,29 @@ abstract class BuilderBase
}
}
public function checkBeforeBuildPHP(int $rule): void
{
if (($rule & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP) {
if (!$this->getOption('enable-zts')) {
throw new WrongUsageException('FrankenPHP SAPI requires ZTS enabled PHP, build with `--enable-zts`!');
}
// frankenphp doesn't support windows, BSD is currently not supported by static-php-cli
if (!in_array(PHP_OS_FAMILY, ['Linux', 'Darwin'])) {
throw new WrongUsageException('FrankenPHP SAPI is only available on Linux and macOS!');
}
// frankenphp needs package go-xcaddy installed
$pkg_dir = PKG_ROOT_PATH . '/go-xcaddy-' . arch2gnu(php_uname('m')) . '-' . osfamily2shortname();
if (!file_exists("{$pkg_dir}/bin/go") || !file_exists("{$pkg_dir}/bin/xcaddy")) {
global $argv;
throw new WrongUsageException("FrankenPHP SAPI requires the go-xcaddy package, please install it first: {$argv[0]} install-pkg go-xcaddy");
}
// frankenphp needs libxml2 lib on macos, see: https://github.com/php/frankenphp/blob/main/frankenphp.go#L17
if (PHP_OS_FAMILY === 'Darwin' && !$this->getLib('libxml2')) {
throw new WrongUsageException('FrankenPHP SAPI for macOS requires libxml2 library, please include the `xml` extension in your build.');
}
}
}
/**
* Generate micro extension test php code.
*/

View File

@@ -53,26 +53,26 @@ class Extension
}
}
public function getFrameworks(): array
{
return Config::getExt($this->getName(), 'frameworks', []);
}
/**
* 获取开启该扩展的 PHP 编译添加的参数
*
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getConfigureArg(): string
public function getConfigureArg(bool $shared = false): string
{
$arg = $this->getEnableArg();
switch (PHP_OS_FAMILY) {
case 'Windows':
$arg .= $this->getWindowsConfigureArg();
break;
case 'Darwin':
case 'Linux':
case 'BSD':
$arg .= $this->getUnixConfigureArg();
break;
}
return $arg;
return match (PHP_OS_FAMILY) {
'Windows' => $this->getWindowsConfigureArg($shared),
'Darwin',
'Linux',
'BSD' => $this->getUnixConfigureArg($shared),
default => throw new WrongUsageException(PHP_OS_FAMILY . ' build is not supported yet'),
};
}
/**
@@ -81,13 +81,13 @@ class Extension
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getEnableArg(): string
public function getEnableArg(bool $shared = false): string
{
$_name = str_replace('_', '-', $this->name);
return match ($arg_type = Config::getExt($this->name, 'arg-type', 'enable')) {
'enable' => '--enable-' . $_name . ' ',
'with' => '--with-' . $_name . ' ',
'with-prefix' => '--with-' . $_name . '="' . BUILD_ROOT_PATH . '" ',
'enable' => '--enable-' . $_name . ($shared ? '=shared' : '') . ' ',
'with' => '--with-' . $_name . ($shared ? '=shared' : '') . ' ',
'with-prefix' => '--with-' . $_name . '=' . ($shared ? 'shared,' : '') . '"' . BUILD_ROOT_PATH . '" ',
'none', 'custom' => '',
default => throw new WrongUsageException("argType does not accept {$arg_type}, use [enable/with/with-prefix] ."),
};
@@ -147,15 +147,15 @@ class Extension
return $this->name;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
return '';
return $this->getEnableArg();
// Windows is not supported yet
}
public function getUnixConfigureArg(bool $shared = false): string
{
return '';
return $this->getEnableArg($shared);
}
/**
@@ -189,18 +189,80 @@ class Extension
}
/**
* Run shared extension check when cli is enabled
* @throws RuntimeException
* Patch code before shared extension phpize
* If you need to patch some code, overwrite this
* return true if you patched something, false if not
*/
public function runSharedExtensionCheckUnix(): void
public function patchBeforeSharedPhpize(): bool
{
[$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "extension=' . BUILD_LIB_PATH . '/' . $this->getName() . '.so" --ri ' . $this->getName());
if ($ret !== 0) {
throw new RuntimeException($this->getName() . '.so failed to load');
return false;
}
/**
* Patch code before shared extension ./configure
* If you need to patch some code, overwrite this
* return true if you patched something, false if not
*/
public function patchBeforeSharedConfigure(): bool
{
return false;
}
/**
* Patch code before shared extension make
* If you need to patch some code, overwrite this
* return true if you patched something, false if not
*/
public function patchBeforeSharedMake(): bool
{
return false;
}
/**
* @return string
* returns a command line string with all required shared extensions to load
* i.e.; pdo_pgsql would return:
*
* `-d "extension=pgsql" -d "extension=pdo_pgsql"`
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getSharedExtensionLoadString(): string
{
$loaded = [];
$order = [];
$resolve = function ($extension) use (&$resolve, &$loaded, &$order) {
if (isset($loaded[$extension->getName()])) {
return;
}
$loaded[$extension->getName()] = true;
foreach ($this->dependencies as $dependency) {
$resolve($dependency);
}
$order[] = $extension;
};
$resolve($this);
$ret = '';
foreach ($order as $ext) {
if ($ext instanceof Extension && $ext->isBuildShared()) {
if (Config::getExt($ext->getName(), 'zend-extension', false) === true) {
$ret .= " -d \"zend_extension={$ext->getName()}\"";
} else {
$ret .= " -d \"extension={$ext->getName()}\"";
}
}
}
if ($this->isBuildStatic()) {
logger()->warning($this->getName() . '.so test succeeded, but has little significance since it is also compiled in statically.');
if ($ret !== '') {
$ret = ' -d "extension_dir=' . BUILD_MODULES_PATH . '"' . $ret;
}
return $ret;
}
/**
@@ -211,9 +273,13 @@ class Extension
// Run compile check if build target is cli
// If you need to run some check, overwrite this or add your assert in src/globals/ext-tests/{extension_name}.php
// If check failed, throw RuntimeException
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "' . $this->getDistName() . '"', false);
$sharedExtensions = $this->getSharedExtensionLoadString();
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);
throw new RuntimeException(
'extension ' . $this->getName() . ' failed runtime check: php-cli returned ' . $ret . "\n" .
join("\n", $out)
);
}
if (file_exists(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php')) {
@@ -224,7 +290,7 @@ class Extension
file_get_contents(ROOT_DIR . '/src/globals/ext-tests/' . $this->getName() . '.php')
);
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n -r "' . trim($test) . '"');
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' -r "' . trim($test) . '"');
if ($ret !== 0) {
if ($this->builder->getOption('debug')) {
var_dump($out);
@@ -275,6 +341,30 @@ class Extension
*/
public function buildShared(): void
{
if (Config::getExt($this->getName(), 'type') === 'builtin' || Config::getExt($this->getName(), 'build-with-php') === true) {
if (file_exists(BUILD_MODULES_PATH . '/' . $this->getName() . '.so')) {
logger()->info('Shared extension [' . $this->getName() . '] was already built by php-src/configure (' . $this->getName() . '.so)');
return;
}
if (Config::getExt($this->getName(), 'build-with-php') === true) {
logger()->warning('Shared extension [' . $this->getName() . '] did not build with php-src/configure (' . $this->getName() . '.so)');
logger()->warning('Try deleting your build and source folders and running `spc build`` again.');
return;
}
}
if (file_exists(BUILD_MODULES_PATH . '/' . $this->getName() . '.so')) {
logger()->info('Shared extension [' . $this->getName() . '] was already built, skipping (' . $this->getName() . '.so)');
}
logger()->info('Building extension [' . $this->getName() . '] as shared extension (' . $this->getName() . '.so)');
foreach ($this->dependencies as $dependency) {
if (!$dependency instanceof Extension) {
continue;
}
if (!$dependency->isBuildStatic()) {
logger()->info('extension ' . $this->getName() . ' requires extension ' . $dependency->getName());
$dependency->buildShared();
}
}
match (PHP_OS_FAMILY) {
'Darwin', 'Linux' => $this->buildUnixShared(),
default => throw new WrongUsageException(PHP_OS_FAMILY . ' build shared extensions is not supported yet'),
@@ -292,26 +382,58 @@ class Extension
*/
public function buildUnixShared(): void
{
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()]);
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()], with_dependencies: true);
[$staticLibString, $sharedLibString] = $this->getStaticAndSharedLibs();
// macOS ld64 doesn't understand these, while Linux and BSD do
// use them to make sure that all symbols are picked up, even if a library has already been visited before
$preStatic = PHP_OS_FAMILY !== 'Darwin' ? '-Wl,-Bstatic -Wl,--start-group ' : '';
$postStatic = PHP_OS_FAMILY !== 'Darwin' ? ' -Wl,--end-group -Wl,-Bdynamic ' : ' ';
$env = [
'CFLAGS' => $config['cflags'],
'CXXFLAGS' => $config['cflags'],
'LDFLAGS' => $config['ldflags'],
'LIBS' => $config['libs'],
'LIBS' => $preStatic . $staticLibString . $postStatic . $sharedLibString,
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
];
if ($this->patchBeforeSharedPhpize()) {
logger()->info("Extension [{$this->getName()}] patched before shared phpize");
}
// prepare configure args
shell()->cd($this->source_dir)
->setEnv($env)
->exec(BUILD_BIN_PATH . '/phpize')
->exec('./configure ' . $this->getUnixConfigureArg(true) . ' --with-php-config=' . BUILD_BIN_PATH . '/php-config --enable-shared --disable-static')
->exec('make clean')
->exec('make -j' . $this->builder->concurrency);
->exec(BUILD_BIN_PATH . '/phpize');
// copy shared library
copy($this->source_dir . '/modules/' . $this->getDistName() . '.so', BUILD_LIB_PATH . '/' . $this->getDistName() . '.so');
// check shared extension with php-cli
if (file_exists(BUILD_BIN_PATH . '/php')) {
$this->runSharedExtensionCheckUnix();
if ($this->patchBeforeSharedConfigure()) {
logger()->info("Extension [{$this->getName()}] patched before shared configure");
}
shell()->cd($this->source_dir)
->setEnv($env)
->exec(
'./configure ' . $this->getUnixConfigureArg(true) .
' --with-php-config=' . BUILD_BIN_PATH . '/php-config ' .
'--enable-shared --disable-static'
);
// some extensions don't define their dependencies well, this patch is only needed for a few
FileSystem::replaceFileRegex(
$this->source_dir . '/Makefile',
'/^(.*_SHARED_LIBADD\s*=.*)$/m',
'$1 ' . $staticLibString
);
if ($this->patchBeforeSharedMake()) {
logger()->info("Extension [{$this->getName()}] patched before shared make");
}
shell()->cd($this->source_dir)
->setEnv($env)
->exec('make clean')
->exec('make -j' . $this->builder->concurrency)
->exec('make install');
}
/**
@@ -382,6 +504,37 @@ class Extension
}
}
/**
* Get required static and shared libraries as a pair of strings in format -l{libname} -l{libname2}
*
* @return array [staticLibString, sharedLibString]
*/
protected function getStaticAndSharedLibs(): array
{
$config = (new SPCConfigUtil($this->builder))->config([$this->getName()], with_dependencies: true);
$sharedLibString = '';
$staticLibString = '';
$staticLibs = $this->getLibFilesString();
$staticLibs = str_replace(BUILD_LIB_PATH . '/lib', '-l', $staticLibs);
$staticLibs = str_replace('.a', '', $staticLibs);
$staticLibs = explode('-l', $staticLibs . ' ' . $config['libs']);
foreach ($staticLibs as $lib) {
$lib = trim($lib);
if ($lib === '') {
continue;
}
$static_lib = 'lib' . $lib . '.a';
if (file_exists(BUILD_LIB_PATH . '/' . $static_lib) && !str_contains($static_lib, 'libphp')) {
if (!str_contains($staticLibString, '-l' . $lib . ' ')) {
$staticLibString .= '-l' . $lib . ' ';
}
} elseif (!str_contains($sharedLibString, '-l' . $lib . ' ')) {
$sharedLibString .= '-l' . $lib . ' ';
}
}
return [trim($staticLibString), trim($sharedLibString)];
}
private function getLibraryDependencies(bool $recursive = false): array
{
$ret = array_filter($this->dependencies, fn ($x) => $x instanceof LibraryBase);
@@ -407,6 +560,11 @@ class Extension
}
}
if (array_key_exists(0, $deps)) {
$zero = [0 => $deps[0]];
unset($deps[0]);
return $zero + $deps;
}
return $deps;
}
}

View File

@@ -10,10 +10,14 @@ use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\Downloader;
use SPC\store\FileSystem;
use SPC\store\LockFile;
use SPC\store\SourceManager;
use SPC\util\GlobalValueTrait;
abstract class LibraryBase
{
use GlobalValueTrait;
/** @var string */
public const NAME = 'unknown';
@@ -31,7 +35,7 @@ abstract class LibraryBase
if (static::NAME === 'unknown') {
throw new RuntimeException('no unknown!!!!!');
}
$this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . static::NAME);
$this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . Config::getLib(static::NAME, 'source'));
}
/**
@@ -43,12 +47,11 @@ abstract class LibraryBase
*/
public function setup(bool $force = false): int
{
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
$source = Config::getLib(static::NAME, 'source');
// if source is locked as pre-built, we just tryInstall it
$pre_built_name = Downloader::getPreBuiltLockName($source);
if (isset($lock[$pre_built_name]) && ($lock[$pre_built_name]['lock_as'] ?? SPC_DOWNLOAD_SOURCE) === SPC_DOWNLOAD_PRE_BUILT) {
return $this->tryInstall($lock[$pre_built_name]['filename'], $force);
if (($lock = LockFile::get($pre_built_name)) && $lock['lock_as'] === SPC_DOWNLOAD_PRE_BUILT) {
return $this->tryInstall($lock, $force);
}
return $this->tryBuild($force);
}
@@ -163,14 +166,15 @@ abstract class LibraryBase
* @throws WrongUsageException
* @throws FileSystemException
*/
public function tryInstall(string $install_file, bool $force_install = false): int
public function tryInstall(array $lock, bool $force_install = false): int
{
$install_file = $lock['filename'];
if ($force_install) {
logger()->info('Installing required library [' . static::NAME . '] from pre-built binaries');
// Extract files
try {
FileSystem::extractPackage($install_file, DOWNLOAD_PATH . '/' . $install_file, BUILD_ROOT_PATH);
FileSystem::extractPackage($install_file, $lock['source_type'], DOWNLOAD_PATH . '/' . $install_file, BUILD_ROOT_PATH);
$this->install();
return LIB_STATUS_OK;
} catch (FileSystemException|RuntimeException $e) {
@@ -180,19 +184,19 @@ abstract class LibraryBase
}
foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryInstall($install_file, true);
$this->tryInstall($lock, true);
return LIB_STATUS_OK;
}
}
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryInstall($install_file, true);
$this->tryInstall($lock, true);
return LIB_STATUS_OK;
}
}
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
if (static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryInstall($install_file, true);
$this->tryInstall($lock, true);
return LIB_STATUS_OK;
}
return LIB_STATUS_ALREADY;
@@ -328,21 +332,6 @@ abstract class LibraryBase
return false;
}
public function getIncludeDir(): string
{
return BUILD_INCLUDE_PATH;
}
public function getBuildRootPath(): string
{
return BUILD_ROOT_PATH;
}
public function getLibDir(): string
{
return BUILD_LIB_PATH;
}
/**
* Build this library.
*

View File

@@ -25,10 +25,10 @@ class amqp extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-amqp --with-librabbitmq-dir=' . BUILD_ROOT_PATH;
return '--with-amqp' . ($shared ? '=shared' : '') . ' --with-librabbitmq-dir=' . BUILD_ROOT_PATH;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg($shared = false): string
{
return '--with-amqp';
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\linux\LinuxBuilder;
use SPC\builder\macos\MacOSBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\WrongUsageException;
@@ -21,7 +22,7 @@ class curl extends Extension
{
logger()->info('patching before-configure for curl checks');
$file1 = "AC_DEFUN([PHP_CHECK_LIBRARY], [\n $3\n])";
$files = FileSystem::readFile(SOURCE_PATH . '/php-src/ext/curl/config.m4');
$files = FileSystem::readFile($this->source_dir . '/config.m4');
$file2 = 'AC_DEFUN([PHP_CHECK_LIBRARY], [
save_old_LDFLAGS=$LDFLAGS
ac_stuff="$5"
@@ -40,7 +41,7 @@ class curl extends Extension
$4
])dnl
])';
file_put_contents(SOURCE_PATH . '/php-src/ext/curl/config.m4', $file1 . "\n" . $files . "\n" . $file2);
file_put_contents($this->source_dir . '/config.m4', $file1 . "\n" . $files . "\n" . $file2);
return true;
}
@@ -52,6 +53,72 @@ class curl extends Extension
{
$frameworks = $this->builder instanceof MacOSBuilder ? ' ' . $this->builder->getFrameworks(true) . ' ' : '';
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/configure', '/-lcurl/', $this->getLibFilesString() . $frameworks);
$this->patchBeforeSharedConfigure();
return true;
}
public function patchBeforeSharedConfigure(): bool
{
$file = $this->source_dir . '/config.m4';
$content = FileSystem::readFile($file);
// Inject patch before it
$patch = ' save_LIBS="$LIBS"
LIBS="$LIBS $CURL_LIBS"
';
// Check if already patched
if (str_contains($content, $patch)) {
return false; // Already patched
}
// Match the line containing PHP_CHECK_LIBRARY for curl
$pattern = '/(PHP_CHECK_LIBRARY\(\[curl],\s*\[curl_easy_perform],)/';
// Restore LIBS after the check — append this just after the macro block
$restore = '
LIBS="$save_LIBS"';
// Apply patch
$patched = preg_replace_callback($pattern, function ($matches) use ($patch) {
return $patch . $matches[1];
}, $content, 1);
// Inject restore after the matching PHP_CHECK_LIBRARY block
$patched = preg_replace(
'/(PHP_CHECK_LIBRARY\(\[curl],\s*\[curl_easy_perform],.*?\)\n)/s',
"$1{$restore}\n",
$patched,
1
);
if ($patched === null) {
throw new \RuntimeException('Failed to patch config.m4 due to a regex error');
}
FileSystem::writeFile($file, $patched);
return true;
}
public function buildUnixShared(): void
{
if (!$this->builder instanceof LinuxBuilder) {
parent::buildUnixShared();
return;
}
FileSystem::replaceFileStr(
$this->source_dir . '/config.m4',
['$ext_dir/phar.1', '$ext_dir/phar.phar.1'],
['${ext_dir}phar.1', '${ext_dir}phar.phar.1']
);
try {
parent::buildUnixShared();
} finally {
FileSystem::replaceFileStr(
$this->source_dir . '/config.m4',
['${ext_dir}phar.1', '${ext_dir}phar.phar.1'],
['$ext_dir/phar.1', '$ext_dir/phar.phar.1']
);
}
}
}

View File

@@ -12,11 +12,11 @@ class dba extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
$qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . BUILD_ROOT_PATH) : '';
return '--enable-dba' . $qdbm;
$qdbm = $this->builder->getLib('qdbm') ? (' --with-qdbm=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH) : '';
return '--enable-dba' . ($shared ? '=shared' : '') . $qdbm;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
$qdbm = $this->builder->getLib('qdbm') ? ' --with-qdbm' : '';
return '--with-dba' . $qdbm;

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('dom')]
class dom extends Extension
{
/**
* @throws RuntimeException
*/
public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-dom' . ($shared ? '=shared' : '');
$arg .= ' --with-libxml="' . BUILD_ROOT_PATH . '"';
return $arg;
}
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/win32/build/config.w32', 'dllmain.c ', '');
return true;
}
public function getWindowsConfigureArg($shared = false): string
{
return '--with-dom';
}
}

View File

@@ -12,10 +12,10 @@ class ffi extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-ffi --enable-zend-signals';
return '--with-ffi' . ($shared ? '=shared' : '') . ' --enable-zend-signals';
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
return '--with-ffi';
}

View File

@@ -12,7 +12,7 @@ class gd extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-gd';
$arg = '--enable-gd' . ($shared ? '=shared' : '');
$arg .= $this->builder->getLib('freetype') ? ' --with-freetype' : '';
$arg .= $this->builder->getLib('libjpeg') ? ' --with-jpeg' : '';
$arg .= $this->builder->getLib('libwebp') ? ' --with-webp' : '';

View File

@@ -35,7 +35,7 @@ class glfw extends Extension
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
return '--enable-glfw=static';
}

View File

@@ -12,10 +12,13 @@ class imagick extends Extension
{
public function patchBeforeMake(): bool
{
if (getenv('SPC_LIBC') !== 'musl') {
if (PHP_OS_FAMILY !== 'Linux') {
return false;
}
// imagick with calls omp_pause_all which requires -lgomp, on non-musl we build imagick without openmp
if (getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10')) {
return false;
}
// imagick with calls omp_pause_all, which requires openmp, on non-musl we build imagick without openmp
$extra_libs = trim(getenv('SPC_EXTRA_LIBS') . ' -lgomp');
f_putenv('SPC_EXTRA_LIBS=' . $extra_libs);
return true;
@@ -23,7 +26,18 @@ class imagick extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
$disable_omp = getenv('SPC_LIBC') === 'musl' ? '' : ' ac_cv_func_omp_pause_resource_all=no';
return '--with-imagick=' . BUILD_ROOT_PATH . $disable_omp;
$disable_omp = !(getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10')) ? '' : ' ac_cv_func_omp_pause_resource_all=no';
return '--with-imagick=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . $disable_omp;
}
protected function getStaticAndSharedLibs(): array
{
// on centos 7, it will use the symbol _ZTINSt6thread6_StateE, which is not defined in system libstdc++.so.6
[$static, $shared] = parent::getStaticAndSharedLibs();
if (getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10')) {
$static .= ' -lstdc++';
$shared = str_replace('-lstdc++', '', $shared);
}
return [$static, $shared];
}
}

View File

@@ -20,16 +20,13 @@ class intl extends Extension
'EXTENSION("intl", "php_intl.c intl_convert.c intl_convertcpp.cpp intl_error.c ", true,',
'EXTENSION("intl", "php_intl.c intl_convert.c intl_convertcpp.cpp intl_error.c ", PHP_INTL_SHARED,'
);
} else {
// TODO: remove the following line when https://github.com/php/php-src/pull/14002 will be released
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/ext/intl/config.m4', 'PHP_CXX_COMPILE_STDCXX(11', 'PHP_CXX_COMPILE_STDCXX(17');
// Also need to use clang++ -std=c++17 to force override the default C++ standard
if (is_string($env = getenv('CXX')) && !str_contains($env, 'std=c++17')) {
f_putenv('CXX=' . $env . ' -std=c++17');
} else {
f_putenv('CXX=clang++ -std=c++17');
}
return true;
}
return true;
return false;
}
public function patchBeforeSharedPhpize(): bool
{
return $this->patchBeforeBuildconf();
}
}

View File

@@ -15,7 +15,7 @@ class lz4 extends Extension
return '--enable-lz4' . ($shared ? '=shared' : '') . ' --with-lz4-includedir=' . BUILD_ROOT_PATH;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
return '--enable-lz4';
}

View File

@@ -16,7 +16,7 @@ class mbregex extends Extension
return 'mbstring';
}
public function getConfigureArg(): string
public function getConfigureArg(bool $shared = false): string
{
return '';
}
@@ -26,7 +26,8 @@ class mbregex extends Extension
*/
public function runCliCheckUnix(): void
{
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "mbstring" | grep regex', false);
$sharedext = $this->builder->getExt('mbstring')->isBuildShared() ? '-d "extension_dir=' . BUILD_MODULES_PATH . '" -d "extension=mbstring"' : '';
[$ret] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n' . $sharedext . ' --ri "mbstring" | grep regex', false);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: compiled php-cli mbstring extension does not contain regex !');
}

View File

@@ -10,9 +10,20 @@ use SPC\util\CustomExt;
#[CustomExt('mbstring')]
class mbstring extends Extension
{
public function getConfigureArg(): string
public function getConfigureArg(bool $shared = false): string
{
$arg = '--enable-mbstring';
$arg = '--enable-mbstring' . ($shared ? '=shared' : '');
if ($this->builder->getExt('mbregex') === null) {
$arg .= ' --disable-mbregex';
} else {
$arg .= ' --enable-mbregex';
}
return $arg;
}
public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-mbstring' . ($shared ? '=shared' : '');
if ($this->builder->getExt('mbregex') === null) {
$arg .= ' --disable-mbregex';
} else {

View File

@@ -14,7 +14,7 @@ class memcache extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-memcache --with-zlib-dir=' . BUILD_ROOT_PATH;
return '--enable-memcache' . ($shared ? '=shared' : '') . ' --with-zlib-dir=' . BUILD_ROOT_PATH;
}
/**

View File

@@ -12,8 +12,11 @@ class memcached extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
$rootdir = BUILD_ROOT_PATH;
$zlib_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : "--with-zlib-dir={$rootdir}";
return "--enable-memcached {$zlib_dir} --with-libmemcached-dir={$rootdir} --disable-memcached-sasl --enable-memcached-json";
return '--enable-memcached' . ($shared ? '=shared' : '') . ' ' .
'--with-zlib-dir=' . BUILD_ROOT_PATH . ' ' .
'--with-libmemcached-dir=' . BUILD_ROOT_PATH . ' ' .
'--disable-memcached-sasl ' .
'--enable-memcached-json ' .
'--with-system-fastlz';
}
}

View File

@@ -12,6 +12,6 @@ class odbc extends Extension
{
public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-unixODBC=' . BUILD_ROOT_PATH;
return '--with-unixODBC=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH;
}
}

View File

@@ -26,6 +26,6 @@ class openssl extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
$openssl_dir = $this->builder->getPHPVersionID() >= 80400 ? '' : ' --with-openssl-dir=' . BUILD_ROOT_PATH;
return '--with-openssl=' . BUILD_ROOT_PATH . $openssl_dir;
return '--with-openssl=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . $openssl_dir;
}
}

View File

@@ -19,10 +19,10 @@ class pdo_odbc extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
return '--with-pdo-odbc=unixODBC,' . BUILD_ROOT_PATH;
return '--with-pdo-odbc=' . ($shared ? 'shared,' : '') . 'unixODBC,' . BUILD_ROOT_PATH;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
return '--with-pdo-odbc';
}

View File

@@ -10,7 +10,7 @@ use SPC\util\CustomExt;
#[CustomExt('pdo_pgsql')]
class pdo_pgsql extends Extension
{
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
return '--with-pdo-pgsql=yes';
}

View File

@@ -36,16 +36,21 @@ class pgsql extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
if ($this->builder->getPHPVersionID() >= 80400) {
return '--with-pgsql PGSQL_CFLAGS=-I' . BUILD_INCLUDE_PATH . ' PGSQL_LIBS="-L' . BUILD_LIB_PATH . ' -lpq -lpgport -lpgcommon"';
$libfiles = $this->getLibFilesString();
$libfiles = str_replace(BUILD_LIB_PATH . '/lib', '-l', $libfiles);
$libfiles = str_replace('.a', '', $libfiles);
return '--with-pgsql' . ($shared ? '=shared' : '') .
' PGSQL_CFLAGS=-I' . BUILD_INCLUDE_PATH .
' PGSQL_LIBS="-L' . BUILD_LIB_PATH . ' ' . $libfiles . '"';
}
return '--with-pgsql=' . BUILD_ROOT_PATH;
return '--with-pgsql=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH;
}
/**
* @throws WrongUsageException
* @throws RuntimeException
*/
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
if ($this->builder->getPHPVersionID() >= 80400) {
return '--with-pgsql';

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\builder\linux\LinuxBuilder;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('phar')]
class phar extends Extension
{
public function buildUnixShared(): void
{
if (!$this->builder instanceof LinuxBuilder) {
parent::buildUnixShared();
return;
}
FileSystem::replaceFileStr(
$this->source_dir . '/config.m4',
['$ext_dir/phar.1', '$ext_dir/phar.phar.1'],
['${ext_dir}phar.1', '${ext_dir}phar.phar.1']
);
try {
parent::buildUnixShared();
} finally {
FileSystem::replaceFileStr(
$this->source_dir . '/config.m4',
['${ext_dir}phar.1', '${ext_dir}phar.phar.1'],
['$ext_dir/phar.1', '$ext_dir/phar.phar.1']
);
}
}
}

View File

@@ -15,8 +15,9 @@ class protobuf extends Extension
if ($this->builder->getPHPVersionID() < 80000 && getenv('SPC_SKIP_PHP_VERSION_CHECK') !== 'yes') {
throw new \RuntimeException('The latest protobuf extension requires PHP 8.0 or later');
}
$grpc = $this->builder->getExt('grpc');
// protobuf conflicts with grpc
if ($this->builder->getExt('grpc') !== null) {
if ($grpc?->isBuildStatic()) {
throw new \RuntimeException('protobuf conflicts with grpc, please remove grpc or protobuf extension');
}
}

View File

@@ -11,6 +11,13 @@ use SPC\util\CustomExt;
#[CustomExt('rdkafka')]
class rdkafka extends Extension
{
public function patchBeforeBuildconf(): bool
{
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\n", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm \$RDKAFKA_LIBS\n");
FileSystem::replaceFileStr("{$this->source_dir}/config.m4", "-L\$RDKAFKA_DIR/\$PHP_LIBDIR -lm\"\n", '-L$RDKAFKA_DIR/$PHP_LIBDIR -lm $RDKAFKA_LIBS"');
return true;
}
public function patchBeforeMake(): bool
{
// when compiling rdkafka with inline builds, it shows some errors, I don't know why.
@@ -27,10 +34,10 @@ class rdkafka extends Extension
return true;
}
public function getConfigureArg(): string
public function getUnixConfigureArg(bool $shared = false): string
{
$pkgconf_libs = shell()->execWithResult('pkg-config --libs --static rdkafka')[1];
$pkgconf_libs = trim(implode('', $pkgconf_libs));
return '--with-rdkafka=' . BUILD_ROOT_PATH . ' LIBS="' . $pkgconf_libs . '"';
return '--with-rdkafka=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . ' RDKAFKA_LIBS="' . $pkgconf_libs . '"';
}
}

View File

@@ -24,4 +24,18 @@ class readline extends Extension
);
return true;
}
public function getUnixConfigureArg(bool $shared = false): string
{
return '--without-libedit --with-readline=' . BUILD_ROOT_PATH;
}
public function buildUnixShared(): void
{
if (!file_exists(BUILD_BIN_PATH . '/php') || !file_exists(BUILD_INCLUDE_PATH . '/php/sapi/cli/cli.h')) {
logger()->warning('CLI mode is not enabled, skipping readline build');
return;
}
parent::buildUnixShared();
}
}

View File

@@ -24,7 +24,7 @@ class redis extends Extension
return $arg;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
$arg = '--enable-redis';
$arg .= $this->builder->getExt('session') ? ' --enable-redis-session' : ' --disable-redis-session';

View File

@@ -5,28 +5,28 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\WrongUsageException;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('spx')]
class spx extends Extension
{
/**
* @throws WrongUsageException
*/
public function validate(): void
{
if ($this->builder->getOption('enable-zts')) {
throw new WrongUsageException('ext-spx is not thread safe, do not build it with ZTS builds');
}
}
public function getUnixConfigureArg(bool $shared = false): string
{
$arg = '--enable-spx';
if ($this->builder->getExt('zlib') === null) {
$arg = '--enable-spx' . ($shared ? '=shared' : '');
if ($this->builder->getLib('zlib') !== null) {
$arg .= ' --with-zlib-dir=' . BUILD_ROOT_PATH;
}
return $arg;
}
public function patchBeforeConfigure(): bool
{
FileSystem::replaceFileStr(
$this->source_dir . '/Makefile.frag',
'@cp -r assets/web-ui/*',
'@cp -r ' . $this->source_dir . '/assets/web-ui/*',
);
return true;
}
}

View File

@@ -29,7 +29,7 @@ class swoole_hook_mysql extends Extension
if ($this->builder->getExt('swoole') === null) {
return;
}
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "swoole"', false);
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n' . $this->getSharedExtensionLoadString() . ' --ri "swoole"', false);
$out = implode('', $out);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);

View File

@@ -37,7 +37,8 @@ class swoole_hook_pgsql extends Extension
if ($this->builder->getExt('swoole') === null) {
return;
}
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "swoole"', false);
$sharedExtensions = $this->getSharedExtensionLoadString();
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
$out = implode('', $out);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);

View File

@@ -37,7 +37,8 @@ class swoole_hook_sqlite extends Extension
if ($this->builder->getExt('swoole') === null) {
return;
}
[$ret, $out] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n --ri "swoole"', false);
$sharedExtensions = $this->getSharedExtensionLoadString();
[$ret, $out] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n' . $sharedExtensions . ' --ri "' . $this->getDistName() . '"');
$out = implode('', $out);
if ($ret !== 0) {
throw new RuntimeException('extension ' . $this->getName() . ' failed compile check: php-cli returned ' . $ret);

View File

@@ -18,7 +18,7 @@ class swow extends Extension
}
}
public function getConfigureArg(): string
public function getConfigureArg(bool $shared = false): string
{
$arg = '--enable-swow';
$arg .= $this->builder->getLib('openssl') ? ' --enable-swow-ssl' : ' --disable-swow-ssl';

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\store\FileSystem;
use SPC\util\CustomExt;
#[CustomExt('uv')]
@@ -16,4 +17,13 @@ class uv extends Extension
throw new \RuntimeException('The latest uv extension requires PHP 8.0 or later');
}
}
public function patchBeforeSharedMake(): bool
{
if (PHP_OS_FAMILY !== 'Linux' || arch2gnu(php_uname('m')) !== 'aarch64') {
return false;
}
FileSystem::replaceFileRegex($this->source_dir . '/Makefile', '/^(LDFLAGS =.*)$/m', '$1 -luv -ldl -lrt -pthread');
return true;
}
}

View File

@@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
namespace SPC\builder\extension;
use SPC\builder\Extension;
use SPC\exception\RuntimeException;
use SPC\util\CustomExt;
#[CustomExt('xdebug')]
class xdebug extends Extension
{
public function runSharedExtensionCheckUnix(): void
{
[$ret] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -d "zend_extension=' . BUILD_LIB_PATH . '/xdebug.so" --ri xdebug');
if ($ret !== 0) {
throw new RuntimeException('xdebug.so failed to load.');
}
}
}

View File

@@ -20,7 +20,7 @@ class xlswriter extends Extension
return $arg;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
return '--with-xlswriter';
}

View File

@@ -13,7 +13,6 @@ use SPC\util\CustomExt;
#[CustomExt('soap')]
#[CustomExt('xmlreader')]
#[CustomExt('xmlwriter')]
#[CustomExt('dom')]
#[CustomExt('simplexml')]
class xml extends Extension
{
@@ -27,11 +26,10 @@ class xml extends Extension
'soap' => '--enable-soap',
'xmlreader' => '--enable-xmlreader',
'xmlwriter' => '--enable-xmlwriter',
'dom' => '--enable-dom',
'simplexml' => '--enable-simplexml',
default => throw new RuntimeException('Not accept non-xml extension'),
};
$arg .= ' --with-libxml="' . BUILD_ROOT_PATH . '"';
$arg .= ($shared ? '=shared' : '') . ' --with-libxml="' . BUILD_ROOT_PATH . '"';
return $arg;
}
@@ -41,14 +39,13 @@ class xml extends Extension
return true;
}
public function getWindowsConfigureArg(): string
public function getWindowsConfigureArg(bool $shared = false): string
{
$arg = match ($this->name) {
'xml' => '--with-xml',
'soap' => '--enable-soap',
'xmlreader' => '--enable-xmlreader',
'xmlwriter' => '--enable-xmlwriter',
'dom' => '--with-dom',
'simplexml' => '--with-simplexml',
default => throw new RuntimeException('Not accept non-xml extension'),
};

View File

@@ -21,6 +21,6 @@ class yac extends Extension
public function getUnixConfigureArg(bool $shared = false): string
{
return '--enable-yac --enable-igbinary --enable-json';
return '--enable-yac' . ($shared ? '=shared' : '') . ' --enable-igbinary --enable-json --with-system-fastlz';
}
}

View File

@@ -96,6 +96,7 @@ class BSDBuilder extends UnixBuilderBase
$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;
shell()->cd(SOURCE_PATH . '/php-src')
->exec(
@@ -143,7 +144,14 @@ class BSDBuilder extends UnixBuilderBase
}
$this->buildEmbed();
}
if ($enableFrankenphp) {
logger()->info('building frankenphp');
$this->buildFrankenphp();
}
}
public function testPHP(int $build_target = BUILD_TARGET_NONE)
{
if (php_uname('m') === $this->getOption('arch')) {
$this->emitPatchPoint('before-sanity-check');
$this->sanityCheck($build_target);

View File

@@ -10,9 +10,9 @@ class curl extends BSDLibraryBase
public const NAME = 'curl';
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string
{
$libs = parent::getStaticLibFiles($style, $recursive);
$libs = parent::getStaticLibFiles($style, $recursive, $include_self);
if ($this->builder->getLib('openssl')) {
$this->builder->setOption('extra-libs', $this->builder->getOption('extra-libs') . ' /usr/lib/libpthread.a /usr/lib/libdl.a');
}

View File

@@ -48,7 +48,7 @@ class openssl extends BSDLibraryBase
$ex_lib = trim($zlib->getStaticLibFiles() . ' ' . $ex_lib);
}
shell()->cd($this->source_dir)
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
"./Configure no-shared {$extra} " .
'--prefix=/ ' . // use prefix=/

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\freebsd\library;
class watcher extends BSDLibraryBase
{
use \SPC\builder\unix\library\watcher;
public const NAME = 'watcher';
}

View File

@@ -33,7 +33,6 @@ class LinuxBuilder extends UnixBuilderBase
if (getenv('SPC_LIBC') === 'musl' && !SystemUtil::isMuslDist()) {
$this->setOptionIfNotExist('library_path', "LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\"");
$this->setOptionIfNotExist('ld_library_path', "LD_LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\"");
GlobalEnvManager::putenv("PATH=/usr/local/musl/bin:/usr/local/musl/{$arch}-linux-musl/bin:" . getenv('PATH'));
$configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
$configure = "LD_LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\" " . $configure;
GlobalEnvManager::putenv("SPC_CMD_PREFIX_PHP_CONFIGURE={$configure}");
@@ -110,10 +109,11 @@ class LinuxBuilder extends UnixBuilderBase
$config_file_scan_dir = $this->getOption('with-config-file-scan-dir', false) ?
('--with-config-file-scan-dir=' . $this->getOption('with-config-file-scan-dir') . ' ') : '';
$enable_cli = ($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI;
$enable_fpm = ($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM;
$enable_micro = ($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO;
$enable_embed = ($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED;
$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;
$mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : '';
// prepare build php envs
@@ -125,7 +125,7 @@ class LinuxBuilder extends UnixBuilderBase
]);
// process micro upx patch if micro sapi enabled
if ($enable_micro) {
if ($enableMicro) {
if (version_compare($this->getMicroVersion(), '0.2.0') < 0) {
// for phpmicro 0.1.x
$this->processMicroUPXLegacy();
@@ -137,10 +137,10 @@ class LinuxBuilder extends UnixBuilderBase
shell()->cd(SOURCE_PATH . '/php-src')
->exec(
getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' .
($enable_cli ? '--enable-cli ' : '--disable-cli ') .
($enable_fpm ? '--enable-fpm ' . ($this->getLib('libacl') !== null ? '--with-fpm-acl ' : '') : '--disable-fpm ') .
($enable_embed ? "--enable-embed={$embed_type} " : '--disable-embed ') .
($enable_micro ? '--enable-micro=all-static ' : '--disable-micro ') .
($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 ') .
$config_file_path .
$config_file_scan_dir .
$disable_jit .
@@ -156,26 +156,33 @@ class LinuxBuilder extends UnixBuilderBase
$this->cleanMake();
if ($enable_cli) {
if ($enableCli) {
logger()->info('building cli');
$this->buildCli();
}
if ($enable_fpm) {
if ($enableFpm) {
logger()->info('building fpm');
$this->buildFpm();
}
if ($enable_micro) {
if ($enableMicro) {
logger()->info('building micro');
$this->buildMicro();
}
if ($enable_embed) {
if ($enableEmbed) {
logger()->info('building embed');
if ($enable_micro) {
if ($enableMicro) {
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'OVERALL_TARGET =', 'OVERALL_TARGET = libphp.la');
}
$this->buildEmbed();
}
if ($enableFrankenphp) {
logger()->info('building frankenphp');
$this->buildFrankenphp();
}
}
public function testPHP(int $build_target = BUILD_TARGET_NONE)
{
$this->emitPatchPoint('before-sanity-check');
$this->sanityCheck($build_target);
}
@@ -189,9 +196,10 @@ class LinuxBuilder extends UnixBuilderBase
protected function buildCli(): void
{
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("\$SPC_CMD_PREFIX_PHP_MAKE {$vars} cli");
->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} cli");
if ($this->getOption('with-upx-pack')) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/cli')
@@ -227,10 +235,11 @@ class LinuxBuilder extends UnixBuilderBase
// patch fake cli for micro
$vars['EXTRA_CFLAGS'] .= $enable_fake_cli;
$vars = SystemUtil::makeEnvVarString($vars);
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("\$SPC_CMD_PREFIX_PHP_MAKE {$vars} micro");
->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} micro");
$this->processMicroUPX();
@@ -250,9 +259,10 @@ class LinuxBuilder extends UnixBuilderBase
protected function buildFpm(): void
{
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec("\$SPC_CMD_PREFIX_PHP_MAKE {$vars} fpm");
->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} fpm");
if ($this->getOption('with-upx-pack')) {
shell()->cd(SOURCE_PATH . '/php-src/sapi/fpm')
@@ -275,7 +285,38 @@ class LinuxBuilder extends UnixBuilderBase
shell()->cd(SOURCE_PATH . '/php-src')
->exec('sed -i "s|//lib|/lib|g" Makefile')
->exec('sed -i "s|^EXTENSION_DIR = .*|EXTENSION_DIR = /' . basename(BUILD_MODULES_PATH) . '|" Makefile')
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
$ldflags = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS');
if (preg_match('/-release\s+(\S+)/', $ldflags, $matches)) {
$release = $matches[1];
$realLibName = 'libphp-' . $release . '.so';
$realLib = BUILD_LIB_PATH . '/' . $realLibName;
rename(BUILD_LIB_PATH . '/libphp.so', $realLib);
$cwd = getcwd();
chdir(BUILD_LIB_PATH);
symlink($realLibName, 'libphp.so');
chdir(BUILD_MODULES_PATH);
foreach ($this->getExts() as $ext) {
if (!$ext->isBuildShared()) {
continue;
}
$name = $ext->getName();
$versioned = "{$name}-{$release}.so";
$unversioned = "{$name}.so";
if (is_file(BUILD_MODULES_PATH . "/{$versioned}")) {
rename(BUILD_MODULES_PATH . "/{$versioned}", BUILD_MODULES_PATH . "/{$unversioned}");
shell()->cd(BUILD_MODULES_PATH)
->exec(sprintf(
'patchelf --set-soname %s %s',
escapeshellarg($unversioned),
escapeshellarg($unversioned)
));
}
}
chdir($cwd);
}
$this->patchPhpScripts();
}
@@ -284,6 +325,7 @@ class LinuxBuilder extends UnixBuilderBase
return [
'EXTRA_CFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_CFLAGS'),
'EXTRA_LIBS' => getenv('SPC_EXTRA_LIBS') . ' ' . getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS'),
'EXTRA_LDFLAGS' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS'),
'EXTRA_LDFLAGS_PROGRAM' => getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM'),
];
}

View File

@@ -11,6 +11,8 @@ class SystemUtil
{
use UnixSystemUtilTrait;
public static ?string $libc_version = null;
/** @noinspection PhpMissingBreakStatementInspection */
public static function getOSRelease(): array
{
@@ -188,6 +190,9 @@ class SystemUtil
*/
public static function getLibcVersionIfExists(): ?string
{
if (self::$libc_version !== null) {
return self::$libc_version;
}
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'glibc') {
$result = shell()->execWithResult('ldd --version', false);
if ($result[0] !== 0) {
@@ -198,7 +203,8 @@ class SystemUtil
// match ldd version: "ldd (some useless text) 2.17" match 2.17
$pattern = '/ldd\s+\(.*?\)\s+(\d+\.\d+)/';
if (preg_match($pattern, $first_line, $matches)) {
return $matches[1];
self::$libc_version = $matches[1];
return self::$libc_version;
}
return null;
}
@@ -212,7 +218,8 @@ class SystemUtil
// match ldd version: "Version 1.2.3" match 1.2.3
$pattern = '/Version\s+(\d+\.\d+\.\d+)/';
if (preg_match($pattern, $result[1][1] ?? '', $matches)) {
return $matches[1];
self::$libc_version = $matches[1];
return self::$libc_version;
}
}
return null;

View File

@@ -10,9 +10,9 @@ class curl extends LinuxLibraryBase
public const NAME = 'curl';
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string
{
$libs = parent::getStaticLibFiles($style, $recursive);
$libs = parent::getStaticLibFiles($style, $recursive, $include_self);
if ($this->builder->getLib('openssl')) {
$libs .= ' -ldl -lpthread';
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class fastlz extends LinuxLibraryBase
{
use \SPC\builder\unix\library\fastlz;
public const NAME = 'fastlz';
}

View File

@@ -14,10 +14,10 @@ class icu extends LinuxLibraryBase
protected function build(): void
{
$cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -fPIC -fPIE -fno-ident"';
$cxxflags = 'CXXFLAGS="-std=c++17"';
$cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -DPIC -fPIC"';
$cxxflags = 'CXXFLAGS="-std=c++17 -DPIC -fPIC -fno-ident"';
$ldflags = getenv('SPC_LIBC') !== 'glibc' ? 'LDFLAGS="-static"' : '';
shell()->cd($this->source_dir . '/source')
shell()->cd($this->source_dir . '/source')->initializeEnv($this)
->exec(
"{$cppflags} {$cxxflags} {$ldflags} " .
'./runConfigureICU Linux ' .

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\linux\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
class libffi extends LinuxLibraryBase
{
@@ -17,23 +18,14 @@ class libffi extends LinuxLibraryBase
*/
public function build(): void
{
[$lib, , $destdir] = SEPARATED_PATH;
$arch = getenv('SPC_ARCH');
shell()->cd($this->source_dir)
->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
"--host={$arch}-unknown-linux " .
"--target={$arch}-unknown-linux " .
'--prefix= ' .
"--libdir={$lib}"
UnixAutoconfExecutor::create($this)
->configure(
"--host={$arch}-unknown-linux",
"--target={$arch}-unknown-linux",
"--libdir={$this->getLibDir()}"
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec("make install DESTDIR={$destdir}");
->make();
if (is_file(BUILD_ROOT_PATH . '/lib64/libffi.a')) {
copy(BUILD_ROOT_PATH . '/lib64/libffi.a', BUILD_ROOT_PATH . '/lib/libffi.a');

View File

@@ -4,17 +4,14 @@ declare(strict_types=1);
namespace SPC\builder\linux\library;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixCMakeExecutor;
/**
* gmp is a template library class for unix
*/
class libmemcached extends LinuxLibraryBase
{
public const NAME = 'libmemcached';
public function build()
public function build(): void
{
throw new RuntimeException('libmemcached is currently not supported on Linux platform');
UnixCMakeExecutor::create($this)->build();
}
}

View File

@@ -24,6 +24,7 @@ namespace SPC\builder\linux\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\util\executor\UnixAutoconfExecutor;
class libpng extends LinuxLibraryBase
{
@@ -36,28 +37,22 @@ class libpng extends LinuxLibraryBase
*/
public function build(): void
{
$optimizations = match (getenv('SPC_ARCH')) {
'x86_64' => '--enable-intel-sse ',
'aarch64' => '--enable-arm-neon ',
default => '',
};
shell()->cd($this->source_dir)->initializeEnv($this)
UnixAutoconfExecutor::create($this)
->exec('chmod +x ./configure')
->exec('chmod +x ./install-sh')
->exec(
'LDFLAGS="-L' . BUILD_LIB_PATH . '" ' .
'./configure ' .
'--disable-shared ' .
'--enable-static ' .
'--enable-hardware-optimizations ' .
'--with-zlib-prefix="' . BUILD_ROOT_PATH . '" ' .
$optimizations .
'--prefix='
->appendEnv(['LDFLAGS' => "-L{$this->getLibDir()}"])
->configure(
'--enable-hardware-optimizations',
"--with-zlib-prefix={$this->getBuildRootPath()}",
match (getenv('SPC_ARCH')) {
'x86_64' => '--enable-intel-sse',
'aarch64' => '--enable-arm-neon',
default => '',
}
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I{$this->source_dir} -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la")
->exec('make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH);
->make('libpng16.la', 'install-libLTLIBRARIES install-data-am', after_env_vars: ['DEFAULT_INCLUDES' => "-I{$this->source_dir} -I{$this->getIncludeDir()}"]);
$this->patchPkgconfPrefix(['libpng16.pc'], PKGCONF_PATCH_PREFIX);
$this->cleanLaFiles();
$this->patchLaDependencyPrefix();
}
}

View File

@@ -92,9 +92,9 @@ class openssl extends LinuxLibraryBase
FileSystem::replaceFileRegex(BUILD_LIB_PATH . '/cmake/OpenSSL/OpenSSLConfig.cmake', '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}/libz.a")');
}
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string
{
$libFiles = parent::getStaticLibFiles($style, $recursive);
$libFiles = parent::getStaticLibFiles($style, $recursive, $include_self);
if (!str_contains('-ldl -lpthread', $libFiles)) {
$libFiles .= ' -ldl -lpthread';
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class watcher extends LinuxLibraryBase
{
use \SPC\builder\unix\library\watcher;
public const NAME = 'watcher';
}

View File

@@ -67,6 +67,10 @@ class MacOSBuilder extends UnixBuilderBase
array_push($frameworks, ...$lib->getFrameworks());
}
foreach ($this->exts as $ext) {
array_push($frameworks, ...$ext->getFrameworks());
}
if ($asString) {
return implode(' ', array_map(fn ($x) => "-framework {$x}", $frameworks));
}
@@ -118,6 +122,7 @@ class MacOSBuilder extends UnixBuilderBase
$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;
// prepare build php envs
$mimallocLibs = $this->getLib('mimalloc') !== null ? BUILD_LIB_PATH . '/mimalloc.o ' : '';
@@ -176,7 +181,14 @@ class MacOSBuilder extends UnixBuilderBase
}
$this->buildEmbed();
}
if ($enableFrankenphp) {
logger()->info('building frankenphp');
$this->buildFrankenphp();
}
}
public function testPHP(int $build_target = BUILD_TARGET_NONE)
{
$this->emitPatchPoint('before-sanity-check');
$this->sanityCheck($build_target);
}
@@ -192,9 +204,10 @@ class MacOSBuilder extends UnixBuilderBase
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
$shell = shell()->cd(SOURCE_PATH . '/php-src');
$shell->exec("\$SPC_CMD_PREFIX_PHP_MAKE {$vars} cli");
$SPC_CMD_PREFIX_PHP_MAKE = getenv('SPC_CMD_PREFIX_PHP_MAKE') ?: 'make';
$shell->exec("{$SPC_CMD_PREFIX_PHP_MAKE} {$vars} cli");
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/cli/php')->exec('strip sapi/cli/php');
$shell->exec('dsymutil -f sapi/cli/php')->exec('strip -S sapi/cli/php');
}
$this->deployBinary(BUILD_TARGET_CLI);
}
@@ -221,12 +234,15 @@ class MacOSBuilder extends UnixBuilderBase
// patch fake cli for micro
$vars['EXTRA_CFLAGS'] .= $enable_fake_cli;
if ($this->getOption('no-strip', false)) {
$vars['STRIP'] = 'dsymutil -f ';
}
$vars = SystemUtil::makeEnvVarString($vars);
shell()->cd(SOURCE_PATH . '/php-src')->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . " {$vars} micro");
$shell = shell()->cd(SOURCE_PATH . '/php-src');
// build
$shell->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . " {$vars} micro");
// strip
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/micro/micro.sfx')->exec('strip -S sapi/micro/micro.sfx');
}
$this->deployBinary(BUILD_TARGET_MICRO);
@@ -248,7 +264,7 @@ class MacOSBuilder extends UnixBuilderBase
$shell = shell()->cd(SOURCE_PATH . '/php-src');
$shell->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . " {$vars} fpm");
if (!$this->getOption('no-strip', false)) {
$shell->exec('dsymutil -f sapi/fpm/php-fpm')->exec('strip sapi/fpm/php-fpm');
$shell->exec('dsymutil -f sapi/fpm/php-fpm')->exec('strip -S sapi/fpm/php-fpm');
}
$this->deployBinary(BUILD_TARGET_FPM);
}
@@ -263,15 +279,12 @@ class MacOSBuilder extends UnixBuilderBase
$vars = SystemUtil::makeEnvVarString($this->getMakeExtraVars());
shell()->cd(SOURCE_PATH . '/php-src')
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install")
// Workaround for https://github.com/php/php-src/issues/12082
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o')
->exec('mkdir ' . BUILD_ROOT_PATH . '/lib/php-o')
->cd(BUILD_ROOT_PATH . '/lib/php-o')
->exec('ar x ' . BUILD_ROOT_PATH . '/lib/libphp.a')
->exec('rm ' . BUILD_ROOT_PATH . '/lib/libphp.a')
->exec('ar rcs ' . BUILD_ROOT_PATH . '/lib/libphp.a *.o')
->exec('rm -Rf ' . BUILD_ROOT_PATH . '/lib/php-o');
->exec(getenv('SPC_CMD_PREFIX_PHP_MAKE') . ' INSTALL_ROOT=' . BUILD_ROOT_PATH . " {$vars} install");
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'static') {
shell()->cd(SOURCE_PATH . '/php-src')
->exec('ar -t ' . BUILD_LIB_PATH . "/libphp.a | grep '\\.a$' | xargs -n1 ar d " . BUILD_LIB_PATH . '/libphp.a');
}
$this->patchPhpScripts();
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class fastlz extends MacOSLibraryBase
{
use \SPC\builder\unix\library\fastlz;
public const NAME = 'fastlz';
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\macos\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
class libffi extends MacOSLibraryBase
{
@@ -17,20 +18,13 @@ class libffi extends MacOSLibraryBase
*/
protected function build(): void
{
[, , $destdir] = SEPARATED_PATH;
$arch = getenv('SPC_ARCH');
shell()->cd($this->source_dir)
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
"--host={$arch}-apple-darwin " .
"--target={$arch}-apple-darwin " .
'--prefix= ' // use prefix=/
UnixAutoconfExecutor::create($this)
->configure(
"--host={$arch}-apple-darwin",
"--target={$arch}-apple-darwin",
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec("make install DESTDIR={$destdir}");
->make();
$this->patchPkgconfPrefix(['libffi.pc']);
}
}

View File

@@ -4,24 +4,9 @@ declare(strict_types=1);
namespace SPC\builder\macos\library;
use SPC\store\FileSystem;
class libheif extends MacOSLibraryBase
{
use \SPC\builder\unix\library\libheif;
public const NAME = 'libheif';
public function patchBeforeBuild(): bool
{
if (!str_contains(file_get_contents($this->source_dir . '/CMakeLists.txt'), 'libbrotlienc')) {
FileSystem::replaceFileStr(
$this->source_dir . '/CMakeLists.txt',
'list(APPEND REQUIRES_PRIVATE "libbrotlidec")',
'list(APPEND REQUIRES_PRIVATE "libbrotlidec")' . "\n" . ' list(APPEND REQUIRES_PRIVATE "libbrotlienc")'
);
return true;
}
return false;
}
}

View File

@@ -4,28 +4,14 @@ declare(strict_types=1);
namespace SPC\builder\macos\library;
/**
* gmp is a template library class for unix
*/
use SPC\util\executor\UnixCMakeExecutor;
class libmemcached extends MacOSLibraryBase
{
public const NAME = 'libmemcached';
public function build(): void
{
$rootdir = BUILD_ROOT_PATH;
shell()->cd($this->source_dir)
->exec('chmod +x configure')
->exec(
'./configure ' .
'--enable-static --disable-shared ' .
'--disable-sasl ' .
"--prefix={$rootdir}"
)
->exec('make clean')
->exec('sed -ie "s/-Werror//g" ' . $this->source_dir . '/Makefile')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
UnixCMakeExecutor::create($this)->build();
}
}

View File

@@ -24,6 +24,7 @@ namespace SPC\builder\macos\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\util\executor\UnixAutoconfExecutor;
class libpng extends MacOSLibraryBase
{
@@ -36,29 +37,25 @@ class libpng extends MacOSLibraryBase
*/
protected function build(): void
{
$optimizations = match (php_uname('m')) {
'x86_64' => '--enable-intel-sse ',
'arm64' => '--enable-arm-neon ',
default => '',
};
shell()->cd($this->source_dir)
$arch = arch2gnu(php_uname('m'));
UnixAutoconfExecutor::create($this)
->exec('chmod +x ./configure')
->exec('chmod +x ./install-sh')
->exec(
'./configure ' .
'--host=' . arch2gnu(php_uname('m')) . '-apple-darwin ' .
'--disable-shared ' .
'--enable-static ' .
'--enable-hardware-optimizations ' .
$optimizations .
'--prefix='
->appendEnv(['LDFLAGS' => "-L{$this->getLibDir()}"])
->configure(
"--host={$arch}-apple-darwin",
'--enable-hardware-optimizations',
"--with-zlib-prefix={$this->getBuildRootPath()}",
match (getenv('SPC_ARCH')) {
'x86_64' => '--enable-intel-sse',
'aarch64' => '--enable-arm-neon',
default => '',
}
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency} DEFAULT_INCLUDES='-I. -I" . BUILD_INCLUDE_PATH . "' LIBS= libpng16.la")
->exec('make install-libLTLIBRARIES install-data-am DESTDIR=' . BUILD_ROOT_PATH)
->cd(BUILD_LIB_PATH)
->exec('ln -sf libpng16.a libpng.a');
->make('libpng16.la', 'install-libLTLIBRARIES install-data-am', after_env_vars: ['DEFAULT_INCLUDES' => "-I{$this->source_dir} -I{$this->getIncludeDir()}"]);
shell()->cd(BUILD_LIB_PATH)->exec('ln -sf libpng16.a libpng.a');
$this->patchPkgconfPrefix(['libpng16.pc'], PKGCONF_PATCH_PREFIX);
$this->cleanLaFiles();
$this->patchLaDependencyPrefix();
}
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class watcher extends MacOSLibraryBase
{
use \SPC\builder\unix\library\watcher;
public const NAME = 'watcher';
}

View File

@@ -17,9 +17,9 @@ trait UnixLibraryTrait
* @throws FileSystemException
* @throws WrongUsageException
*/
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true, bool $include_self = true): string
{
$libs = [$this];
$libs = $include_self ? [$this] : [];
if ($recursive) {
array_unshift($libs, ...array_values($this->getDependencies(recursive: true)));
}
@@ -84,19 +84,34 @@ trait UnixLibraryTrait
}
}
/**
* remove libtool archive files
*
* @throws FileSystemException
* @throws WrongUsageException
*/
public function cleanLaFiles(): void
public function patchLaDependencyPrefix(?array $files = null): void
{
foreach ($this->getStaticLibs() as $lib) {
$filename = pathinfo($lib, PATHINFO_FILENAME) . '.la';
if (file_exists(BUILD_LIB_PATH . '/' . $filename)) {
unlink(BUILD_LIB_PATH . '/' . $filename);
logger()->info('Patching library [' . static::NAME . '] la files');
$throwOnMissing = true;
if ($files === null) {
$files = $this->getStaticLibs();
$files = array_map(fn ($name) => str_replace('.a', '.la', $name), $files);
$throwOnMissing = false;
}
foreach ($files as $name) {
$realpath = realpath(BUILD_LIB_PATH . '/' . $name);
if ($realpath === false) {
if ($throwOnMissing) {
throw new RuntimeException('Cannot find library [' . static::NAME . '] la file [' . $name . '] !');
}
logger()->warning('Cannot find library [' . static::NAME . '] la file [' . $name . '] !');
continue;
}
logger()->debug('Patching ' . $realpath);
// replace prefix
$file = FileSystem::readFile($realpath);
$file = str_replace(
' /lib/',
' ' . BUILD_LIB_PATH . '/',
$file
);
$file = preg_replace('/^libdir=.*$/m', "libdir='" . BUILD_LIB_PATH . "'", $file);
FileSystem::writeFile($realpath, $file);
}
}

View File

@@ -12,6 +12,8 @@ use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\CurlHook;
use SPC\store\Downloader;
use SPC\store\FileSystem;
use SPC\util\DependencyUtil;
use SPC\util\SPCConfigUtil;
@@ -153,13 +155,13 @@ abstract class UnixBuilderBase extends BuilderBase
// sanity check for php-cli
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
logger()->info('running cli sanity check');
[$ret, $output] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n -r "echo \"hello\";"');
[$ret, $output] = shell()->execWithResult(BUILD_BIN_PATH . '/php -n -r "echo \"hello\";"');
$raw_output = implode('', $output);
if ($ret !== 0 || trim($raw_output) !== 'hello') {
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
}
foreach ($this->getExts(false) as $ext) {
foreach ($this->getExts() as $ext) {
logger()->debug('testing ext: ' . $ext->getName());
$ext->runCliCheckUnix();
}
@@ -218,6 +220,21 @@ abstract class UnixBuilderBase extends BuilderBase
throw new RuntimeException('embed failed sanity check: run failed. Error message: ' . implode("\n", $output));
}
}
// sanity check for frankenphp
if (($build_target & BUILD_TARGET_FRANKENPHP) === BUILD_TARGET_FRANKENPHP) {
logger()->info('running frankenphp sanity check');
$frankenphp = BUILD_BIN_PATH . '/frankenphp';
if (!file_exists($frankenphp)) {
throw new RuntimeException('FrankenPHP binary not found: ' . $frankenphp);
}
[$ret, $output] = shell()
->setEnv(['LD_LIBRARY_PATH' => BUILD_LIB_PATH])
->execWithResult("{$frankenphp} version");
if ($ret !== 0 || !str_contains(implode('', $output), 'FrankenPHP')) {
throw new RuntimeException('FrankenPHP failed sanity check: ret[' . $ret . ']. out[' . implode('', $output) . ']');
}
}
}
/**
@@ -236,8 +253,8 @@ abstract class UnixBuilderBase extends BuilderBase
default => throw new RuntimeException('Deployment does not accept type ' . $type),
};
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
FileSystem::createDir(BUILD_ROOT_PATH . '/bin');
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '/bin/'));
FileSystem::createDir(BUILD_BIN_PATH);
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_BIN_PATH));
return true;
}
@@ -263,6 +280,7 @@ abstract class UnixBuilderBase extends BuilderBase
logger()->debug('Patching phpize prefix');
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
FileSystem::replaceFileStr(BUILD_LIB_PATH . '/php/build/phpize.m4', 'test "[$]$1" = "no" && $1=yes', '# test "[$]$1" = "no" && $1=yes');
}
// patch php-config
if (file_exists(BUILD_BIN_PATH . '/php-config')) {
@@ -276,4 +294,70 @@ abstract class UnixBuilderBase extends BuilderBase
FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
}
}
/**
* @throws WrongUsageException
* @throws RuntimeException
*/
protected function buildFrankenphp(): void
{
$os = match (PHP_OS_FAMILY) {
'Linux' => 'linux',
'Windows' => 'win',
'Darwin' => 'macos',
'BSD' => 'freebsd',
default => throw new RuntimeException('Unsupported OS: ' . PHP_OS_FAMILY),
};
$arch = arch2gnu(php_uname('m'));
// define executables for go and xcaddy
$xcaddy_exec = PKG_ROOT_PATH . "/go-xcaddy-{$arch}-{$os}/bin/xcaddy";
$nobrotli = $this->getLib('brotli') === null ? ',nobrotli' : '';
$nowatcher = $this->getLib('watcher') === null ? ',nowatcher' : '';
$xcaddyModules = getenv('SPC_CMD_VAR_FRANKENPHP_XCADDY_MODULES');
// make it possible to build from a different frankenphp directory!
if (!str_contains($xcaddyModules, '--with github.com/dunglas/frankenphp')) {
$xcaddyModules = '--with github.com/dunglas/frankenphp ' . $xcaddyModules;
}
if ($this->getLib('brotli') === null && str_contains($xcaddyModules, '--with github.com/dunglas/caddy-cbrotli')) {
logger()->warning('caddy-cbrotli module is enabled, but brotli library is not built. Disabling caddy-cbrotli.');
$xcaddyModules = str_replace('--with github.com/dunglas/caddy-cbrotli', '', $xcaddyModules);
}
$lrt = PHP_OS_FAMILY === 'Linux' ? '-lrt' : '';
$releaseInfo = json_decode(Downloader::curlExec('https://api.github.com/repos/php/frankenphp/releases/latest', retries: 3, hooks: [[CurlHook::class, 'setupGithubToken']]), true);
$frankenPhpVersion = $releaseInfo['tag_name'];
$libphpVersion = $this->getPHPVersion();
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
$libphpVersion = preg_replace('/\.\d$/', '', $libphpVersion);
}
$debugFlags = $this->getOption('no-strip') ? "'-w -s' " : '';
$extLdFlags = "-extldflags '-pie'";
$muslTags = '';
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') {
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000'";
$muslTags = 'static_build,';
}
$config = (new SPCConfigUtil($this))->config($this->ext_list, $this->lib_list, with_dependencies: true);
$env = [
'PATH' => PKG_ROOT_PATH . "/go-xcaddy-{$arch}-{$os}/bin:" . getenv('PATH'),
'GOROOT' => PKG_ROOT_PATH . "/go-xcaddy-{$arch}-{$os}",
'GOBIN' => PKG_ROOT_PATH . "/go-xcaddy-{$arch}-{$os}/bin",
'GOPATH' => PKG_ROOT_PATH . '/go',
'CGO_ENABLED' => '1',
'CGO_CFLAGS' => $config['cflags'],
'CGO_LDFLAGS' => "{$config['ldflags']} {$config['libs']} {$lrt}",
'XCADDY_GO_BUILD_FLAGS' => '-buildmode=pie ' .
'-ldflags \"-linkmode=external ' . $extLdFlags . ' ' . $debugFlags .
'-X \'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP ' .
"{$frankenPhpVersion} PHP {$libphpVersion} Caddy'\\\" " .
"-tags={$muslTags}nobadger,nomysql,nopgx{$nobrotli}{$nowatcher}",
'LD_LIBRARY_PATH' => BUILD_LIB_PATH,
];
shell()->cd(BUILD_BIN_PATH)
->setEnv($env)
->exec("{$xcaddy_exec} build --output frankenphp {$xcaddyModules}");
}
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait attr
{
@@ -13,14 +14,11 @@ trait attr
*/
protected function build(): void
{
shell()->cd($this->source_dir)->initializeEnv($this)
->appendEnv(['CFLAGS' => "-I{$this->getIncludeDir()}", 'LDFLAGS' => "-L{$this->getLibDir()}"])
UnixAutoconfExecutor::create($this)
->exec('libtoolize --force --copy')
->exec('./autogen.sh || autoreconf -if')
->exec('./configure --prefix= --enable-static --disable-shared --with-pic --disable-nls')
->exec("make -j {$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
->configure('--disable-nls')
->make();
$this->patchPkgconfPrefix(['libattr.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -23,6 +23,8 @@ trait brotli
->build();
$this->patchPkgconfPrefix(['libbrotlicommon.pc', 'libbrotlidec.pc', 'libbrotlienc.pc']);
FileSystem::replaceFileLineContainsString(BUILD_LIB_PATH . '/pkgconfig/libbrotlidec.pc', 'Libs: -L${libdir} -lbrotlidec', 'Libs: -L${libdir} -lbrotlidec -lbrotlicommon');
FileSystem::replaceFileLineContainsString(BUILD_LIB_PATH . '/pkgconfig/libbrotlienc.pc', 'Libs: -L${libdir} -lbrotlienc', 'Libs: -L${libdir} -lbrotlienc -lbrotlicommon');
shell()->cd(BUILD_ROOT_PATH . '/lib')->exec('ln -sf libbrotlicommon.a libbrotli.a');
foreach (FileSystem::scanDirFiles(BUILD_ROOT_PATH . '/lib/', false, true) as $filename) {
if (str_starts_with($filename, 'libbrotli') && (str_contains($filename, '.so') || str_ends_with($filename, '.dylib'))) {

View File

@@ -24,6 +24,7 @@ trait curl
->optionalLib('libssh2', fn ($lib) => "-DLIBSSH2_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DLIBSSH2_INCLUDE_DIR={$lib->getIncludeDir()}", '-DCURL_USE_LIBSSH2=OFF')
->optionalLib('nghttp2', fn ($lib) => "-DUSE_NGHTTP2=ON -DNGHTTP2_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGHTTP2_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGHTTP2=OFF')
->optionalLib('nghttp3', fn ($lib) => "-DUSE_NGHTTP3=ON -DNGHTTP3_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGHTTP3_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGHTTP3=OFF')
->optionalLib('ngtcp2', fn ($lib) => "-DUSE_NGTCP2=ON -DNGNGTCP2_LIBRARY=\"{$lib->getStaticLibFiles(style: 'cmake')}\" -DNGNGTCP2_INCLUDE_DIR={$lib->getIncludeDir()}", '-DUSE_NGTCP2=OFF')
->optionalLib('ldap', ...cmake_boolean_args('CURL_DISABLE_LDAP', true))
->optionalLib('zstd', ...cmake_boolean_args('CURL_ZSTD'))
->optionalLib('idn2', ...cmake_boolean_args('USE_LIBIDN2'))

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
trait fastlz
{
protected function build(): void
{
shell()->cd($this->source_dir)->initializeEnv($this)
->exec((getenv('CC') ?: 'cc') . ' -c -O3 -fPIC fastlz.c -o fastlz.o')
->exec((getenv('AR') ?: 'ar') . ' rcs libfastlz.a fastlz.o');
if (!copy($this->source_dir . '/fastlz.h', BUILD_INCLUDE_PATH . '/fastlz.h')) {
throw new \RuntimeException('Failed to copy fastlz.h');
}
if (!copy($this->source_dir . '/libfastlz.a', BUILD_LIB_PATH . '/libfastlz.a')) {
throw new \RuntimeException('Failed to copy libfastlz.a');
}
}
}

View File

@@ -38,7 +38,5 @@ trait freetype
' -L/lib ',
' -L' . BUILD_ROOT_PATH . '/lib '
);
$this->cleanLaFiles();
}
}

View File

@@ -4,34 +4,34 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixAutoconfExecutor;
trait gettext
{
protected function build(): void
{
$extra = $this->builder->getLib('ncurses') ? ('--with-libncurses-prefix=' . BUILD_ROOT_PATH . ' ') : '';
$extra .= $this->builder->getLib('libxml2') ? ('--with-libxml2-prefix=' . BUILD_ROOT_PATH . ' ') : '';
$autoconf = UnixAutoconfExecutor::create($this)
->optionalLib('ncurses', "--with-libncurses-prefix={$this->getBuildRootPath()}")
->optionalLib('libxml2', "--with-libxml2-prefix={$this->getBuildRootPath()}")
->addConfigureArgs(
'--disable-java',
'--disable-c++',
'--with-included-gettext',
"--with-iconv-prefix={$this->getBuildRootPath()}",
);
$zts = $this->builder->getOption('enable-zts') ? '--enable-threads=isoc+posix ' : '--disable-threads ';
// zts
if ($this->builder->getOption('enable-zts')) {
$autoconf->addConfigureArgs('--enable-threads=isoc+posix')
->appendEnv([
'CFLAGS' => '-lpthread -D_REENTRANT',
'LDFLGAS' => '-lpthread',
]);
} else {
$autoconf->addConfigureArgs('--disable-threads');
}
$cflags = $this->builder->getOption('enable-zts') ? '-lpthread -D_REENTRANT' : '';
$ldflags = $this->builder->getOption('enable-zts') ? '-lpthread' : '';
shell()->cd($this->source_dir)->initializeEnv($this)
->appendEnv(['CFLAGS' => $cflags, 'LDFLAGS' => $ldflags])
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
'--disable-java ' .
'--disable-c++ ' .
$zts .
$extra .
'--with-included-gettext ' .
'--with-libiconv-prefix=' . BUILD_ROOT_PATH . ' ' .
'--prefix=' . BUILD_ROOT_PATH
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
$autoconf->configure()->make(with_clean: true);
$this->patchLaDependencyPrefix();
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait gmp
{
@@ -15,15 +16,7 @@ trait gmp
*/
protected function build(): void
{
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static --disable-shared ' .
'--prefix='
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
UnixAutoconfExecutor::create($this)->configure()->make();
$this->patchPkgconfPrefix(['gmp.pc']);
}
}

View File

@@ -9,6 +9,7 @@ use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait imagemagick
{
@@ -18,45 +19,39 @@ trait imagemagick
*/
protected function build(): void
{
// TODO: glibc rh 10 toolset's libgomp.a was built without -fPIC -fPIE so we can't use openmp without depending on libgomp.so
$openmp = getenv('SPC_LIBC') === 'musl' ? '--enable-openmp' : '--disable-openmp';
$extra = "--without-jxl --without-x {$openmp} ";
$required_libs = '';
$optional_libs = [
'libzip' => 'zip',
'libjpeg' => 'jpeg',
'libpng' => 'png',
'libwebp' => 'webp',
'libxml2' => 'xml',
'libheif' => 'heic',
'zlib' => 'zlib',
'xz' => 'lzma',
'zstd' => 'zstd',
'freetype' => 'freetype',
'bzip2' => 'bzlib',
];
foreach ($optional_libs as $lib => $option) {
$extra .= $this->builder->getLib($lib) ? "--with-{$option} " : "--without-{$option} ";
if ($this->builder->getLib($lib) instanceof LinuxLibraryBase) {
$required_libs .= ' ' . $this->builder->getLib($lib)->getStaticLibFiles();
}
}
$ac = UnixAutoconfExecutor::create($this)
->optionalLib('libzip', ...ac_with_args('zip'))
->optionalLib('libjpeg', ...ac_with_args('jpeg'))
->optionalLib('libpng', ...ac_with_args('png'))
->optionalLib('libwebp', ...ac_with_args('webp'))
->optionalLib('libxml2', ...ac_with_args('xml'))
->optionalLib('libheif', ...ac_with_args('heic'))
->optionalLib('zlib', ...ac_with_args('zlib'))
->optionalLib('xz', ...ac_with_args('lzma'))
->optionalLib('zstd', ...ac_with_args('zstd'))
->optionalLib('freetype', ...ac_with_args('freetype'))
->optionalLib('bzip2', ...ac_with_args('bzlib'))
->addConfigureArgs(
// TODO: glibc rh 10 toolset's libgomp.a was built without -fPIC so we can't use openmp without depending on libgomp.so
getenv('SPC_LIBC') === 'glibc' && str_contains(getenv('CC'), 'devtoolset-10') ? '--disable-openmp' : '--enable-openmp',
'--without-jxl',
'--without-x',
);
// special: linux musl needs `-static`
$ldflags = ($this instanceof LinuxLibraryBase) && getenv('SPC_LIBC') !== 'glibc' ? ('-static -ldl') : '-ldl';
// libxml iconv patch
$required_libs .= $this instanceof MacOSLibraryBase ? ('-liconv') : '';
shell()->cd($this->source_dir)->initializeEnv($this)
->appendEnv(['LDFLAGS' => $ldflags, 'LIBS' => $required_libs, 'PKG_CONFIG' => '$PKG_CONFIG --static'])
->exec(
'./configure ' .
'--enable-static --disable-shared ' .
$extra .
'--prefix='
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
// special: macOS needs -iconv
$libs = $this instanceof MacOSLibraryBase ? '-liconv' : '';
$ac->appendEnv([
'LDFLAGS' => $ldflags,
'LIBS' => $libs,
'PKG_CONFIG' => '$PKG_CONFIG --static',
]);
$ac->configure()->make();
$filelist = [
'ImageMagick.pc',
'ImageMagick-7.Q16HDRI.pc',
@@ -75,5 +70,6 @@ trait imagemagick
'includearchdir=${prefix}/include/ImageMagick-7'
);
}
$this->patchLaDependencyPrefix();
}
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait ldap
{
@@ -17,33 +18,25 @@ trait ldap
protected function build(): void
{
$alt = '';
// openssl support
$alt .= $this->builder->getLib('openssl') ? '--with-tls=openssl ' : '';
// gmp support
$alt .= $this->builder->getLib('gmp') ? '--with-mp=gmp ' : '';
// libsodium support
$alt .= $this->builder->getLib('libsodium') ? '--with-argon2=libsodium ' : '--enable-argon2=no ';
f_putenv('PKG_CONFIG=' . BUILD_ROOT_PATH . '/bin/pkg-config');
f_putenv('PKG_CONFIG_PATH=' . BUILD_LIB_PATH . '/pkgconfig');
shell()->cd($this->source_dir)->initializeEnv($this)
->appendEnv(['LDFLAGS' => "-L{$this->getLibDir()}"])
->exec(
$this->builder->makeAutoconfFlags(AUTOCONF_CPPFLAGS) .
' ./configure ' .
'--enable-static ' .
'--disable-shared ' .
'--disable-slapd ' .
'--without-systemd ' .
'--without-cyrus-sasl ' .
$alt .
'--prefix='
UnixAutoconfExecutor::create($this)
->optionalLib('openssl', '--with-tls=openssl')
->optionalLib('gmp', '--with-mp=gmp')
->optionalLib('libsodium', '--with-argon2=libsodium', '--enable-argon2=no')
->addConfigureArgs(
'--disable-slapd',
'--without-systemd',
'--without-cyrus-sasl',
)
->exec('make clean')
// remove tests and doc to prevent compile failed with error: soelim not found
->appendEnv([
'LDFLAGS' => "-L{$this->getLibDir()}",
'CPPFLAGS' => "-I{$this->getIncludeDir()}",
])
->configure()
->exec('sed -i -e "s/SUBDIRS= include libraries clients servers tests doc/SUBDIRS= include libraries clients servers/g" Makefile')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
->make();
FileSystem::replaceFileLineContainsString(BUILD_LIB_PATH . '/pkgconfig/ldap.pc', 'Libs: -L${libdir} -lldap', 'Libs: -L${libdir} -lldap -llber');
$this->patchPkgconfPrefix(['ldap.pc', 'lber.pc']);
$this->patchLaDependencyPrefix();
}
}

View File

@@ -7,6 +7,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait libacl
{
@@ -29,14 +30,11 @@ trait libacl
*/
protected function build(): void
{
shell()->cd($this->source_dir)->initializeEnv($this)
->appendEnv(['CFLAGS' => "-I{$this->getIncludeDir()}", 'LDFLAGS' => "-L{$this->getLibDir()}"])
UnixAutoconfExecutor::create($this)
->exec('libtoolize --force --copy')
->exec('./autogen.sh || autoreconf -if')
->exec('./configure --prefix= --enable-static --disable-shared --disable-tests --disable-nls')
->exec("make -j {$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
->configure('--disable-nls', '--disable-tests')
->make();
$this->patchPkgconfPrefix(['libacl.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -23,6 +23,5 @@ trait libavif
->build();
// patch pkgconfig
$this->patchPkgconfPrefix(['libavif.pc']);
$this->cleanLaFiles();
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait libcares
{
@@ -24,11 +25,7 @@ trait libcares
*/
protected function build(): void
{
shell()->cd($this->source_dir)->initializeEnv($this)
->exec('./configure --prefix= --enable-static --disable-shared --disable-tests --with-pic')
->exec("make -j {$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
UnixAutoconfExecutor::create($this)->configure('--disable-tests')->make();
$this->patchPkgconfPrefix(['libcares.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -40,15 +40,19 @@ trait libevent
*/
protected function build(): void
{
UnixCMakeExecutor::create($this)
$cmake = UnixCMakeExecutor::create($this)
->addConfigureArgs(
'-DEVENT__LIBRARY_TYPE=STATIC',
'-DEVENT__DISABLE_BENCHMARK=ON',
'-DEVENT__DISABLE_THREAD_SUPPORT=ON',
'-DEVENT__DISABLE_TESTS=ON',
'-DEVENT__DISABLE_SAMPLES=ON',
)
->build();
'-DEVENT__DISABLE_MBEDTLS=ON ',
);
if (version_compare(get_cmake_version(), '4.0.0', '>=')) {
$cmake->addConfigureArgs('-DCMAKE_POLICY_VERSION_MINIMUM=3.10');
}
$cmake->build();
$this->patchPkgconfPrefix(['libevent.pc', 'libevent_core.pc', 'libevent_extra.pc', 'libevent_openssl.pc']);

View File

@@ -6,10 +6,24 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\executor\UnixCMakeExecutor;
trait libheif
{
public function patchBeforeBuild(): bool
{
if (!str_contains(file_get_contents($this->source_dir . '/CMakeLists.txt'), 'libbrotlienc')) {
FileSystem::replaceFileStr(
$this->source_dir . '/CMakeLists.txt',
'list(APPEND REQUIRES_PRIVATE "libbrotlidec")',
'list(APPEND REQUIRES_PRIVATE "libbrotlidec")' . "\n" . ' list(APPEND REQUIRES_PRIVATE "libbrotlienc")'
);
return true;
}
return false;
}
/**
* @throws RuntimeException
* @throws FileSystemException

View File

@@ -4,26 +4,13 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixAutoconfExecutor;
trait libiconv
{
protected function build(): void
{
[,,$destdir] = SEPARATED_PATH;
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
'--enable-extra-encodings ' .
'--prefix='
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . $destdir);
if (file_exists(BUILD_BIN_PATH . '/iconv')) {
unlink(BUILD_BIN_PATH . '/iconv');
}
UnixAutoconfExecutor::create($this)->configure('--enable-extra-encodings')->make();
$this->patchLaDependencyPrefix();
}
}

View File

@@ -26,6 +26,5 @@ trait libjpeg
->build();
// patch pkgconfig
$this->patchPkgconfPrefix(['libjpeg.pc', 'libturbojpeg.pc']);
$this->cleanLaFiles();
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait librdkafka
{
@@ -15,25 +16,33 @@ trait librdkafka
*/
protected function build(): void
{
$builddir = BUILD_ROOT_PATH;
$zstd_option = $this->builder->getLib('zstd') ? ("STATIC_LIB_libzstd={$builddir}/lib/libzstd.a ") : '';
shell()->cd($this->source_dir)
->exec(
$zstd_option .
'./configure ' .
'--enable-static --disable-shared --disable-curl --disable-sasl --disable-valgrind --disable-zlib --disable-ssl ' .
($zstd_option == '' ? '--disable-zstd ' : '') .
'--prefix='
UnixAutoconfExecutor::create($this)
->optionalLib(
'zstd',
function ($lib) {
putenv("STATIC_LIB_libzstd={$lib->getLibDir()}/libzstd.a");
return '';
},
'--disable-zstd'
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec("make install DESTDIR={$builddir}");
->removeConfigureArgs(
'--with-pic',
'--enable-pic',
)
->configure(
'--disable-curl',
'--disable-sasl',
'--disable-valgrind',
'--disable-zlib',
'--disable-ssl',
)
->make();
$this->patchPkgconfPrefix(['rdkafka.pc', 'rdkafka-static.pc', 'rdkafka++.pc', 'rdkafka++-static.pc']);
// remove dynamic libs
shell()
->exec("rm -rf {$builddir}/lib/*.so.*")
->exec("rm -rf {$builddir}/lib/*.so")
->exec("rm -rf {$builddir}/lib/*.dylib");
->exec("rm -rf {$this->getLibDir()}/*.so.*")
->exec("rm -rf {$this->getLibDir()}/*.so")
->exec("rm -rf {$this->getLibDir()}/*.dylib");
}
}

View File

@@ -4,16 +4,13 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixAutoconfExecutor;
trait libsodium
{
protected function build(): void
{
shell()->cd($this->source_dir)
->exec('./configure --enable-static --disable-shared --prefix=')
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
UnixAutoconfExecutor::create($this)->configure()->make();
$this->patchPkgconfPrefix(['libsodium.pc'], PKGCONF_PATCH_PREFIX);
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait libtiff
{
@@ -15,30 +16,26 @@ trait libtiff
*/
protected function build(): void
{
// zlib
$extra_libs = '--enable-zlib --with-zlib-include-dir=' . BUILD_ROOT_PATH . '/include --with-zlib-lib-dir=' . BUILD_ROOT_PATH . '/lib';
// libjpeg
$extra_libs .= ' --enable-jpeg --disable-old-jpeg --disable-jpeg12 --with-jpeg-include-dir=' . BUILD_ROOT_PATH . '/include --with-jpeg-lib-dir=' . BUILD_ROOT_PATH . '/lib';
// We disabled lzma, zstd, webp, libdeflate by default to reduce the size of the binary
$extra_libs .= ' --disable-lzma --disable-zstd --disable-webp --disable-libdeflate';
$shell = shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static --disable-shared ' .
"{$extra_libs} " .
'--disable-cxx ' .
'--prefix='
);
// TODO: Remove this check when https://gitlab.com/libtiff/libtiff/-/merge_requests/635 will be merged and released
if (file_exists($this->source_dir . '/html')) {
$shell->exec('make clean');
}
$shell
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
UnixAutoconfExecutor::create($this)
->configure(
// zlib deps
'--enable-zlib',
"--with-zlib-include-dir={$this->getIncludeDir()}",
"--with-zlib-lib-dir={$this->getLibDir()}",
// libjpeg deps
'--enable-jpeg',
'--disable-old-jpeg',
'--disable-jpeg12',
"--with-jpeg-include-dir={$this->getIncludeDir()}",
"--with-jpeg-lib-dir={$this->getLibDir()}",
// We disabled lzma, zstd, webp, libdeflate by default to reduce the size of the binary
'--disable-lzma',
'--disable-zstd',
'--disable-webp',
'--disable-libdeflate',
'--disable-cxx',
)
->make();
$this->patchPkgconfPrefix(['libtiff-4.pc']);
}
}

View File

@@ -24,8 +24,6 @@ trait libwebp
// patch pkgconfig
$this->patchPkgconfPrefix(['libsharpyuv.pc', 'libwebp.pc', 'libwebpdecoder.pc', 'libwebpdemux.pc', 'libwebpmux.pc'], PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR);
$this->patchPkgconfPrefix(['libsharpyuv.pc'], PKGCONF_PATCH_CUSTOM, ['/^includedir=.*$/m', 'includedir=${prefix}/include/webp']);
$this->cleanLaFiles();
// fix imagemagick binary linking issue
$this->patchPkgconfPrefix(['libwebp.pc'], PKGCONF_PATCH_CUSTOM, ['/-lwebp$/m', '-lwebp -lsharpyuv']);
}
}

View File

@@ -17,7 +17,13 @@ trait libxml2
public function build(): void
{
$cmake = UnixCMakeExecutor::create($this)
->optionalLib('zlib', "-DLIBXML2_WITH_ZLIB=ON -DZLIB_LIBRARY={$this->getLibDir()}/libz.a -DZLIB_INCLUDE_DIR={$this->getIncludeDir()}", '-DLIBXML2_WITH_ZLIB=OFF')
->optionalLib(
'zlib',
'-DLIBXML2_WITH_ZLIB=ON ' .
"-DZLIB_LIBRARY={$this->getLibDir()}/libz.a " .
"-DZLIB_INCLUDE_DIR={$this->getIncludeDir()}",
'-DLIBXML2_WITH_ZLIB=OFF',
)
->optionalLib('icu', ...cmake_boolean_args('LIBXML2_WITH_ICU'))
->optionalLib('xz', ...cmake_boolean_args('LIBXML2_WITH_LZMA'))
->addConfigureArgs(
@@ -35,8 +41,13 @@ trait libxml2
FileSystem::replaceFileStr(
BUILD_LIB_PATH . '/pkgconfig/libxml-2.0.pc',
'-licudata -licui18n -licuuc',
'-licui18n -licuuc -licudata'
'-lxml2 -liconv',
'-lxml2'
);
FileSystem::replaceFileStr(
BUILD_LIB_PATH . '/pkgconfig/libxml-2.0.pc',
'-lxml2',
'-lxml2 -liconv'
);
}
}

View File

@@ -8,6 +8,7 @@ use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\util\executor\UnixAutoconfExecutor;
trait libxslt
{
@@ -18,34 +19,26 @@ trait libxslt
*/
protected function build(): void
{
$required_libs = '';
foreach ($this->getDependencies() as $dep) {
if ($dep instanceof LinuxLibraryBase) {
$required_libs .= ' ' . $dep->getStaticLibFiles();
}
}
shell()->cd($this->source_dir)->initializeEnv($this)
$static_libs = $this instanceof LinuxLibraryBase ? $this->getStaticLibFiles(include_self: false) : '';
$ac = UnixAutoconfExecutor::create($this)
->appendEnv([
'CFLAGS' => "-I{$this->getIncludeDir()}",
'LDFLAGS' => "-L{$this->getLibDir()}",
'LIBS' => "{$required_libs} -lstdc++",
'LIBS' => "{$static_libs} -lstdc++",
])
->exec(
"{$this->builder->getOption('library_path')} " .
"{$this->builder->getOption('ld_library_path')} " .
'./configure ' .
'--enable-static --disable-shared ' .
'--without-python ' .
'--without-mem-debug ' .
'--without-crypto ' .
'--without-debug ' .
'--without-debugger ' .
'--with-libxml-prefix=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
'--prefix='
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . escapeshellarg(BUILD_ROOT_PATH));
->addConfigureArgs(
'--without-python',
'--without-crypto',
'--without-debug',
'--without-debugger',
"--with-libxml-prefix={$this->getBuildRootPath()}",
);
$ac->exec("{$this->builder->getOption('library_path')} {$this->builder->getOption('ld_library_path')} ./configure {$ac->getConfigureArgsString()}")->make();
$this->patchPkgconfPrefix(['libexslt.pc']);
$this->patchLaDependencyPrefix();
shell()->cd(BUILD_LIB_PATH)
->exec("ar -t libxslt.a | grep '\\.a$' | xargs -n1 ar d libxslt.a")
->exec("ar -t libexslt.a | grep '\\.a$' | xargs -n1 ar d libexslt.a");
}
}

View File

@@ -26,6 +26,10 @@ trait libyaml
protected function build(): void
{
UnixCMakeExecutor::create($this)->addConfigureArgs('-DBUILD_TESTING=OFF')->build();
$cmake = UnixCMakeExecutor::create($this)->addConfigureArgs('-DBUILD_TESTING=OFF');
if (version_compare(get_cmake_version(), '4.0.0', '>=')) {
$cmake->addConfigureArgs('-DCMAKE_POLICY_VERSION_MINIMUM=3.5');
}
$cmake->build();
}
}

View File

@@ -24,7 +24,6 @@ trait libzip
->addConfigureArgs(
'-DENABLE_GNUTLS=OFF',
'-DENABLE_MBEDTLS=OFF',
'-DBUILD_SHARED_LIBS=OFF',
'-DBUILD_DOC=OFF',
'-DBUILD_EXAMPLES=OFF',
'-DBUILD_REGRESS=OFF',

View File

@@ -5,37 +5,33 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait ncurses
{
protected function build(): void
{
$filelist = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true);
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
'--enable-overwrite ' .
'--with-curses-h ' .
'--enable-pc-files ' .
'--enable-echo ' .
'--disable-widec ' .
'--with-normal ' .
'--with-ticlib ' .
'--without-tests ' .
'--without-dlsym ' .
'--without-debug ' .
'-enable-symlinks ' .
'--bindir=' . BUILD_ROOT_PATH . '/bin ' .
'--includedir=' . BUILD_ROOT_PATH . '/include ' .
'--libdir=' . BUILD_ROOT_PATH . '/lib ' .
'--prefix=' . BUILD_ROOT_PATH
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install');
UnixAutoconfExecutor::create($this)
->configure(
'--enable-overwrite',
'--with-curses-h',
'--enable-pc-files',
'--enable-echo',
'--disable-widec',
'--with-normal',
'--with-ticlib',
'--without-tests',
'--without-dlsym',
'--without-debug',
'-enable-symlinks',
"--bindir={$this->getBinDir()}",
"--includedir={$this->getIncludeDir()}",
"--libdir={$this->getLibDir()}",
"--prefix={$this->getBuildRootPath()}",
)
->make();
$final = FileSystem::scanDirFiles(BUILD_BIN_PATH, relative: true);
// Remove the new files
$new_files = array_diff($final, $filelist);

View File

@@ -7,6 +7,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\util\executor\UnixAutoconfExecutor;
trait nghttp2
{
@@ -17,42 +18,33 @@ trait nghttp2
*/
protected function build(): void
{
$args = $this->builder->makeAutoconfArgs(static::NAME, [
'zlib' => null,
'openssl' => null,
'libxml2' => null,
'libev' => null,
'libcares' => null,
'libngtcp2' => null,
'libnghttp3' => null,
'libbpf' => null,
'libevent-openssl' => null,
'jansson' => null,
'jemalloc' => null,
'systemd' => null,
]);
if ($brotli = $this->builder->getLib('brotli')) {
/* @phpstan-ignore-next-line */
$args .= ' --with-libbrotlidec=yes LIBBROTLIDEC_CFLAGS="-I' . BUILD_ROOT_PATH . '/include" LIBBROTLIDEC_LIBS="' . $brotli->getStaticLibFiles() . '"';
/* @phpstan-ignore-next-line */
$args .= ' --with-libbrotlienc=yes LIBBROTLIENC_CFLAGS="-I' . BUILD_ROOT_PATH . '/include" LIBBROTLIENC_LIBS="' . $brotli->getStaticLibFiles() . '"';
}
[,,$destdir] = SEPARATED_PATH;
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
'--with-pic ' .
'--enable-lib-only ' .
$args . ' ' .
'--prefix='
UnixAutoconfExecutor::create($this)
->optionalLib('zlib', ...ac_with_args('zlib', true))
->optionalLib('openssl', ...ac_with_args('openssl', true))
->optionalLib('libxml2', ...ac_with_args('libxml2', true))
->optionalLib('libev', ...ac_with_args('libev', true))
->optionalLib('libcares', ...ac_with_args('libcares', true))
->optionalLib('ngtcp2', ...ac_with_args('libngtcp2', true))
->optionalLib('nghttp3', ...ac_with_args('libnghttp3', true))
// ->optionalLib('libbpf', ...ac_with_args('libbpf', true))
// ->optionalLib('libevent-openssl', ...ac_with_args('libevent-openssl', true))
// ->optionalLib('jansson', ...ac_with_args('jansson', true))
// ->optionalLib('jemalloc', ...ac_with_args('jemalloc', true))
// ->optionalLib('systemd', ...ac_with_args('systemd', true))
->optionalLib(
'brotli',
fn ($lib) => implode(' ', [
'--with-brotlidec=yes',
"LIBBROTLIDEC_CFLAGS=\"-I{$lib->getIncludeDir()}\"",
"LIBBROTLIDEC_LIBS=\"{$lib->getStaticLibFiles()}\"",
'--with-libbrotlienc=yes',
"LIBBROTLIENC_CFLAGS=\"-I{$lib->getIncludeDir()}\"",
"LIBBROTLIENC_LIBS=\"{$lib->getStaticLibFiles()}\"",
])
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec("make install DESTDIR={$destdir}");
->configure('--enable-lib-only')
->make();
$this->patchPkgconfPrefix(['libnghttp2.pc']);
$this->patchLaDependencyPrefix();
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait nghttp3
{
@@ -15,18 +16,8 @@ trait nghttp3
*/
protected function build(): void
{
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
'--with-pic ' .
'--enable-lib-only ' .
'--prefix='
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
UnixAutoconfExecutor::create($this)->configure('--enable-lib-only')->make();
$this->patchPkgconfPrefix(['libnghttp3.pc']);
$this->patchLaDependencyPrefix();
}
}

View File

@@ -7,6 +7,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\util\executor\UnixAutoconfExecutor;
trait ngtcp2
{
@@ -17,37 +18,34 @@ trait ngtcp2
*/
protected function build(): void
{
$args = $this->builder->makeAutoconfArgs(static::NAME, [
'openssl' => null,
'libev' => null,
'jemalloc' => null,
'libnghttp3' => null,
]);
if ($brotli = $this->builder->getLib('brotli')) {
/* @phpstan-ignore-next-line */
$args .= ' --with-libbrotlidec=yes LIBBROTLIDEC_CFLAGS="-I' . BUILD_ROOT_PATH . '/include" LIBBROTLIDEC_LIBS="' . $brotli->getStaticLibFiles() . '"';
/* @phpstan-ignore-next-line */
$args .= ' --with-libbrotlienc=yes LIBBROTLIENC_CFLAGS="-I' . BUILD_ROOT_PATH . '/include" LIBBROTLIENC_LIBS="' . $brotli->getStaticLibFiles() . '"';
}
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
'--with-pic ' .
'--enable-lib-only ' .
$args . ' ' .
'--prefix='
UnixAutoconfExecutor::create($this)
->optionalLib('openssl', fn ($lib) => implode(' ', [
'--with-openssl=yes',
"OPENSSL_LIBS=\"{$lib->getStaticLibFiles()}\"",
"OPENSSL_CFLAGS=\"-I{$lib->getIncludeDir()}\"",
]), '--with-openssl=no')
->optionalLib('libev', ...ac_with_args('libev', true))
->optionalLib('nghttp3', ...ac_with_args('libnghttp3', true))
->optionalLib('jemalloc', ...ac_with_args('jemalloc', true))
->optionalLib(
'brotli',
fn ($lib) => implode(' ', [
'--with-brotlidec=yes',
"LIBBROTLIDEC_CFLAGS=\"-I{$lib->getIncludeDir()}\"",
"LIBBROTLIDEC_LIBS=\"{$lib->getStaticLibFiles()}\"",
'--with-libbrotlienc=yes',
"LIBBROTLIENC_CFLAGS=\"-I{$lib->getIncludeDir()}\"",
"LIBBROTLIENC_LIBS=\"{$lib->getStaticLibFiles()}\"",
])
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
->appendEnv(['PKG_CONFIG' => '$PKG_CONFIG --static'])
->configure('--enable-lib-only')
->make();
$this->patchPkgconfPrefix(['libngtcp2.pc', 'libngtcp2_crypto_ossl.pc']);
$this->patchLaDependencyPrefix();
// on macOS, the static library may contain other static libraries?
// ld: archive member 'libssl.a' not a mach-o file in libngtcp2_crypto_ossl.a
shell()->cd(BUILD_LIB_PATH)
->exec("ar -t libngtcp2_crypto_ossl.a | grep '\\.a$' | xargs -n1 ar d libngtcp2_crypto_ossl.a");
shell()->cd(BUILD_LIB_PATH)->exec("ar -t libngtcp2_crypto_ossl.a | grep '\\.a$' | xargs -n1 ar d libngtcp2_crypto_ossl.a");
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait onig
{
@@ -15,13 +16,7 @@ trait onig
*/
protected function build(): void
{
[,,$destdir] = SEPARATED_PATH;
shell()->cd($this->source_dir)->initializeEnv($this)
->exec('./configure --enable-static --disable-shared --prefix=')
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec("make install DESTDIR={$destdir}");
UnixAutoconfExecutor::create($this)->configure()->make();
$this->patchPkgconfPrefix(['oniguruma.pc']);
}
}

View File

@@ -5,32 +5,27 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\builder\linux\library\LinuxLibraryBase;
use SPC\util\executor\UnixAutoconfExecutor;
trait pkgconfig
{
protected function build(): void
{
$cflags = PHP_OS_FAMILY !== 'Linux' ? "{$this->builder->arch_c_flags} -Wimplicit-function-declaration -Wno-int-conversion" : '';
$ldflags = !($this instanceof LinuxLibraryBase) || getenv('SPC_LIBC') === 'glibc' ? '' : '--static';
shell()->cd($this->source_dir)->initializeEnv($this)
->appendEnv(['CFLAGS' => $cflags, 'LDFLAGS' => $ldflags])
->exec(
'./configure ' .
'--disable-shared ' .
'--enable-static ' .
'--with-internal-glib ' .
'--disable-host-tool ' .
'--with-pic ' .
'--prefix=' . BUILD_ROOT_PATH . ' ' .
'--without-sysroot ' .
'--without-system-include-path ' .
'--without-system-library-path ' .
'--without-pc-path'
UnixAutoconfExecutor::create($this)
->appendEnv([
'CFLAGS' => PHP_OS_FAMILY !== 'Linux' ? '-Wimplicit-function-declaration -Wno-int-conversion' : '',
'LDFLAGS' => !($this instanceof LinuxLibraryBase) || getenv('SPC_LIBC') === 'glibc' ? '' : '--static',
])
->configure(
'--with-internal-glib',
'--disable-host-tool',
'--without-sysroot',
'--without-system-include-path',
'--without-system-library-path',
'--without-pc-path',
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install-exec');
->make(with_install: 'install-exec');
shell()->exec('strip ' . BUILD_ROOT_PATH . '/bin/pkg-config');
}
}

View File

@@ -22,7 +22,7 @@ trait postgresql
$packages = 'zlib openssl readline libxml-2.0';
$optional_packages = [
'zstd' => 'libzstd',
// 'ldap' => 'ldap',
'ldap' => 'ldap',
'libxslt' => 'libxslt',
'icu' => 'icu-i18n',
];
@@ -39,10 +39,12 @@ trait postgresql
$output = shell()->execWithResult("pkg-config --cflags-only-I --static {$packages}");
$error_exec_cnt += $output[0] === 0 ? 0 : 1;
$macos_15_bug_cflags = PHP_OS_FAMILY === 'Darwin' ? ' -Wno-unguarded-availability-new' : '';
$cflags = '';
if (!empty($output[1][0])) {
$cppflags = $output[1][0];
$macos_15_bug_cflags = PHP_OS_FAMILY === 'Darwin' ? ' -Wno-unguarded-availability-new' : '';
$envs .= " CPPFLAGS=\"{$cppflags} -fPIC -fPIE -fno-ident{$macos_15_bug_cflags}\"";
$cflags = $output[1][0];
$envs .= ' CPPFLAGS="-DPIC"';
$cflags = "{$cflags} -fno-ident{$macos_15_bug_cflags}";
}
$output = shell()->execWithResult("pkg-config --libs-only-L --static {$packages}");
$error_exec_cnt += $output[0] === 0 ? 0 : 1;
@@ -79,17 +81,19 @@ trait postgresql
}
// configure
shell()->cd($this->source_dir . '/build')
shell()->cd($this->source_dir . '/build')->initializeEnv($this)
->appendEnv(['CFLAGS' => $cflags])
->exec(
"{$envs} ../configure " .
"--prefix={$builddir} " .
'--disable-thread-safety ' .
($this->builder->getOption('enable-zts') ? '--enable-thread-safety ' : '--disable-thread-safety ') .
'--enable-coverage=no ' .
'--with-ssl=openssl ' .
'--with-readline ' .
'--with-libxml ' .
($this->builder->getLib('icu') ? '--with-icu ' : '--without-icu ') .
'--without-ldap ' .
($this->builder->getLib('ldap') ? '--with-ldap ' : '--without-ldap ') .
// '--without-ldap ' .
($this->builder->getLib('libxslt') ? '--with-libxslt ' : '--without-libxslt ') .
($this->builder->getLib('zstd') ? '--with-zstd ' : '--without-zstd ') .
'--without-lz4 ' .
@@ -98,11 +102,7 @@ trait postgresql
'--without-pam ' .
'--without-bonjour ' .
'--without-tcl '
);
// ($this->builder->getLib('ldap') ? '--with-ldap ' : '--without-ldap ') .
// build
shell()->cd($this->source_dir . '/build')
)
->exec($envs . ' make -C src/bin/pg_config install')
->exec($envs . ' make -C src/include install')
->exec($envs . ' make -C src/common install')
@@ -114,6 +114,8 @@ trait postgresql
->exec("rm -rf {$builddir}/lib/*.so.*")
->exec("rm -rf {$builddir}/lib/*.so")
->exec("rm -rf {$builddir}/lib/*.dylib");
FileSystem::replaceFileStr(BUILD_LIB_PATH . '/pkgconfig/libpq.pc', '-lldap', '-lldap -llber');
}
private function getVersion(): string

View File

@@ -8,6 +8,7 @@ use SPC\builder\macos\library\MacOSLibraryBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
use SPC\util\executor\UnixAutoconfExecutor;
trait qdbm
{
@@ -17,17 +18,9 @@ trait qdbm
*/
protected function build(): void
{
shell()->cd($this->source_dir)
->exec(
'./configure ' .
'--enable-static --disable-shared ' .
'--prefix='
)
->exec('make clean');
$ac = UnixAutoconfExecutor::create($this)->configure();
FileSystem::replaceFileRegex($this->source_dir . '/Makefile', '/MYLIBS = libqdbm.a.*/m', 'MYLIBS = libqdbm.a');
shell()->cd($this->source_dir)
->exec("make -j{$this->builder->concurrency}" . ($this instanceof MacOSLibraryBase ? ' mac' : ''))
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
$ac->make($this instanceof MacOSLibraryBase ? 'mac' : '');
$this->patchPkgconfPrefix(['qdbm.pc']);
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait readline
{
@@ -15,18 +16,12 @@ trait readline
*/
protected function build(): void
{
shell()->cd($this->source_dir)->initializeEnv($this)
->exec(
'./configure ' .
'--enable-static=yes ' .
'--enable-shared=no ' .
'--prefix= ' .
'--with-curses ' .
'--enable-multibyte=yes'
UnixAutoconfExecutor::create($this)
->configure(
'--with-curses',
'--enable-multibyte=yes',
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
->make();
$this->patchPkgconfPrefix(['readline.pc']);
}
}

View File

@@ -4,15 +4,13 @@ declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\util\executor\UnixAutoconfExecutor;
trait sqlite
{
protected function build(): void
{
shell()->cd($this->source_dir)->initializeEnv($this)
->exec('./configure --enable-static --disable-shared --prefix=')
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
UnixAutoconfExecutor::create($this)->configure()->make();
$this->patchPkgconfPrefix(['sqlite3.pc']);
}
}

View File

@@ -16,13 +16,16 @@ trait tidy
*/
protected function build(): void
{
UnixCMakeExecutor::create($this)
$cmake = UnixCMakeExecutor::create($this)
->setBuildDir("{$this->source_dir}/build-dir")
->addConfigureArgs(
'-DSUPPORT_CONSOLE_APP=OFF',
'-DBUILD_SHARED_LIB=OFF'
)
->build();
);
if (version_compare(get_cmake_version(), '4.0.0', '>=')) {
$cmake->addConfigureArgs('-DCMAKE_POLICY_VERSION_MINIMUM=3.5');
}
$cmake->build();
$this->patchPkgconfPrefix(['tidy.pc']);
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait unixodbc
{
@@ -15,21 +16,16 @@ trait unixodbc
*/
protected function build(): void
{
shell()->cd($this->source_dir)
->exec(
'./configure ' .
'--enable-static --disable-shared ' .
'--disable-debug ' .
'--disable-dependency-tracking ' .
'--with-libiconv-prefix=' . BUILD_ROOT_PATH . ' ' .
'--with-included-ltdl ' .
'--enable-gui=no ' .
'--prefix='
UnixAutoconfExecutor::create($this)
->configure(
'--disable-debug',
'--disable-dependency-tracking',
"--with-libiconv-prefix={$this->getBuildRootPath()}",
'--with-included-ltdl',
'--enable-gui=no',
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
->make();
$this->patchPkgconfPrefix(['odbc.pc', 'odbccr.pc', 'odbcinst.pc']);
$this->cleanLaFiles();
$this->patchLaDependencyPrefix();
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait watcher
{
/**
* @throws RuntimeException
* @throws FileSystemException
*/
protected function build(): void
{
shell()->cd($this->source_dir . '/watcher-c')
->initializeEnv($this)
->exec(getenv('CC') . ' -c -o libwatcher-c.o ./src/watcher-c.cpp -I ./include -I ../include -std=c++17 -Wall -Wextra -fPIC')
->exec(getenv('AR') . ' rcs libwatcher-c.a libwatcher-c.o');
copy($this->source_dir . '/watcher-c/libwatcher-c.a', BUILD_LIB_PATH . '/libwatcher-c.a');
FileSystem::createDir(BUILD_INCLUDE_PATH . '/wtr');
copy($this->source_dir . '/watcher-c/include/wtr/watcher-c.h', BUILD_INCLUDE_PATH . '/wtr/watcher-c.h');
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait xz
{
@@ -15,19 +16,14 @@ trait xz
*/
public function build(): void
{
shell()->cd($this->source_dir)
->exec(
'./configure ' .
'--enable-static ' .
'--disable-shared ' .
'--disable-scripts ' .
'--disable-doc ' .
'--with-libiconv ' .
'--prefix='
UnixAutoconfExecutor::create($this)
->configure(
'--disable-scripts',
'--disable-doc',
'--with-libiconv',
)
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
->make();
$this->patchPkgconfPrefix(['liblzma.pc']);
$this->patchLaDependencyPrefix();
}
}

View File

@@ -6,6 +6,7 @@ namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\util\executor\UnixAutoconfExecutor;
trait zlib
{
@@ -15,13 +16,7 @@ trait zlib
*/
protected function build(): void
{
[,,$destdir] = SEPARATED_PATH;
shell()->cd($this->source_dir)->initializeEnv($this)
->exec('./configure --static --prefix=')
->exec('make clean')
->exec("make -j{$this->builder->concurrency}")
->exec("make install DESTDIR={$destdir}");
UnixAutoconfExecutor::create($this)->exec("./configure --static --prefix={$this->getBuildRootPath()}")->make();
$this->patchPkgconfPrefix(['zlib.pc']);
}
}

Some files were not shown because too many files have changed in this diff Show More