zig toolchain stuff

This commit is contained in:
DubbleClick 2025-07-01 14:01:48 +07:00
parent 5370af4a84
commit 0a33fba23e
10 changed files with 149 additions and 38 deletions

View File

@ -65,21 +65,23 @@ UPX_EXEC="${PKG_ROOT_PATH}\bin\upx.exe"
SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime140,win32,zend_stream,cli_static SPC_MICRO_PATCHES=static_extensions_win32,cli_checks,disable_huge_page,vcruntime140,win32,zend_stream,cli_static
[linux] [linux]
; Linux can use different build toolchain, but the toolchain can not be changed in this file: ; Linux can use different build toolchains.
; - musl (default): used for general linux distros, can build `musl-static` target only. ; - musl (default, when SPC_LIBC=musl): used for general linux distros, can build `musl` (statically linked) only.
; - zig (WIP): used for general linux distros, can build `musl` and `glibc` targets. ; - zig (will become default): usable on all Linux distros, can build `-musl`, `arch-linux-musl -dynamic` and `arch-linux-gnu` targets. Can specify version such as `x86_64-linux-gnu.2.17`.
; - musl-native: used for alpine linux, can build `musl-static` and `musl`(WIP) target. ; - musl-native: used for alpine linux, can build `musl` and `musl -dynamic` target.
; - gnu-native (assume): used for general linux distros, can build `glibc` target only and have portability issues. ; - gnu-native: used for general linux distros, can build gnu target for the installed glibc version only.
; build target: ; LEGACY option to specify the target, switch to SPC_TARGET with zig toolchain instead
; - musl-static (default): pure static linking, using musl-libc, can run on any linux distro.
; - musl: static linking with dynamic linking to musl-libc, can run on musl-based linux distro.
; - glibc: static linking with dynamic linking to glibc, can run on glibc-based linux distro.
; include PATH for musl libc.
SPC_LIBC=musl SPC_LIBC=musl
SPC_LIBC_VERSION=
SPC_LIBC_LINKAGE=-static ; Recommended: specify your target here. Zig toolchain will be used.
; examples:
; `native-native-gnu` - links against glibc, version 2.17
; `native-native-gnu.2.17` - links against glibc, version 2.17
; `native-native` - static linking against musl
; `native-native-musl -dynamic` - links against musl libc
; SPC_TARGET=
; compiler environments ; compiler environments
CC=${SPC_LINUX_DEFAULT_CC} CC=${SPC_LINUX_DEFAULT_CC}
CXX=${SPC_LINUX_DEFAULT_CXX} CXX=${SPC_LINUX_DEFAULT_CXX}

View File

@ -82,7 +82,7 @@ and this extension cannot be compiled into php by static linking, so it cannot b
## xdebug ## xdebug
1. Xdebug is only buildable as a shared extension. You need to use a build target other than `musl-static` for SPC_TARGET. 1. Xdebug is only buildable as a shared extension. On Linux, you'll need to use a SPC_TARGET like `native-native -dynamic` or `native-native-gnu`.
2. When using Linux/glibc or macOS, you can compile Xdebug as a shared extension using --build-shared="xdebug". 2. When using Linux/glibc or macOS, you can compile Xdebug as a shared extension using --build-shared="xdebug".
The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`. The compiled `./php` binary can be configured and run by specifying the INI, eg `./php -d 'zend_extension=/path/to/xdebug.so' your-code.php`.

View File

@ -10,6 +10,8 @@ use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\store\FileSystem; use SPC\store\FileSystem;
use SPC\store\SourcePatcher; use SPC\store\SourcePatcher;
use SPC\toolchain\ToolchainManager;
use SPC\toolchain\ZigToolchain;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
class LinuxBuilder extends UnixBuilderBase class LinuxBuilder extends UnixBuilderBase
@ -66,7 +68,7 @@ class LinuxBuilder extends UnixBuilderBase
} }
// add libstdc++, some extensions or libraries need it // add libstdc++, some extensions or libraries need it
$extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lstdc++ ' : ''); $extra_libs .= (empty($extra_libs) ? '' : ' ') . ($this->hasCpp() ? '-lstdc++ ' : '');
$extra_libs .= (SystemUtil::getCCType() === 'clang' ? ' -lunwind' : ''); $extra_libs .= (ToolchainManager::getToolchainClass() === ZigToolchain::class ? ' -lunwind' : '');
f_putenv('SPC_EXTRA_LIBS=' . $extra_libs); f_putenv('SPC_EXTRA_LIBS=' . $extra_libs);
$cflags = $this->arch_c_flags; $cflags = $this->arch_c_flags;
f_putenv('CFLAGS=' . $cflags); f_putenv('CFLAGS=' . $cflags);

View File

@ -33,10 +33,10 @@ trait libxslt
'--without-debugger', '--without-debugger',
"--with-libxml-prefix={$this->getBuildRootPath()}", "--with-libxml-prefix={$this->getBuildRootPath()}",
); );
if (getenv('SPC_LINUX_DEFAULT_LD_LIBRARY_PATH') && getenv('SPC_LINUX_DEFAULT_LIBRARY_PATH')) { if (getenv('SPC_LD_LIBRARY_PATH') && getenv('SPC_LIBRARY_PATH')) {
$ac->appendEnv([ $ac->appendEnv([
'LD_LIBRARY_PATH' => getenv('SPC_LINUX_DEFAULT_LD_LIBRARY_PATH'), 'LD_LIBRARY_PATH' => getenv('SPC_LD_LIBRARY_PATH'),
'LIBRARY_PATH' => getenv('SPC_LINUX_DEFAULT_LIBRARY_PATH'), 'LIBRARY_PATH' => getenv('SPC_LIBRARY_PATH'),
]); ]);
} }
$ac->configure()->make(); $ac->configure()->make();

View File

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace SPC\doctor\item;
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;
use SPC\exception\WrongUsageException;
use SPC\store\Downloader;
use SPC\store\FileSystem;
use SPC\store\PackageManager;
use SPC\store\pkg\Zig;
use SPC\store\SourcePatcher;
use SPC\toolchain\MuslToolchain;
use SPC\toolchain\ZigToolchain;
#[OptionalCheck([self::class, 'optionalCheck'])]
class ZigCheck
{
public static function optionalCheck(): bool
{
return getenv('SPC_TOOLCHAIN') === ZigToolchain::class;
}
/** @noinspection PhpUnused */
#[AsCheckItem('if zig is installed', level: 800)]
public function checkZig(): CheckResult
{
if (Zig::isInstalled()) {
return CheckResult::ok();
}
return CheckResult::fail('zig is not installed', 'install-zig');
}
/** @noinspection PhpUnused */
/**
* @throws FileSystemException
* @throws WrongUsageException
*/
#[AsFixItem('install-zig')]
public function fixMuslCrossMake(): bool
{
$arch = arch2gnu(php_uname('m'));
$os = match (PHP_OS_FAMILY) {
'Windows' => 'win',
'Darwin' => 'macos',
'BSD' => 'freebsd',
default => 'linux',
};
PackageManager::installPackage("musl-toolchain-{$arch}-{$os}");
return Zig::isInstalled();
}
}

View File

@ -13,4 +13,6 @@ abstract class CustomPackage
abstract public function extract(string $name): void; abstract public function extract(string $name): void;
abstract public static function getEnvironment(): array; abstract public static function getEnvironment(): array;
abstract public static function isInstalled(): bool;
} }

View File

@ -11,6 +11,27 @@ use SPC\store\LockFile;
class Zig extends CustomPackage class Zig extends CustomPackage
{ {
private static function getPath(): string
{
$arch = arch2gnu(php_uname('m'));
$os = match (PHP_OS_FAMILY) {
'Linux' => 'linux',
'Windows' => 'win',
'Darwin' => 'macos',
'BSD' => 'freebsd',
default => 'linux',
};
$packageName = "zig-{$arch}-{$os}";
return PKG_ROOT_PATH . "/{$packageName}";
}
public static function isInstalled(): bool
{
$path = self::getPath();
return file_exists("$path/zig") && file_exists("$path/zig-cc") && file_exists("$path/zig-c++");
}
public function getSupportName(): array public function getSupportName(): array
{ {
return [ return [

View File

@ -20,8 +20,8 @@ class MuslToolchain implements ToolchainInterface
GlobalEnvManager::addPathIfNotExists('/usr/local/musl/bin'); GlobalEnvManager::addPathIfNotExists('/usr/local/musl/bin');
GlobalEnvManager::addPathIfNotExists("/usr/local/musl/{$arch}-linux-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_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"); GlobalEnvManager::putenv("SPC_LIBRARY_PATH=/usr/local/musl/lib:/usr/local/musl/{$arch}-linux-musl/lib");
} }
public function afterInit(): void public function afterInit(): void
@ -29,7 +29,7 @@ class MuslToolchain implements ToolchainInterface
$arch = getenv('GNU_ARCH'); $arch = getenv('GNU_ARCH');
// append LD_LIBRARY_PATH to $configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE'); // append LD_LIBRARY_PATH to $configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
$configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE'); $configure = getenv('SPC_CMD_PREFIX_PHP_CONFIGURE');
$ld_library_path = getenv('SPC_LINUX_DEFAULT_LD_LIBRARY_PATH'); $ld_library_path = getenv('SPC_LD_LIBRARY_PATH');
GlobalEnvManager::putenv("SPC_CMD_PREFIX_PHP_CONFIGURE=LD_LIBRARY_PATH=\"{$ld_library_path}\" {$configure}"); 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")) { if (!file_exists("/usr/local/musl/{$arch}-linux-musl/lib/libc.a")) {

View File

@ -11,33 +11,36 @@ use SPC\util\GlobalEnvManager;
class ToolchainManager class ToolchainManager
{ {
public const array OS_DEFAULT_TOOLCHAIN = [ public const array OS_DEFAULT_TOOLCHAIN = [
'Linux' => MuslToolchain::class, // use musl toolchain by default, after zig pr merged, change this to ZigToolchain::class 'Linux' => ZigToolchain::class,
'Windows' => MSVCToolchain::class, 'Windows' => MSVCToolchain::class,
'Darwin' => ClangNativeToolchain::class, 'Darwin' => ClangNativeToolchain::class,
'BSD' => ClangNativeToolchain::class, 'BSD' => ClangNativeToolchain::class,
]; ];
public static function getToolchainClass(): string
{
$libc = getenv('SPC_LIBC');
if ($libc !== false) {
logger()->warning('SPC_LIBC is deprecated, please use SPC_TARGET instead.');
return match ($libc) {
'musl' => SystemUtil::isMuslDist() ? GccNativeToolchain::class : MuslToolchain::class,
'glibc' => !SystemUtil::isMuslDist() ? GccNativeToolchain::class : throw new WrongUsageException('SPC_TARGET must be musl for musl dist.'),
default => throw new WrongUsageException('Unsupported SPC_LIBC value: ' . $libc),
};
}
return self::OS_DEFAULT_TOOLCHAIN[PHP_OS_FAMILY];
}
/** /**
* @throws WrongUsageException * @throws WrongUsageException
*/ */
public static function initToolchain(): void public static function initToolchain(): void
{ {
$libc = getenv('SPC_LIBC'); $toolchainClass = self::getToolchainClass();
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 */ /* @var ToolchainInterface $toolchainClass */
(new $toolchainClass())->initEnv(); (new $toolchainClass())->initEnv();
GlobalEnvManager::putenv("SPC_TOOLCHAIN={$toolchain}"); GlobalEnvManager::putenv("SPC_TOOLCHAIN={$toolchainClass}");
} }
public static function afterInitToolchain(): void public static function afterInitToolchain(): void

View File

@ -4,9 +4,31 @@ declare(strict_types=1);
namespace SPC\toolchain; namespace SPC\toolchain;
use SPC\exception\WrongUsageException;
use SPC\store\pkg\Zig;
use SPC\util\GlobalEnvManager;
class ZigToolchain implements ToolchainInterface class ZigToolchain implements ToolchainInterface
{ {
public function initEnv(): void {} public function initEnv(): void
{
$arch = getenv('GNU_ARCH');
// Set environment variables for musl toolchain
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CC=zig-cc");
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_CXX=zig-c++");
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_AR=ar");
GlobalEnvManager::putenv("SPC_LINUX_DEFAULT_LD=ld");
GlobalEnvManager::addPathIfNotExists('/usr/local/musl/bin');
GlobalEnvManager::addPathIfNotExists("/usr/local/musl/{$arch}-linux-musl/bin");
public function afterInit(): void {} GlobalEnvManager::putenv("SPC_LD_LIBRARY_PATH=/usr/local/musl/lib:/usr/local/musl/{$arch}-linux-musl/lib");
GlobalEnvManager::putenv("SPC_LIBRARY_PATH=/usr/local/musl/lib:/usr/local/musl/{$arch}-linux-musl/lib");
}
public function afterInit(): void
{
if (!is_dir(Zig::getEnvironment()['PATH'])) {
throw new WrongUsageException('You are building with zig, but zig is not installed, please install zig first. (You can use `doctor` command to install it)');
}
}
} }