source_dir = $source_dir ?? (SOURCE_PATH . '/' . static::NAME); } /** * 获取 lib 库的根目录 */ public function getSourceDir(): string { return $this->source_dir; } /** * 获取当前 lib 库的所有依赖列表 * * @param bool $recursive 是否递归获取(默认为 False) * @return array 依赖的 Map */ 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; } /** * 计算依赖列表,不符合依赖将抛出异常 * * @throws RuntimeException * @throws FileSystemException */ public function calcDependency(): void { // 先从配置文件添加依赖,这里根据不同的操作系统分别选择不同的元信息 /* 选择规则: 如果是 Windows 系统,则依次尝试有无 lib-depends-windows、lib-depends-win、lib-depends。 如果是 macOS 系统,则依次尝试 lib-depends-darwin、lib-depends-unix、lib-depends。 如果是 Linux 系统,则依次尝试 lib-depends-linux、lib-depends-unix、lib-depends。 */ 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); } } /** * 获取当前库编译出来获取到的静态库文件列表 * * @return string[] 获取编译出来后的需要的静态库文件列表 * @throws FileSystemException * @throws RuntimeException */ public function getStaticLibs(): array { return Config::getLib(static::NAME, 'static-libs', []); } /** * 获取当前 lib 编译出来的 C Header 文件列表 * * @return string[] 获取编译出来后需要的 C Header 文件列表 * @throws FileSystemException * @throws RuntimeException */ public function getHeaders(): array { return Config::getLib(static::NAME, 'headers', []); } /** * 证明该库是否已编译好且就绪,如果没有就绪,内部会调用 build 来进行构建该库 * * @throws RuntimeException * @throws FileSystemException */ public function tryBuild(bool $force_build = false): int { // 传入 true,表明直接编译 if ($force_build) { logger()->info('Building required library [' . static::NAME . ']'); $this->build(); return BUILD_STATUS_OK; } // 看看这些库是不是存在,如果不存在,则调用编译并返回结果状态 foreach ($this->getStaticLibs() as $name) { if (!file_exists(BUILD_LIB_PATH . "/{$name}")) { $this->tryBuild(true); return BUILD_STATUS_OK; } } // 头文件同理 foreach ($this->getHeaders() as $name) { if (!file_exists(BUILD_INCLUDE_PATH . "/{$name}")) { $this->tryBuild(true); return BUILD_STATUS_OK; } } // 到这里说明所有的文件都存在,就跳过编译 return BUILD_STATUS_ALREADY; } /** * 获取构建当前 lib 的 Builder 对象 */ abstract public function getBuilder(): BuilderBase; /** * 构建该库需要调用的命令和操作 * * @throws RuntimeException */ abstract protected function build(); /** * 添加 lib 库的依赖库 * * @param string $name 依赖名称 * @param bool $optional 是否是可选依赖(默认为 False) * @throws RuntimeException */ protected function addLibraryDependency(string $name, bool $optional = false): void { // Log::i("add $name as dep of {$this->name}"); $dep_lib = $this->getBuilder()->getLib($name); if (!$dep_lib) { if (!$optional) { throw new RuntimeException(static::NAME . " requires library {$name}"); } logger()->debug('enabling ' . static::NAME . " without {$name}"); } else { $this->dependencies[$name] = $dep_lib; } } }