mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-17 20:34:51 +08:00
Compare commits
7 Commits
4fb6d8cafd
...
17e0265ed0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17e0265ed0 | ||
|
|
da03db051d | ||
|
|
357b25905b | ||
|
|
e62cefa9e5 | ||
|
|
fd835deb8d | ||
|
|
063b55ae0d | ||
|
|
79efecb5a9 |
@ -154,6 +154,9 @@
|
||||
"headers": [
|
||||
"libxml2"
|
||||
],
|
||||
"lib-depends": [
|
||||
"libiconv"
|
||||
],
|
||||
"lib-suggests": [
|
||||
"icu",
|
||||
"xz",
|
||||
@ -166,6 +169,17 @@
|
||||
"pthreads4w"
|
||||
]
|
||||
},
|
||||
"libiconv": {
|
||||
"source": "libiconv",
|
||||
"static-libs-unix": [
|
||||
"libiconv.a"
|
||||
],
|
||||
"headers": [
|
||||
"iconv.h",
|
||||
"libcharset.h",
|
||||
"localcharset.h"
|
||||
]
|
||||
},
|
||||
"libyaml": {
|
||||
"source": "libyaml",
|
||||
"static-libs-unix": [
|
||||
|
||||
@ -223,6 +223,15 @@
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"libiconv":{
|
||||
"type": "filelist",
|
||||
"url": "https://ftp.gnu.org/gnu/libiconv/",
|
||||
"regex": "/href=\"(?<file>libiconv-(?<version>[^\"]+)\\.tar\\.gz)\"/",
|
||||
"license": {
|
||||
"type": "text",
|
||||
"text": "TODO"
|
||||
}
|
||||
},
|
||||
"xz": {
|
||||
"type": "filelist",
|
||||
"url": "https://tukaani.org/xz/",
|
||||
|
||||
107
ext-support.md
107
ext-support.md
@ -5,59 +5,60 @@
|
||||
> - empty: not supported yet
|
||||
> - faulty with issue link: not supported yet due to issue
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
|------------|-------|--------------------------------------------------------------------|---------|
|
||||
| bcmath | | yes | |
|
||||
| bz2 | | untested | |
|
||||
| calendar | | yes | |
|
||||
| ctype | | yes | |
|
||||
| curl | | yes | |
|
||||
| date | | yes | |
|
||||
| dom | | untested | |
|
||||
| event | | | |
|
||||
| exif | | yes | |
|
||||
| filter | | yes | |
|
||||
| fileinfo | | | |
|
||||
| ftp | | yes | |
|
||||
| gd | | untested | |
|
||||
| gmp | | untested | |
|
||||
| hash | | yes | |
|
||||
| iconv | | | |
|
||||
| inotify | | | |
|
||||
| json | | yes | |
|
||||
| libxml | | yes | |
|
||||
| mbstring | | yes | |
|
||||
| mcrypt | | [faulty](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
|
||||
| mongodb | | | |
|
||||
| mysqli | | | |
|
||||
| mysqlnd | | yes | |
|
||||
| openssl | | yes | |
|
||||
| pcntl | | untested | |
|
||||
| pcre | | yes | |
|
||||
| pdo | | yes | |
|
||||
| pdo_mysql | | yes | |
|
||||
| pdo_sqlite | | yes | |
|
||||
| pdo_pgsql | | | |
|
||||
| phar | | yes | |
|
||||
| posix | | yes | |
|
||||
| protobuf | | | |
|
||||
| readline | | | |
|
||||
| redis | | yes | |
|
||||
| Reflection | | yes | |
|
||||
| session | | yes | |
|
||||
| shmop | | | |
|
||||
| simplexml | | untested | |
|
||||
| soap | | | |
|
||||
| sockets | | | |
|
||||
| sqlite3 | | untested | |
|
||||
| swow | | | |
|
||||
| swoole | | [faulty](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
|
||||
| tokenizer | | yes | |
|
||||
| xml | | yes | |
|
||||
| xmlreader | | untested | |
|
||||
| xmlwriter | | untested | |
|
||||
| zip | | yes | |
|
||||
| zlib | | yes | |
|
||||
| | Linux | macOS | Windows |
|
||||
|------------|----------|--------------------------------------------------------------------|---------|
|
||||
| bcmath | yes | yes | |
|
||||
| bz2 | yes | untested | |
|
||||
| calendar | yes | yes | |
|
||||
| ctype | yes | yes | |
|
||||
| curl | untested | yes | |
|
||||
| date | | yes | |
|
||||
| dba | yes | yes | |
|
||||
| dom | untested | untested | |
|
||||
| event | | | |
|
||||
| exif | | yes | |
|
||||
| filter | | yes | |
|
||||
| fileinfo | | | |
|
||||
| ftp | | yes | |
|
||||
| gd | | untested | |
|
||||
| gmp | | untested | |
|
||||
| hash | yes | yes | |
|
||||
| iconv | untested | | |
|
||||
| inotify | | | |
|
||||
| json | yes | yes | |
|
||||
| libxml | | yes | |
|
||||
| mbstring | | yes | |
|
||||
| mcrypt | | [faulty](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
|
||||
| mongodb | | | |
|
||||
| mysqli | | | |
|
||||
| mysqlnd | | yes | |
|
||||
| openssl | untested | yes | |
|
||||
| pcntl | untested | untested | |
|
||||
| pcre | | yes | |
|
||||
| pdo | | yes | |
|
||||
| pdo_mysql | | yes | |
|
||||
| pdo_sqlite | | yes | |
|
||||
| pdo_pgsql | | | |
|
||||
| phar | yes | yes | |
|
||||
| posix | yes | yes | |
|
||||
| protobuf | | | |
|
||||
| readline | | | |
|
||||
| redis | | yes | |
|
||||
| Reflection | | yes | |
|
||||
| session | | yes | |
|
||||
| shmop | | | |
|
||||
| simplexml | | untested | |
|
||||
| soap | | | |
|
||||
| sockets | | | |
|
||||
| sqlite3 | | untested | |
|
||||
| swow | | | |
|
||||
| swoole | | [faulty](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
|
||||
| tokenizer | | yes | |
|
||||
| xml | | yes | |
|
||||
| xmlreader | | untested | |
|
||||
| xmlwriter | | untested | |
|
||||
| zip | | yes | |
|
||||
| zlib | yes | yes | |
|
||||
|
||||
## Additional Requirements
|
||||
|
||||
|
||||
@ -31,12 +31,12 @@ class BuilderProvider
|
||||
cxx: $input->getOption('cxx'),
|
||||
arch: $input->getOption('arch'),
|
||||
),
|
||||
// 'Linux' => new LinuxBuilder(
|
||||
// cc: $input->getOption('cc'),
|
||||
// cxx: $input->getOption('cxx'),
|
||||
// arch: $input->getOption('arch'),
|
||||
// ),
|
||||
default => throw new RuntimeException('Current OS is not supported yet'),
|
||||
'Linux' => new LinuxBuilder(
|
||||
cc: $input->getOption('cc'),
|
||||
cxx: $input->getOption('cxx'),
|
||||
arch: $input->getOption('arch'),
|
||||
),
|
||||
default => throw new RuntimeException('Current OS "' . PHP_OS_FAMILY . '" is not supported yet'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
333
src/SPC/builder/linux/LinuxBuilder.php
Normal file
333
src/SPC/builder/linux/LinuxBuilder.php
Normal file
@ -0,0 +1,333 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux;
|
||||
|
||||
use SPC\builder\BuilderBase;
|
||||
use SPC\builder\linux\library\LinuxLibraryBase;
|
||||
use SPC\builder\traits\UnixBuilderTrait;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\util\Patcher;
|
||||
|
||||
/**
|
||||
* Linux 系统环境下的构建器
|
||||
*/
|
||||
class LinuxBuilder extends BuilderBase
|
||||
{
|
||||
/** 编译的 Unix 工具集 */
|
||||
use UnixBuilderTrait;
|
||||
|
||||
/** @var string[] Linux 环境下编译依赖的命令 */
|
||||
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'pkg-config', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
|
||||
|
||||
/** @var string 使用的 libc */
|
||||
public string $libc;
|
||||
|
||||
/** @var array 特殊架构下的 cflags */
|
||||
public array $tune_c_flags;
|
||||
|
||||
/** @var string pkg-config 环境变量 */
|
||||
public string $pkgconf_env;
|
||||
|
||||
/** @var string 交叉编译变量 */
|
||||
public string $cross_compile_prefix = '';
|
||||
|
||||
public string $note_section = "Je pense, donc je suis\0";
|
||||
|
||||
private bool $phar_patched = false;
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct(?string $cc = null, ?string $cxx = null, ?string $arch = null)
|
||||
{
|
||||
// 初始化一些默认参数
|
||||
$this->cc = $cc ?? 'musl-gcc';
|
||||
$this->cxx = $cxx ?? 'g++';
|
||||
$this->arch = $arch ?? php_uname('m');
|
||||
$this->gnu_arch = arch2gnu($this->arch);
|
||||
$this->libc = 'musl'; // SystemUtil::selectLibc($this->cc);
|
||||
|
||||
// 根据 CPU 线程数设置编译进程数
|
||||
$this->concurrency = SystemUtil::getCpuCount();
|
||||
// 设置 cflags
|
||||
$this->arch_c_flags = SystemUtil::getArchCFlags($this->cc, $this->arch);
|
||||
$this->arch_cxx_flags = SystemUtil::getArchCFlags($this->cxx, $this->arch);
|
||||
$this->tune_c_flags = SystemUtil::checkCCFlags(SystemUtil::getTuneCFlags($this->arch), $this->cc);
|
||||
// 设置 cmake
|
||||
$this->cmake_toolchain_file = SystemUtil::makeCmakeToolchainFile(
|
||||
os: 'Linux',
|
||||
target_arch: $this->arch,
|
||||
cflags: $this->arch_c_flags,
|
||||
cc: $this->cc,
|
||||
cxx: $this->cxx
|
||||
);
|
||||
// 设置 pkgconfig
|
||||
$this->pkgconf_env = 'PKG_CONFIG_PATH="' . BUILD_LIB_PATH . '/pkgconfig"';
|
||||
// 设置 configure 依赖的环境变量
|
||||
$this->configure_env =
|
||||
$this->pkgconf_env . ' ' .
|
||||
"CC='{$this->cc}' " .
|
||||
"CXX='{$this->cxx}' " .
|
||||
(php_uname('m') === $this->arch ? '' : "CFLAGS='{$this->arch_c_flags}'");
|
||||
// 交叉编译依赖的,TODO
|
||||
if (php_uname('m') !== $this->arch) {
|
||||
$this->cross_compile_prefix = SystemUtil::getCrossCompilePrefix($this->cc, $this->arch);
|
||||
logger()->info('using cross compile prefix: ' . $this->cross_compile_prefix);
|
||||
$this->configure_env .= " CROSS_COMPILE='{$this->cross_compile_prefix}'";
|
||||
}
|
||||
|
||||
$missing = [];
|
||||
foreach (self::REQUIRED_COMMANDS as $cmd) {
|
||||
if (SystemUtil::findCommand($cmd) === null) {
|
||||
$missing[] = $cmd;
|
||||
}
|
||||
}
|
||||
if (!empty($missing)) {
|
||||
throw new RuntimeException('missing system commands: ' . implode(', ', $missing));
|
||||
}
|
||||
|
||||
// 创立 pkg-config 和放头文件的目录
|
||||
f_mkdir(BUILD_LIB_PATH . '/pkgconfig', recursive: true);
|
||||
f_mkdir(BUILD_INCLUDE_PATH, recursive: true);
|
||||
}
|
||||
|
||||
public function makeAutoconfArgs(string $name, array $libSpecs): string
|
||||
{
|
||||
$ret = '';
|
||||
foreach ($libSpecs as $libName => $arr) {
|
||||
$lib = $this->getLib($libName);
|
||||
|
||||
$arr = $arr ?? [];
|
||||
|
||||
$disableArgs = $arr[0] ?? null;
|
||||
$prefix = $arr[1] ?? null;
|
||||
if ($lib instanceof LinuxLibraryBase) {
|
||||
logger()->info("{$name} \033[32;1mwith\033[0;1m {$libName} support");
|
||||
$ret .= $lib->makeAutoconfEnv($prefix) . ' ';
|
||||
} else {
|
||||
logger()->info("{$name} \033[31;1mwithout\033[0;1m {$libName} support");
|
||||
$ret .= ($disableArgs ?? "--with-{$libName}=no") . ' ';
|
||||
}
|
||||
}
|
||||
return rtrim($ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
public function buildPHP(int $build_micro_rule = BUILD_MICRO_NONE, bool $with_clean = false, bool $bloat = false)
|
||||
{
|
||||
if (!$bloat) {
|
||||
$extra_libs = implode(' ', $this->getAllStaticLibFiles());
|
||||
} else {
|
||||
logger()->info('bloat linking');
|
||||
$extra_libs = implode(
|
||||
' ',
|
||||
array_map(
|
||||
fn ($x) => "-Xcompiler {$x}",
|
||||
array_filter($this->getAllStaticLibFiles())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$envs = $this->pkgconf_env . ' ' .
|
||||
"CC='{$this->cc}' " .
|
||||
"CXX='{$this->cxx}' ";
|
||||
$cflags = $this->arch_c_flags;
|
||||
$use_lld = '';
|
||||
|
||||
switch ($this->libc) {
|
||||
case 'musl_wrapper':
|
||||
case 'glibc':
|
||||
$cflags .= ' -static-libgcc -I"' . BUILD_INCLUDE_PATH . '"';
|
||||
break;
|
||||
case 'musl':
|
||||
if (str_ends_with($this->cc, 'clang') && SystemUtil::findCommand('lld')) {
|
||||
$use_lld = '-Xcompiler -fuse-ld=lld';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException('libc ' . $this->libc . ' is not implemented yet');
|
||||
}
|
||||
|
||||
$envs = "{$envs} CFLAGS='{$cflags}' LIBS='-ldl -lpthread'";
|
||||
|
||||
Patcher::patchPHPBeforeConfigure($this);
|
||||
|
||||
f_passthru(
|
||||
$this->set_x . ' && ' .
|
||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
||||
'./buildconf --force'
|
||||
);
|
||||
|
||||
Patcher::patchPHPConfigure($this);
|
||||
|
||||
f_passthru(
|
||||
$this->set_x . ' && ' .
|
||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
||||
'./configure ' .
|
||||
'--prefix= ' .
|
||||
'--with-valgrind=no ' .
|
||||
'--enable-shared=no ' .
|
||||
'--enable-static=yes ' .
|
||||
"--host={$this->gnu_arch}-unknown-linux " .
|
||||
'--disable-all ' .
|
||||
'--disable-cgi ' .
|
||||
'--disable-phpdbg ' .
|
||||
'--enable-cli ' .
|
||||
'--enable-micro=all-static ' .
|
||||
($this->zts ? '--enable-zts' : '') . ' ' .
|
||||
$this->makeExtensionArgs() . ' ' .
|
||||
$envs
|
||||
);
|
||||
|
||||
$extra_libs .= $this->generateExtraLibs();
|
||||
|
||||
file_put_contents('/tmp/comment', $this->note_section);
|
||||
|
||||
if ($with_clean) {
|
||||
logger()->info('cleaning up');
|
||||
f_passthru(
|
||||
$this->set_x . ' && ' .
|
||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
||||
'make clean'
|
||||
);
|
||||
}
|
||||
|
||||
if ($bloat) {
|
||||
logger()->info('bloat linking');
|
||||
$extra_libs = "-Wl,--whole-archive {$extra_libs} -Wl,--no-whole-archive";
|
||||
}
|
||||
|
||||
switch ($build_micro_rule) {
|
||||
case BUILD_MICRO_NONE:
|
||||
logger()->info('building cli');
|
||||
$this->buildCli($extra_libs, $use_lld);
|
||||
break;
|
||||
case BUILD_MICRO_ONLY:
|
||||
logger()->info('building micro');
|
||||
$this->buildMicro($extra_libs, $use_lld, $cflags);
|
||||
break;
|
||||
case BUILD_MICRO_BOTH:
|
||||
logger()->info('building cli and micro');
|
||||
$this->buildCli($extra_libs, $use_lld);
|
||||
$this->buildMicro($extra_libs, $use_lld, $cflags);
|
||||
break;
|
||||
}
|
||||
|
||||
if (php_uname('m') === $this->arch) {
|
||||
$this->sanityCheck($build_micro_rule);
|
||||
}
|
||||
|
||||
if ($this->phar_patched) {
|
||||
f_passthru('cd ' . SOURCE_PATH . '/php-src && patch -p1 -R < sapi/micro/patches/phar.patch');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function buildCli(string $extra_libs, string $use_lld): void
|
||||
{
|
||||
f_passthru(
|
||||
$this->set_x . ' && ' .
|
||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
||||
'sed -i "s|//lib|/lib|g" Makefile && ' .
|
||||
"make -j{$this->concurrency} " .
|
||||
'EXTRA_CFLAGS="-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags)) . '" ' .
|
||||
"EXTRA_LIBS=\"{$extra_libs}\" " .
|
||||
"EXTRA_LDFLAGS_PROGRAM='{$use_lld}" .
|
||||
' -all-static' .
|
||||
"' " .
|
||||
'cli && ' .
|
||||
'cd sapi/cli && ' .
|
||||
"{$this->cross_compile_prefix}objcopy --only-keep-debug php php.debug && " .
|
||||
'elfedit --output-osabi linux php && ' .
|
||||
"{$this->cross_compile_prefix}strip --strip-all php && " .
|
||||
"{$this->cross_compile_prefix}objcopy --update-section .comment=/tmp/comment --add-gnu-debuglink=php.debug --remove-section=.note php"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function buildMicro(string $extra_libs, string $use_lld, string $cflags): void
|
||||
{
|
||||
if ($this->getExt('phar')) {
|
||||
$this->phar_patched = true;
|
||||
try {
|
||||
f_passthru('cd ' . SOURCE_PATH . '/php-src && patch -p1 < sapi/micro/patches/phar.patch');
|
||||
} catch (RuntimeException $e) {
|
||||
logger()->error('failed to patch phat due to patch exit with code ' . $e->getCode());
|
||||
$this->phar_patched = false;
|
||||
}
|
||||
}
|
||||
|
||||
$vars = [
|
||||
'EXTRA_CFLAGS' => quote('-g -Os -fno-ident ' . implode(' ', array_map(fn ($x) => "-Xcompiler {$x}", $this->tune_c_flags))),
|
||||
'EXTRA_LIBS' => quote($extra_libs),
|
||||
'EXTRA_LDFLAGS_PROGRAM' => quote("{$cflags} {$use_lld}" . ' -all-static', "'"),
|
||||
'POST_MICRO_BUILD_COMMANDS' => quote(
|
||||
"sh -xc '" .
|
||||
'cd sapi/micro && ' .
|
||||
"{$this->cross_compile_prefix}objcopy --only-keep-debug micro.sfx micro.sfx.debug && " .
|
||||
'elfedit --output-osabi linux micro.sfx && ' .
|
||||
"{$this->cross_compile_prefix}strip --strip-all micro.sfx && " .
|
||||
"{$this->cross_compile_prefix}objcopy --update-section .comment=/tmp/comment --add-gnu-debuglink=micro.sfx.debug --remove-section=.note micro.sfx'"
|
||||
),
|
||||
];
|
||||
$var_cmdline = '';
|
||||
foreach ($vars as $k => $v) {
|
||||
$var_cmdline .= $k . '=' . $v . ' ';
|
||||
}
|
||||
|
||||
f_passthru(
|
||||
$this->set_x . ' && ' .
|
||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
||||
'sed -i "s|//lib|/lib|g" Makefile && ' .
|
||||
"make -j{$this->concurrency} " .
|
||||
$var_cmdline .
|
||||
'micro'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function generateExtraLibs(): string
|
||||
{
|
||||
if ($this->libc === 'glibc') {
|
||||
$glibc_libs = [
|
||||
'rt',
|
||||
'm',
|
||||
'c',
|
||||
'pthread',
|
||||
'dl',
|
||||
'nsl',
|
||||
'anl',
|
||||
// 'crypt',
|
||||
'resolv',
|
||||
'util',
|
||||
];
|
||||
$makefile = file_get_contents(SOURCE_PATH . '/php-src/Makefile');
|
||||
preg_match('/^EXTRA_LIBS\s*=\s*(.*)$/m', $makefile, $matches);
|
||||
if (!$matches) {
|
||||
throw new RuntimeException('failed to find EXTRA_LIBS in Makefile');
|
||||
}
|
||||
$_extra_libs = [];
|
||||
foreach (array_filter(explode(' ', $matches[1])) as $used) {
|
||||
foreach ($glibc_libs as $libName) {
|
||||
if ("-l{$libName}" === $used && !in_array("-l{$libName}", $_extra_libs, true)) {
|
||||
array_unshift($_extra_libs, "-l{$libName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
return ' ' . implode(' ', $_extra_libs);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
241
src/SPC/builder/linux/SystemUtil.php
Normal file
241
src/SPC/builder/linux/SystemUtil.php
Normal file
@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
class SystemUtil
|
||||
{
|
||||
use UnixSystemUtilTrait;
|
||||
|
||||
/**
|
||||
* 查找并选择编译器命令
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function selectCC(): string
|
||||
{
|
||||
logger()->debug('Choose cc');
|
||||
if (self::findCommand('clang')) {
|
||||
logger()->info('using clang');
|
||||
return 'clang';
|
||||
}
|
||||
if (self::findCommand('gcc')) {
|
||||
logger()->info('using gcc');
|
||||
return 'gcc';
|
||||
}
|
||||
throw new RuntimeException('no supported cc found');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找并选择编译器命令
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function selectCXX(): string
|
||||
{
|
||||
logger()->debug('Choose cxx');
|
||||
if (self::findCommand('clang++')) {
|
||||
logger()->info('using clang++');
|
||||
return 'clang++';
|
||||
}
|
||||
if (self::findCommand('g++')) {
|
||||
logger()->info('using g++');
|
||||
return 'g++';
|
||||
}
|
||||
return self::selectCC();
|
||||
}
|
||||
|
||||
#[ArrayShape(['dist' => 'mixed|string', 'ver' => 'mixed|string'])]
|
||||
public static function getOSRelease(): array
|
||||
{
|
||||
$ret = [
|
||||
'dist' => 'unknown',
|
||||
'ver' => 'unknown',
|
||||
];
|
||||
switch (true) {
|
||||
case file_exists('/etc/os-release'):
|
||||
$lines = file('/etc/os-release');
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/^ID=(.*)$/', $line, $matches)) {
|
||||
$ret['dist'] = $matches[1];
|
||||
}
|
||||
if (preg_match('/^VERSION_ID=(.*)$/', $line, $matches)) {
|
||||
$ret['ver'] = $matches[1];
|
||||
}
|
||||
}
|
||||
$ret['dist'] = trim($ret['dist'], '"\'');
|
||||
$ret['ver'] = trim($ret['ver'], '"\'');
|
||||
if (strcasecmp($ret['dist'], 'centos') === 0) {
|
||||
$ret['dist'] = 'redhat';
|
||||
}
|
||||
break;
|
||||
case file_exists('/etc/centos-release'):
|
||||
$lines = file('/etc/centos-release');
|
||||
goto rh;
|
||||
case file_exists('/etc/redhat-release'):
|
||||
$lines = file('/etc/redhat-release');
|
||||
rh:
|
||||
foreach ($lines as $line) {
|
||||
if (preg_match('/release\s+(\d+(\.\d+)*)/', $line, $matches)) {
|
||||
$ret['dist'] = 'redhat';
|
||||
$ret['ver'] = $matches[1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function getCpuCount(): int
|
||||
{
|
||||
$ncpu = 1;
|
||||
|
||||
if (is_file('/proc/cpuinfo')) {
|
||||
$cpuinfo = file_get_contents('/proc/cpuinfo');
|
||||
preg_match_all('/^processor/m', $cpuinfo, $matches);
|
||||
$ncpu = count($matches[0]);
|
||||
}
|
||||
|
||||
return $ncpu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function getCCType(string $cc): string
|
||||
{
|
||||
return match (true) {
|
||||
str_ends_with($cc, 'c++'), str_ends_with($cc, 'cc'), str_ends_with($cc, 'g++'), str_ends_with($cc, 'gcc') => 'gcc',
|
||||
$cc === 'clang++', $cc === 'clang', str_starts_with($cc, 'musl-clang') => 'clang',
|
||||
default => throw new RuntimeException("unknown cc type: {$cc}"),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function getArchCFlags(string $cc, string $arch): string
|
||||
{
|
||||
if (php_uname('m') === $arch) {
|
||||
return '';
|
||||
}
|
||||
return match (static::getCCType($cc)) {
|
||||
'clang' => match ($arch) {
|
||||
'x86_64' => '--target=x86_64-unknown-linux',
|
||||
'arm64', 'aarch64' => '--target=arm64-unknown-linux',
|
||||
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
||||
},
|
||||
'gcc' => '',
|
||||
default => throw new RuntimeException('cc compiler ' . $cc . ' is not supported'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function getTuneCFlags(string $arch): array
|
||||
{
|
||||
return match ($arch) {
|
||||
'x86_64' => [
|
||||
'-march=corei7',
|
||||
'-mtune=core-avx2',
|
||||
],
|
||||
'arm64', 'aarch64' => [],
|
||||
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
||||
};
|
||||
}
|
||||
|
||||
public static function checkCCFlags(array $flags, string $cc): array
|
||||
{
|
||||
return array_filter($flags, fn ($flag) => static::checkCCFlag($flag, $cc));
|
||||
}
|
||||
|
||||
public static function checkCCFlag(string $flag, string $cc): string
|
||||
{
|
||||
$ret = 0;
|
||||
f_exec("echo | {$cc} -E -x c - {$flag}", $dummy, $ret);
|
||||
if ($ret != 0) {
|
||||
return '';
|
||||
}
|
||||
return $flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function getCrossCompilePrefix(string $cc, string $arch): string
|
||||
{
|
||||
return match (static::getCCType($cc)) {
|
||||
// guessing clang toolchains
|
||||
'clang' => match ($arch) {
|
||||
'x86_64' => 'x86_64-linux-gnu-',
|
||||
'arm64', 'aarch64' => 'aarch64-linux-gnu-',
|
||||
default => throw new RuntimeException('unsupported arch: ' . $arch),
|
||||
},
|
||||
// remove gcc postfix
|
||||
'gcc' => str_replace('-cc', '', str_replace('-gcc', '', $cc)) . '-',
|
||||
default => throw new RuntimeException('unsupported cc'),
|
||||
};
|
||||
}
|
||||
|
||||
public static function findStaticLib(string $name): ?array
|
||||
{
|
||||
$paths = getenv('LIBPATH');
|
||||
if (!$paths) {
|
||||
$paths = '/lib:/lib64:/usr/lib:/usr/lib64:/usr/local/lib:/usr/local/lib64';
|
||||
}
|
||||
foreach (explode(':', $paths) as $path) {
|
||||
if (file_exists("{$path}/{$name}")) {
|
||||
return ["{$path}", "{$name}"];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function findStaticLibs(array $names): ?array
|
||||
{
|
||||
$ret = [];
|
||||
foreach ($names as $name) {
|
||||
$path = static::findStaticLib($name);
|
||||
if (!$path) {
|
||||
logger()->warning("static library {$name} not found");
|
||||
return null;
|
||||
}
|
||||
$ret[] = $path;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function findHeader(string $name): ?array
|
||||
{
|
||||
$paths = getenv('INCLUDEPATH');
|
||||
if (!$paths) {
|
||||
$paths = '/include:/usr/include:/usr/local/include';
|
||||
}
|
||||
foreach (explode(':', $paths) as $path) {
|
||||
if (file_exists("{$path}/{$name}") || is_dir("{$path}/{$name}")) {
|
||||
return ["{$path}", "{$name}"];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function findHeaders(array $names): ?array
|
||||
{
|
||||
$ret = [];
|
||||
foreach ($names as $name) {
|
||||
$path = static::findHeader($name);
|
||||
if (!$path) {
|
||||
logger()->warning("header {$name} not found");
|
||||
return null;
|
||||
}
|
||||
$ret[] = $path;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
77
src/SPC/builder/linux/library/LinuxLibraryBase.php
Normal file
77
src/SPC/builder/linux/library/LinuxLibraryBase.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\builder\BuilderBase;
|
||||
use SPC\builder\LibraryBase;
|
||||
use SPC\builder\linux\LinuxBuilder;
|
||||
use SPC\builder\traits\UnixLibraryTrait;
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
abstract class LinuxLibraryBase extends LibraryBase
|
||||
{
|
||||
use UnixLibraryTrait;
|
||||
|
||||
protected array $static_libs = [];
|
||||
|
||||
protected array $headers;
|
||||
|
||||
protected array $pkgconfs;
|
||||
|
||||
/**
|
||||
* 依赖的名字及是否可选,例如:curl => true,代表依赖 curl 但可选
|
||||
*/
|
||||
protected array $dep_names;
|
||||
|
||||
public function __construct(protected LinuxBuilder $builder)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function getBuilder(): BuilderBase
|
||||
{
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function tryBuild(bool $force_build = false): int
|
||||
{
|
||||
// 传入 true,表明直接编译
|
||||
if ($force_build) {
|
||||
$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;
|
||||
}
|
||||
|
||||
protected function makeFakePkgconfs()
|
||||
{
|
||||
$workspace = BUILD_ROOT_PATH;
|
||||
if ($workspace === '/') {
|
||||
$workspace = '';
|
||||
}
|
||||
foreach ($this->pkgconfs as $name => $content) {
|
||||
file_put_contents(BUILD_LIB_PATH . "/pkgconfig/{$name}", "prefix={$workspace}\n" . $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
59
src/SPC/builder/linux/library/brotli.php
Normal file
59
src/SPC/builder/linux/library/brotli.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
||||
*
|
||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
||||
* software according to the terms and conditions of the
|
||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
class brotli extends LinuxLibraryBase
|
||||
{
|
||||
public const NAME = 'brotli';
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
||||
f_passthru(
|
||||
"{$this->builder->set_x} && " .
|
||||
"cd {$this->source_dir} && " .
|
||||
'rm -rf build && ' .
|
||||
'mkdir -p build && ' .
|
||||
'cd build && ' .
|
||||
"{$this->builder->configure_env} " . ' cmake ' .
|
||||
// '--debug-find ' .
|
||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||
'.. && ' .
|
||||
"cmake --build . -j {$this->builder->concurrency} --target brotlicommon-static && " .
|
||||
"cmake --build . -j {$this->builder->concurrency} --target brotlidec-static && " .
|
||||
"cmake --build . -j {$this->builder->concurrency} --target brotlienc-static && " .
|
||||
'cp libbrotlidec-static.a ' . BUILD_LIB_PATH . ' && ' .
|
||||
'cp libbrotlienc-static.a ' . BUILD_LIB_PATH . ' && ' .
|
||||
'cp libbrotlicommon-static.a ' . BUILD_LIB_PATH . ' && ' .
|
||||
'cp -r ../c/include/brotli ' . BUILD_INCLUDE_PATH
|
||||
);
|
||||
}
|
||||
}
|
||||
47
src/SPC/builder/linux/library/bzip2.php
Normal file
47
src/SPC/builder/linux/library/bzip2.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
||||
*
|
||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
||||
* software according to the terms and conditions of the
|
||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
class bzip2 extends LinuxLibraryBase
|
||||
{
|
||||
public const NAME = 'bzip2';
|
||||
|
||||
protected array $dep_names = [];
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
f_passthru(
|
||||
$this->builder->set_x . ' && ' .
|
||||
"cd {$this->source_dir} && " .
|
||||
"make {$this->builder->configure_env} PREFIX='" . BUILD_ROOT_PATH . "' clean" . ' && ' .
|
||||
"make -j{$this->builder->concurrency} {$this->builder->configure_env} PREFIX='" . BUILD_ROOT_PATH . "' libbz2.a" . ' && ' .
|
||||
// make install may fail when cross-compiling, so we copy files.
|
||||
'cp libbz2.a ' . BUILD_LIB_PATH . ' && ' .
|
||||
'cp bzlib.h ' . BUILD_INCLUDE_PATH
|
||||
);
|
||||
// $this->makeFakePkgconfs();
|
||||
}
|
||||
}
|
||||
163
src/SPC/builder/linux/library/curl.php
Normal file
163
src/SPC/builder/linux/library/curl.php
Normal file
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
||||
*
|
||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
||||
* software according to the terms and conditions of the
|
||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
class curl extends LinuxLibraryBase
|
||||
{
|
||||
public const NAME = 'curl';
|
||||
|
||||
protected array $static_libs = ['libcurl.a'];
|
||||
|
||||
protected array $headers = ['curl'];
|
||||
|
||||
protected array $pkgconfs = [
|
||||
'libcurl.pc' => <<<'EOF'
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
supported_protocols="DICT FILE FTP FTPS GOPHER GOPHERS HTTP HTTPS IMAP IMAPS MQTT POP3 POP3S RTSP SCP SFTP SMB SMBS SMTP SMTPS TELNET TFTP"
|
||||
supported_features="AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets alt-svc brotli libz zstd"
|
||||
|
||||
Name: libcurl
|
||||
URL: https://curl.se/
|
||||
Description: Library to transfer files with ftp, http, etc.
|
||||
Version: 7.83.0
|
||||
Libs: -L${libdir} -lcurl
|
||||
Libs.private: -lnghttp2 -lidn2 -lssh2 -lssh2 -lpsl -lssl -lcrypto -lssl -lcrypto -lgssapi_krb5 -lzstd -lbrotlidec -lz
|
||||
Cflags: -I${includedir}
|
||||
EOF
|
||||
];
|
||||
|
||||
protected array $dep_names = [
|
||||
'zlib' => false,
|
||||
'libssh2' => true,
|
||||
'brotli' => true,
|
||||
'nghttp2' => true,
|
||||
'zstd' => true,
|
||||
'openssl' => true,
|
||||
'idn2' => true,
|
||||
'psl' => true,
|
||||
];
|
||||
|
||||
public function getStaticLibFiles(string $style = 'autoconf', bool $recursive = true): string
|
||||
{
|
||||
$libs = parent::getStaticLibFiles($style, $recursive);
|
||||
if ($this->builder->getLib('openssl')) {
|
||||
$libs .= ' -ldl -lpthread';
|
||||
}
|
||||
return $libs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$extra = '';
|
||||
// lib:openssl
|
||||
$openssl = $this->builder->getLib('openssl');
|
||||
if ($openssl instanceof LinuxLibraryBase) {
|
||||
$extra .= '-DCURL_USE_OPENSSL=ON -DCURL_ENABLE_SSL=ON ';
|
||||
} else {
|
||||
$extra .= '-DCURL_USE_OPENSSL=OFF -DCURL_ENABLE_SSL=OFF ';
|
||||
}
|
||||
// lib:zlib
|
||||
$zlib = $this->builder->getLib('zlib');
|
||||
if ($zlib instanceof LinuxLibraryBase) {
|
||||
$extra .= '-DZLIB_LIBRARIES="' . $zlib->getStaticLibFiles(style: 'cmake') . '" ' .
|
||||
'-DZLIB_INCLUDE_DIRS="' . BUILD_INCLUDE_PATH . '" ';
|
||||
}
|
||||
// lib:libssh2
|
||||
$libssh2 = $this->builder->getLib('libssh2');
|
||||
if ($libssh2 instanceof LinuxLibraryBase) {
|
||||
$extra .= '-DLIBSSH2_LIBRARY="' . $libssh2->getStaticLibFiles(style: 'cmake') . '" ' .
|
||||
'-DLIBSSH2_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
||||
} else {
|
||||
$extra .= '-DCURL_USE_LIBSSH2=OFF ';
|
||||
}
|
||||
// lib:brotli
|
||||
$brotli = $this->builder->getLib('brotli');
|
||||
if ($brotli) {
|
||||
$extra .= '-DCURL_BROTLI=ON ' .
|
||||
'-DBROTLIDEC_LIBRARY="' . realpath(BUILD_LIB_PATH . '/libbrotlidec-static.a') . ';' . realpath(BUILD_LIB_PATH . '/libbrotlicommon-static.a') . '" ' .
|
||||
'-DBROTLICOMMON_LIBRARY="' . realpath(BUILD_LIB_PATH . '/libbrotlicommon-static.a') . '" ' .
|
||||
'-DBROTLI_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
||||
} else {
|
||||
$extra .= '-DCURL_BROTLI=OFF ';
|
||||
}
|
||||
// lib:nghttp2
|
||||
$nghttp2 = $this->builder->getLib('nghttp2');
|
||||
if ($nghttp2 instanceof LinuxLibraryBase) {
|
||||
$extra .= '-DUSE_NGHTTP2=ON ' .
|
||||
'-DNGHTTP2_LIBRARY="' . $nghttp2->getStaticLibFiles(style: 'cmake') . '" ' .
|
||||
'-DNGHTTP2_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
||||
} else {
|
||||
$extra .= '-DUSE_NGHTTP2=OFF ';
|
||||
}
|
||||
// lib:ldap
|
||||
$ldap = $this->builder->getLib('ldap');
|
||||
if ($ldap instanceof LinuxLibraryBase) {
|
||||
// $extra .= '-DCURL_DISABLE_LDAP=OFF ';
|
||||
// TODO: LDAP support
|
||||
throw new RuntimeException('LDAP support is not implemented yet');
|
||||
}
|
||||
$extra .= '-DCURL_DISABLE_LDAP=ON ';
|
||||
// lib:zstd
|
||||
$zstd = $this->builder->getLib('zstd');
|
||||
if ($zstd instanceof LinuxLibraryBase) {
|
||||
$extra .= '-DCURL_ZSTD=ON ' .
|
||||
'-DZstd_LIBRARY="' . $zstd->getStaticLibFiles(style: 'cmake') . '" ' .
|
||||
'-DZstd_INCLUDE_DIR="' . BUILD_INCLUDE_PATH . '" ';
|
||||
} else {
|
||||
$extra .= '-DCURL_ZSTD=OFF ';
|
||||
}
|
||||
// lib:idn2
|
||||
$idn2 = $this->builder->getLib('idn2');
|
||||
$extra .= $idn2 instanceof LinuxLibraryBase ? '-DUSE_LIBIDN2=ON ' : '-DUSE_LIBIDN2=OFF ';
|
||||
// lib:psl
|
||||
$libpsl = $this->builder->getLib('psl');
|
||||
$extra .= $libpsl instanceof LinuxLibraryBase ? '-DCURL_USE_LIBPSL=ON ' : '-DCURL_USE_LIBPSL=OFF ';
|
||||
|
||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
||||
// compile!
|
||||
f_passthru(
|
||||
$this->builder->set_x . ' && ' .
|
||||
"cd {$this->source_dir} && " .
|
||||
'rm -rf build && ' .
|
||||
'mkdir -p build && ' .
|
||||
'cd build && ' .
|
||||
"{$this->builder->configure_env} " . ' cmake ' .
|
||||
// '--debug-find ' .
|
||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||
$extra .
|
||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||
'.. && ' .
|
||||
"make -j{$this->builder->concurrency} && " .
|
||||
'make install DESTDIR="' . $destdir . '"'
|
||||
);
|
||||
}
|
||||
}
|
||||
50
src/SPC/builder/linux/library/libiconv.php
Normal file
50
src/SPC/builder/linux/library/libiconv.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
||||
*
|
||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
||||
* software according to the terms and conditions of the
|
||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
class libiconv extends LinuxLibraryBase
|
||||
{
|
||||
public const NAME = 'libiconv';
|
||||
|
||||
protected array $dep_names = [];
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
[,,$destdir] = SEPARATED_PATH;
|
||||
|
||||
f_passthru(
|
||||
$this->builder->set_x . ' && ' .
|
||||
"cd {$this->source_dir} && " .
|
||||
"{$this->builder->configure_env} ./configure " .
|
||||
'--enable-static ' .
|
||||
'--disable-shared ' .
|
||||
'--prefix= && ' . // use prefix=/
|
||||
'make clean && ' .
|
||||
"make -j{$this->builder->concurrency} && " .
|
||||
'make install DESTDIR=' . $destdir
|
||||
);
|
||||
}
|
||||
}
|
||||
104
src/SPC/builder/linux/library/libxml2.php
Normal file
104
src/SPC/builder/linux/library/libxml2.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
||||
*
|
||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
||||
* software according to the terms and conditions of the
|
||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\store\FileSystem;
|
||||
|
||||
class libxml2 extends LinuxLibraryBase
|
||||
{
|
||||
public const NAME = 'libxml2';
|
||||
|
||||
protected array $static_libs = ['libxml2.a'];
|
||||
|
||||
protected array $headers = [
|
||||
'libxml2',
|
||||
];
|
||||
|
||||
protected array $pkgconfs = [
|
||||
'libxml-2.0.pc' => <<<'EOF'
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
modules=1
|
||||
|
||||
Name: libXML
|
||||
Version: 2.9.14
|
||||
Description: libXML library version2.
|
||||
Requires:
|
||||
Libs: -L${libdir} -lxml2
|
||||
Cflags: -I${includedir}/libxml2
|
||||
EOF
|
||||
];
|
||||
|
||||
protected array $dep_names = [
|
||||
'icu' => true,
|
||||
'xz' => true,
|
||||
'zlib' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$enable_zlib = $this->builder->getLib('zlib') ? 'ON' : 'OFF';
|
||||
$enable_icu = $this->builder->getLib('icu') ? 'ON' : 'OFF';
|
||||
$enable_xz = $this->builder->getLib('xz') ? 'ON' : 'OFF';
|
||||
|
||||
[$lib, $include, $destdir] = SEPARATED_PATH;
|
||||
|
||||
f_passthru(
|
||||
$this->builder->set_x . ' && ' .
|
||||
"cd {$this->source_dir} && " .
|
||||
'rm -rf build && ' .
|
||||
'mkdir -p build && ' .
|
||||
'cd build && ' .
|
||||
"{$this->builder->configure_env} " . ' cmake ' .
|
||||
// '--debug-find ' .
|
||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||
'-DBUILD_SHARED_LIBS=OFF ' .
|
||||
'-DLIBXML2_WITH_ICONV=ON ' .
|
||||
'-DIconv_IS_BUILT_IN=OFF ' .
|
||||
"-DLIBXML2_WITH_ZLIB={$enable_zlib} " .
|
||||
"-DLIBXML2_WITH_ICU={$enable_icu} " .
|
||||
"-DLIBXML2_WITH_LZMA={$enable_xz} " .
|
||||
'-DLIBXML2_WITH_PYTHON=OFF ' .
|
||||
'-DLIBXML2_WITH_PROGRAMS=OFF ' .
|
||||
'-DLIBXML2_WITH_TESTS=OFF ' .
|
||||
'-DCMAKE_INSTALL_PREFIX=/ ' .
|
||||
"-DCMAKE_INSTALL_LIBDIR={$lib} " .
|
||||
"-DCMAKE_INSTALL_INCLUDEDIR={$include} " .
|
||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||
'.. && ' .
|
||||
"cmake --build . -j {$this->builder->concurrency} && " .
|
||||
'make install DESTDIR="' . $destdir . '"'
|
||||
);
|
||||
if (is_dir(BUILD_INCLUDE_PATH . '/libxml2/libxml')) {
|
||||
if (is_dir(BUILD_INCLUDE_PATH . '/libxml')) {
|
||||
f_passthru('rm -rf "' . BUILD_INCLUDE_PATH . '/libxml"');
|
||||
}
|
||||
$path = FileSystem::convertPath(BUILD_INCLUDE_PATH . '/libxml2/libxml');
|
||||
$dst_path = FileSystem::convertPath(BUILD_INCLUDE_PATH . '/');
|
||||
f_passthru('mv "' . $path . '" "' . $dst_path . '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
127
src/SPC/builder/linux/library/openssl.php
Normal file
127
src/SPC/builder/linux/library/openssl.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
||||
*
|
||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
||||
* software according to the terms and conditions of the
|
||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
class openssl extends LinuxLibraryBase
|
||||
{
|
||||
public const NAME = 'openssl';
|
||||
|
||||
protected array $static_libs = [
|
||||
'libssl.a',
|
||||
'libcrypto.a',
|
||||
];
|
||||
|
||||
protected array $headers = ['openssl'];
|
||||
|
||||
protected array $pkgconfs = [
|
||||
'openssl.pc' => <<<'EOF'
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: OpenSSL
|
||||
Description: Secure Sockets Layer and cryptography libraries and tools
|
||||
Version: 3.0.3
|
||||
Requires: libssl libcrypto
|
||||
EOF,
|
||||
'libssl.pc' => <<<'EOF'
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: OpenSSL-libssl
|
||||
Description: Secure Sockets Layer and cryptography libraries
|
||||
Version: 3.0.3
|
||||
Requires.private: libcrypto
|
||||
Libs: -L${libdir} -lssl
|
||||
Cflags: -I${includedir}
|
||||
EOF,
|
||||
'libcrypto.pc' => <<<'EOF'
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
enginesdir=${libdir}/engines-3
|
||||
|
||||
Name: OpenSSL-libcrypto
|
||||
Description: OpenSSL cryptography library
|
||||
Version: 3.0.3
|
||||
Libs: -L${libdir} -lcrypto
|
||||
Libs.private: -lz -ldl -pthread
|
||||
Cflags: -I${includedir}
|
||||
EOF,
|
||||
];
|
||||
|
||||
protected array $dep_names = ['zlib' => true];
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
[$lib,$include,$destdir] = SEPARATED_PATH;
|
||||
|
||||
$extra = '';
|
||||
$ex_lib = '-ldl -pthread';
|
||||
|
||||
$env = $this->builder->pkgconf_env . " CFLAGS='{$this->builder->arch_c_flags}'";
|
||||
$env .= " CC='{$this->builder->cc} --static -static-libgcc -idirafter " . BUILD_INCLUDE_PATH .
|
||||
' -idirafter /usr/include/ ' .
|
||||
' -idirafter /usr/include/' . $this->builder->arch . '-linux-gnu/ ' .
|
||||
"' ";
|
||||
// lib:zlib
|
||||
$zlib = $this->builder->getLib('zlib');
|
||||
if ($zlib instanceof LinuxLibraryBase) {
|
||||
$extra = 'zlib';
|
||||
$ex_lib = trim($zlib->getStaticLibFiles() . ' ' . $ex_lib);
|
||||
$zlib_extra =
|
||||
'--with-zlib-include=' . BUILD_INCLUDE_PATH . ' ' .
|
||||
'--with-zlib-lib=' . BUILD_LIB_PATH . ' ';
|
||||
} else {
|
||||
$zlib_extra = '';
|
||||
}
|
||||
|
||||
$ex_lib = trim($ex_lib);
|
||||
|
||||
$clang_postfix = SystemUtil::getCCType($this->builder->cc) === 'clang' ? '-clang' : '';
|
||||
|
||||
f_passthru(
|
||||
$this->builder->set_x . ' && ' .
|
||||
"cd {$this->source_dir} && " .
|
||||
"{$this->builder->configure_env} {$env} ./Configure no-shared {$extra} " .
|
||||
'--prefix=/ ' . // use prefix=/
|
||||
"--libdir={$lib} " .
|
||||
'--static -static ' .
|
||||
"{$zlib_extra}" .
|
||||
'no-legacy ' .
|
||||
"linux-{$this->builder->arch}{$clang_postfix} && " .
|
||||
'make clean && ' .
|
||||
"make -j{$this->builder->concurrency} CNF_EX_LIBS=\"{$ex_lib}\" && " .
|
||||
'make install_sw DESTDIR=' . $destdir
|
||||
// remove liblegacy
|
||||
// 'ar t lib/libcrypto.a | grep -e \'^liblegacy-\' | xargs ar d lib/libcrypto.a'
|
||||
);
|
||||
}
|
||||
}
|
||||
47
src/SPC/builder/linux/library/zlib.php
Normal file
47
src/SPC/builder/linux/library/zlib.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2022 Yun Dou <dixyes@gmail.com>
|
||||
*
|
||||
* lwmbs is licensed under Mulan PSL v2. You can use this
|
||||
* software according to the terms and conditions of the
|
||||
* Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
class zlib extends LinuxLibraryBase
|
||||
{
|
||||
public const NAME = 'zlib';
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
[,,$destdir] = SEPARATED_PATH;
|
||||
|
||||
f_passthru(
|
||||
$this->builder->set_x . ' && ' .
|
||||
"cd {$this->source_dir} && " .
|
||||
"{$this->builder->configure_env} ./configure " .
|
||||
'--static ' .
|
||||
'--prefix= && ' . // use prefix=/
|
||||
'make clean && ' .
|
||||
"make -j{$this->builder->concurrency} && " .
|
||||
'make install DESTDIR=' . $destdir
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ namespace SPC\builder\traits;
|
||||
use SPC\builder\LibraryBase;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\store\FileSystem;
|
||||
|
||||
trait UnixLibraryTrait
|
||||
{
|
||||
@ -33,7 +34,7 @@ trait UnixLibraryTrait
|
||||
foreach ($libs as $lib) {
|
||||
$libFiles = [];
|
||||
foreach ($lib->getStaticLibs() as $name) {
|
||||
$name = str_replace(' ', '\ ', realpath(BUILD_LIB_PATH . "/{$name}"));
|
||||
$name = str_replace(' ', '\ ', FileSystem::convertPath(BUILD_LIB_PATH . "/{$name}"));
|
||||
$name = str_replace('"', '\"', $name);
|
||||
$libFiles[] = $name;
|
||||
}
|
||||
|
||||
@ -44,6 +44,10 @@ SET(CMAKE_C_FLAGS "{$cflags}")
|
||||
SET(CMAKE_CXX_FLAGS "{$cflags}")
|
||||
SET(CMAKE_FIND_ROOT_PATH "{$root}")
|
||||
CMAKE;
|
||||
// 有时候系统的 cmake 找不到 ar 命令,真奇怪
|
||||
if (PHP_OS_FAMILY === 'Linux') {
|
||||
$toolchain .= "\nSET(CMAKE_AR \"ar\")";
|
||||
}
|
||||
file_put_contents(SOURCE_PATH . '/toolchain.cmake', $toolchain);
|
||||
return realpath(SOURCE_PATH . '/toolchain.cmake');
|
||||
}
|
||||
|
||||
@ -77,8 +77,8 @@ class BuildCliCommand extends BuildCommand
|
||||
if ($input->getOption('debug')) {
|
||||
ExceptionHandler::getInstance()->handle($e);
|
||||
} else {
|
||||
logger()->critical('Build failed, please check terminal output, or build with --debug option to see more details.');
|
||||
logger()->critical($e->getMessage());
|
||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
||||
logger()->critical('Please check with --debug option to see more details.');
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\builder\BuilderProvider;
|
||||
use SPC\exception\ExceptionHandler;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
@ -30,6 +31,7 @@ class BuildLibsCommand extends BuildCommand
|
||||
if ($input->getOption('all')) {
|
||||
$input->setArgument('libraries', '');
|
||||
}
|
||||
parent::initialize($input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,15 +57,25 @@ class BuildLibsCommand extends BuildCommand
|
||||
}
|
||||
}
|
||||
|
||||
// 构建对象
|
||||
$builder = BuilderProvider::makeBuilderByInput($input);
|
||||
// 只编译 library 的情况下,标记
|
||||
$builder->setLibsOnly();
|
||||
// 编译和检查库完整
|
||||
$builder->buildLibs($libraries);
|
||||
try {
|
||||
// 构建对象
|
||||
$builder = BuilderProvider::makeBuilderByInput($input);
|
||||
// 只编译 library 的情况下,标记
|
||||
$builder->setLibsOnly();
|
||||
// 编译和检查库完整
|
||||
$builder->buildLibs($libraries);
|
||||
|
||||
$time = round(microtime(true) - START_TIME, 3);
|
||||
logger()->info('Build libs complete, used ' . $time . ' s !');
|
||||
return 0;
|
||||
$time = round(microtime(true) - START_TIME, 3);
|
||||
logger()->info('Build libs complete, used ' . $time . ' s !');
|
||||
return 0;
|
||||
} catch (\Throwable $e) {
|
||||
if ($input->getOption('debug')) {
|
||||
ExceptionHandler::getInstance()->handle($e);
|
||||
} else {
|
||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
||||
logger()->critical('Please check with --debug option to see more details.');
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user