From 0a33fba23e1c5dd71545486a998016dd71cdb892 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Tue, 1 Jul 2025 14:01:48 +0700 Subject: [PATCH] zig toolchain stuff --- config/env.ini | 28 +++++------ docs/en/guide/extension-notes.md | 2 +- src/SPC/builder/linux/LinuxBuilder.php | 4 +- src/SPC/builder/unix/library/libxslt.php | 6 +-- src/SPC/doctor/item/ZigCheck.php | 59 ++++++++++++++++++++++++ src/SPC/store/pkg/CustomPackage.php | 2 + src/SPC/store/pkg/Zig.php | 21 +++++++++ src/SPC/toolchain/MuslToolchain.php | 6 +-- src/SPC/toolchain/ToolchainManager.php | 33 +++++++------ src/SPC/toolchain/ZigToolchain.php | 26 ++++++++++- 10 files changed, 149 insertions(+), 38 deletions(-) create mode 100644 src/SPC/doctor/item/ZigCheck.php diff --git a/config/env.ini b/config/env.ini index c49b9334..242887bc 100644 --- a/config/env.ini +++ b/config/env.ini @@ -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 [linux] -; Linux can use different build toolchain, but the toolchain can not be changed in this file: -; - musl (default): used for general linux distros, can build `musl-static` target only. -; - zig (WIP): used for general linux distros, can build `musl` and `glibc` targets. -; - musl-native: used for alpine linux, can build `musl-static` and `musl`(WIP) target. -; - gnu-native (assume): used for general linux distros, can build `glibc` target only and have portability issues. +; Linux can use different build toolchains. +; - musl (default, when SPC_LIBC=musl): used for general linux distros, can build `musl` (statically linked) only. +; - 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` and `musl -dynamic` target. +; - gnu-native: used for general linux distros, can build gnu target for the installed glibc version only. -; build target: -; - 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. +; LEGACY option to specify the target, switch to SPC_TARGET with zig toolchain instead 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 CC=${SPC_LINUX_DEFAULT_CC} CXX=${SPC_LINUX_DEFAULT_CXX} diff --git a/docs/en/guide/extension-notes.md b/docs/en/guide/extension-notes.md index 4dad0cfd..609fda7b 100644 --- a/docs/en/guide/extension-notes.md +++ b/docs/en/guide/extension-notes.md @@ -82,7 +82,7 @@ and this extension cannot be compiled into php by static linking, so it cannot b ## 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". 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`. diff --git a/src/SPC/builder/linux/LinuxBuilder.php b/src/SPC/builder/linux/LinuxBuilder.php index 42636d66..7ff6cff7 100644 --- a/src/SPC/builder/linux/LinuxBuilder.php +++ b/src/SPC/builder/linux/LinuxBuilder.php @@ -10,6 +10,8 @@ use SPC\exception\RuntimeException; use SPC\exception\WrongUsageException; use SPC\store\FileSystem; use SPC\store\SourcePatcher; +use SPC\toolchain\ToolchainManager; +use SPC\toolchain\ZigToolchain; use SPC\util\GlobalEnvManager; class LinuxBuilder extends UnixBuilderBase @@ -66,7 +68,7 @@ class LinuxBuilder extends UnixBuilderBase } // add libstdc++, some extensions or libraries need it $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); $cflags = $this->arch_c_flags; f_putenv('CFLAGS=' . $cflags); diff --git a/src/SPC/builder/unix/library/libxslt.php b/src/SPC/builder/unix/library/libxslt.php index aabc277d..90c63f89 100644 --- a/src/SPC/builder/unix/library/libxslt.php +++ b/src/SPC/builder/unix/library/libxslt.php @@ -33,10 +33,10 @@ trait libxslt '--without-debugger', "--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([ - 'LD_LIBRARY_PATH' => getenv('SPC_LINUX_DEFAULT_LD_LIBRARY_PATH'), - 'LIBRARY_PATH' => getenv('SPC_LINUX_DEFAULT_LIBRARY_PATH'), + 'LD_LIBRARY_PATH' => getenv('SPC_LD_LIBRARY_PATH'), + 'LIBRARY_PATH' => getenv('SPC_LIBRARY_PATH'), ]); } $ac->configure()->make(); diff --git a/src/SPC/doctor/item/ZigCheck.php b/src/SPC/doctor/item/ZigCheck.php new file mode 100644 index 00000000..3848895e --- /dev/null +++ b/src/SPC/doctor/item/ZigCheck.php @@ -0,0 +1,59 @@ + 'win', + 'Darwin' => 'macos', + 'BSD' => 'freebsd', + default => 'linux', + }; + PackageManager::installPackage("musl-toolchain-{$arch}-{$os}"); + return Zig::isInstalled(); + } +} diff --git a/src/SPC/store/pkg/CustomPackage.php b/src/SPC/store/pkg/CustomPackage.php index bc6f6e46..0602f8b6 100644 --- a/src/SPC/store/pkg/CustomPackage.php +++ b/src/SPC/store/pkg/CustomPackage.php @@ -13,4 +13,6 @@ abstract class CustomPackage abstract public function extract(string $name): void; abstract public static function getEnvironment(): array; + + abstract public static function isInstalled(): bool; } diff --git a/src/SPC/store/pkg/Zig.php b/src/SPC/store/pkg/Zig.php index aa06922f..e8c5600c 100644 --- a/src/SPC/store/pkg/Zig.php +++ b/src/SPC/store/pkg/Zig.php @@ -11,6 +11,27 @@ use SPC\store\LockFile; 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 { return [ diff --git a/src/SPC/toolchain/MuslToolchain.php b/src/SPC/toolchain/MuslToolchain.php index dd795556..e996ef1f 100644 --- a/src/SPC/toolchain/MuslToolchain.php +++ b/src/SPC/toolchain/MuslToolchain.php @@ -20,8 +20,8 @@ class MuslToolchain implements ToolchainInterface 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"); + 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 @@ -29,7 +29,7 @@ class MuslToolchain implements ToolchainInterface $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'); + $ld_library_path = getenv('SPC_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")) { diff --git a/src/SPC/toolchain/ToolchainManager.php b/src/SPC/toolchain/ToolchainManager.php index 76807bf2..5d39977a 100644 --- a/src/SPC/toolchain/ToolchainManager.php +++ b/src/SPC/toolchain/ToolchainManager.php @@ -11,33 +11,36 @@ 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 + 'Linux' => ZigToolchain::class, 'Windows' => MSVCToolchain::class, 'Darwin' => 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 */ 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; + $toolchainClass = self::getToolchainClass(); /* @var ToolchainInterface $toolchainClass */ (new $toolchainClass())->initEnv(); - GlobalEnvManager::putenv("SPC_TOOLCHAIN={$toolchain}"); + GlobalEnvManager::putenv("SPC_TOOLCHAIN={$toolchainClass}"); } public static function afterInitToolchain(): void diff --git a/src/SPC/toolchain/ZigToolchain.php b/src/SPC/toolchain/ZigToolchain.php index 3922fecb..d4e5a82d 100644 --- a/src/SPC/toolchain/ZigToolchain.php +++ b/src/SPC/toolchain/ZigToolchain.php @@ -4,9 +4,31 @@ declare(strict_types=1); namespace SPC\toolchain; +use SPC\exception\WrongUsageException; +use SPC\store\pkg\Zig; +use SPC\util\GlobalEnvManager; + 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)'); + } + } }