static-php-cli/src/SPC/builder/LibraryBase.php

202 lines
5.8 KiB
PHP
Raw Normal View History

2023-03-18 17:32:21 +08:00
<?php
declare(strict_types=1);
namespace SPC\builder;
use SPC\builder\macos\library\MacOSLibraryBase;
2023-03-18 17:32:21 +08:00
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
2023-03-18 17:32:21 +08:00
use SPC\store\Config;
abstract class LibraryBase
{
/** @var string */
2023-03-18 17:32:21 +08:00
public const NAME = 'unknown';
protected string $source_dir;
protected array $dependencies = [];
/**
* @throws RuntimeException
*/
public function __construct(?string $source_dir = null)
{
if (static::NAME === 'unknown') {
throw new RuntimeException('no unknown!!!!!');
}
$this->source_dir = $source_dir ?? (SOURCE_PATH . '/' . static::NAME);
}
/**
* Get current lib source root dir.
2023-03-18 17:32:21 +08:00
*/
public function getSourceDir(): string
{
return $this->source_dir;
}
/**
* Get current lib dependencies.
2023-03-18 17:32:21 +08:00
*
* @return array<string, LibraryBase>
2023-03-18 17:32:21 +08:00
*/
public function getDependencies(bool $recursive = false): array
{
// 非递归情况下直接返回通过 addLibraryDependency 方法添加的依赖
if (!$recursive) {
return $this->dependencies;
}
$deps = [];
$added = 1;
while ($added !== 0) {
$added = 0;
foreach ($this->dependencies as $depName => $dep) {
foreach ($dep->getDependencies(true) as $depdepName => $depdep) {
if (!in_array($depdepName, array_keys($deps), true)) {
$deps[$depdepName] = $depdep;
++$added;
}
}
if (!in_array($depName, array_keys($deps), true)) {
$deps[$depName] = $dep;
}
}
}
return $deps;
}
/**
* Calculate dependencies for current library.
2023-03-18 17:32:21 +08:00
*
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
2023-03-18 17:32:21 +08:00
*/
public function calcDependency(): void
{
// Add dependencies from the configuration file. Here, choose different metadata based on the operating system.
2023-03-18 17:32:21 +08:00
/*
Rules:
If it is a Windows system, try the following dependencies in order: lib-depends-windows, lib-depends-win, lib-depends.
If it is a macOS system, try the following dependencies in order: lib-depends-darwin, lib-depends-unix, lib-depends.
If it is a Linux system, try the following dependencies in order: lib-depends-linux, lib-depends-unix, lib-depends.
*/
2023-03-18 17:32:21 +08:00
foreach (Config::getLib(static::NAME, 'lib-depends', []) as $dep_name) {
$this->addLibraryDependency($dep_name);
}
foreach (Config::getLib(static::NAME, 'lib-suggests', []) as $dep_name) {
$this->addLibraryDependency($dep_name, true);
}
}
/**
* Get config static libs.
2023-03-18 17:32:21 +08:00
*
* @throws FileSystemException
* @throws WrongUsageException
2023-03-18 17:32:21 +08:00
*/
public function getStaticLibs(): array
{
return Config::getLib(static::NAME, 'static-libs', []);
}
/**
* Get config headers.
2023-03-18 17:32:21 +08:00
*
* @throws FileSystemException
* @throws WrongUsageException
2023-03-18 17:32:21 +08:00
*/
public function getHeaders(): array
{
return Config::getLib(static::NAME, 'headers', []);
}
/**
* Try to build this library, before build, we check first.
*
* BUILD_STATUS_OK if build success
* BUILD_STATUS_ALREADY if already built
* BUILD_STATUS_FAILED if build failed
2023-03-18 17:32:21 +08:00
*
* @throws RuntimeException
* @throws FileSystemException
* @throws WrongUsageException
2023-03-18 17:32:21 +08:00
*/
public function tryBuild(bool $force_build = false): int
{
// force means just build
2023-03-18 17:32:21 +08:00
if ($force_build) {
2023-04-23 20:31:58 +08:00
logger()->info('Building required library [' . static::NAME . ']');
$this->patchBeforeBuild();
2023-03-18 17:32:21 +08:00
$this->build();
return BUILD_STATUS_OK;
}
// check if these libraries exist, if not, invoke compilation and return the result status
2023-03-18 17:32:21 +08:00
foreach ($this->getStaticLibs() as $name) {
if (!file_exists(BUILD_LIB_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
}
// header files the same
2023-03-18 17:32:21 +08:00
foreach ($this->getHeaders() as $name) {
if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
}
// pkg-config is treated specially. If it is pkg-config, check if the pkg-config binary exists
if ($this instanceof MacOSLibraryBase && static::NAME === 'pkg-config' && !file_exists(BUILD_ROOT_PATH . '/bin/pkg-config')) {
$this->tryBuild(true);
return BUILD_STATUS_OK;
}
// if all the files exist at this point, skip the compilation process
2023-03-18 17:32:21 +08:00
return BUILD_STATUS_ALREADY;
}
/**
* Patch before build, overwrite this and return true to patch libs.
*/
public function patchBeforeBuild(): bool
{
return false;
}
/**
* Get current builder object.
2023-03-18 17:32:21 +08:00
*/
abstract public function getBuilder(): BuilderBase;
/**
* Build this library.
2023-03-18 17:32:21 +08:00
*
* @throws RuntimeException
*/
abstract protected function build();
/**
* Add lib dependency
2023-03-18 17:32:21 +08:00
*
* @throws RuntimeException
*/
protected function addLibraryDependency(string $name, bool $optional = false): void
{
$dep_lib = $this->getBuilder()->getLib($name);
if ($dep_lib) {
2023-03-18 17:32:21 +08:00
$this->dependencies[$name] = $dep_lib;
return;
}
if (!$optional) {
throw new RuntimeException(static::NAME . " requires library {$name}");
2023-03-18 17:32:21 +08:00
}
logger()->debug('enabling ' . static::NAME . " without {$name}");
2023-03-18 17:32:21 +08:00
}
}