mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-04 15:25:41 +08:00
<
This commit is contained in:
@@ -9,6 +9,7 @@ use SPC\command\BuildPHPCommand;
|
||||
use SPC\command\CraftCommand;
|
||||
use SPC\command\DeleteDownloadCommand;
|
||||
use SPC\command\dev\AllExtCommand;
|
||||
use SPC\command\dev\EnvCommand;
|
||||
use SPC\command\dev\ExtVerCommand;
|
||||
use SPC\command\dev\GenerateExtDepDocsCommand;
|
||||
use SPC\command\dev\GenerateExtDocCommand;
|
||||
@@ -70,6 +71,7 @@ final class ConsoleApplication extends Application
|
||||
new GenerateExtDepDocsCommand(),
|
||||
new GenerateLibDepDocsCommand(),
|
||||
new PackLibCommand(),
|
||||
new EnvCommand(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use SPC\store\Config;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\store\LockFile;
|
||||
use SPC\store\SourceManager;
|
||||
use SPC\store\SourcePatcher;
|
||||
use SPC\util\CustomExt;
|
||||
|
||||
abstract class BuilderBase
|
||||
@@ -203,6 +204,8 @@ abstract class BuilderBase
|
||||
$this->emitPatchPoint('before-exts-extract');
|
||||
SourceManager::initSource(exts: [...$static_extensions, ...$shared_extensions]);
|
||||
$this->emitPatchPoint('after-exts-extract');
|
||||
// patch micro
|
||||
SourcePatcher::patchMicro();
|
||||
}
|
||||
|
||||
foreach ([...$static_extensions, ...$shared_extensions] as $extension) {
|
||||
|
||||
@@ -11,6 +11,7 @@ use SPC\exception\WrongUsageException;
|
||||
use SPC\store\Config;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\SPCConfigUtil;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
class Extension
|
||||
{
|
||||
@@ -545,6 +546,11 @@ class Extension
|
||||
$sharedLibString .= '-l' . $lib . ' ';
|
||||
}
|
||||
}
|
||||
// move static libstdc++ to shared if we are on non-full-static build target
|
||||
if (!SPCTarget::isStatic() && in_array(SPCTarget::getLibc(), SPCTarget::LIBC_LIST)) {
|
||||
$staticLibString .= ' -lstdc++';
|
||||
$sharedLibString = str_replace('-lstdc++', '', $sharedLibString);
|
||||
}
|
||||
return [trim($staticLibString), trim($sharedLibString)];
|
||||
}
|
||||
|
||||
|
||||
@@ -12,17 +12,7 @@ class imagick extends Extension
|
||||
{
|
||||
public function getUnixConfigureArg(bool $shared = false): string
|
||||
{
|
||||
return '--with-imagick=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . ' ac_cv_func_omp_pause_resource_all=no';
|
||||
}
|
||||
|
||||
protected function getStaticAndSharedLibs(): array
|
||||
{
|
||||
// on centos 7, it will use the symbol _ZTINSt6thread6_StateE, which is not defined in system libstdc++.so.6
|
||||
[$static, $shared] = parent::getStaticAndSharedLibs();
|
||||
if (str_contains(getenv('CC'), 'devtoolset-10')) {
|
||||
$static .= ' -lstdc++';
|
||||
$shared = str_replace('-lstdc++', '', $shared);
|
||||
}
|
||||
return [$static, $shared];
|
||||
$disable_omp = ' ac_cv_func_omp_pause_resource_all=no';
|
||||
return '--with-imagick=' . ($shared ? 'shared,' : '') . BUILD_ROOT_PATH . $disable_omp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,22 +25,8 @@ class LinuxBuilder extends UnixBuilderBase
|
||||
{
|
||||
$this->options = $options;
|
||||
|
||||
// check musl-cross make installed if we use musl-cross-make
|
||||
$arch = arch2gnu(php_uname('m'));
|
||||
|
||||
GlobalEnvManager::init();
|
||||
|
||||
if (getenv('SPC_LIBC') === 'musl' && !SystemUtil::isMuslDist() && !str_contains((string) getenv('CC'), 'zig')) {
|
||||
$this->setOptionIfNotExist('library_path', "LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\"");
|
||||
$this->setOptionIfNotExist('ld_library_path', "LD_LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\"");
|
||||
$configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
|
||||
$configure = "LD_LIBRARY_PATH=\"/usr/local/musl/{$arch}-linux-musl/lib\" " . $configure;
|
||||
GlobalEnvManager::putenv("SPC_CMD_PREFIX_PHP_CONFIGURE={$configure}");
|
||||
|
||||
if (!file_exists("/usr/local/musl/{$arch}-linux-musl/lib/libc.a")) {
|
||||
throw new WrongUsageException('You are building with musl-libc target in glibc distro, but musl-toolchain is not installed, please install musl-toolchain first. (You can use `doctor` command to install it)');
|
||||
}
|
||||
}
|
||||
GlobalEnvManager::afterInit();
|
||||
|
||||
// concurrency
|
||||
$this->concurrency = intval(getenv('SPC_CONCURRENCY'));
|
||||
@@ -104,10 +90,6 @@ class LinuxBuilder extends UnixBuilderBase
|
||||
$zts = '';
|
||||
}
|
||||
$disable_jit = $this->getOption('disable-opcache-jit', false) ? '--disable-opcache-jit ' : '';
|
||||
$cc = trim(getenv('CC'));
|
||||
if (!$disable_jit && $this->getExt('opcache') && str_contains($cc, 'zig')) {
|
||||
f_putenv("CC={$cc} -fno-sanitize=undefined");
|
||||
}
|
||||
|
||||
$config_file_path = $this->getOption('with-config-file-path', false) ?
|
||||
('--with-config-file-path=' . $this->getOption('with-config-file-path') . ' ') : '';
|
||||
@@ -139,9 +121,6 @@ class LinuxBuilder extends UnixBuilderBase
|
||||
}
|
||||
|
||||
$embed_type = getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') ?: 'static';
|
||||
if ($embed_type !== 'static' && getenv('SPC_LIBC') === 'musl' && getenv('SPC_LIBC_LINKAGE') === '-static') {
|
||||
throw new WrongUsageException('Musl libc does not support dynamic linking of PHP embed!');
|
||||
}
|
||||
shell()->cd(SOURCE_PATH . '/php-src')
|
||||
->exec(
|
||||
getenv('SPC_CMD_PREFIX_PHP_CONFIGURE') . ' ' .
|
||||
@@ -183,9 +162,6 @@ class LinuxBuilder extends UnixBuilderBase
|
||||
}
|
||||
$this->buildEmbed();
|
||||
}
|
||||
if (!$disable_jit && $this->getExt('opcache') && str_contains($cc, 'zig')) {
|
||||
f_putenv("CC={$cc}");
|
||||
}
|
||||
if ($enableFrankenphp) {
|
||||
logger()->info('building frankenphp');
|
||||
$this->buildFrankenphp();
|
||||
|
||||
@@ -192,12 +192,12 @@ class SystemUtil
|
||||
/**
|
||||
* Get libc version string from ldd
|
||||
*/
|
||||
public static function getLibcVersionIfExists(): ?string
|
||||
public static function getLibcVersionIfExists(string $libc): ?string
|
||||
{
|
||||
if (self::$libc_version !== null) {
|
||||
return self::$libc_version;
|
||||
}
|
||||
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'glibc') {
|
||||
if ($libc === 'glibc') {
|
||||
$result = shell()->execWithResult('ldd --version', false);
|
||||
if ($result[0] !== 0) {
|
||||
return null;
|
||||
@@ -212,7 +212,7 @@ class SystemUtil
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') {
|
||||
if ($libc === 'musl') {
|
||||
if (self::isMuslDist()) {
|
||||
$result = shell()->execWithResult('ldd 2>&1', false);
|
||||
} else {
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
class icu extends LinuxLibraryBase
|
||||
{
|
||||
@@ -16,7 +17,7 @@ class icu extends LinuxLibraryBase
|
||||
{
|
||||
$cppflags = 'CPPFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_USING_ICU_NAMESPACE=1 -DU_STATIC_IMPLEMENTATION=1 -DPIC -fPIC"';
|
||||
$cxxflags = 'CXXFLAGS="-std=c++17 -DPIC -fPIC -fno-ident"';
|
||||
$ldflags = getenv('SPC_LIBC') !== 'glibc' ? 'LDFLAGS="-static"' : '';
|
||||
$ldflags = SPCTarget::isStatic() ? 'LDFLAGS="-static"' : '';
|
||||
shell()->cd($this->source_dir . '/source')->initializeEnv($this)
|
||||
->exec(
|
||||
"{$cppflags} {$cxxflags} {$ldflags} " .
|
||||
|
||||
@@ -29,6 +29,7 @@ class MacOSBuilder extends UnixBuilderBase
|
||||
|
||||
// apply global environment variables
|
||||
GlobalEnvManager::init();
|
||||
GlobalEnvManager::afterInit();
|
||||
|
||||
// ---------- set necessary compile vars ----------
|
||||
// concurrency
|
||||
|
||||
@@ -19,6 +19,7 @@ use SPC\store\pkg\GoXcaddy;
|
||||
use SPC\util\DependencyUtil;
|
||||
use SPC\util\GlobalEnvManager;
|
||||
use SPC\util\SPCConfigUtil;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
abstract class UnixBuilderBase extends BuilderBase
|
||||
{
|
||||
@@ -202,16 +203,8 @@ abstract class UnixBuilderBase extends BuilderBase
|
||||
$util = new SPCConfigUtil($this);
|
||||
$config = $util->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
|
||||
$lens = "{$config['cflags']} {$config['ldflags']} {$config['libs']}";
|
||||
$lens .= ' ' . getenv('SPC_LIBC_LINKAGE');
|
||||
// if someone changed to EMBED_TYPE=shared, we need to add LD_LIBRARY_PATH
|
||||
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
|
||||
$ext_path = 'LD_LIBRARY_PATH=' . BUILD_LIB_PATH . ':$LD_LIBRARY_PATH ';
|
||||
FileSystem::removeFileIfExists(BUILD_LIB_PATH . '/libphp.a');
|
||||
} else {
|
||||
$ext_path = '';
|
||||
foreach (glob(BUILD_LIB_PATH . '/libphp*.so') as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
if (SPCTarget::isStatic()) {
|
||||
$lens .= ' -static';
|
||||
}
|
||||
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens);
|
||||
if ($ret !== 0) {
|
||||
@@ -327,8 +320,7 @@ abstract class UnixBuilderBase extends BuilderBase
|
||||
$debugFlags = $this->getOption('no-strip') ? "'-w -s' " : '';
|
||||
$extLdFlags = "-extldflags '-pie'";
|
||||
$muslTags = '';
|
||||
$staticFlags = '';
|
||||
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl' && getenv('SPC_LIBC_LINKAGE') === 'static') {
|
||||
if (SPCTarget::isStatic()) {
|
||||
$extLdFlags = "-extldflags '-static-pie -Wl,-z,stack-size=0x80000'";
|
||||
$muslTags = 'static_build,';
|
||||
$staticFlags = '-static -static-pie';
|
||||
|
||||
@@ -4,18 +4,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\unix\library;
|
||||
|
||||
use SPC\builder\linux\library\LinuxLibraryBase;
|
||||
use SPC\builder\macos\library\MacOSLibraryBase;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\executor\UnixAutoconfExecutor;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
trait imagemagick
|
||||
{
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
* @throws FileSystemException
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
protected function build(): void
|
||||
{
|
||||
@@ -37,11 +38,11 @@ trait imagemagick
|
||||
'--without-x',
|
||||
);
|
||||
|
||||
// special: linux musl needs `-static`
|
||||
$ldflags = ($this instanceof LinuxLibraryBase) && getenv('SPC_LIBC') !== 'glibc' ? ('-static -ldl') : '-ldl';
|
||||
// special: linux-static target needs `-static`
|
||||
$ldflags = SPCTarget::isStatic() ? ('-static -ldl') : '-ldl';
|
||||
|
||||
// special: macOS needs -iconv
|
||||
$libs = $this instanceof MacOSLibraryBase ? '-liconv' : '';
|
||||
$libs = SPCTarget::getTargetOS() === 'Darwin' ? '-liconv' : '';
|
||||
|
||||
$ac->appendEnv([
|
||||
'LDFLAGS' => $ldflags,
|
||||
|
||||
@@ -6,12 +6,13 @@ namespace SPC\builder\unix\library;
|
||||
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\executor\UnixAutoconfExecutor;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
trait ldap
|
||||
{
|
||||
public function patchBeforeBuild(): bool
|
||||
{
|
||||
$extra = getenv('SPC_LIBC') === 'glibc' ? '-ldl -lpthread -lm -lresolv -lutil' : '';
|
||||
$extra = SPCTarget::getLibc() === 'glibc' ? '-ldl -lpthread -lm -lresolv -lutil' : '';
|
||||
FileSystem::replaceFileStr($this->source_dir . '/configure', '"-lssl -lcrypto', '"-lssl -lcrypto -lz ' . $extra);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,13 @@ trait libxslt
|
||||
'--without-debugger',
|
||||
"--with-libxml-prefix={$this->getBuildRootPath()}",
|
||||
);
|
||||
$ac->exec("{$this->builder->getOption('library_path')} {$this->builder->getOption('ld_library_path')} ./configure {$ac->getConfigureArgsString()}")->make();
|
||||
if (getenv('SPC_LINUX_DEFAULT_LD_LIBRARY_PATH') && getenv('SPC_LINUX_DEFAULT_LIBRARY_PATH')) {
|
||||
$ac->appendEnv([
|
||||
'LD_LIBRARY_PATH' => getenv('SPC_LINUX_DEFAULT_LD_LIBRARY_PATH'),
|
||||
'LIBRARY_PATH' => getenv('SPC_LINUX_DEFAULT_LIBRARY_PATH'),
|
||||
]);
|
||||
}
|
||||
$ac->configure()->make();
|
||||
|
||||
$this->patchPkgconfPrefix(['libexslt.pc']);
|
||||
$this->patchLaDependencyPrefix();
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace SPC\builder\unix\library;
|
||||
|
||||
use SPC\util\executor\UnixCMakeExecutor;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
trait mimalloc
|
||||
{
|
||||
@@ -13,9 +14,9 @@ trait mimalloc
|
||||
$cmake = UnixCMakeExecutor::create($this)
|
||||
->addConfigureArgs(
|
||||
'-DMI_BUILD_SHARED=OFF',
|
||||
'-DMI_INSTALL_TOPLEVEL=ON'
|
||||
'-DMI_INSTALL_TOPLEVEL=ON',
|
||||
);
|
||||
if (getenv('SPC_LIBC') === 'musl') {
|
||||
if (SPCTarget::getLibc() === 'musl') {
|
||||
$cmake->addConfigureArgs('-DMI_LIBC_MUSL=ON');
|
||||
}
|
||||
$cmake->build();
|
||||
|
||||
@@ -4,17 +4,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\unix\library;
|
||||
|
||||
use SPC\builder\linux\library\LinuxLibraryBase;
|
||||
use SPC\util\executor\UnixAutoconfExecutor;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
trait pkgconfig
|
||||
{
|
||||
protected function build(): void
|
||||
{
|
||||
UnixAutoconfExecutor::create($this)
|
||||
->appendEnv([
|
||||
->appendEnv([[
|
||||
'CFLAGS' => '-Wimplicit-function-declaration -Wno-int-conversion',
|
||||
'LDFLAGS' => !($this instanceof LinuxLibraryBase) || getenv('SPC_LIBC') === 'glibc' ? '' : '--static',
|
||||
'LDFLAGS' => SPCTarget::isStatic() ? '--static' : '',
|
||||
])
|
||||
->configure(
|
||||
'--with-internal-glib',
|
||||
|
||||
@@ -8,6 +8,7 @@ use SPC\builder\linux\library\LinuxLibraryBase;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
trait postgresql
|
||||
{
|
||||
@@ -50,7 +51,7 @@ trait postgresql
|
||||
$error_exec_cnt += $output[0] === 0 ? 0 : 1;
|
||||
if (!empty($output[1][0])) {
|
||||
$ldflags = $output[1][0];
|
||||
$envs .= !($this instanceof LinuxLibraryBase) || getenv('SPC_LIBC') === 'glibc' ? " LDFLAGS=\"{$ldflags}\" " : " LDFLAGS=\"{$ldflags} -static\" ";
|
||||
$envs .= SPCTarget::isStatic() ? " LDFLAGS=\"{$ldflags} -static\" " : " LDFLAGS=\"{$ldflags}\" ";
|
||||
}
|
||||
$output = shell()->execWithResult("pkg-config --libs-only-l --static {$packages}");
|
||||
$error_exec_cnt += $output[0] === 0 ? 0 : 1;
|
||||
|
||||
@@ -34,6 +34,7 @@ class WindowsBuilder extends BuilderBase
|
||||
$this->options = $options;
|
||||
|
||||
GlobalEnvManager::init();
|
||||
GlobalEnvManager::afterInit();
|
||||
|
||||
// ---------- set necessary options ----------
|
||||
// set sdk (require visual studio 16 or 17)
|
||||
|
||||
@@ -99,6 +99,7 @@ abstract class BaseCommand extends Command
|
||||
// init GlobalEnv
|
||||
if (!$this instanceof BuildCommand) {
|
||||
GlobalEnvManager::init();
|
||||
f_putenv('SPC_SKIP_TOOLCHAIN_CHECK=yes');
|
||||
}
|
||||
if ($this->shouldExecute()) {
|
||||
try {
|
||||
|
||||
@@ -13,6 +13,7 @@ use SPC\store\SourcePatcher;
|
||||
use SPC\util\DependencyUtil;
|
||||
use SPC\util\GlobalEnvManager;
|
||||
use SPC\util\LicenseDumper;
|
||||
use SPC\util\SPCTarget;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
@@ -63,8 +64,8 @@ class BuildPHPCommand extends BuildCommand
|
||||
|
||||
// check dynamic extension build env
|
||||
// linux must build with glibc
|
||||
if (!empty($shared_extensions) && PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') !== 'glibc' && getenv('SPC_LIBC_LINKAGE') === '-static') {
|
||||
$this->output->writeln('Linux does not support dynamic extension loading with musl-libc full-static build, please build with glibc!');
|
||||
if (!empty($shared_extensions) && SPCTarget::isStatic()) {
|
||||
$this->output->writeln('Linux does not support dynamic extension loading with fully static builds, please build with a shared C runtime target!');
|
||||
return static::FAILURE;
|
||||
}
|
||||
$static_and_shared = array_intersect($static_extensions, $shared_extensions);
|
||||
@@ -133,6 +134,8 @@ class BuildPHPCommand extends BuildCommand
|
||||
// print info
|
||||
$indent_texts = [
|
||||
'Build OS' => PHP_OS_FAMILY . ' (' . php_uname('m') . ')',
|
||||
'Build Target' => getenv('SPC_TARGET'),
|
||||
'Build Toolchain' => getenv('SPC_TOOLCHAIN'),
|
||||
'Build SAPI' => $builder->getBuildTypeName($rule),
|
||||
'Static Extensions (' . count($static_extensions) . ')' => implode(',', $static_extensions),
|
||||
'Shared Extensions (' . count($shared_extensions) . ')' => implode(',', $shared_extensions),
|
||||
|
||||
@@ -10,7 +10,7 @@ use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
#[AsCommand('craft', 'Build static-php from craft.yml')]
|
||||
class CraftCommand extends BaseCommand
|
||||
class CraftCommand extends BuildCommand
|
||||
{
|
||||
public function configure(): void
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||
use SPC\exception\DownloaderException;
|
||||
use SPC\exception\FileSystemException;
|
||||
@@ -14,6 +13,7 @@ use SPC\store\Config;
|
||||
use SPC\store\Downloader;
|
||||
use SPC\store\LockFile;
|
||||
use SPC\util\DependencyUtil;
|
||||
use SPC\util\SPCTarget;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -223,8 +223,8 @@ class DownloadCommand extends BaseCommand
|
||||
'{name}' => $source,
|
||||
'{arch}' => arch2gnu(php_uname('m')),
|
||||
'{os}' => strtolower(PHP_OS_FAMILY),
|
||||
'{libc}' => getenv('SPC_LIBC') ?: 'default',
|
||||
'{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default',
|
||||
'{libc}' => SPCTarget::getLibc() ?? 'default',
|
||||
'{libcver}' => SPCTarget::getLibcVersion() ?? 'default',
|
||||
];
|
||||
$find = str_replace(array_keys($replace), array_values($replace), Config::getPreBuilt('match-pattern'));
|
||||
// find filename in asset list
|
||||
|
||||
@@ -11,7 +11,7 @@ use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand('spc-config', 'Build dependencies')]
|
||||
class SPCConfigCommand extends BuildCommand
|
||||
class SPCConfigCommand extends BaseCommand
|
||||
{
|
||||
protected bool $no_motd = true;
|
||||
|
||||
|
||||
37
src/SPC/command/dev/EnvCommand.php
Normal file
37
src/SPC/command/dev/EnvCommand.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command\dev;
|
||||
|
||||
use SPC\command\BaseCommand;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
#[AsCommand('dev:env', 'Returns the internally defined environment variables')]
|
||||
class EnvCommand extends BaseCommand
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->addArgument('env', InputArgument::REQUIRED, 'The environment variable to show, if not set, all will be shown');
|
||||
}
|
||||
|
||||
public function initialize(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
$this->no_motd = true;
|
||||
parent::initialize($input, $output);
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$env = $this->getArgument('env');
|
||||
if (($val = getenv($env)) === false) {
|
||||
$this->output->writeln("<error>Environment variable '{$env}' is not set.</error>");
|
||||
return static::FAILURE;
|
||||
}
|
||||
$this->output->writeln("<info>{$val}</info>");
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ namespace SPC\command\dev;
|
||||
|
||||
use SPC\builder\BuilderProvider;
|
||||
use SPC\builder\LibraryBase;
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\command\BuildCommand;
|
||||
use SPC\exception\ExceptionHandler;
|
||||
use SPC\exception\FileSystemException;
|
||||
@@ -16,6 +15,7 @@ use SPC\store\Config;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\store\LockFile;
|
||||
use SPC\util\DependencyUtil;
|
||||
use SPC\util\SPCTarget;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
@@ -76,8 +76,8 @@ class PackLibCommand extends BuildCommand
|
||||
'{name}' => $lib->getName(),
|
||||
'{arch}' => arch2gnu(php_uname('m')),
|
||||
'{os}' => strtolower(PHP_OS_FAMILY),
|
||||
'{libc}' => getenv('SPC_LIBC') ?: 'default',
|
||||
'{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default',
|
||||
'{libc}' => SPCTarget::getLibc() ?? 'default',
|
||||
'{libcver}' => SPCTarget::getLibcVersion() ?? 'default',
|
||||
];
|
||||
// detect suffix, for proper tar option
|
||||
$tar_option = $this->getTarOptionFromSuffix(Config::getPreBuilt('match-pattern'));
|
||||
|
||||
@@ -72,6 +72,14 @@ final class CheckListHandler
|
||||
{
|
||||
foreach (FileSystem::getClassesPsr4(__DIR__ . '/item', 'SPC\doctor\item') as $class) {
|
||||
$ref = new \ReflectionClass($class);
|
||||
$optional = $ref->getAttributes(OptionalCheck::class)[0] ?? null;
|
||||
if ($optional !== null) {
|
||||
/** @var OptionalCheck $instance */
|
||||
$instance = $optional->newInstance();
|
||||
if (is_callable($instance->check) && !call_user_func($instance->check)) {
|
||||
continue; // skip this class if optional check is false
|
||||
}
|
||||
}
|
||||
foreach ($ref->getMethods() as $method) {
|
||||
foreach ($method->getAttributes() as $a) {
|
||||
if (is_a($a->getName(), AsCheckItem::class, true)) {
|
||||
|
||||
11
src/SPC/doctor/OptionalCheck.php
Normal file
11
src/SPC/doctor/OptionalCheck.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\doctor;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
|
||||
class OptionalCheck
|
||||
{
|
||||
public function __construct(public array $check) {}
|
||||
}
|
||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\doctor\item;
|
||||
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\doctor\AsCheckItem;
|
||||
use SPC\doctor\AsFixItem;
|
||||
use SPC\doctor\CheckResult;
|
||||
use SPC\doctor\OptionalCheck;
|
||||
use SPC\exception\DownloaderException;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
@@ -16,23 +16,20 @@ use SPC\store\Downloader;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\store\PackageManager;
|
||||
use SPC\store\SourcePatcher;
|
||||
use SPC\toolchain\MuslToolchain;
|
||||
|
||||
#[OptionalCheck([self::class, 'optionalCheck'])]
|
||||
class LinuxMuslCheck
|
||||
{
|
||||
public static function optionalCheck(): bool
|
||||
{
|
||||
return getenv('SPC_TOOLCHAIN') === MuslToolchain::class;
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
#[AsCheckItem('if musl-wrapper is installed', limit_os: 'Linux', level: 800)]
|
||||
public function checkMusl(): CheckResult
|
||||
{
|
||||
if (SystemUtil::isMuslDist()) {
|
||||
return CheckResult::ok('musl-based distro, skipped');
|
||||
}
|
||||
if (getenv('SPC_LIBC') === 'glibc') {
|
||||
return CheckResult::ok('Building with glibc, skipped');
|
||||
}
|
||||
if (str_contains(getenv('CC'), 'zig')) {
|
||||
return CheckResult::ok('Building with zig, skipped');
|
||||
}
|
||||
|
||||
$musl_wrapper_lib = sprintf('/lib/ld-musl-%s.so.1', php_uname('m'));
|
||||
if (file_exists($musl_wrapper_lib) && file_exists('/usr/local/musl/lib/libc.a')) {
|
||||
return CheckResult::ok();
|
||||
@@ -43,16 +40,6 @@ class LinuxMuslCheck
|
||||
#[AsCheckItem('if musl-cross-make is installed', limit_os: 'Linux', level: 799)]
|
||||
public function checkMuslCrossMake(): CheckResult
|
||||
{
|
||||
if (SystemUtil::isMuslDist()) {
|
||||
return CheckResult::ok('musl-based distro, skipped');
|
||||
}
|
||||
if (getenv('SPC_LIBC') === 'glibc') {
|
||||
return CheckResult::ok('Building with glibc, skipped');
|
||||
}
|
||||
if (str_contains(getenv('CC'), 'zig')) {
|
||||
return CheckResult::ok('Building with zig, skipped');
|
||||
}
|
||||
|
||||
$arch = arch2gnu(php_uname('m'));
|
||||
$cross_compile_lib = "/usr/local/musl/{$arch}-linux-musl/lib/libc.a";
|
||||
$cross_compile_gcc = "/usr/local/musl/bin/{$arch}-linux-musl-gcc";
|
||||
|
||||
@@ -51,6 +51,7 @@ class LinuxToolCheckList
|
||||
'binutils-gold' => 'ld.gold',
|
||||
'base-devel' => 'automake',
|
||||
'gettext-devel' => 'gettextize',
|
||||
'gettext-dev' => 'gettextize',
|
||||
];
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
|
||||
@@ -4,13 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\store;
|
||||
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\exception\DownloaderException;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\store\pkg\CustomPackage;
|
||||
use SPC\store\source\CustomSourceBase;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
/**
|
||||
* Source Downloader.
|
||||
@@ -591,7 +591,12 @@ class Downloader
|
||||
|
||||
public static function getPreBuiltLockName(string $source): string
|
||||
{
|
||||
return "{$source}-" . PHP_OS_FAMILY . '-' . getenv('GNU_ARCH') . '-' . (getenv('SPC_LIBC') ?: 'default') . '-' . (SystemUtil::getLibcVersionIfExists() ?? 'default');
|
||||
$os_family = PHP_OS_FAMILY;
|
||||
$gnu_arch = getenv('GNU_ARCH') ?: 'unknown';
|
||||
$libc = SPCTarget::getLibc();
|
||||
$libc_version = SPCTarget::getLibcVersion() ?? 'default';
|
||||
|
||||
return "{$source}-{$os_family}-{$gnu_arch}-{$libc}-{$libc_version}";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,13 +11,13 @@ use SPC\builder\unix\UnixBuilderBase;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\util\SPCTarget;
|
||||
|
||||
class SourcePatcher
|
||||
{
|
||||
public static function init(): void
|
||||
{
|
||||
// FileSystem::addSourceExtractHook('swow', [__CLASS__, 'patchSwow']);
|
||||
FileSystem::addSourceExtractHook('micro', [__CLASS__, 'patchMicro']);
|
||||
FileSystem::addSourceExtractHook('openssl', [__CLASS__, 'patchOpenssl11Darwin']);
|
||||
FileSystem::addSourceExtractHook('swoole', [__CLASS__, 'patchSwoole']);
|
||||
FileSystem::addSourceExtractHook('php-src', [__CLASS__, 'patchPhpLibxml212']);
|
||||
@@ -105,7 +105,7 @@ class SourcePatcher
|
||||
* @throws RuntimeException
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
public static function patchMicro(string $name = '', string $target = '', ?array $items = null): bool
|
||||
public static function patchMicro(?array $items = null): bool
|
||||
{
|
||||
if (!file_exists(SOURCE_PATH . '/php-src/sapi/micro/php_micro.c')) {
|
||||
return false;
|
||||
@@ -152,11 +152,7 @@ class SourcePatcher
|
||||
|
||||
foreach ($patches as $patch) {
|
||||
logger()->info("Patching micro with {$patch}");
|
||||
$patchesStr = str_replace('/', DIRECTORY_SEPARATOR, $patch);
|
||||
f_passthru(
|
||||
'cd ' . SOURCE_PATH . '/php-src && ' .
|
||||
(PHP_OS_FAMILY === 'Windows' ? 'type' : 'cat') . ' ' . $patchesStr . ' | patch -p1 '
|
||||
);
|
||||
self::patchFile(SOURCE_PATH . "/php-src/{$patch}", SOURCE_PATH . '/php-src');
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -165,24 +161,32 @@ class SourcePatcher
|
||||
/**
|
||||
* Use existing patch file for patching
|
||||
*
|
||||
* @param string $patch_name Patch file name in src/globals/patch/
|
||||
* @param string $patch_name Patch file name in src/globals/patch/ or absolute path
|
||||
* @param string $cwd Working directory for patch command
|
||||
* @param bool $reverse Reverse patches (default: False)
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public static function patchFile(string $patch_name, string $cwd, bool $reverse = false): bool
|
||||
{
|
||||
if (!file_exists(ROOT_DIR . "/src/globals/patch/{$patch_name}")) {
|
||||
if (FileSystem::isRelativePath($patch_name)) {
|
||||
$patch_file = ROOT_DIR . "/src/globals/patch/{$patch_name}";
|
||||
} else {
|
||||
$patch_file = $patch_name;
|
||||
}
|
||||
if (!file_exists($patch_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$patch_file = ROOT_DIR . "/src/globals/patch/{$patch_name}";
|
||||
$patch_str = str_replace('/', DIRECTORY_SEPARATOR, $patch_file);
|
||||
$patch_str = FileSystem::convertPath($patch_file);
|
||||
if (!file_exists($patch_str)) {
|
||||
throw new RuntimeException("Patch file [{$patch_str}] does not exist");
|
||||
}
|
||||
|
||||
// Copy patch from phar
|
||||
if (\Phar::running() !== '') {
|
||||
file_put_contents(SOURCE_PATH . '/' . $patch_name, file_get_contents($patch_file));
|
||||
$patch_str = str_replace('/', DIRECTORY_SEPARATOR, SOURCE_PATH . '/' . $patch_name);
|
||||
if (str_starts_with($patch_str, 'phar://')) {
|
||||
$filename = pathinfo($patch_file, PATHINFO_BASENAME);
|
||||
file_put_contents(SOURCE_PATH . "/{$filename}", file_get_contents($patch_file));
|
||||
$patch_str = FileSystem::convertPath(SOURCE_PATH . "/{$filename}");
|
||||
}
|
||||
|
||||
// detect
|
||||
@@ -458,7 +462,7 @@ class SourcePatcher
|
||||
|
||||
public static function patchFfiCentos7FixO3strncmp(): bool
|
||||
{
|
||||
if (PHP_OS_FAMILY !== 'Linux' || SystemUtil::getLibcVersionIfExists() > '2.17') {
|
||||
if (!($ver = SPCTarget::getLibcVersion()) || version_compare($ver, '2.17', '>')) {
|
||||
return false;
|
||||
}
|
||||
if (!file_exists(SOURCE_PATH . '/php-src/main/php_version.h')) {
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace SPC\store\pkg;
|
||||
use SPC\store\Downloader;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\store\LockFile;
|
||||
use SPC\util\GlobalEnvManager;
|
||||
|
||||
class GoXcaddy extends CustomPackage
|
||||
{
|
||||
@@ -65,7 +64,6 @@ class GoXcaddy extends CustomPackage
|
||||
|
||||
FileSystem::extractPackage($name, $source_type, $filename, $extract);
|
||||
|
||||
GlobalEnvManager::init();
|
||||
// install xcaddy
|
||||
shell()
|
||||
->appendEnv([
|
||||
|
||||
33
src/SPC/toolchain/ClangNativeToolchain.php
Normal file
33
src/SPC/toolchain/ClangNativeToolchain.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\toolchain;
|
||||
|
||||
use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil;
|
||||
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
|
||||
use SPC\builder\macos\SystemUtil as MacOSSystemUtil;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\util\GlobalEnvManager;
|
||||
|
||||
class ClangNativeToolchain implements ToolchainInterface
|
||||
{
|
||||
public function initEnv(): void
|
||||
{
|
||||
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CC=clang');
|
||||
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=clang++');
|
||||
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar');
|
||||
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld');
|
||||
}
|
||||
|
||||
public function afterInit(): void
|
||||
{
|
||||
// check clang exists
|
||||
match (PHP_OS_FAMILY) {
|
||||
'Linux' => LinuxSystemUtil::findCommand('clang++') ?? throw new WrongUsageException('Clang++ not found, please install it or manually set CC/CXX to a valid path.'),
|
||||
'Darwin' => MacOSSystemUtil::findCommand('clang++') ?? throw new WrongUsageException('Clang++ not found, please install it or set CC/CXX to a valid path.'),
|
||||
'BSD' => FreeBSDSystemUtil::findCommand('clang++') ?? throw new WrongUsageException('Clang++ not found, please install it or set CC/CXX to a valid path.'),
|
||||
default => throw new WrongUsageException('Clang is not supported on ' . PHP_OS_FAMILY . '.'),
|
||||
};
|
||||
}
|
||||
}
|
||||
33
src/SPC/toolchain/GccNativeToolchain.php
Normal file
33
src/SPC/toolchain/GccNativeToolchain.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\toolchain;
|
||||
|
||||
use SPC\builder\freebsd\SystemUtil as FreeBSDSystemUtil;
|
||||
use SPC\builder\linux\SystemUtil as LinuxSystemUtil;
|
||||
use SPC\builder\macos\SystemUtil as MacOSSystemUtil;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\util\GlobalEnvManager;
|
||||
|
||||
class GccNativeToolchain implements ToolchainInterface
|
||||
{
|
||||
public function initEnv(): void
|
||||
{
|
||||
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CC=gcc');
|
||||
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_CXX=g++');
|
||||
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_AR=ar');
|
||||
GlobalEnvManager::putenv('SPC_LINUX_DEFAULT_LD=ld.gold');
|
||||
}
|
||||
|
||||
public function afterInit(): void
|
||||
{
|
||||
// check gcc exists
|
||||
match (PHP_OS_FAMILY) {
|
||||
'Linux' => LinuxSystemUtil::findCommand('g++') ?? throw new WrongUsageException('g++ not found, please install it or set CC/CXX to a valid path.'),
|
||||
'Darwin' => MacOSSystemUtil::findCommand('g++') ?? throw new WrongUsageException('g++ not found, please install it or set CC/CXX to a valid path.'),
|
||||
'BSD' => FreeBSDSystemUtil::findCommand('g++') ?? throw new WrongUsageException('g++ not found, please install it or set CC/CXX to a valid path.'),
|
||||
default => throw new \RuntimeException('GCC is not supported on ' . PHP_OS_FAMILY . '.'),
|
||||
};
|
||||
}
|
||||
}
|
||||
12
src/SPC/toolchain/MSVCToolchain.php
Normal file
12
src/SPC/toolchain/MSVCToolchain.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\toolchain;
|
||||
|
||||
class MSVCToolchain implements ToolchainInterface
|
||||
{
|
||||
public function initEnv(): void {}
|
||||
|
||||
public function afterInit(): void {}
|
||||
}
|
||||
39
src/SPC/toolchain/MuslToolchain.php
Normal file
39
src/SPC/toolchain/MuslToolchain.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\toolchain;
|
||||
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\util\GlobalEnvManager;
|
||||
|
||||
class MuslToolchain implements ToolchainInterface
|
||||
{
|
||||
public function initEnv(): void
|
||||
{
|
||||
$arch = getenv('GNU_ARCH');
|
||||
// Set environment variables for musl toolchain
|
||||
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CC={$arch}-linux-musl-gcc");
|
||||
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CXX={$arch}-linux-musl-g++");
|
||||
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_AR={$arch}-linux-musl-ar");
|
||||
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_LD={$arch}-linux-musl-ld");
|
||||
GlobalEnvManager::addPathIfNotExists('/usr/local/musl/bin');
|
||||
GlobalEnvManager::addPathIfNotExists("/usr/local/musl/{$arch}-linux-musl/bin");
|
||||
|
||||
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_LD_LIBRARY_PATH=/usr/local/musl/lib:/usr/local/musl/{$arch}-linux-musl/lib");
|
||||
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_LIBRARY_PATH=/usr/local/musl/lib:/usr/local/musl/{$arch}-linux-musl/lib");
|
||||
}
|
||||
|
||||
public function afterInit(): void
|
||||
{
|
||||
$arch = getenv('GNU_ARCH');
|
||||
// append LD_LIBRARY_PATH to $configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
|
||||
$configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
|
||||
$ld_library_path = getenv('SPC_LINUX_DEFAULT_LD_LIBRARY_PATH');
|
||||
GlobalEnvManager::putenv("SPC_CMD_PREFIX_PHP_CONFIGURE=LD_LIBRARY_PATH=\"{$ld_library_path}\" {$configure}");
|
||||
|
||||
if (!file_exists("/usr/local/musl/{$arch}-linux-musl/lib/libc.a")) {
|
||||
throw new WrongUsageException('You are building with musl-libc target in glibc distro, but musl-toolchain is not installed, please install musl-toolchain first. (You can use `doctor` command to install it)');
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/SPC/toolchain/ToolchainInterface.php
Normal file
18
src/SPC/toolchain/ToolchainInterface.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\toolchain;
|
||||
|
||||
interface ToolchainInterface
|
||||
{
|
||||
/**
|
||||
* Initialize the environment for the given target.
|
||||
*/
|
||||
public function initEnv(): void;
|
||||
|
||||
/**
|
||||
* Perform actions after the environment has been initialized for the given target.
|
||||
*/
|
||||
public function afterInit(): void;
|
||||
}
|
||||
52
src/SPC/toolchain/ToolchainManager.php
Normal file
52
src/SPC/toolchain/ToolchainManager.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\toolchain;
|
||||
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\util\GlobalEnvManager;
|
||||
|
||||
class ToolchainManager
|
||||
{
|
||||
public const array OS_DEFAULT_TOOLCHAIN = [
|
||||
'Linux' => MuslToolchain::class, // use musl toolchain by default, after zig pr merged, change this to ZigToolchain::class
|
||||
'Windows' => MSVCToolchain::class,
|
||||
'Darwin' => ClangNativeToolchain::class,
|
||||
'BSD' => ClangNativeToolchain::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
public static function initToolchain(): void
|
||||
{
|
||||
$libc = getenv('SPC_LIBC');
|
||||
if ($libc !== false) {
|
||||
// uncomment this when zig pr is merged
|
||||
// logger()->warning('SPC_LIBC is deprecated, please use SPC_TARGET instead.');
|
||||
$toolchain = match ($libc) {
|
||||
'musl' => SystemUtil::isMuslDist() ? GccNativeToolchain::class : MuslToolchain::class,
|
||||
'glibc' => !SystemUtil::isMuslDist() ? GccNativeToolchain::class : throw new WrongUsageException('SPC_TARGET must be musl-static or musl for musl dist.'),
|
||||
default => throw new WrongUsageException('Unsupported SPC_LIBC value: ' . $libc),
|
||||
};
|
||||
} else {
|
||||
$toolchain = self::OS_DEFAULT_TOOLCHAIN[PHP_OS_FAMILY];
|
||||
}
|
||||
$toolchainClass = $toolchain;
|
||||
/* @var ToolchainInterface $toolchainClass */
|
||||
(new $toolchainClass())->initEnv();
|
||||
GlobalEnvManager::putenv("SPC_TOOLCHAIN={$toolchain}");
|
||||
}
|
||||
|
||||
public static function afterInitToolchain(): void
|
||||
{
|
||||
if (!getenv('SPC_TOOLCHAIN')) {
|
||||
throw new WrongUsageException('SPC_TOOLCHAIN not set');
|
||||
}
|
||||
$toolchain = getenv('SPC_TOOLCHAIN');
|
||||
/* @var ToolchainInterface $toolchain */
|
||||
(new $toolchain())->afterInit();
|
||||
}
|
||||
}
|
||||
12
src/SPC/toolchain/ZigToolchain.php
Normal file
12
src/SPC/toolchain/ZigToolchain.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\toolchain;
|
||||
|
||||
class ZigToolchain implements ToolchainInterface
|
||||
{
|
||||
public function initEnv(): void {}
|
||||
|
||||
public function afterInit(): void {}
|
||||
}
|
||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\util;
|
||||
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\store\pkg\Zig;
|
||||
use SPC\toolchain\ToolchainManager;
|
||||
|
||||
/**
|
||||
* Environment variable manager
|
||||
@@ -41,30 +41,6 @@ class GlobalEnvManager
|
||||
self::putenv('PKG_CONFIG_PATH=' . BUILD_ROOT_PATH . '/lib/pkgconfig');
|
||||
}
|
||||
|
||||
// Define env vars for linux
|
||||
if (PHP_OS_FAMILY === 'Linux') {
|
||||
$arch = getenv('GNU_ARCH');
|
||||
|
||||
if (str_contains((string) getenv('CC'), 'zig')) {
|
||||
self::putenv('SPC_LINUX_DEFAULT_CC=zig-cc');
|
||||
self::putenv('SPC_LINUX_DEFAULT_CXX=zig-c++');
|
||||
self::putenv('SPC_LINUX_DEFAULT_AR=ar');
|
||||
self::putenv('SPC_LINUX_DEFAULT_LD=ld.lld');
|
||||
} elseif (SystemUtil::isMuslDist() || getenv('SPC_LIBC') === 'glibc') {
|
||||
self::putenv('SPC_LINUX_DEFAULT_CC=gcc');
|
||||
self::putenv('SPC_LINUX_DEFAULT_CXX=g++');
|
||||
self::putenv('SPC_LINUX_DEFAULT_AR=ar');
|
||||
self::putenv('SPC_LINUX_DEFAULT_LD=ld.gold');
|
||||
} else {
|
||||
self::putenv("SPC_LINUX_DEFAULT_CC={$arch}-linux-musl-gcc");
|
||||
self::putenv("SPC_LINUX_DEFAULT_CXX={$arch}-linux-musl-g++");
|
||||
self::putenv("SPC_LINUX_DEFAULT_AR={$arch}-linux-musl-ar");
|
||||
self::putenv("SPC_LINUX_DEFAULT_LD={$arch}-linux-musl-ld");
|
||||
self::addPathIfNotExists('/usr/local/musl/bin');
|
||||
self::addPathIfNotExists("/usr/local/musl/{$arch}-linux-musl/bin");
|
||||
}
|
||||
}
|
||||
|
||||
$ini = self::readIniFile();
|
||||
|
||||
$default_put_list = [];
|
||||
@@ -87,6 +63,9 @@ class GlobalEnvManager
|
||||
self::putenv("{$k}={$v}");
|
||||
}
|
||||
}
|
||||
|
||||
ToolchainManager::initToolchain();
|
||||
|
||||
// apply second time
|
||||
$ini2 = self::readIniFile();
|
||||
|
||||
@@ -107,17 +86,6 @@ class GlobalEnvManager
|
||||
self::putenv("{$k}={$v}");
|
||||
}
|
||||
}
|
||||
if (getenv('SPC_LIBC_LINKAGE') === '-static' && getenv('SPC_LIBC') === 'glibc') {
|
||||
self::putenv('SPC_LIBC_LINKAGE=');
|
||||
}
|
||||
if (str_contains((string) getenv('CC'), 'zig') || str_contains((string) getenv('CXX'), 'zig')) {
|
||||
$zigEnv = Zig::getEnvironment();
|
||||
foreach ($zigEnv as $key => $value) {
|
||||
if ($key === 'PATH') {
|
||||
self::addPathIfNotExists($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function putenv(string $val): void
|
||||
@@ -133,6 +101,19 @@ class GlobalEnvManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the toolchain after the environment variables are set.
|
||||
* The toolchain or environment availability check is done here.
|
||||
*
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
public static function afterInit(): void
|
||||
{
|
||||
if (!filter_var(getenv('SPC_SKIP_TOOLCHAIN_CHECK'), FILTER_VALIDATE_BOOL)) {
|
||||
ToolchainManager::afterInitToolchain();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
|
||||
@@ -56,7 +56,7 @@ class SPCConfigUtil
|
||||
ob_get_clean();
|
||||
$ldflags = $this->getLdflagsString();
|
||||
$libs = $this->getLibsString($libraries, $with_dependencies);
|
||||
if (PHP_OS_FAMILY === 'Darwin') {
|
||||
if (SPCTarget::getTargetOS() === 'Darwin') {
|
||||
$libs .= " {$this->getFrameworksString($extensions)}";
|
||||
}
|
||||
$cflags = $this->getIncludesString();
|
||||
|
||||
87
src/SPC/util/SPCTarget.php
Normal file
87
src/SPC/util/SPCTarget.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\util;
|
||||
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\exception\WrongUsageException;
|
||||
|
||||
/**
|
||||
* SPC build target constants and toolchain initialization.
|
||||
* format: {target_name}[-{libc_subtype}]
|
||||
*/
|
||||
class SPCTarget
|
||||
{
|
||||
public const array LIBC_LIST = [
|
||||
'musl',
|
||||
'glibc',
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns whether the target is a full-static target.
|
||||
*/
|
||||
public static function isStatic(): bool
|
||||
{
|
||||
$env = getenv('SPC_TARGET');
|
||||
$libc = getenv('SPC_LIBC');
|
||||
// if SPC_LIBC is set, it means the target is static, remove it when 3.0 is released
|
||||
if ($libc === 'musl') {
|
||||
return true;
|
||||
}
|
||||
// TODO: add zig target parser here
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the libc type if set, for other OS, it will always return null.
|
||||
*/
|
||||
public static function getLibc(): ?string
|
||||
{
|
||||
$env = getenv('SPC_TARGET');
|
||||
$libc = getenv('SPC_LIBC');
|
||||
if ($libc !== false) {
|
||||
return $libc;
|
||||
}
|
||||
// TODO: zig target parser
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the libc version if set, for other OS, it will always return null.
|
||||
*/
|
||||
public static function getLibcVersion(): ?string
|
||||
{
|
||||
$env = getenv('SPC_TARGET');
|
||||
$libc = getenv('SPC_LIBC');
|
||||
if ($libc !== false) {
|
||||
// legacy method: get a version from system
|
||||
return SystemUtil::getLibcVersionIfExists($libc);
|
||||
}
|
||||
// TODO: zig target parser
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target OS family, e.g. Linux, Darwin, Windows, BSD.
|
||||
* Currently, we only support native building.
|
||||
*
|
||||
* @return 'BSD'|'Darwin'|'Linux'|'Windows'
|
||||
* @throws WrongUsageException
|
||||
*/
|
||||
public static function getTargetOS(): string
|
||||
{
|
||||
$target = getenv('SPC_TARGET');
|
||||
if ($target === false) {
|
||||
return PHP_OS_FAMILY;
|
||||
}
|
||||
// TODO: zig target parser like below?
|
||||
return match (true) {
|
||||
str_contains($target, 'linux') => 'Linux',
|
||||
str_contains($target, 'macos') => 'Darwin',
|
||||
str_contains($target, 'windows') => 'Windows',
|
||||
default => throw new WrongUsageException('Cannot parse target.'),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -21,15 +21,15 @@ $test_php_version = [
|
||||
|
||||
// test os (macos-13, macos-14, macos-15, ubuntu-latest, windows-latest are available)
|
||||
$test_os = [
|
||||
// 'macos-13',
|
||||
// 'macos-14',
|
||||
// 'macos-15',
|
||||
// 'ubuntu-latest',
|
||||
// 'ubuntu-22.04',
|
||||
// 'ubuntu-22.04-arm',
|
||||
'ubuntu-24.04',
|
||||
'ubuntu-24.04-arm',
|
||||
// 'windows-latest',
|
||||
// 'macos-13', // bin/spc for x86_64
|
||||
// 'macos-14', // bin/spc for arm64
|
||||
'macos-15', // bin/spc for arm64
|
||||
'ubuntu-latest', // bin/spc-alpine-docker for x86_64
|
||||
'ubuntu-22.04', // bin/spc-gnu-docker for x86_64
|
||||
'ubuntu-24.04', // bin/spc for x86_64
|
||||
// 'ubuntu-22.04-arm', // bin/spc-gnu-docker for arm64
|
||||
// 'ubuntu-24.04-arm', // bin/spc for arm64
|
||||
// 'windows-latest', // .\bin\spc.ps1
|
||||
];
|
||||
|
||||
$zig = true;
|
||||
@@ -84,7 +84,7 @@ $with_libs = match (PHP_OS_FAMILY) {
|
||||
// You can use `common`, `bulk`, `minimal` or `none`.
|
||||
// note: combination is only available for *nix platform. Windows must use `none` combination
|
||||
$base_combination = match (PHP_OS_FAMILY) {
|
||||
'Linux', 'Darwin' => 'minimal',
|
||||
'Linux', 'Darwin' => 'common',
|
||||
'Windows' => 'none',
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user