static-php-cli/src/SPC/util/PkgConfigUtil.php

127 lines
4.3 KiB
PHP
Raw Normal View History

2025-07-22 17:23:13 +08:00
<?php
declare(strict_types=1);
namespace SPC\util;
use SPC\exception\ExecutionException;
2025-07-22 17:23:13 +08:00
/**
* Utility class for pkg-config operations
*
* This class provides methods to interact with pkg-config to get
* compilation flags and library information for building extensions.
*/
2025-07-22 17:23:13 +08:00
class PkgConfigUtil
{
/**
* Find the pkg-config executable which is compatible with static builds.
*
* @return null|string Path to pkg-config executable, or null if not found
*/
public static function findPkgConfig(): ?string
{
// Find pkg-config executable
$find_list = [
PKG_ROOT_PATH . '/bin/pkg-config',
BUILD_BIN_PATH . '/pkg-config',
];
$found = null;
foreach ($find_list as $file) {
if (file_exists($file) && is_executable($file)) {
$found = $file;
break;
}
}
return $found;
}
/**
* Returns the version of a module.
* This method uses `pkg-config --modversion` to get the version of the specified module.
*
* @param string $pkg_config_str .pc file str, accepts multiple files
* @return string version string, e.g. "1.2.3"
*/
public static function getModuleVersion(string $pkg_config_str): string
{
$result = self::execWithResult("pkg-config --modversion {$pkg_config_str}");
return trim($result);
}
2025-07-22 17:23:13 +08:00
/**
* Get CFLAGS from pkg-config
*
* Returns --cflags-only-other output from pkg-config.
2025-07-22 17:23:13 +08:00
* The reason we return the string is we cannot use array_unique() on cflags,
* some cflags may contains spaces.
*
* @param string $pkg_config_str .pc file string, accepts multiple files
* @return string CFLAGS string, e.g. "-Wno-implicit-int-float-conversion ..."
2025-07-22 17:23:13 +08:00
*/
public static function getCflags(string $pkg_config_str): string
{
2026-02-20 08:42:30 +07:00
$static = getenv('SPC_LINK_STATIC') ? '--static' : '';
2025-07-22 17:23:13 +08:00
// get other things
2026-02-19 22:09:42 +07:00
$result = self::execWithResult("pkg-config {$static} --cflags-only-other {$pkg_config_str}");
2025-07-22 17:23:13 +08:00
return trim($result);
}
/**
* Get library flags from pkg-config
*
2025-07-22 17:23:13 +08:00
* Returns --libs-only-l and --libs-only-other output.
* The reason we return the array is to avoid duplicate lib defines.
*
* @param string $pkg_config_str .pc file string, accepts multiple files
* @return array Unique libs array, e.g. [-lz, -lxml, ...]
2025-07-22 17:23:13 +08:00
*/
2025-07-23 09:53:31 +07:00
public static function getLibsArray(string $pkg_config_str): array
2025-07-22 17:23:13 +08:00
{
// Use this instead of shell() to avoid unnecessary outputs
2026-02-20 08:42:30 +07:00
$static = getenv('SPC_LINK_STATIC') ? '--static' : '';
2026-02-19 22:09:42 +07:00
$result = self::execWithResult("pkg-config {$static} --libs-only-l {$pkg_config_str}");
2025-07-22 17:23:13 +08:00
$libs = explode(' ', trim($result));
// get other things
2026-02-19 22:09:42 +07:00
$result = self::execWithResult("pkg-config {$static} --libs-only-other {$pkg_config_str}");
2025-07-22 17:23:13 +08:00
// convert libxxx.a to -L{path} -lxxx
$exp = explode(' ', trim($result));
foreach ($exp as $item) {
if (str_starts_with($item, '-L')) {
$libs[] = $item;
continue;
}
2025-07-22 17:23:13 +08:00
// if item ends with .a, convert it to -lxxx
if (str_ends_with($item, '.a') && (str_starts_with($item, 'lib') || str_starts_with($item, BUILD_LIB_PATH))) {
2025-07-22 17:23:13 +08:00
$name = pathinfo($item, PATHINFO_BASENAME);
$name = substr($name, 3, -2); // remove 'lib' prefix and '.a' suffix
$shortlib = "-l{$name}";
if (!in_array($shortlib, $libs)) {
$libs[] = $shortlib;
}
} elseif (!in_array($item, $libs)) {
2025-07-22 17:23:13 +08:00
$libs[] = $item;
}
}
2025-07-22 22:25:21 +08:00
// enhancement for linker
return array_reverse(array_unique(array_reverse($libs)));
2025-07-22 17:23:13 +08:00
}
/**
* Execute pkg-config command and return result
*
* @param string $cmd The pkg-config command to execute
* @return string The command output
*/
2025-07-22 17:23:13 +08:00
private static function execWithResult(string $cmd): string
{
f_exec($cmd, $output, $result_code);
if ($result_code !== 0) {
throw new ExecutionException($cmd, "pkg-config command failed with code: {$result_code}");
2025-07-22 17:23:13 +08:00
}
return implode("\n", $output);
}
}