diff --git a/src/Package/Artifact/go_xcaddy.php b/src/Package/Artifact/go_xcaddy.php
index 152dc2e5c..293f7c62b 100644
--- a/src/Package/Artifact/go_xcaddy.php
+++ b/src/Package/Artifact/go_xcaddy.php
@@ -4,13 +4,13 @@
namespace Package\Artifact;
-use SPC\util\GlobalEnvManager;
use StaticPHP\Artifact\ArtifactDownloader;
use StaticPHP\Artifact\Downloader\DownloadResult;
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
use StaticPHP\Attribute\Artifact\CustomBinary;
use StaticPHP\Exception\DownloaderException;
use StaticPHP\Runtime\SystemTarget;
+use StaticPHP\Util\GlobalEnvManager;
use StaticPHP\Util\System\LinuxUtil;
class go_xcaddy
diff --git a/src/Package/Artifact/zig.php b/src/Package/Artifact/zig.php
new file mode 100644
index 000000000..2ac7b454b
--- /dev/null
+++ b/src/Package/Artifact/zig.php
@@ -0,0 +1,98 @@
+executeCurl('https://ziglang.org/download/index.json', retries: $downloader->getRetry());
+ $index_json = json_decode($index_json ?: '', true);
+ $latest_version = null;
+ foreach ($index_json as $version => $data) {
+ $latest_version = $version;
+ break;
+ }
+
+ if (!$latest_version) {
+ throw new DownloaderException('Could not determine latest Zig version');
+ }
+ $zig_arch = SystemTarget::getTargetArch();
+ $zig_os = match (SystemTarget::getTargetOS()) {
+ 'Windows' => 'win',
+ 'Darwin' => 'macos',
+ 'Linux' => 'linux',
+ default => throw new DownloaderException('Unsupported OS for Zig: ' . SystemTarget::getTargetOS()),
+ };
+ $platform_key = "{$zig_arch}-{$zig_os}";
+ if (!isset($index_json[$latest_version][$platform_key])) {
+ throw new DownloaderException("No download available for {$platform_key} in Zig version {$latest_version}");
+ }
+ $download_info = $index_json[$latest_version][$platform_key];
+ $url = $download_info['tarball'];
+ $sha256 = $download_info['shasum'];
+ $filename = basename($url);
+ $path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . $filename;
+ default_shell()->executeCurlDownload($url, $path, retries: $downloader->getRetry());
+ // verify hash
+ $file_hash = hash_file('sha256', $path);
+ if ($file_hash !== $sha256) {
+ throw new DownloaderException("Hash mismatch for downloaded Zig binary. Expected {$sha256}, got {$file_hash}");
+ }
+ return DownloadResult::archive(basename($path), ['url' => $url, 'version' => $latest_version], extract: PKG_ROOT_PATH . '/zig', verified: true, version: $latest_version);
+ }
+
+ #[AfterBinaryExtract('zig', [
+ 'linux-x86_64',
+ 'linux-aarch64',
+ 'macos-x86_64',
+ 'macos-aarch64',
+ ])]
+ public function postExtractZig(string $target_path): void
+ {
+ $files = ['zig', 'zig-cc', 'zig-c++', 'zig-ar', 'zig-ld.lld', 'zig-ranlib', 'zig-objcopy'];
+ $all_exist = true;
+ foreach ($files as $file) {
+ if (!file_exists("{$target_path}/{$file}")) {
+ $all_exist = false;
+ break;
+ }
+ }
+ if ($all_exist) {
+ return;
+ }
+
+ $script_path = ROOT_DIR . '/src/globals/scripts/zig-cc.sh';
+ $script_content = file_get_contents($script_path);
+
+ file_put_contents("{$target_path}/zig-cc", $script_content);
+ chmod("{$target_path}/zig-cc", 0755);
+
+ $script_content = str_replace('zig cc', 'zig c++', $script_content);
+ file_put_contents("{$target_path}/zig-c++", $script_content);
+ file_put_contents("{$target_path}/zig-ar", "#!/usr/bin/env bash\nexec zig ar $@");
+ file_put_contents("{$target_path}/zig-ld.lld", "#!/usr/bin/env bash\nexec zig ld.lld $@");
+ file_put_contents("{$target_path}/zig-ranlib", "#!/usr/bin/env bash\nexec zig ranlib $@");
+ file_put_contents("{$target_path}/zig-objcopy", "#!/usr/bin/env bash\nexec zig objcopy $@");
+ chmod("{$target_path}/zig-c++", 0755);
+ chmod("{$target_path}/zig-ar", 0755);
+ chmod("{$target_path}/zig-ld.lld", 0755);
+ chmod("{$target_path}/zig-ranlib", 0755);
+ chmod("{$target_path}/zig-objcopy", 0755);
+ }
+}
diff --git a/src/Package/Target/go_xcaddy.php b/src/Package/Target/go_xcaddy.php
index cafaacf7e..01c4ade3d 100644
--- a/src/Package/Target/go_xcaddy.php
+++ b/src/Package/Target/go_xcaddy.php
@@ -4,9 +4,9 @@
namespace Package\Target;
-use SPC\util\GlobalEnvManager;
use StaticPHP\Attribute\Package\InitPackage;
use StaticPHP\Attribute\Package\Target;
+use StaticPHP\Util\GlobalEnvManager;
#[Target('go-xcaddy')]
class go_xcaddy
diff --git a/src/StaticPHP/Artifact/ArtifactDownloader.php b/src/StaticPHP/Artifact/ArtifactDownloader.php
index 4fb651cfb..2b7ac0de6 100644
--- a/src/StaticPHP/Artifact/ArtifactDownloader.php
+++ b/src/StaticPHP/Artifact/ArtifactDownloader.php
@@ -113,7 +113,7 @@ public function __construct(protected array $options = [])
foreach ($ls as $name) {
$this->fetch_prefs[$name] = Artifact::FETCH_PREFER_SOURCE;
}
- } elseif ($options['prefer-source'] === null) {
+ } elseif ($options['prefer-source'] === null || $options['prefer-source'] === true) {
$this->default_fetch_pref = Artifact::FETCH_PREFER_SOURCE;
}
}
@@ -124,7 +124,7 @@ public function __construct(protected array $options = [])
foreach ($ls as $name) {
$this->fetch_prefs[$name] = Artifact::FETCH_PREFER_BINARY;
}
- } elseif ($options['prefer-binary'] === null) {
+ } elseif ($options['prefer-binary'] === null || $options['prefer-binary'] === true) {
$this->default_fetch_pref = Artifact::FETCH_PREFER_BINARY;
}
}
@@ -134,7 +134,7 @@ public function __construct(protected array $options = [])
foreach ($ls as $name) {
$this->fetch_prefs[$name] = Artifact::FETCH_PREFER_BINARY;
}
- } elseif ($options['prefer-pre-built'] === null) {
+ } elseif ($options['prefer-pre-built'] === null || $options['prefer-pre-built'] === true) {
$this->default_fetch_pref = Artifact::FETCH_PREFER_BINARY;
}
}
@@ -145,7 +145,7 @@ public function __construct(protected array $options = [])
foreach ($ls as $name) {
$this->fetch_prefs[$name] = Artifact::FETCH_ONLY_SOURCE;
}
- } elseif ($options['source-only'] === null) {
+ } elseif ($options['source-only'] === null || $options['source-only'] === true) {
$this->default_fetch_pref = Artifact::FETCH_ONLY_SOURCE;
}
}
@@ -156,7 +156,7 @@ public function __construct(protected array $options = [])
foreach ($ls as $name) {
$this->fetch_prefs[$name] = Artifact::FETCH_ONLY_BINARY;
}
- } elseif ($options['binary-only'] === null) {
+ } elseif ($options['binary-only'] === null || $options['binary-only'] === true) {
$this->default_fetch_pref = Artifact::FETCH_ONLY_BINARY;
}
}
@@ -164,7 +164,7 @@ public function __construct(protected array $options = [])
if (array_key_exists('ignore-cache', $options)) {
if (is_string($options['ignore-cache'])) {
$this->ignore_cache = parse_comma_list($options['ignore-cache']);
- } elseif ($options['ignore-cache'] === null) {
+ } elseif ($options['ignore-cache'] === null || $options['ignore-cache'] === true) {
$this->ignore_cache = true;
}
}
@@ -172,7 +172,7 @@ public function __construct(protected array $options = [])
if (array_key_exists('ignore-cache-sources', $options)) {
if (is_string($options['ignore-cache-sources'])) {
$this->ignore_cache = parse_comma_list($options['ignore-cache-sources']);
- } elseif ($options['ignore-cache-sources'] === null) {
+ } elseif ($options['ignore-cache-sources'] === null || $options['ignore-cache-sources'] === true) {
$this->ignore_cache = true;
}
}
diff --git a/src/StaticPHP/Command/Dev/IsInstalledCommand.php b/src/StaticPHP/Command/Dev/IsInstalledCommand.php
new file mode 100644
index 000000000..a3f693217
--- /dev/null
+++ b/src/StaticPHP/Command/Dev/IsInstalledCommand.php
@@ -0,0 +1,34 @@
+no_motd = true;
+ $this->addArgument('package', InputArgument::REQUIRED, 'The package name to check installation status');
+ }
+
+ public function handle(): int
+ {
+ $installer = new PackageInstaller();
+ $package = $this->input->getArgument('package');
+ $installer->addInstallPackage($package);
+ $installed = $installer->isPackageInstalled($package);
+ if ($installed) {
+ $this->output->writeln("Package [{$package}] is installed correctly.");
+ return static::SUCCESS;
+ }
+ $this->output->writeln("Package [{$package}] is not installed.");
+ return static::FAILURE;
+ }
+}
diff --git a/src/StaticPHP/Command/Dev/ShellCommand.php b/src/StaticPHP/Command/Dev/ShellCommand.php
new file mode 100644
index 000000000..560cc7fed
--- /dev/null
+++ b/src/StaticPHP/Command/Dev/ShellCommand.php
@@ -0,0 +1,33 @@
+output->writeln("Entering interactive shell. Type 'exit' to leave.");
+
+ if (SystemTarget::isUnix()) {
+ passthru('PS1=\'[StaticPHP] > \' /bin/bash', $code);
+ return $code;
+ }
+ if (SystemTarget::getTargetOS() === 'Windows') {
+ passthru('cmd.exe', $code);
+ return $code;
+ }
+ $this->output->writeln('Unsupported OS for shell command.');
+ return static::FAILURE;
+ }
+}
diff --git a/src/StaticPHP/ConsoleApplication.php b/src/StaticPHP/ConsoleApplication.php
index 1f63190b3..0484c1114 100644
--- a/src/StaticPHP/ConsoleApplication.php
+++ b/src/StaticPHP/ConsoleApplication.php
@@ -6,6 +6,8 @@
use StaticPHP\Command\BuildLibsCommand;
use StaticPHP\Command\BuildTargetCommand;
+use StaticPHP\Command\Dev\IsInstalledCommand;
+use StaticPHP\Command\Dev\ShellCommand;
use StaticPHP\Command\DoctorCommand;
use StaticPHP\Command\DownloadCommand;
use StaticPHP\Command\ExtractCommand;
@@ -47,6 +49,10 @@ public function __construct()
new BuildLibsCommand(),
new ExtractCommand(),
new SPCConfigCommand(),
+
+ // dev commands
+ new ShellCommand(),
+ new IsInstalledCommand(),
]);
// add additional commands from registries
diff --git a/src/StaticPHP/Doctor/Item/LinuxToolCheck.php b/src/StaticPHP/Doctor/Item/LinuxToolCheck.php
new file mode 100644
index 000000000..09161c74e
--- /dev/null
+++ b/src/StaticPHP/Doctor/Item/LinuxToolCheck.php
@@ -0,0 +1,147 @@
+ '/usr/share/perl5/FindBin.pm',
+ 'binutils-gold' => 'ld.gold',
+ 'base-devel' => 'automake',
+ 'gettext-devel' => 'gettextize',
+ 'gettext-dev' => 'gettextize',
+ 'perl-IPC-Cmd' => '/usr/share/perl5/vendor_perl/IPC/Cmd.pm',
+ 'perl-Time-Piece' => '/usr/lib64/perl5/Time/Piece.pm',
+ ];
+
+ /** @noinspection PhpUnused */
+ #[CheckItem('if necessary tools are installed', limit_os: 'Linux', level: 999)]
+ public function checkCliTools(): ?CheckResult
+ {
+ $distro = LinuxUtil::getOSRelease();
+
+ $required = match ($distro['dist']) {
+ 'alpine' => self::TOOLS_ALPINE,
+ 'redhat' => self::TOOLS_RHEL,
+ 'centos' => array_merge(self::TOOLS_RHEL, ['perl-IPC-Cmd', 'perl-Time-Piece']),
+ 'arch' => self::TOOLS_ARCH,
+ default => self::TOOLS_DEBIAN,
+ };
+ $missing = [];
+ foreach ($required as $package) {
+ if (LinuxUtil::findCommand(self::PROVIDED_COMMAND[$package] ?? $package) === null) {
+ $missing[] = $package;
+ }
+ }
+ if (!empty($missing)) {
+ return CheckResult::fail(implode(', ', $missing) . ' not installed on your system', 'install-linux-tools', [$distro, $missing]);
+ }
+ return CheckResult::ok();
+ }
+
+ #[CheckItem('if cmake version >= 3.22', limit_os: 'Linux')]
+ public function checkCMakeVersion(): ?CheckResult
+ {
+ $ver = get_cmake_version();
+ if ($ver === null) {
+ return CheckResult::fail('Failed to get cmake version');
+ }
+ if (version_compare($ver, '3.22.0') < 0) {
+ return CheckResult::fail('cmake version is too low (' . $ver . '), please update it manually!');
+ }
+ return CheckResult::ok($ver);
+ }
+
+ /** @noinspection PhpUnused */
+ #[CheckItem('if necessary linux headers are installed', limit_os: 'Linux')]
+ public function checkSystemOSPackages(): ?CheckResult
+ {
+ if (LinuxUtil::isMuslDist()) {
+ // check linux-headers installation
+ if (!file_exists('/usr/include/linux/mman.h')) {
+ return CheckResult::fail('linux-headers not installed on your system', 'install-linux-tools', [LinuxUtil::getOSRelease(), ['linux-headers']]);
+ }
+ }
+ return CheckResult::ok();
+ }
+
+ #[FixItem('install-linux-tools')]
+ public function fixBuildTools(array $distro, array $missing): bool
+ {
+ $install_cmd = match ($distro['dist']) {
+ 'ubuntu', 'debian', 'Deepin', 'neon' => 'apt-get install -y',
+ 'alpine' => 'apk add',
+ 'redhat' => 'dnf install -y',
+ 'centos' => 'yum install -y',
+ 'arch' => 'pacman -S --noconfirm',
+ default => null,
+ };
+ if ($install_cmd === null) {
+ // try family
+ $family = explode(' ', strtolower($distro['family']));
+ if (in_array('debian', $family)) {
+ $install_cmd = 'apt-get install -y';
+ } elseif (in_array('rhel', $family) || in_array('fedora', $family)) {
+ $install_cmd = 'dnf install -y';
+ } else {
+ throw new EnvironmentException(
+ "Current linux distro [{$distro['dist']}] does not have an auto-install script for packages yet.",
+ 'You can submit an issue to request support: https://github.com/crazywhalecc/static-php-cli/issues'
+ );
+ }
+ }
+ $prefix = '';
+ if (($user = exec('whoami')) !== 'root') {
+ $prefix = 'sudo ';
+ logger()->warning("Current user ({$user}) is not root, using sudo for running command (may require password input)");
+ }
+
+ $is_debian = LinuxUtil::isDebianDist();
+ $to_install = $is_debian ? str_replace('xz', 'xz-utils', $missing) : $missing;
+ // debian, alpine libtool -> libtoolize
+ $to_install = str_replace('libtoolize', 'libtool', $to_install);
+ shell()->exec($prefix . $install_cmd . ' ' . implode(' ', $to_install));
+
+ return true;
+ }
+}
diff --git a/src/StaticPHP/Doctor/Item/PkgConfigCheck.php b/src/StaticPHP/Doctor/Item/PkgConfigCheck.php
index 757c14ed8..4a0ba498d 100644
--- a/src/StaticPHP/Doctor/Item/PkgConfigCheck.php
+++ b/src/StaticPHP/Doctor/Item/PkgConfigCheck.php
@@ -45,7 +45,7 @@ public function checkFunctional(): CheckResult
public function fix(): bool
{
ApplicationContext::set('elephant', true);
- $installer = new PackageInstaller(['dl-prefer-binary' => true]);
+ $installer = new PackageInstaller(['dl-binary-only' => true]);
$installer->addInstallPackage('pkg-config');
$installer->run(false, true);
return true;
diff --git a/src/StaticPHP/Doctor/Item/ZigCheck.php b/src/StaticPHP/Doctor/Item/ZigCheck.php
new file mode 100644
index 000000000..c8d00574b
--- /dev/null
+++ b/src/StaticPHP/Doctor/Item/ZigCheck.php
@@ -0,0 +1,53 @@
+addInstallPackage($package);
+ $installed = $installer->isPackageInstalled($package);
+ if ($installed) {
+ return CheckResult::ok();
+ }
+ return CheckResult::fail('zig is not installed', 'install-zig');
+ }
+
+ #[FixItem('install-zig')]
+ public function installZig(): bool
+ {
+ $arch = arch2gnu(php_uname('m'));
+ $os = match (PHP_OS_FAMILY) {
+ 'Windows' => 'win',
+ 'Darwin' => 'macos',
+ 'BSD' => 'freebsd',
+ default => 'linux',
+ };
+ $installer = new PackageInstaller();
+ $installer->addInstallPackage('zig');
+ $installer->run(false);
+ return $installer->isPackageInstalled('zig');
+ }
+}
diff --git a/src/StaticPHP/Package/LibraryPackage.php b/src/StaticPHP/Package/LibraryPackage.php
index c83985501..2063ee897 100644
--- a/src/StaticPHP/Package/LibraryPackage.php
+++ b/src/StaticPHP/Package/LibraryPackage.php
@@ -33,22 +33,28 @@ public function addBuildFunction(string $platform, callable $func): void
public function isInstalled(): bool
{
foreach (PackageConfig::get($this->getName(), 'static-libs', []) as $lib) {
- if (!file_exists("{$this->getLibDir()}/{$lib}")) {
+ $path = FileSystem::isRelativePath($lib) ? "{$this->getLibDir()}/{$lib}" : $lib;
+ if (!file_exists($path)) {
return false;
}
}
foreach (PackageConfig::get($this->getName(), 'headers', []) as $header) {
- if (!file_exists("{$this->getIncludeDir()}/{$header}")) {
+ $path = FileSystem::isRelativePath($header) ? "{$this->getIncludeDir()}/{$header}" : $header;
+ if (!file_exists($path)) {
return false;
}
}
foreach (PackageConfig::get($this->getName(), 'pkg-configs', []) as $pc) {
- if (!file_exists("{$this->getLibDir()}/pkgconfig/{$pc}.pc")) {
+ if (!str_ends_with($pc, '.pc')) {
+ $pc .= '.pc';
+ }
+ if (!file_exists("{$this->getLibDir()}/pkgconfig/{$pc}")) {
return false;
}
}
foreach (PackageConfig::get($this->getName(), 'static-bins', []) as $bin) {
- if (!file_exists("{$this->getBinDir()}/{$bin}")) {
+ $path = FileSystem::isRelativePath($bin) ? "{$this->getBinDir()}/{$bin}" : $bin;
+ if (!file_exists($path)) {
return false;
}
}
diff --git a/src/StaticPHP/Package/PackageInstaller.php b/src/StaticPHP/Package/PackageInstaller.php
index 34e246214..c6aa34213 100644
--- a/src/StaticPHP/Package/PackageInstaller.php
+++ b/src/StaticPHP/Package/PackageInstaller.php
@@ -108,8 +108,10 @@ public function setDownload(bool $download = true): static
*/
public function run(bool $interactive = true, bool $disable_delay_msg = false): void
{
- // resolve input, make dependency graph
- $this->resolvePackages();
+ if (empty($this->packages)) {
+ // resolve input, make dependency graph
+ $this->resolvePackages();
+ }
if ($interactive && !$disable_delay_msg) {
// show install or build options in terminal with beautiful output
@@ -148,7 +150,10 @@ public function run(bool $interactive = true, bool $disable_delay_msg = false):
}
$builder = ApplicationContext::get(PackageBuilder::class);
foreach ($this->packages as $package) {
- if ($this->isBuildPackage($package) || $package instanceof LibraryPackage && $package->hasStage('build')) {
+ if (
+ $this->isBuildPackage($package) ||
+ $package instanceof LibraryPackage && $package->hasStage('build') && !$package->getArtifact()->shouldUseBinary()
+ ) {
if ($interactive) {
InteractiveTerm::indicateProgress('Building package: ' . ConsoleColor::yellow($package->getName()));
}
@@ -213,6 +218,31 @@ public function isPackageResolved(string $package_name): bool
return isset($this->packages[$package_name]);
}
+ public function isPackageInstalled(Package|string $package_name): bool
+ {
+ if (empty($this->packages)) {
+ $this->resolvePackages();
+ }
+ if (is_string($package_name)) {
+ $package = $this->getPackage($package_name);
+ if ($package === null) {
+ throw new WrongUsageException("Package '{$package_name}' is not resolved.");
+ }
+ } else {
+ $package = $package_name;
+ }
+
+ // check if package is built/installed
+ if ($this->isBuildPackage($package)) {
+ return $package->isInstalled();
+ }
+ if ($package instanceof LibraryPackage && $package->getArtifact()->shouldUseBinary()) {
+ $artifact = $package->getArtifact();
+ return $artifact->isBinaryExtracted();
+ }
+ return false;
+ }
+
/**
* Returns the download status of all artifacts for the resolved packages.
*
diff --git a/src/StaticPHP/Util/SPCConfigUtil.php b/src/StaticPHP/Util/SPCConfigUtil.php
index 317258d03..c525f8c79 100644
--- a/src/StaticPHP/Util/SPCConfigUtil.php
+++ b/src/StaticPHP/Util/SPCConfigUtil.php
@@ -225,11 +225,15 @@ private function getLibsString(array $packages, bool $use_short_libs = true): st
// convert all static-libs to short names
$libs = array_reverse(PackageConfig::get($package, 'static-libs', []));
foreach ($libs as $lib) {
- // check file existence
- if (!file_exists(BUILD_LIB_PATH . "/{$lib}")) {
- throw new WrongUsageException("Library file '{$lib}' for lib [{$package}] does not exist in '" . BUILD_LIB_PATH . "'. Please build it first.");
+ if (FileSystem::isRelativePath($lib)) {
+ // check file existence
+ if (!file_exists(BUILD_LIB_PATH . "/{$lib}")) {
+ throw new WrongUsageException("Library file '{$lib}' for lib [{$package}] does not exist in '" . BUILD_LIB_PATH . "'. Please build it first.");
+ }
+ $lib_names[] = $this->getShortLibName($lib);
+ } else {
+ $lib_names[] = $lib;
}
- $lib_names[] = $this->getShortLibName($lib);
}
// add frameworks for macOS
if (SystemTarget::getTargetOS() === 'Darwin') {
diff --git a/src/globals/scripts/zig-cc.sh b/src/globals/scripts/zig-cc.sh
new file mode 100755
index 000000000..5c9017c7f
--- /dev/null
+++ b/src/globals/scripts/zig-cc.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+
+if [ "$BUILD_ROOT_PATH" = "" ]; then
+ echo "The script must be run in the SPC build environment."
+ exit 1
+fi
+
+SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
+BUILDROOT_ABS=$BUILD_ROOT_PATH
+PARSED_ARGS=()
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -isystem)
+ shift
+ ARG="$1"
+ shift
+ ARG_ABS="$(realpath "$ARG" 2>/dev/null || true)"
+ [[ "$ARG_ABS" == "$BUILDROOT_ABS" ]] && PARSED_ARGS+=("-I$ARG") || PARSED_ARGS+=("-isystem" "$ARG")
+ ;;
+ -isystem*)
+ ARG="${1#-isystem}"
+ shift
+ ARG_ABS="$(realpath "$ARG" 2>/dev/null || true)"
+ [[ "$ARG_ABS" == "$BUILDROOT_ABS" ]] && PARSED_ARGS+=("-I$ARG") || PARSED_ARGS+=("-isystem$ARG")
+ ;;
+ -march=*|-mcpu=*)
+ OPT_NAME="${1%%=*}"
+ OPT_VALUE="${1#*=}"
+ # Skip armv8- flags entirely as Zig doesn't support them
+ if [[ "$OPT_VALUE" == armv8-* ]]; then
+ shift
+ continue
+ fi
+ # replace -march=x86-64 with -march=x86_64
+ OPT_VALUE="${OPT_VALUE//-/_}"
+ PARSED_ARGS+=("${OPT_NAME}=${OPT_VALUE}")
+ shift
+ ;;
+ *)
+ PARSED_ARGS+=("$1")
+ shift
+ ;;
+ esac
+done
+
+[[ -n "$SPC_TARGET" ]] && TARGET="-target $SPC_TARGET" || TARGET=""
+
+if [[ "$SPC_TARGET" =~ \.[0-9]+\.[0-9]+ ]]; then
+ output=$(zig cc $TARGET $SPC_COMPILER_EXTRA "${PARSED_ARGS[@]}" 2>&1)
+ status=$?
+
+ if [[ $status -eq 0 ]]; then
+ echo "$output"
+ exit 0
+ fi
+
+ if echo "$output" | grep -qE "version '.*' in target triple"; then
+ filtered_output=$(echo "$output" | grep -vE "version '.*' in target triple")
+ echo "$filtered_output"
+ exit 0
+ fi
+fi
+
+exec zig cc $TARGET $SPC_COMPILER_EXTRA "${PARSED_ARGS[@]}"