2024-12-10 23:06:47 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace SPC\util;
|
|
|
|
|
|
|
|
|
|
use SPC\builder\BuilderBase;
|
|
|
|
|
use SPC\builder\BuilderProvider;
|
|
|
|
|
use SPC\builder\macos\MacOSBuilder;
|
2025-04-18 14:38:22 +08:00
|
|
|
use SPC\exception\FileSystemException;
|
|
|
|
|
use SPC\exception\RuntimeException;
|
|
|
|
|
use SPC\exception\WrongUsageException;
|
2024-12-10 23:06:47 +08:00
|
|
|
use SPC\store\Config;
|
|
|
|
|
use Symfony\Component\Console\Input\ArgvInput;
|
|
|
|
|
|
|
|
|
|
class SPCConfigUtil
|
|
|
|
|
{
|
2025-03-26 12:38:53 +08:00
|
|
|
private ?BuilderBase $builder = null;
|
|
|
|
|
|
|
|
|
|
public function __construct(?BuilderBase $builder = null)
|
2024-12-10 23:06:47 +08:00
|
|
|
{
|
2025-03-26 12:38:53 +08:00
|
|
|
if ($builder !== null) {
|
|
|
|
|
$this->builder = $builder; // BuilderProvider::makeBuilderByInput($input ?? new ArgvInput());
|
2024-12-10 23:06:47 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-18 14:38:22 +08:00
|
|
|
/**
|
|
|
|
|
* Generate configuration for building PHP extensions.
|
|
|
|
|
*
|
|
|
|
|
* @param array $extensions Extension name list
|
|
|
|
|
* @param array $libraries Additional library name list
|
|
|
|
|
* @param bool $include_suggest_ext Include suggested extensions
|
|
|
|
|
* @param bool $include_suggest_lib Include suggested libraries
|
|
|
|
|
* @return array{
|
|
|
|
|
* cflags: string,
|
|
|
|
|
* ldflags: string,
|
|
|
|
|
* libs: string
|
|
|
|
|
* }
|
|
|
|
|
* @throws \ReflectionException
|
|
|
|
|
* @throws FileSystemException
|
|
|
|
|
* @throws RuntimeException
|
|
|
|
|
* @throws WrongUsageException
|
|
|
|
|
* @throws \Throwable
|
|
|
|
|
*/
|
2025-06-07 23:00:26 +07:00
|
|
|
public function config(array $extensions = [], array $libraries = [], bool $include_suggest_ext = false, bool $include_suggest_lib = false, bool $with_dependencies = false): array
|
2024-12-10 23:06:47 +08:00
|
|
|
{
|
|
|
|
|
[$extensions, $libraries] = DependencyUtil::getExtsAndLibs($extensions, $libraries, $include_suggest_ext, $include_suggest_lib);
|
|
|
|
|
|
|
|
|
|
ob_start();
|
2025-03-26 12:38:53 +08:00
|
|
|
if ($this->builder === null) {
|
|
|
|
|
$this->builder = BuilderProvider::makeBuilderByInput(new ArgvInput());
|
|
|
|
|
$this->builder->proveLibs($libraries);
|
2025-04-18 14:50:58 +08:00
|
|
|
$this->builder->proveExts($extensions, skip_extract: true);
|
2025-03-26 12:38:53 +08:00
|
|
|
}
|
2024-12-10 23:06:47 +08:00
|
|
|
ob_get_clean();
|
|
|
|
|
$ldflags = $this->getLdflagsString();
|
2025-05-22 12:27:41 +07:00
|
|
|
$libs = $this->getLibsString($libraries, $with_dependencies);
|
2025-06-28 16:36:05 +08:00
|
|
|
if (SPCTarget::isTarget(SPCTarget::MACHO)) {
|
2025-06-12 01:16:57 +08:00
|
|
|
$libs .= " {$this->getFrameworksString($extensions)}";
|
|
|
|
|
}
|
2024-12-10 23:06:47 +08:00
|
|
|
$cflags = $this->getIncludesString();
|
|
|
|
|
|
|
|
|
|
// embed
|
2025-06-12 01:16:57 +08:00
|
|
|
$libs = trim("-lphp -lc {$libs}");
|
2024-12-10 23:06:47 +08:00
|
|
|
$extra_env = getenv('SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS');
|
|
|
|
|
if (is_string($extra_env)) {
|
2025-03-10 00:39:20 +08:00
|
|
|
$libs .= ' ' . trim($extra_env, '"');
|
2024-12-10 23:06:47 +08:00
|
|
|
}
|
|
|
|
|
// c++
|
|
|
|
|
if ($this->builder->hasCpp()) {
|
|
|
|
|
$libs .= $this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++';
|
|
|
|
|
}
|
2025-03-20 07:27:38 +01:00
|
|
|
// mimalloc must come first
|
|
|
|
|
if (str_contains($libs, BUILD_LIB_PATH . '/mimalloc.o')) {
|
|
|
|
|
$libs = BUILD_LIB_PATH . '/mimalloc.o ' . str_replace(BUILD_LIB_PATH . '/mimalloc.o', '', $libs);
|
|
|
|
|
}
|
2024-12-10 23:06:47 +08:00
|
|
|
return [
|
2025-03-27 11:12:19 +07:00
|
|
|
'cflags' => trim(getenv('CFLAGS') . ' ' . $cflags),
|
|
|
|
|
'ldflags' => trim(getenv('LDFLAGS') . ' ' . $ldflags),
|
|
|
|
|
'libs' => trim(getenv('LIBS') . ' ' . $libs),
|
2024-12-10 23:06:47 +08:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getIncludesString(): string
|
|
|
|
|
{
|
|
|
|
|
$base = BUILD_INCLUDE_PATH;
|
|
|
|
|
$php_embed_includes = [
|
|
|
|
|
"-I{$base}",
|
|
|
|
|
"-I{$base}/php",
|
|
|
|
|
"-I{$base}/php/main",
|
|
|
|
|
"-I{$base}/php/TSRM",
|
|
|
|
|
"-I{$base}/php/Zend",
|
|
|
|
|
"-I{$base}/php/ext",
|
|
|
|
|
];
|
|
|
|
|
return implode(' ', $php_embed_includes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getLdflagsString(): string
|
|
|
|
|
{
|
|
|
|
|
return '-L' . BUILD_LIB_PATH;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-22 12:27:41 +07:00
|
|
|
private function getLibsString(array $libraries, bool $withDependencies = false): string
|
2024-12-10 23:06:47 +08:00
|
|
|
{
|
|
|
|
|
$short_name = [];
|
|
|
|
|
foreach (array_reverse($libraries) as $library) {
|
|
|
|
|
$libs = Config::getLib($library, 'static-libs', []);
|
|
|
|
|
foreach ($libs as $lib) {
|
2025-05-22 12:27:41 +07:00
|
|
|
if ($withDependencies) {
|
|
|
|
|
$noExt = str_replace('.a', '', $lib);
|
|
|
|
|
$requiredLibs = [];
|
|
|
|
|
$pkgconfFile = BUILD_LIB_PATH . "/pkgconfig/{$noExt}.pc";
|
|
|
|
|
if (file_exists($pkgconfFile)) {
|
|
|
|
|
$lines = file($pkgconfFile);
|
|
|
|
|
foreach ($lines as $value) {
|
|
|
|
|
if (str_starts_with($value, 'Libs')) {
|
|
|
|
|
$items = explode(' ', $value);
|
|
|
|
|
foreach ($items as $item) {
|
|
|
|
|
$item = trim($item);
|
|
|
|
|
if (str_starts_with($item, '-l')) {
|
|
|
|
|
$requiredLibs[] = $item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-22 12:45:06 +07:00
|
|
|
} else {
|
2025-05-22 12:44:48 +07:00
|
|
|
$requiredLibs[] = $this->getShortLibName($lib);
|
|
|
|
|
}
|
2025-05-22 12:27:41 +07:00
|
|
|
foreach ($requiredLibs as $requiredLib) {
|
|
|
|
|
if (!in_array($requiredLib, $short_name)) {
|
|
|
|
|
$short_name[] = $requiredLib;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-22 12:29:19 +07:00
|
|
|
} else {
|
2025-05-22 12:27:41 +07:00
|
|
|
$short_name[] = $this->getShortLibName($lib);
|
|
|
|
|
}
|
2024-12-10 23:06:47 +08:00
|
|
|
}
|
|
|
|
|
if (PHP_OS_FAMILY !== 'Darwin') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
foreach (Config::getLib($library, 'frameworks', []) as $fw) {
|
|
|
|
|
$ks = '-framework ' . $fw;
|
|
|
|
|
if (!in_array($ks, $short_name)) {
|
|
|
|
|
$short_name[] = $ks;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return implode(' ', $short_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getShortLibName(string $lib): string
|
|
|
|
|
{
|
|
|
|
|
if (!str_starts_with($lib, 'lib') || !str_ends_with($lib, '.a')) {
|
|
|
|
|
return BUILD_LIB_PATH . '/' . $lib;
|
|
|
|
|
}
|
|
|
|
|
// get short name
|
|
|
|
|
return '-l' . substr($lib, 3, -2);
|
|
|
|
|
}
|
2025-06-12 01:16:57 +08:00
|
|
|
|
|
|
|
|
private function getFrameworksString(array $extensions): string
|
|
|
|
|
{
|
|
|
|
|
$list = [];
|
|
|
|
|
foreach ($extensions as $extension) {
|
|
|
|
|
foreach (Config::getExt($extension, 'frameworks', []) as $fw) {
|
|
|
|
|
$ks = '-framework ' . $fw;
|
|
|
|
|
if (!in_array($ks, $list)) {
|
|
|
|
|
$list[] = $ks;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return implode(' ', $list);
|
|
|
|
|
}
|
2024-12-10 23:06:47 +08:00
|
|
|
}
|