2023-03-18 17:32:21 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
|
|
namespace SPC\builder\macos;
|
|
|
|
|
|
|
|
|
|
|
|
use SPC\builder\BuilderBase;
|
|
|
|
|
|
use SPC\builder\macos\library\MacOSLibraryBase;
|
|
|
|
|
|
use SPC\builder\traits\UnixBuilderTrait;
|
|
|
|
|
|
use SPC\exception\FileSystemException;
|
|
|
|
|
|
use SPC\exception\RuntimeException;
|
2023-03-29 21:39:36 +08:00
|
|
|
|
use SPC\exception\WrongUsageException;
|
2023-04-30 12:42:19 +08:00
|
|
|
|
use SPC\store\SourcePatcher;
|
2023-03-18 17:32:21 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* macOS 系统环境下的构建器
|
|
|
|
|
|
* 源于 Config,但因为感觉叫 Config 不太合适,就换成了 Builder
|
|
|
|
|
|
*/
|
|
|
|
|
|
class MacOSBuilder extends BuilderBase
|
|
|
|
|
|
{
|
|
|
|
|
|
/** 编译的 Unix 工具集 */
|
|
|
|
|
|
use UnixBuilderTrait;
|
|
|
|
|
|
|
|
|
|
|
|
/** @var bool 标记是否 patch 了 phar */
|
|
|
|
|
|
private bool $phar_patched = false;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2023-03-29 21:39:36 +08:00
|
|
|
|
* @param null|string $cc C编译器名称,如果不传入则默认使用clang
|
|
|
|
|
|
* @param null|string $cxx C++编译器名称,如果不传入则默认使用clang++
|
|
|
|
|
|
* @param null|string $arch 当前架构,如果不传入则默认使用当前系统架构
|
2023-03-18 17:32:21 +08:00
|
|
|
|
* @throws RuntimeException
|
2023-03-29 21:39:36 +08:00
|
|
|
|
* @throws WrongUsageException
|
2023-03-18 17:32:21 +08:00
|
|
|
|
*/
|
2023-05-17 22:19:28 +08:00
|
|
|
|
public function __construct(?string $cc = null, ?string $cxx = null, ?string $arch = null, bool $zts = false)
|
2023-03-18 17:32:21 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 如果是 Debug 模式,才使用 set -x 显示每条执行的命令
|
|
|
|
|
|
$this->set_x = defined('DEBUG_MODE') ? 'set -x' : 'true';
|
|
|
|
|
|
// 初始化一些默认参数
|
|
|
|
|
|
$this->cc = $cc ?? 'clang';
|
|
|
|
|
|
$this->cxx = $cxx ?? 'clang++';
|
|
|
|
|
|
$this->arch = $arch ?? php_uname('m');
|
|
|
|
|
|
$this->gnu_arch = arch2gnu($this->arch);
|
2023-05-17 22:19:28 +08:00
|
|
|
|
$this->zts = $zts;
|
2023-03-18 17:32:21 +08:00
|
|
|
|
// 根据 CPU 线程数设置编译进程数
|
|
|
|
|
|
$this->concurrency = SystemUtil::getCpuCount();
|
|
|
|
|
|
// 设置 cflags
|
|
|
|
|
|
$this->arch_c_flags = SystemUtil::getArchCFlags($this->arch);
|
|
|
|
|
|
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->arch);
|
|
|
|
|
|
// 设置 cmake
|
|
|
|
|
|
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile('Darwin', $this->arch, $this->arch_c_flags);
|
|
|
|
|
|
// 设置 configure 依赖的环境变量
|
|
|
|
|
|
$this->configure_env =
|
2023-05-10 02:04:08 +08:00
|
|
|
|
'PKG_CONFIG="' . BUILD_ROOT_PATH . '/bin/pkg-config" ' .
|
2023-03-18 17:32:21 +08:00
|
|
|
|
'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig/" ' .
|
|
|
|
|
|
"CC='{$this->cc}' " .
|
|
|
|
|
|
"CXX='{$this->cxx}' " .
|
|
|
|
|
|
"CFLAGS='{$this->arch_c_flags} -Wimplicit-function-declaration'";
|
|
|
|
|
|
|
|
|
|
|
|
// 创立 pkg-config 和放头文件的目录
|
|
|
|
|
|
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
|
|
|
|
|
|
f_mkdir(BUILD_INCLUDE_PATH, recursive: true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 生成库构建采用的 autoconf 参数列表
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $name 要构建的 lib 库名,传入仅供输出日志
|
|
|
|
|
|
* @param array $lib_specs 依赖的 lib 库的 autoconf 文件
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function makeAutoconfArgs(string $name, array $lib_specs): string
|
|
|
|
|
|
{
|
|
|
|
|
|
$ret = '';
|
|
|
|
|
|
foreach ($lib_specs as $libName => $arr) {
|
|
|
|
|
|
$lib = $this->getLib($libName);
|
|
|
|
|
|
|
|
|
|
|
|
$arr = $arr ?? [];
|
|
|
|
|
|
|
|
|
|
|
|
$disableArgs = $arr[0] ?? null;
|
|
|
|
|
|
$prefix = $arr[1] ?? null;
|
|
|
|
|
|
if ($lib instanceof MacOSLibraryBase) {
|
|
|
|
|
|
logger()->info("{$name} \033[32;1mwith\033[0;1m {$libName} support");
|
2023-04-29 18:59:47 +08:00
|
|
|
|
$ret .= '--with-' . $libName . '=yes ';
|
2023-03-18 17:32:21 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
logger()->info("{$name} \033[31;1mwithout\033[0;1m {$libName} support");
|
|
|
|
|
|
$ret .= ($disableArgs ?? "--with-{$libName}=no") . ' ';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return rtrim($ret);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 返回 macOS 系统依赖的框架列表
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param bool $asString 是否以字符串形式返回(默认为 False)
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getFrameworks(bool $asString = false): array|string
|
|
|
|
|
|
{
|
|
|
|
|
|
$libs = [];
|
|
|
|
|
|
|
|
|
|
|
|
// reorder libs
|
|
|
|
|
|
foreach ($this->libs as $lib) {
|
|
|
|
|
|
foreach ($lib->getDependencies() as $dep) {
|
|
|
|
|
|
$libs[] = $dep;
|
|
|
|
|
|
}
|
|
|
|
|
|
$libs[] = $lib;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$frameworks = [];
|
|
|
|
|
|
/** @var MacOSLibraryBase $lib */
|
|
|
|
|
|
foreach ($libs as $lib) {
|
|
|
|
|
|
array_push($frameworks, ...$lib->getFrameworks());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($asString) {
|
|
|
|
|
|
return implode(' ', array_map(fn ($x) => "-framework {$x}", $frameworks));
|
|
|
|
|
|
}
|
|
|
|
|
|
return $frameworks;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2023-07-24 23:49:52 +08:00
|
|
|
|
* @param int $build_target build target
|
|
|
|
|
|
* @param bool $bloat just raw add all lib files
|
2023-03-18 17:32:21 +08:00
|
|
|
|
* @throws FileSystemException
|
2023-07-24 23:49:52 +08:00
|
|
|
|
* @throws RuntimeException
|
|
|
|
|
|
* @throws WrongUsageException
|
2023-03-18 17:32:21 +08:00
|
|
|
|
*/
|
2023-04-23 20:31:58 +08:00
|
|
|
|
public function buildPHP(int $build_target = BUILD_TARGET_NONE, bool $bloat = false): void
|
2023-03-18 17:32:21 +08:00
|
|
|
|
{
|
2023-07-24 23:49:52 +08:00
|
|
|
|
$extra_libs = $this->getFrameworks(true) . ' ' . ($this->hasCppExtension() ? '-lc++' : '');
|
2023-03-18 17:32:21 +08:00
|
|
|
|
if (!$bloat) {
|
|
|
|
|
|
$extra_libs .= implode(' ', $this->getAllStaticLibFiles());
|
|
|
|
|
|
} else {
|
|
|
|
|
|
logger()->info('bloat linking');
|
|
|
|
|
|
$extra_libs .= implode(
|
|
|
|
|
|
' ',
|
|
|
|
|
|
array_map(
|
|
|
|
|
|
fn ($x) => "-Wl,-force_load,{$x}",
|
|
|
|
|
|
array_filter($this->getAllStaticLibFiles())
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// patch before configure
|
2023-04-30 12:42:19 +08:00
|
|
|
|
SourcePatcher::patchPHPBuildconf($this);
|
2023-03-18 17:32:21 +08:00
|
|
|
|
|
2023-04-15 18:45:34 +08:00
|
|
|
|
shell()->cd(SOURCE_PATH . '/php-src')->exec('./buildconf --force');
|
2023-03-18 17:32:21 +08:00
|
|
|
|
|
2023-04-30 12:42:19 +08:00
|
|
|
|
SourcePatcher::patchPHPConfigure($this);
|
2023-03-18 17:32:21 +08:00
|
|
|
|
|
|
|
|
|
|
if ($this->getLib('libxml2') || $this->getExt('iconv')) {
|
2023-03-18 17:39:08 +08:00
|
|
|
|
$extra_libs .= ' -liconv';
|
2023-03-18 17:32:21 +08:00
|
|
|
|
}
|
2023-05-10 02:04:08 +08:00
|
|
|
|
|
2023-05-04 11:29:55 +08:00
|
|
|
|
if ($this->getPHPVersionID() < 80000) {
|
|
|
|
|
|
$json_74 = '--enable-json ';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$json_74 = '';
|
|
|
|
|
|
}
|
2023-03-18 17:32:21 +08:00
|
|
|
|
|
2023-04-15 18:45:34 +08:00
|
|
|
|
shell()->cd(SOURCE_PATH . '/php-src')
|
|
|
|
|
|
->exec(
|
|
|
|
|
|
'./configure ' .
|
|
|
|
|
|
'--prefix= ' .
|
|
|
|
|
|
'--with-valgrind=no ' . // 不检测内存泄漏
|
|
|
|
|
|
'--enable-shared=no ' .
|
|
|
|
|
|
'--enable-static=yes ' .
|
|
|
|
|
|
"CFLAGS='{$this->arch_c_flags} -Werror=unknown-warning-option' " .
|
|
|
|
|
|
'--disable-all ' .
|
|
|
|
|
|
'--disable-cgi ' .
|
|
|
|
|
|
'--disable-phpdbg ' .
|
|
|
|
|
|
'--enable-cli ' .
|
2023-04-23 20:31:58 +08:00
|
|
|
|
'--enable-fpm ' .
|
2023-05-04 11:29:55 +08:00
|
|
|
|
$json_74 .
|
2023-04-15 18:45:34 +08:00
|
|
|
|
'--enable-micro ' .
|
|
|
|
|
|
($this->zts ? '--enable-zts' : '') . ' ' .
|
|
|
|
|
|
$this->makeExtensionArgs() . ' ' .
|
|
|
|
|
|
$this->configure_env
|
|
|
|
|
|
);
|
2023-03-18 17:32:21 +08:00
|
|
|
|
|
2023-04-30 12:42:19 +08:00
|
|
|
|
SourcePatcher::patchPHPAfterConfigure($this);
|
|
|
|
|
|
|
2023-03-26 22:27:51 +08:00
|
|
|
|
$this->cleanMake();
|
2023-03-18 17:32:21 +08:00
|
|
|
|
|
2023-04-23 20:31:58 +08:00
|
|
|
|
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
|
|
|
|
|
logger()->info('building cli');
|
|
|
|
|
|
$this->buildCli($extra_libs);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (($build_target & BUILD_TARGET_FPM) === BUILD_TARGET_FPM) {
|
|
|
|
|
|
logger()->info('building fpm');
|
|
|
|
|
|
$this->buildFpm($extra_libs);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
|
|
|
|
|
logger()->info('building micro');
|
|
|
|
|
|
$this->buildMicro($extra_libs);
|
2023-03-18 17:32:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (php_uname('m') === $this->arch) {
|
2023-04-23 20:31:58 +08:00
|
|
|
|
$this->sanityCheck($build_target);
|
2023-03-18 17:32:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($this->phar_patched) {
|
2023-05-01 12:50:01 +08:00
|
|
|
|
SourcePatcher::patchMicro(['phar'], true);
|
2023-03-18 17:32:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2023-04-23 20:31:58 +08:00
|
|
|
|
* 构建 cli
|
2023-03-18 17:32:21 +08:00
|
|
|
|
*
|
|
|
|
|
|
* @throws RuntimeException
|
2023-04-23 20:31:58 +08:00
|
|
|
|
* @throws FileSystemException
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function buildCli(string $extra_libs): void
|
|
|
|
|
|
{
|
2023-05-10 21:59:33 +08:00
|
|
|
|
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
|
|
|
|
|
$shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" cli");
|
|
|
|
|
|
if ($this->strip) {
|
|
|
|
|
|
$shell->exec('dsymutil -f sapi/cli/php')->exec('strip sapi/cli/php');
|
|
|
|
|
|
}
|
2023-04-23 20:31:58 +08:00
|
|
|
|
$this->deployBinary(BUILD_TARGET_CLI);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 构建 phpmicro
|
|
|
|
|
|
*
|
|
|
|
|
|
* @throws FileSystemException|RuntimeException
|
2023-03-18 17:32:21 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public function buildMicro(string $extra_libs): void
|
|
|
|
|
|
{
|
2023-03-18 20:08:54 +08:00
|
|
|
|
if ($this->getPHPVersionID() < 80000) {
|
|
|
|
|
|
throw new RuntimeException('phpmicro only support PHP >= 8.0!');
|
|
|
|
|
|
}
|
2023-03-18 17:32:21 +08:00
|
|
|
|
if ($this->getExt('phar')) {
|
|
|
|
|
|
$this->phar_patched = true;
|
2023-05-01 12:50:01 +08:00
|
|
|
|
SourcePatcher::patchMicro(['phar']);
|
2023-03-18 17:32:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-03 20:47:24 +08:00
|
|
|
|
shell()->cd(SOURCE_PATH . '/php-src')
|
2023-05-10 21:59:33 +08:00
|
|
|
|
->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" " . ($this->strip ? 'STRIP="dsymutil -f " ' : '') . 'micro');
|
2023-04-23 20:31:58 +08:00
|
|
|
|
$this->deployBinary(BUILD_TARGET_MICRO);
|
2023-03-18 17:32:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2023-04-23 20:31:58 +08:00
|
|
|
|
* 构建 fpm
|
2023-03-18 17:32:21 +08:00
|
|
|
|
*
|
|
|
|
|
|
* @throws RuntimeException
|
2023-04-03 20:47:24 +08:00
|
|
|
|
* @throws FileSystemException
|
2023-03-18 17:32:21 +08:00
|
|
|
|
*/
|
2023-04-23 20:31:58 +08:00
|
|
|
|
public function buildFpm(string $extra_libs): void
|
2023-03-18 17:32:21 +08:00
|
|
|
|
{
|
2023-05-10 21:59:33 +08:00
|
|
|
|
$shell = shell()->cd(SOURCE_PATH . '/php-src');
|
|
|
|
|
|
$shell->exec("make -j{$this->concurrency} EXTRA_CFLAGS=\"-g -Os -fno-ident\" EXTRA_LIBS=\"{$extra_libs} -lresolv\" fpm");
|
|
|
|
|
|
if ($this->strip) {
|
|
|
|
|
|
$shell->exec('dsymutil -f sapi/fpm/php-fpm')->exec('strip sapi/fpm/php-fpm');
|
|
|
|
|
|
}
|
2023-04-23 20:31:58 +08:00
|
|
|
|
$this->deployBinary(BUILD_TARGET_FPM);
|
2023-03-18 20:08:54 +08:00
|
|
|
|
}
|
2023-03-18 17:32:21 +08:00
|
|
|
|
}
|