Compare commits

..

1 Commits

Author SHA1 Message Date
henderkes
6df778f92f llvm-tools: build host llvm-objcopy/strip/profdata under ZigToolchain
Add an `llvm-tools` target artifact that downloads llvm-project source
matching the version of clang shipped by the active zig install,
builds llvm-objcopy, llvm-strip and llvm-profdata into
PKG_ROOT_PATH/llvm-tools/bin, and exposes them through the same
path/binary/isInstalled static surface as the other artifacts.

A new LlvmToolsCheck doctor item runs when the active toolchain is
ZigToolchain and reports whether the three tools are built, with a
fix that installs the package and runs the build.

PackageBuilder now picks the right tool when the active toolchain is
ZigToolchain:
- extractDebugInfo() honours OBJCOPY from the environment, then falls
  back to llvm-tools' llvm-objcopy under Zig and plain objcopy
  otherwise.
- stripBinary() uses llvm-strip under Zig and plain strip otherwise.

System strip/objcopy refuse zig-produced archives and bitcode
sections, so without this the strip stage breaks LTO builds. Other
toolchains keep using the system binaries.

ApplicationContext::tryGet() wraps the container's get() in a
try/catch and returns null on failure, so PackageBuilder can ask
"which toolchain is active right now" without PHP-DI throwing on
autowirable-but-unconstructable classes.

Depends on v3c/artifact-static-helpers (uses zig::isInstalled()
and zig::binary()).
2026-05-24 21:50:57 +07:00
53 changed files with 316 additions and 323 deletions

View File

@@ -38,9 +38,6 @@ jobs:
- name: "windows-x64"
os: "ubuntu-latest"
filename: "spc-windows-x64.exe"
permissions:
id-token: write
attestations: write
steps:
- name: "Checkout"
uses: "actions/checkout@v5"
@@ -108,12 +105,6 @@ jobs:
fi
fi
- name: "Generate build provenance attestation"
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v4
with:
subject-path: "${{ github.workspace }}/${{ matrix.operating-system.name == 'windows-x64' && 'spc.exe' || 'spc' }}"
- name: "Copy file"
run: |
if [ "${{ matrix.operating-system.name }}" != "windows-x64" ]; then

View File

@@ -1,20 +0,0 @@
ext-fastchart:
type: php-extension
artifact:
source:
type: ghtar
repo: iliaal/fastchart
extract: php-src/ext/fastchart
prefer-stable: true
metadata:
license-files: [LICENSE]
depends:
- freetype
suggests:
- libpng
- libjpeg
- libwebp
php-extension:
os:
- Linux
- Darwin

View File

@@ -1,14 +0,0 @@
ext-fastjson:
type: php-extension
artifact:
source:
type: ghtar
repo: iliaal/fastjson
extract: php-src/ext/fastjson
prefer-stable: true
metadata:
license-files: [LICENSE]
php-extension:
os:
- Linux
- Darwin

View File

@@ -0,0 +1,6 @@
llvm-tools:
type: target
artifact:
binary: custom
depends:
- zig

View File

@@ -0,0 +1,162 @@
<?php
declare(strict_types=1);
namespace Package\Artifact;
use StaticPHP\Artifact\ArtifactDownloader;
use StaticPHP\Artifact\Downloader\DownloadResult;
use StaticPHP\Artifact\Downloader\Type\CheckUpdateResult;
use StaticPHP\Artifact\Downloader\Type\GitHubTokenSetupTrait;
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
use StaticPHP\Attribute\Artifact\CustomBinary;
use StaticPHP\Attribute\Artifact\CustomBinaryCheckUpdate;
use StaticPHP\DI\ApplicationContext;
use StaticPHP\Exception\BuildFailureException;
use StaticPHP\Exception\DownloaderException;
use StaticPHP\Package\PackageBuilder;
class llvm_tools
{
use GitHubTokenSetupTrait;
public const array TOOLS = ['llvm-objcopy', 'llvm-strip', 'llvm-profdata'];
/** Install prefix for the locally-built llvm-tools. */
public static function path(): string
{
return PKG_ROOT_PATH . '/llvm-tools';
}
/** Path to a binary under llvm-tools/bin (llvm-objcopy, llvm-strip, llvm-profdata, …). */
public static function binary(string $name = 'llvm-strip'): string
{
return self::path() . '/bin/' . $name;
}
/** True when every required TOOLS binary is present and executable. */
public static function isInstalled(): bool
{
foreach (self::TOOLS as $t) {
$p = self::binary($t);
if (!is_file($p) || !is_executable($p)) {
return false;
}
}
return true;
}
#[CustomBinary('llvm-tools', [
'linux-x86_64',
'linux-aarch64',
'macos-x86_64',
'macos-aarch64',
])]
public function downBinary(ArtifactDownloader $downloader): DownloadResult
{
$llvmVersion = $this->detectLlvmVersion()
?? throw new DownloaderException('Could not detect a clang version on host; install zig or clang first');
$tarball = "llvm-project-{$llvmVersion}.src.tar.xz";
$url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-{$llvmVersion}/{$tarball}";
$tarballPath = DOWNLOAD_PATH . '/' . $tarball;
default_shell()->executeCurlDownload($url, $tarballPath, headers: $this->getGitHubTokenHeaders(), retries: $downloader->getRetry());
return DownloadResult::archive($tarball, ['url' => $url, 'version' => $llvmVersion], extract: '{source_path}/llvm-tools', verified: false, version: $llvmVersion);
}
#[CustomBinaryCheckUpdate('llvm-tools', [
'linux-x86_64',
'linux-aarch64',
'macos-x86_64',
'macos-aarch64',
])]
public function checkUpdateBinary(?string $old_version, ArtifactDownloader $downloader): CheckUpdateResult
{
$llvmVersion = $this->detectLlvmVersion()
?? throw new DownloaderException('Could not detect a clang version on host; install zig or clang first');
return new CheckUpdateResult(
old: $old_version,
new: $llvmVersion,
needUpdate: $old_version === null || $llvmVersion !== $old_version,
);
}
#[AfterBinaryExtract('llvm-tools', [
'linux-x86_64',
'linux-aarch64',
'macos-x86_64',
'macos-aarch64',
])]
public function postExtract(string $target_path): void
{
$this->buildForHost($target_path);
}
public function buildForHost(?string $sourceRoot = null): void
{
$sourceRoot ??= SOURCE_PATH . '/llvm-tools';
if (self::isInstalled()) {
return;
}
$llvmDir = "{$sourceRoot}/llvm";
if (!is_dir($llvmDir)) {
throw new BuildFailureException("llvm-tools: missing source at {$llvmDir} (extraction layout changed?)");
}
$buildDir = "{$sourceRoot}/build";
$installDir = self::path();
$binDir = self::path() . '/bin';
f_mkdir($buildDir, recursive: true);
f_mkdir($binDir, recursive: true);
$cmakeArgs = implode(' ', array_map('escapeshellarg', [
'-S', $llvmDir,
'-B', $buildDir,
'-DCMAKE_BUILD_TYPE=Release',
'-DLLVM_ENABLE_PROJECTS=',
'-DLLVM_TARGETS_TO_BUILD=',
'-DLLVM_INCLUDE_BENCHMARKS=OFF',
'-DLLVM_INCLUDE_TESTS=OFF',
'-DLLVM_INCLUDE_EXAMPLES=OFF',
'-DLLVM_INCLUDE_DOCS=OFF',
'-DLLVM_ENABLE_ZLIB=OFF',
'-DLLVM_ENABLE_ZSTD=OFF',
'-DLLVM_ENABLE_LIBXML2=OFF',
'-DLLVM_ENABLE_TERMINFO=OFF',
'-DLLVM_ENABLE_LIBEDIT=OFF',
'-DLLVM_ENABLE_LIBPFM=OFF',
'-DLLVM_BUILD_LLVM_DYLIB=OFF',
'-DLLVM_LINK_LLVM_DYLIB=OFF',
'-DBUILD_SHARED_LIBS=OFF',
'-DCMAKE_C_COMPILER=' . zig::binary('zig-cc'),
'-DCMAKE_CXX_COMPILER=' . zig::binary('zig-c++'),
'-DCMAKE_INSTALL_PREFIX=' . $installDir,
]));
$jobs = ApplicationContext::get(PackageBuilder::class)->concurrency;
$targetArgs = implode(' ', array_map(fn ($t) => '--target ' . escapeshellarg($t), self::TOOLS));
shell()
->setEnv(['SPC_TARGET' => GNU_ARCH . '-linux-musl'])
->exec('cmake ' . $cmakeArgs)
->exec('cmake --build ' . escapeshellarg($buildDir) . ' ' . $targetArgs . " -j {$jobs}");
foreach (self::TOOLS as $t) {
$built = "{$buildDir}/bin/{$t}";
if (!is_file($built)) {
throw new BuildFailureException("llvm-tools: missing build output {$built}");
}
copy($built, self::binary($t));
chmod(self::binary($t), 0755);
}
}
private function detectLlvmVersion(): ?string
{
if (!zig::isInstalled()) {
return null;
}
[$rc, $out] = shell()->execWithResult(escapeshellarg(zig::binary()) . ' cc --version', false);
if ($rc !== 0) {
return null;
}
return preg_match('/clang version (\d+\.\d+\.\d+)/', implode("\n", $out), $m) ? $m[1] : null;
}
}

View File

@@ -15,6 +15,23 @@ use StaticPHP\Runtime\SystemTarget;
class zig
{
/** Directory zig extracts into. */
public static function path(): string
{
return PKG_ROOT_PATH . '/zig';
}
/** Path to a binary inside the zig install dir (zig, zig-cc, zig-c++, zig-ar, …). */
public static function binary(string $name = 'zig'): string
{
return self::path() . '/' . $name;
}
public static function isInstalled(): bool
{
return is_file(self::binary());
}
#[CustomBinary('zig', [
'linux-x86_64',
'linux-aarch64',

View File

@@ -27,10 +27,7 @@ class brotli
{
UnixCMakeExecutor::create($lib)
->setBuildDir($lib->getSourceDir() . '/build-dir')
->addConfigureArgs(
"-DSHARE_INSTALL_PREFIX={$lib->getBuildRootPath()}",
'-DBROTLI_DISABLE_TESTS=ON',
)
->addConfigureArgs("-DSHARE_INSTALL_PREFIX={$lib->getBuildRootPath()}")
->build();
// Patch pkg-config files

View File

@@ -17,9 +17,7 @@ class bzip2
#[PatchBeforeBuild]
public function patchBeforeBuild(LibraryPackage $lib): void
{
// Makefile pins -O2 -fPIC; inject SPC_DEFAULT_CFLAGS
$extra = deduplicate_flags(trim((string) getenv('SPC_DEFAULT_CFLAGS')) . ' -fPIC -Wall');
FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS=-Wall', "CFLAGS={$extra}");
FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS=-Wall', 'CFLAGS=-fPIC -Wall');
}
#[BuildFor('Windows')]

View File

@@ -18,11 +18,9 @@ class fastlz
{
$cc = getenv('CC') ?: 'cc';
$ar = getenv('AR') ?: 'ar';
$extra = trim((string) getenv('SPC_DEFAULT_CFLAGS'));
$extra = $extra !== '' ? $extra . ' -fPIC' : '-O3 -fPIC';
shell()->cd($lib->getSourceDir())->initializeEnv($lib)
->exec("{$cc} -c {$extra} fastlz.c -o fastlz.o")
->exec("{$cc} -c -O3 -fPIC fastlz.c -o fastlz.o")
->exec("{$ar} rcs libfastlz.a fastlz.o");
// Copy header file

View File

@@ -8,7 +8,6 @@ use StaticPHP\Attribute\Package\BuildFor;
use StaticPHP\Attribute\Package\Library;
use StaticPHP\Package\LibraryPackage;
use StaticPHP\Runtime\Executor\UnixAutoconfExecutor;
use StaticPHP\Runtime\SystemTarget;
#[Library('gmp')]
class gmp
@@ -17,12 +16,10 @@ class gmp
#[BuildFor('Darwin')]
public function build(LibraryPackage $lib): void
{
$make = UnixAutoconfExecutor::create($lib)->appendEnv(['CFLAGS' => '-std=c17']);
if (SystemTarget::getTargetArch() === 'x86_64' && SystemTarget::getTargetOS() === 'Linux') {
$libc = SystemTarget::getLibc() === 'glibc' ? 'gnu' : 'musl';
$make->addConfigureArgs(["--host=x86_64-pc-linux-{$libc}"]);
}
$make->configure('--enable-fat')->make();
UnixAutoconfExecutor::create($lib)
->appendEnv(['CFLAGS' => '-std=c17'])
->configure('--enable-fat')
->make();
$lib->patchPkgconfPrefix(['gmp.pc']);
}
}

View File

@@ -24,12 +24,9 @@ class icu
#[BuildFor('Linux')]
public function buildLinux(LibraryPackage $lib, ToolchainInterface $toolchain, PackageBuilder $builder): void
{
// runConfigureICU bakes CXXFLAGS/LDFLAGS, apply user flags too
$userCxxFlags = trim((string) getenv('SPC_DEFAULT_CXXFLAGS'));
$userLdFlags = trim((string) getenv('SPC_DEFAULT_LDFLAGS'));
$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 {$userCxxFlags}\"";
$ldflags = $toolchain->isStatic() ? "LDFLAGS=\"-static {$userLdFlags}\"" : "LDFLAGS=\"{$userLdFlags}\"";
$cxxflags = 'CXXFLAGS="-std=c++17 -DPIC -fPIC -fno-ident"';
$ldflags = $toolchain->isStatic() ? 'LDFLAGS="-static"' : '';
shell()->cd($lib->getSourceDir() . '/source')->initializeEnv($lib)
->exec(
"{$cppflags} {$cxxflags} {$ldflags} " .

View File

@@ -45,9 +45,6 @@ class imagemagick
// implicit --with-gcc-arch
// bleeds host cpu features into built binaries
'--without-gcc-arch',
'--disable-docs',
'--without-utilities',
'--disable-dpc',
);
// special: linux-static target needs `-static`

View File

@@ -17,9 +17,7 @@ class jbig
#[PatchBeforeBuild]
public function patchBeforeBuild(LibraryPackage $lib): void
{
$extra = trim((string) getenv('SPC_DEFAULT_CFLAGS'));
$cflags = ($extra !== '' ? $extra : '-O2') . ' -W -Wno-unused-result -fPIC';
FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS = -O2 -W -Wno-unused-result', "CFLAGS = {$cflags}");
FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS = -O2 -W -Wno-unused-result', 'CFLAGS = -O2 -W -Wno-unused-result -fPIC');
}
#[BuildFor('Darwin')]

View File

@@ -35,7 +35,6 @@ class ldap
->optionalPackage('libsodium', '--with-argon2=libsodium', '--enable-argon2=no')
->addConfigureArgs(
'--disable-slapd',
'--disable-debug',
'--without-systemd',
'--without-cyrus-sasl',
'ac_cv_func_pthread_kill_other_threads_np=no'

View File

@@ -9,10 +9,8 @@ use StaticPHP\Attribute\Package\Library;
use StaticPHP\Package\LibraryPackage;
use StaticPHP\Runtime\Executor\UnixCMakeExecutor;
use StaticPHP\Runtime\Executor\WindowsCMakeExecutor;
use StaticPHP\Runtime\SystemTarget;
use StaticPHP\Toolchain\Interface\ToolchainInterface;
use StaticPHP\Toolchain\ZigToolchain;
use StaticPHP\Util\System\UnixUtil;
#[Library('libaom')]
class libaom extends LibraryPackage
@@ -41,23 +39,9 @@ class libaom extends LibraryPackage
$new = trim($extra . ' -D_GNU_SOURCE');
f_putenv("SPC_COMPILER_EXTRA={$new}");
}
$targetCpu = SystemTarget::getTargetArch();
if (str_starts_with($targetCpu, 'aarch')) {
$targetCpu = str_replace('aarch', 'arm', $targetCpu);
}
if (!UnixUtil::findCommand('nasm') && !UnixUtil::findCommand('yasm')) {
$targetCpu = 'generic';
}
UnixCMakeExecutor::create($this)
->setBuildDir("{$this->getSourceDir()}/builddir")
->addConfigureArgs(
"-DAOM_TARGET_CPU={$targetCpu}",
'-DCONFIG_RUNTIME_CPU_DETECT=1',
'-DENABLE_EXAMPLES=OFF',
'-DENABLE_TESTS=OFF',
'-DENABLE_TOOLS=OFF',
'-DENABLE_DOCS=OFF',
)
->addConfigureArgs('-DAOM_TARGET_CPU=generic')
->build();
f_putenv("SPC_COMPILER_EXTRA={$extra}");
$this->patchPkgconfPrefix(['aom.pc']);

View File

@@ -35,12 +35,7 @@ class libavif
->optionalPackage('libjpeg', '-DAVIF_JPEG=SYSTEM', '-DAVIF_JPEG=OFF')
->optionalPackage('libxml2', '-DAVIF_LIBXML2=SYSTEM', '-DAVIF_LIBXML2=OFF')
->optionalPackage('libpng', '-DAVIF_LIBPNG=SYSTEM', '-DAVIF_LIBPNG=OFF')
->addConfigureArgs(
'-DAVIF_LIBYUV=OFF',
'-DAVIF_BUILD_APPS=OFF',
'-DAVIF_BUILD_TESTS=OFF',
'-DAVIF_GTEST=OFF',
)
->addConfigureArgs('-DAVIF_LIBYUV=OFF')
->build();
// patch pkgconfig
$lib->patchPkgconfPrefix(['libavif.pc']);
@@ -54,7 +49,7 @@ class libavif
'-DAVIF_BUILD_APPS=OFF',
'-DAVIF_BUILD_TESTS=OFF',
'-DAVIF_LIBYUV=OFF',
'-DAVIF_GTEST=OFF',
'-DAVIF_ENABLE_GTEST=OFF',
)
->build();
}

View File

@@ -16,7 +16,7 @@ class libffi extends LibraryPackage
public function buildLinux(): void
{
UnixAutoconfExecutor::create($this)
->configure('--disable-docs')->make();
->configure()->make();
if (is_file("{$this->getBuildRootPath()}/lib64/libffi.a")) {
copy("{$this->getBuildRootPath()}/lib64/libffi.a", "{$this->getBuildRootPath()}/lib/libffi.a");
@@ -33,7 +33,6 @@ class libffi extends LibraryPackage
->configure(
"--host={$arch}-apple-darwin",
"--target={$arch}-apple-darwin",
'--disable-docs',
)
->make();
$this->patchPkgconfPrefix(['libffi.pc']);

View File

@@ -24,17 +24,6 @@ class libheif
'list(APPEND REQUIRES_PRIVATE "libbrotlidec")' . "\n" . ' list(APPEND REQUIRES_PRIVATE "libbrotlienc")'
);
}
// libheif 1.22+ ships a C-incompatible header: `struct heif_bad_pixel`
$heif_properties = $lib->getSourceDir() . '/libheif/api/libheif/heif_properties.h';
if (file_exists($heif_properties)
&& str_contains(file_get_contents($heif_properties), 'struct heif_bad_pixel { uint32_t row; uint32_t column; };')
) {
FileSystem::replaceFileStr(
$heif_properties,
'struct heif_bad_pixel { uint32_t row; uint32_t column; };',
'typedef struct heif_bad_pixel { uint32_t row; uint32_t column; } heif_bad_pixel;'
);
}
}
#[BuildFor('Darwin')]
@@ -47,7 +36,6 @@ class libheif
'-DWITH_EXAMPLES=OFF',
'-DWITH_GDK_PIXBUF=OFF',
'-DBUILD_TESTING=OFF',
'-DBUILD_DOCUMENTATION=OFF',
'-DWITH_LIBSHARPYUV=ON', // optional: libwebp
'-DENABLE_PLUGIN_LOADING=OFF',
)

View File

@@ -25,7 +25,6 @@ class libjxl extends LibraryPackage
'-DJPEGXL_ENABLE_MANPAGES=OFF',
'-DJPEGXL_ENABLE_BENCHMARK=OFF',
'-DJPEGXL_ENABLE_PLUGINS=OFF',
'-DJPEGXL_ENABLE_DOXYGEN=OFF',
'-DJPEGXL_ENABLE_SJPEG=ON',
'-DJPEGXL_ENABLE_JNI=OFF',
'-DJPEGXL_ENABLE_TRANSCODE_JPEG=ON',

View File

@@ -12,25 +12,17 @@ use StaticPHP\Runtime\Executor\UnixCMakeExecutor;
#[Library('libmemcached')]
class libmemcached extends LibraryPackage
{
private const array DISABLE_ARGS = [
'-DBUILD_TESTING=OFF',
'-DBUILD_DOCS=OFF',
'-DENABLE_MEMASLAP=OFF',
];
#[BuildFor('Linux')]
public function buildLinux(): void
{
UnixCMakeExecutor::create($this)
->addConfigureArgs('-DCMAKE_INSTALL_RPATH=""', ...self::DISABLE_ARGS)
->addConfigureArgs('-DCMAKE_INSTALL_RPATH=""')
->build();
}
#[BuildFor('Darwin')]
public function buildDarwin(): void
{
UnixCMakeExecutor::create($this)
->addConfigureArgs(...self::DISABLE_ARGS)
->build();
UnixCMakeExecutor::create($this)->build();
}
}

View File

@@ -20,8 +20,6 @@ class libpng
{
$args = [
'--enable-hardware-optimizations',
'--disable-tests',
'--disable-tools',
"--with-zlib-prefix={$lib->getBuildRootPath()}",
];

View File

@@ -13,29 +13,17 @@ use StaticPHP\Runtime\Executor\WindowsCMakeExecutor;
#[Library('librabbitmq')]
class librabbitmq extends LibraryPackage
{
private const array DISABLE_ARGS = [
'-DBUILD_EXAMPLES=OFF',
'-DBUILD_TESTING=OFF',
'-DBUILD_TOOLS=OFF',
'-DBUILD_TOOLS_DOCS=OFF',
'-DBUILD_API_DOCS=OFF',
];
#[BuildFor('Darwin')]
#[BuildFor('Linux')]
public function buildUnix(): void
{
UnixCMakeExecutor::create($this)
->addConfigureArgs('-DBUILD_STATIC_LIBS=ON', ...self::DISABLE_ARGS)
->build();
UnixCMakeExecutor::create($this)->addConfigureArgs('-DBUILD_STATIC_LIBS=ON')->build();
}
#[BuildFor('Windows')]
public function buildWin(): void
{
WindowsCMakeExecutor::create($this)
->addConfigureArgs(...self::DISABLE_ARGS)
->build();
WindowsCMakeExecutor::create($this)->build();
rename("{$this->getLibDir()}\\librabbitmq.4.lib", "{$this->getLibDir()}\\rabbitmq.4.lib");
}
}

View File

@@ -41,9 +41,6 @@ class libtiff
'--disable-libdeflate',
'--disable-tools',
'--disable-contrib',
'--disable-tests',
'--disable-docs',
'--disable-sphinx',
'--disable-cxx',
'--without-x',
)

View File

@@ -13,18 +13,12 @@ use StaticPHP\Runtime\Executor\WindowsCMakeExecutor;
#[Library('libuv')]
class libuv
{
private const array DISABLE_ARGS = [
'-DLIBUV_BUILD_SHARED=OFF',
'-DLIBUV_BUILD_TESTS=OFF',
'-DLIBUV_BUILD_BENCH=OFF',
];
#[BuildFor('Darwin')]
#[BuildFor('Linux')]
public function buildUnix(LibraryPackage $lib): void
{
UnixCMakeExecutor::create($lib)
->addConfigureArgs(...self::DISABLE_ARGS)
->addConfigureArgs('-DLIBUV_BUILD_SHARED=OFF')
->build();
// patch pkgconfig
$lib->patchPkgconfPrefix(['libuv-static.pc']);
@@ -34,7 +28,7 @@ class libuv
public function buildWindows(LibraryPackage $lib): void
{
WindowsCMakeExecutor::create($lib)
->addConfigureArgs(...self::DISABLE_ARGS)
->addConfigureArgs('-DLIBUV_BUILD_SHARED=OFF')
->build();
}
}

View File

@@ -34,7 +34,6 @@ class libxslt
'--without-crypto',
'--without-debug',
'--without-debugger',
'--without-profiler',
"--with-libxml-prefix={$lib->getBuildRootPath()}",
);
if (getenv('SPC_LD_LIBRARY_PATH') && getenv('SPC_LIBRARY_PATH')) {

View File

@@ -21,7 +21,6 @@ class mimalloc
->addConfigureArgs(
'-DMI_BUILD_SHARED=OFF',
'-DMI_BUILD_OBJECT=OFF',
'-DMI_BUILD_TESTS=OFF',
'-DMI_INSTALL_TOPLEVEL=ON',
);
if (SystemTarget::getLibc() === 'musl') {

View File

@@ -6,8 +6,6 @@ namespace Package\Library;
use StaticPHP\Attribute\Package\BuildFor;
use StaticPHP\Attribute\Package\Library;
use StaticPHP\Attribute\Package\PatchBeforeBuild;
use StaticPHP\Attribute\PatchDescription;
use StaticPHP\Package\LibraryPackage;
use StaticPHP\Runtime\Executor\UnixAutoconfExecutor;
use StaticPHP\Toolchain\Interface\ToolchainInterface;
@@ -18,24 +16,6 @@ use StaticPHP\Util\FileSystem;
#[Library('ncursesw')]
class ncurses
{
#[PatchBeforeBuild]
#[PatchDescription('Filter clang/zig "N warning(s) generated." line out of MKlib_gen.sh preprocessor pipe')]
public function patchBeforeBuild(LibraryPackage $lib): void
{
// MKlib_gen.sh feeds the C preprocessor's stdout through a sed/awk
// pipeline into lib_gen.c. zig-cc/clang emits "N warning(s) generated."
// on stdout (not stderr), and that line ends up as invalid C in the
// generated source. Filter it out of the pipe before sed sees it.
$mklibGen = $lib->getSourceDir() . '/ncurses/base/MKlib_gen.sh';
if (is_file($mklibGen) && !str_contains((string) file_get_contents($mklibGen), "| grep -v ' generated")) {
FileSystem::replaceFileStr(
$mklibGen,
'$preprocessor $TMP 2>/dev/null \\',
"\$preprocessor \$TMP 2>/dev/null \\\n| grep -v ' generated\\.\$' \\",
);
}
}
#[BuildFor('Darwin')]
#[BuildFor('Linux')]
public function build(LibraryPackage $package, ToolchainInterface $toolchain): void

View File

@@ -24,7 +24,6 @@ class nghttp3
'-DBUILD_SHARED_LIBS=OFF',
'-DENABLE_STATIC_CRT=ON',
'-DENABLE_LIB_ONLY=ON',
'-DBUILD_TESTING=OFF',
)
->build();
}

View File

@@ -25,7 +25,6 @@ class ngtcp2
'-DENABLE_STATIC_CRT=ON',
'-DENABLE_LIB_ONLY=ON',
'-DENABLE_OPENSSL=OFF',
'-DBUILD_TESTING=OFF',
)
->build();
}

View File

@@ -111,12 +111,6 @@ class openssl
$openssl_dir ??= LinuxUtil::getOSRelease()['dist'] === 'redhat' ? '/etc/pki/tls' : '/etc/ssl';
$ex_lib = trim($ex_lib);
// anything we want included (PGO -fprofile-*, LTO, custom hardening)
// has to be appended on the command line *after* the target name.
$userCFlags = trim((string) getenv('SPC_DEFAULT_CFLAGS'));
$userLdFlags = trim((string) getenv('SPC_DEFAULT_LDFLAGS'));
$userExtra = trim($userCFlags . ' ' . $userLdFlags);
shell()->cd($lib->getSourceDir())->initializeEnv($lib)
->exec(
"{$env} ./Configure no-shared zlib " .
@@ -127,8 +121,7 @@ class openssl
'enable-pie ' .
'no-legacy ' .
'no-tests ' .
"linux-{$arch} " .
$userExtra
"linux-{$arch}"
)
->exec('make clean')
->exec("make -j{$lib->getBuilder()->concurrency} CNF_EX_LIBS=\"{$ex_lib}\"")

View File

@@ -20,11 +20,6 @@ class qdbm
{
$ac = UnixAutoconfExecutor::create($lib)->configure();
FileSystem::replaceFileRegex($lib->getSourceDir() . '/Makefile', '/MYLIBS = libqdbm.a.*/m', 'MYLIBS = libqdbm.a');
// Makefile pins -O3, replace with SPC_DEFAULT_CFLAGS
$extra = trim((string) getenv('SPC_DEFAULT_CFLAGS'));
if ($extra !== '') {
FileSystem::replaceFileRegex($lib->getSourceDir() . '/Makefile', '/^CFLAGS = .*$/m', "CFLAGS = -Wall {$extra}");
}
$ac->make(SystemTarget::getTargetOS() === 'Darwin' ? 'mac' : '');
$lib->patchPkgconfPrefix(['qdbm.pc']);
}

View File

@@ -20,7 +20,6 @@ class readline
->configure(
'--with-curses',
'--enable-multibyte=yes',
'--disable-install-examples',
)
->make();
$lib->patchPkgconfPrefix(['readline.pc']);

View File

@@ -22,8 +22,7 @@ class tidy
->setBuildDir("{$lib->getSourceDir()}/build-dir")
->addConfigureArgs(
'-DSUPPORT_CONSOLE_APP=OFF',
'-DBUILD_SHARED_LIB=OFF',
'-DSUPPORT_LOCALIZATIONS=OFF',
'-DBUILD_SHARED_LIB=OFF'
);
if (version_compare(get_cmake_version(), '4.0.0', '>=')) {
$cmake->addConfigureArgs('-DCMAKE_POLICY_VERSION_MINIMUM=3.5');
@@ -39,8 +38,7 @@ class tidy
->setBuildDir("{$lib->getSourceDir()}/build-dir")
->addConfigureArgs(
'-DSUPPORT_CONSOLE_APP=OFF',
'-DBUILD_SHARED_LIB=OFF',
'-DSUPPORT_LOCALIZATIONS=OFF',
'-DBUILD_SHARED_LIB=OFF'
)->build();
// rename tidy_static.lib to tidy_a.lib

View File

@@ -20,8 +20,8 @@ class unixodbc extends LibraryPackage
{
$sysconf_selector = match ($os = SystemTarget::getTargetOS()) {
'Darwin' => match (SystemTarget::getTargetArch()) {
'x86_64' => is_dir('/usr/local/etc') ? '/usr/local/etc' : '/opt/local/etc',
'aarch64' => is_dir('/opt/homebrew/etc') ? '/opt/homebrew/etc' : '/opt/local/etc',
'x86_64' => '/usr/local/etc',
'aarch64' => '/opt/homebrew/etc',
default => throw new WrongUsageException('Unsupported architecture: ' . GNU_ARCH),
},
'Linux' => '/etc',
@@ -35,7 +35,6 @@ class unixodbc extends LibraryPackage
'--with-included-ltdl',
"--sysconfdir={$sysconf_selector}",
'--enable-gui=no',
'--enable-readline=no',
)
->make();
$this->patchPkgconfPrefix(['odbc.pc', 'odbccr.pc', 'odbcinst.pc']);

View File

@@ -22,11 +22,6 @@ class xz
->configure(
'--disable-scripts',
'--disable-doc',
'--disable-xz',
'--disable-xzdec',
'--disable-lzmadec',
'--disable-lzmainfo',
'--disable-lzma-links',
'--with-libiconv',
'--bindir=/tmp/xz', // xz binary will corrupt `tar` command, that's really strange.
)

View File

@@ -14,20 +14,16 @@ use StaticPHP\Util\FileSystem;
#[Library('zstd')]
class zstd
{
private const array DISABLE_ARGS = [
'-DZSTD_BUILD_STATIC=ON',
'-DZSTD_BUILD_SHARED=OFF',
'-DZSTD_BUILD_PROGRAMS=OFF',
'-DZSTD_BUILD_TESTS=OFF',
];
#[BuildFor('Windows')]
public function buildWin(LibraryPackage $package): void
{
WindowsCMakeExecutor::create($package)
->setWorkingDir("{$package->getSourceDir()}/build/cmake")
->setBuildDir("{$package->getSourceDir()}/build/cmake/build")
->addConfigureArgs(...self::DISABLE_ARGS)
->addConfigureArgs(
'-DZSTD_BUILD_STATIC=ON',
'-DZSTD_BUILD_SHARED=OFF',
)
->build();
FileSystem::copy($package->getLibDir() . '\zstd_static.lib', $package->getLibDir() . '/zstd.lib');
FileSystem::copy($package->getLibDir() . '\zstd_static.lib', $package->getLibDir() . '/libzstd.lib');
@@ -39,7 +35,10 @@ class zstd
{
UnixCMakeExecutor::create($lib)
->setBuildDir("{$lib->getSourceDir()}/build/cmake/build")
->addConfigureArgs(...self::DISABLE_ARGS)
->addConfigureArgs(
'-DZSTD_BUILD_STATIC=ON',
'-DZSTD_BUILD_SHARED=OFF',
)
->build();
$lib->patchPkgconfPrefix(['libzstd.pc'], PKGCONF_PATCH_PREFIX);

View File

@@ -43,8 +43,6 @@ class curl
'-DZSTD_LIBRARY=zstd_static.lib',
'-DBUILD_TESTING=OFF',
'-DBUILD_EXAMPLES=OFF',
'-DBUILD_LIBCURL_DOCS=OFF',
'-DENABLE_CURL_MANUAL=OFF',
'-DUSE_LIBIDN2=OFF',
'-DCURL_USE_LIBPSL=OFF',
'-DUSE_WINDOWS_SSPI=ON',
@@ -83,9 +81,6 @@ class curl
->addConfigureArgs(
'-DBUILD_CURL_EXE=ON',
'-DBUILD_LIBCURL_DOCS=OFF',
'-DBUILD_TESTING=OFF',
'-DBUILD_EXAMPLES=OFF',
'-DENABLE_CURL_MANUAL=OFF',
'-DOPENSSL_ROOT_DIR=' . BUILD_ROOT_PATH,
)
->build();

View File

@@ -60,8 +60,6 @@ class GenExtTestMatrixCommand extends BaseCommand
'glfw',
'imagick',
'intl',
'mongodb',
'gmssl',
];
/**

View File

@@ -98,6 +98,25 @@ class ApplicationContext
return self::getContainer()->has($id);
}
/**
* Resolve $id, returning null if it can't be constructed.
* PHP-DI's has() returns true for any autowirable class even when get()
* would throw on missing scalar args — for "is this resolvable right now"
* semantics use this.
*
* @template T
* @param class-string<T> $id
* @return null|T
*/
public static function tryGet(string $id): mixed
{
try {
return self::getContainer()->get($id);
} catch (\Throwable) {
return null;
}
}
/**
* Set a service in the container.
* Use sparingly - prefer configuration-based definitions.

View File

@@ -73,20 +73,13 @@ class LinuxMuslCheck
$prefix = 'sudo ';
logger()->warning('Current user is not root, using sudo for running command');
}
$sysEnv = ['CC' => 'gcc', 'CXX' => 'g++', 'AR' => 'ar', 'LD' => 'ld', 'RANLIB' => 'ranlib'];
$envFlags = '';
foreach ($sysEnv as $k => $v) {
$envFlags .= "{$k}={$v} ";
}
$envFlags = rtrim($envFlags);
$shell = shell()->cd(SOURCE_PATH . '/musl-wrapper')
->setEnv($sysEnv)
->exec('./configure --disable-gcc-wrapper')
->exec('make -j');
->exec('CC=gcc CXX=g++ AR=ar LD=ld ./configure --disable-gcc-wrapper')
->exec('CC=gcc CXX=g++ AR=ar LD=ld make -j');
if ($prefix !== '') {
f_passthru('cd ' . SOURCE_PATH . "/musl-wrapper && {$envFlags} {$prefix}make install");
f_passthru('cd ' . SOURCE_PATH . "/musl-wrapper && CC=gcc CXX=g++ AR=ar LD=ld {$prefix}make install");
} else {
$shell->exec("{$prefix}make install");
$shell->exec("CC=gcc CXX=g++ AR=ar LD=ld {$prefix}make install");
}
return true;
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace StaticPHP\Doctor\Item;
use Package\Artifact\llvm_tools;
use StaticPHP\Attribute\Doctor\CheckItem;
use StaticPHP\Attribute\Doctor\FixItem;
use StaticPHP\Attribute\Doctor\OptionalCheck;
use StaticPHP\DI\ApplicationContext;
use StaticPHP\Doctor\CheckResult;
use StaticPHP\Package\PackageInstaller;
use StaticPHP\Toolchain\Interface\ToolchainInterface;
use StaticPHP\Toolchain\ZigToolchain;
#[OptionalCheck([self::class, 'optionalCheck'])]
class LlvmToolsCheck
{
public static function optionalCheck(): bool
{
return ApplicationContext::get(ToolchainInterface::class) instanceof ZigToolchain;
}
/** @noinspection PhpUnused */
#[CheckItem('if llvm-tools (objcopy/strip/profdata) are built', level: 798)]
public function checkLlvmTools(): CheckResult
{
if (llvm_tools::isInstalled()) {
return CheckResult::ok(llvm_tools::path() . '/bin');
}
return CheckResult::fail('llvm-tools are not built', 'build-llvm-tools');
}
#[FixItem('build-llvm-tools')]
public function fixLlvmTools(): bool
{
$installer = new PackageInstaller(interactive: false);
$installer->addInstallPackage('llvm-tools');
$installer->run(true);
new llvm_tools()->buildForHost();
return llvm_tools::isInstalled();
}
}

View File

@@ -33,20 +33,15 @@ class MacOSToolCheck
'glibtoolize',
];
#[CheckItem('if homebrew or macports has installed', limit_os: 'Darwin', level: 998)]
public function checkBrewOrPorts(): ?CheckResult
#[CheckItem('if homebrew has installed', limit_os: 'Darwin', level: 998)]
public function checkBrew(): ?CheckResult
{
$brewPath = MacOSUtil::findCommand('brew');
$portPath = MacOSUtil::findCommand('port');
if ($brewPath && $brewPath !== '/opt/homebrew/bin/brew' && getenv('GNU_ARCH') === 'aarch64') {
return CheckResult::fail('Current homebrew (/usr/local/bin/homebrew) is not installed for M1 Mac, please re-install homebrew in /opt/homebrew/ !');
}
if ($brewPath === null && $portPath === null) {
if (($path = MacOSUtil::findCommand('brew')) === null) {
return CheckResult::fail('Homebrew is not installed', 'brew');
}
if ($path !== '/opt/homebrew/bin/brew' && getenv('GNU_ARCH') === 'aarch64') {
return CheckResult::fail('Current homebrew (/usr/local/bin/homebrew) is not installed for M1 Mac, please re-install homebrew in /opt/homebrew/ !');
}
return CheckResult::ok();
}
@@ -65,8 +60,8 @@ class MacOSToolCheck
return CheckResult::ok();
}
#[CheckItem('if homebrew or macports llvm are installed', limit_os: 'Darwin')]
public function checkBrewOrPortsLLVM(): ?CheckResult
#[CheckItem('if homebrew llvm are installed', limit_os: 'Darwin')]
public function checkBrewLLVM(): ?CheckResult
{
if (getenv('SPC_USE_LLVM') === 'brew') {
$homebrew_prefix = getenv('HOMEBREW_PREFIX') ?: (SystemTarget::getTargetArch() === 'aarch64' ? '/opt/homebrew' : '/usr/local/homebrew');
@@ -76,16 +71,6 @@ class MacOSToolCheck
}
return CheckResult::ok($path);
}
if (getenv('SPC_USE_LLVM') === 'port') {
$macportsPrefix = '/opt/local';
if (($path = MacOSUtil::findCommand('clang', ["{$macportsPrefix}/bin"])) === null) {
return CheckResult::fail('MacPorts llvm is not installed', 'build-tools', ['missing' => ['llvm']]);
}
return CheckResult::ok($path);
}
return null;
}
@@ -106,7 +91,7 @@ class MacOSToolCheck
if ($command_path !== []) {
return CheckResult::fail("Current {$bison} version is too old: " . $matches[0]);
}
return $this->checkBisonVersion(['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin', '/opt/local/bin']);
return $this->checkBisonVersion(['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin']);
}
return CheckResult::ok($matches[0]);
}
@@ -123,9 +108,6 @@ class MacOSToolCheck
#[FixItem('build-tools')]
public function fixBuildTools(array $missing): bool
{
$brewPath = MacOSUtil::findCommand('brew');
$portPath = MacOSUtil::findCommand('port');
$replacement = [
'glibtoolize' => 'libtool',
];
@@ -133,18 +115,7 @@ class MacOSToolCheck
if (isset($replacement[$cmd])) {
$cmd = $replacement[$cmd];
}
if ($brewPath !== null) {
shell()->exec('brew install --formula ' . escapeshellarg($cmd));
continue;
}
if ($portPath !== null) {
shell()->exec('port install ' . escapeshellarg($cmd));
continue;
}
return false;
shell()->exec('brew install --formula ' . escapeshellarg($cmd));
}
return true;
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace StaticPHP\Package;
use Package\Artifact\llvm_tools;
use StaticPHP\Config\PackageConfig;
use StaticPHP\DI\ApplicationContext;
use StaticPHP\Exception\SPCException;
@@ -11,6 +12,8 @@ use StaticPHP\Exception\SPCInternalException;
use StaticPHP\Exception\WrongUsageException;
use StaticPHP\Runtime\Shell\Shell;
use StaticPHP\Runtime\SystemTarget;
use StaticPHP\Toolchain\Interface\ToolchainInterface;
use StaticPHP\Toolchain\ZigToolchain;
use StaticPHP\Util\FileSystem;
use StaticPHP\Util\GlobalPathTrait;
use StaticPHP\Util\InteractiveTerm;
@@ -178,14 +181,18 @@ class PackageBuilder
if (SystemTarget::getTargetOS() === 'Darwin') {
shell()->exec("dsymutil -f {$binary_path} -o {$debug_file}");
} elseif (SystemTarget::getTargetOS() === 'Linux') {
$objcopy = getenv('OBJCOPY')
?: (ApplicationContext::tryGet(ToolchainInterface::class) instanceof ZigToolchain
? llvm_tools::binary('llvm-objcopy')
: 'objcopy');
if ($eu_strip = LinuxUtil::findCommand('eu-strip')) {
shell()
->exec("{$eu_strip} -f {$debug_file} {$binary_path}")
->exec("objcopy --add-gnu-debuglink={$debug_file} {$binary_path}");
->exec("{$objcopy} --add-gnu-debuglink={$debug_file} {$binary_path}");
} else {
shell()
->exec("objcopy --only-keep-debug {$binary_path} {$debug_file}")
->exec("objcopy --add-gnu-debuglink={$debug_file} {$binary_path}");
->exec("{$objcopy} --only-keep-debug {$binary_path} {$debug_file}")
->exec("{$objcopy} --add-gnu-debuglink={$debug_file} {$binary_path}");
}
} else {
logger()->debug('extractDebugInfo is only supported on Linux and macOS');
@@ -199,9 +206,12 @@ class PackageBuilder
*/
public function stripBinary(string $binary_path): void
{
$strip = ApplicationContext::tryGet(ToolchainInterface::class) instanceof ZigToolchain
? llvm_tools::binary('llvm-strip')
: 'strip';
shell()->exec(match (SystemTarget::getTargetOS()) {
'Darwin' => "strip -S {$binary_path}",
'Linux' => "strip --strip-unneeded {$binary_path}",
'Darwin' => "{$strip} -S {$binary_path}",
'Linux' => "{$strip} --strip-unneeded {$binary_path}",
'Windows' => 'echo "Skip strip on Windows"', // Windows strip is not available for now
default => throw new SPCInternalException('stripBinary is only supported on Linux and macOS'),
});

View File

@@ -302,12 +302,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES "{$include}")
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES "{$include}")
CMAKE;
// pin AR/RANLIB so cmake uses zig-ar/zig-ranlib instead of system /usr/bin/ranlib (zig archives need it)
// Whoops, linux may need CMAKE_AR sometimes
if (PHP_OS_FAMILY === 'Linux') {
$ar = getenv('SPC_DEFAULT_AR') ?: getenv('AR') ?: 'ar';
$ranlib = getenv('SPC_DEFAULT_RANLIB') ?: (getenv('RANLIB') ?: 'ranlib');
$toolchain .= "\nSET(CMAKE_AR \"{$ar}\")";
$toolchain .= "\nSET(CMAKE_RANLIB \"{$ranlib}\")";
$toolchain .= "\nSET(CMAKE_AR \"ar\")";
}
FileSystem::writeFile(SOURCE_PATH . '/toolchain.cmake', $toolchain);
return $created = realpath(SOURCE_PATH . '/toolchain.cmake');

View File

@@ -15,7 +15,6 @@ class ClangBrewToolchain extends ClangNativeToolchain
GlobalEnvManager::putenv("SPC_DEFAULT_CC={$homebrew_prefix}/opt/llvm/bin/clang");
GlobalEnvManager::putenv("SPC_DEFAULT_CXX={$homebrew_prefix}/opt/llvm/bin/clang++");
GlobalEnvManager::putenv("SPC_DEFAULT_AR={$homebrew_prefix}/opt/llvm/bin/llvm-ar");
GlobalEnvManager::putenv("SPC_DEFAULT_RANLIB={$homebrew_prefix}/opt/llvm/bin/llvm-ranlib");
GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld');
GlobalEnvManager::addPathIfNotExists("{$homebrew_prefix}/opt/llvm/bin");
}

View File

@@ -21,7 +21,6 @@ class ClangNativeToolchain implements UnixToolchainInterface
GlobalEnvManager::putenv('SPC_DEFAULT_CC=clang');
GlobalEnvManager::putenv('SPC_DEFAULT_CXX=clang++');
GlobalEnvManager::putenv('SPC_DEFAULT_AR=ar');
GlobalEnvManager::putenv('SPC_DEFAULT_RANLIB=ranlib');
GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld');
}

View File

@@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
namespace StaticPHP\Toolchain;
use StaticPHP\Util\GlobalEnvManager;
class ClangPortsToolchain extends ClangNativeToolchain
{
public function initEnv(): void
{
$macports_prefix = getenv('MACPORTS_PREFIX') ?: '/opt/local';
GlobalEnvManager::putenv("SPC_DEFAULT_CC={$macports_prefix}/bin/clang");
GlobalEnvManager::putenv("SPC_DEFAULT_CXX={$macports_prefix}/bin/clang++");
GlobalEnvManager::putenv("SPC_DEFAULT_AR={$macports_prefix}/bin/llvm-ar");
GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld');
GlobalEnvManager::addPathIfNotExists("{$macports_prefix}/bin");
}
}

View File

@@ -18,7 +18,6 @@ class GccNativeToolchain implements UnixToolchainInterface
GlobalEnvManager::putenv('SPC_DEFAULT_CC=gcc');
GlobalEnvManager::putenv('SPC_DEFAULT_CXX=g++');
GlobalEnvManager::putenv('SPC_DEFAULT_AR=ar');
GlobalEnvManager::putenv('SPC_DEFAULT_RANLIB=ranlib');
GlobalEnvManager::putenv('SPC_DEFAULT_LD=ld');
}

View File

@@ -41,7 +41,6 @@ class ToolchainManager
'Windows' => MSVCToolchain::class,
'Darwin' => match (getenv('SPC_USE_LLVM') ?: 'system') {
'brew' => ClangBrewToolchain::class,
'port' => ClangPortsToolchain::class,
default => ClangNativeToolchain::class,
},
default => throw new WrongUsageException('Unsupported OS family: ' . PHP_OS_FAMILY),

View File

@@ -16,7 +16,6 @@ class ZigToolchain implements UnixToolchainInterface
GlobalEnvManager::putenv('SPC_DEFAULT_CC=zig-cc');
GlobalEnvManager::putenv('SPC_DEFAULT_CXX=zig-c++');
GlobalEnvManager::putenv('SPC_DEFAULT_AR=zig-ar');
GlobalEnvManager::putenv('SPC_DEFAULT_RANLIB=zig-ranlib');
GlobalEnvManager::putenv('SPC_DEFAULT_LD=zig-ld.lld');
// Generate additional objects needed for zig toolchain

View File

@@ -134,10 +134,10 @@ class GlobalEnvManager
}
// test bison
if (PHP_OS_FAMILY === 'Darwin') {
if ($bison = MacOSUtil::findCommand('bison', ['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin', '/opt/local/bin/bison'])) {
if ($bison = MacOSUtil::findCommand('bison', ['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin'])) {
self::putenv("BISON={$bison}");
}
if ($yacc = MacOSUtil::findCommand('yacc', ['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin', '/opt/local/bin/yacc'])) {
if ($yacc = MacOSUtil::findCommand('yacc', ['/opt/homebrew/opt/bison/bin', '/usr/local/opt/bison/bin'])) {
self::putenv("YACC={$yacc}");
}
}

View File

@@ -256,30 +256,10 @@ function clean_spaces(string $string): string
*/
function deduplicate_flags(string $flags): string
{
// Flags that take their value as a separate token.
static $paired = [
'-Xclang', '-Xpreprocessor', '-Xlinker', '-Xassembler',
'-framework', '-arch', '-target',
'-include', '-imacros', '-isystem', '-isysroot', '-iquote', '-idirafter',
'-MT', '-MF', '-MQ',
];
$tokens = preg_split('/\s+/', trim($flags)) ?: [];
// Group paired flag+value into a single atom before dedup.
$atoms = [];
$n = count($tokens);
for ($i = 0; $i < $n; ++$i) {
if (in_array($tokens[$i], $paired, true) && $i + 1 < $n) {
$atoms[] = $tokens[$i] . ' ' . $tokens[$i + 1];
++$i;
} else {
$atoms[] = $tokens[$i];
}
}
$tokens = preg_split('/\s+/', trim($flags));
// Reverse, unique, reverse back - keeps last occurrence of duplicates
$deduplicated = array_reverse(array_unique(array_reverse($atoms)));
$deduplicated = array_reverse(array_unique(array_reverse($tokens)));
return implode(' ', $deduplicated);
}