From 52d234f1f4eb12cf1c071ddaa869a054a4ba7d09 Mon Sep 17 00:00:00 2001 From: Luther Monson Date: Tue, 19 May 2026 21:59:18 -0700 Subject: [PATCH 1/4] fix windows test failures: path separators and arch normalization --- src/StaticPHP/Artifact/Artifact.php | 2 +- src/StaticPHP/Artifact/ArtifactCache.php | 4 ++-- tests/StaticPHP/Artifact/ArtifactTest.php | 15 ++++++++------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/StaticPHP/Artifact/Artifact.php b/src/StaticPHP/Artifact/Artifact.php index e241d4fe..224bcff3 100644 --- a/src/StaticPHP/Artifact/Artifact.php +++ b/src/StaticPHP/Artifact/Artifact.php @@ -327,7 +327,7 @@ class Artifact public function getSourceRoot(): string { if (isset($this->config['metadata']['source-root'])) { - return $this->getSourceDir() . '/' . ltrim($this->config['metadata']['source-root'], '/'); + return FileSystem::convertPath($this->getSourceDir() . '/' . ltrim($this->config['metadata']['source-root'], '/')); } return $this->getSourceDir(); } diff --git a/src/StaticPHP/Artifact/ArtifactCache.php b/src/StaticPHP/Artifact/ArtifactCache.php index 5a2c8bac..2b0c8b54 100644 --- a/src/StaticPHP/Artifact/ArtifactCache.php +++ b/src/StaticPHP/Artifact/ArtifactCache.php @@ -223,8 +223,8 @@ class ArtifactCache public function getCacheFullPath(array $cache_info): string { return match ($cache_info['cache_type']) { - 'archive', 'file' => DOWNLOAD_PATH . '/' . $cache_info['filename'], - 'git' => DOWNLOAD_PATH . '/' . $cache_info['dirname'], + 'archive', 'file' => FileSystem::convertPath(DOWNLOAD_PATH . '/' . $cache_info['filename']), + 'git' => FileSystem::convertPath(DOWNLOAD_PATH . '/' . $cache_info['dirname']), 'local' => $cache_info['dirname'], // local dirname is absolute path default => throw new SPCInternalException("Unknown cache type: {$cache_info['cache_type']}"), }; diff --git a/tests/StaticPHP/Artifact/ArtifactTest.php b/tests/StaticPHP/Artifact/ArtifactTest.php index e1cb8ccd..0effb109 100644 --- a/tests/StaticPHP/Artifact/ArtifactTest.php +++ b/tests/StaticPHP/Artifact/ArtifactTest.php @@ -254,11 +254,16 @@ class ArtifactTest extends TestCase ApplicationContext::initialize(); ApplicationContext::set(ArtifactCache::class, $cache); + // Use a platform-appropriate absolute path: a Unix-style /tmp/... isn't + // absolute on Windows (no drive letter), so the test would otherwise + // fall through into the SOURCE_PATH-prefixed branch on Windows. + $extract = DIRECTORY_SEPARATOR === '\\' ? 'C:\tmp\my-pkg-extract' : '/tmp/my-pkg-extract'; + $artifact = new Artifact('my-pkg', [ - 'source' => ['type' => 'url', 'url' => 'https://example.com/file.tar.gz', 'extract' => '/tmp/my-pkg-extract'], + 'source' => ['type' => 'url', 'url' => 'https://example.com/file.tar.gz', 'extract' => $extract], ]); - $expected = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, '/tmp/my-pkg-extract'); + $expected = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $extract); $this->assertSame($expected, $artifact->getSourceDir()); } @@ -703,11 +708,7 @@ class ArtifactTest extends TestCase 'Windows' => 'windows', default => 'linux', }; - $arch = php_uname('m'); - if ($arch === 'arm64') { - $arch = 'aarch64'; - } - return "{$os}-{$arch}"; + return "{$os}-" . arch2gnu(php_uname('m')); } private function injectArtifactConfig(string $name, array $config): void From a9e54bb725e707c468b09e4ae6d3d15ce2129e70 Mon Sep 17 00:00:00 2001 From: Luther Monson Date: Wed, 20 May 2026 17:58:22 -0700 Subject: [PATCH 2/4] fix(windows): add -products * to vswhere so Build Tools are found vswhere.exe defaults to searching Community, Professional, and Enterprise editions only. CI environments typically install the lightweight Build Tools product which is a separate product type (Microsoft.VisualStudio.Product.BuildTools). Without -products * the tool returns no results and the build fails with "Visual Studio with C++ tools not found". See: https://github.com/microsoft/vswhere/wiki/Find-MSBuild --- src/StaticPHP/Util/System/WindowsUtil.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/StaticPHP/Util/System/WindowsUtil.php b/src/StaticPHP/Util/System/WindowsUtil.php index 40637262..3e17b4d2 100644 --- a/src/StaticPHP/Util/System/WindowsUtil.php +++ b/src/StaticPHP/Util/System/WindowsUtil.php @@ -54,6 +54,7 @@ class WindowsUtil } $args = [ '-latest', + '-products', '*', '-format', 'json', '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', ]; From ae26ef3bdb758ecdd567412cf56c0189fbad74a1 Mon Sep 17 00:00:00 2001 From: Luther Monson Date: Wed, 20 May 2026 20:57:12 -0700 Subject: [PATCH 3/4] fix(macos): remove -fno-plt from macOS CFLAGS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -fno-plt is an ELF-only flag that has no effect on macOS Mach-O targets — clang emits "argument unused" when it encounters it. Libraries like xz that run -Werror sanity checks during configure promote that warning to a fatal error, breaking the build. --- config/env.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/env.ini b/config/env.ini index acad2523..483ae408 100644 --- a/config/env.ini +++ b/config/env.ini @@ -142,7 +142,7 @@ CXX=${SPC_DEFAULT_CXX} AR=${SPC_DEFAULT_AR} LD=${SPC_DEFAULT_LD} ; default compiler flags, used in CMake toolchain file, openssl and pkg-config build -SPC_DEFAULT_CFLAGS="--target=${MAC_ARCH}-apple-darwin -O3 -fno-plt -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections" +SPC_DEFAULT_CFLAGS="--target=${MAC_ARCH}-apple-darwin -O3 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffunction-sections -fdata-sections" SPC_DEFAULT_CXXFLAGS="${SPC_DEFAULT_CFLAGS}" SPC_DEFAULT_LDFLAGS="-Wl,-dead_strip" ; phpmicro patches, for more info, see: https://github.com/easysoft/phpmicro/tree/master/patches From 4a274b69ac0ff6622234b18d61df85af10593f36 Mon Sep 17 00:00:00 2001 From: Luther Monson Date: Wed, 20 May 2026 21:09:27 -0700 Subject: [PATCH 4/4] fix: use ftpmirror.gnu.org instead of ftp.gnu.org ftp.gnu.org is unreliable and frequently times out during CI builds. ftpmirror.gnu.org is GNU's own CDN that auto-redirects to the nearest mirror. This is the recommended download method per https://www.gnu.org/prep/ftp.en.html Also normalizes /pub/gnu/ paths to /gnu/ since ftpmirror only serves the latter. Affects: libiconv, gettext, gmp, idn2, libunistring, ncurses, readline --- config/artifact/ncurses.yml | 2 +- config/pkg/lib/gettext.yml | 2 +- config/pkg/lib/gmp.yml | 2 +- config/pkg/lib/idn2.yml | 2 +- config/pkg/lib/libiconv.yml | 2 +- config/pkg/lib/libunistring.yml | 2 +- config/pkg/lib/readline.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/artifact/ncurses.yml b/config/artifact/ncurses.yml index 173d4c32..8d39e81b 100644 --- a/config/artifact/ncurses.yml +++ b/config/artifact/ncurses.yml @@ -4,5 +4,5 @@ ncurses: - COPYING source: type: filelist - url: 'https://ftp.gnu.org/pub/gnu/ncurses/' + url: 'https://ftpmirror.gnu.org/gnu/ncurses/' regex: '/href="(?ncurses-(?[^"]+)\.tar\.gz)"/' diff --git a/config/pkg/lib/gettext.yml b/config/pkg/lib/gettext.yml index 58f541f8..04743033 100644 --- a/config/pkg/lib/gettext.yml +++ b/config/pkg/lib/gettext.yml @@ -3,7 +3,7 @@ gettext: artifact: source: type: filelist - url: 'https://ftp.gnu.org/pub/gnu/gettext/' + url: 'https://ftpmirror.gnu.org/gnu/gettext/' regex: '/href="(?gettext-(?[^"]+)\.tar\.xz)"/' metadata: license-files: [gettext-runtime/intl/COPYING.LIB] diff --git a/config/pkg/lib/gmp.yml b/config/pkg/lib/gmp.yml index c1469774..80303056 100644 --- a/config/pkg/lib/gmp.yml +++ b/config/pkg/lib/gmp.yml @@ -3,7 +3,7 @@ gmp: artifact: source: type: filelist - url: 'https://ftp.gnu.org/gnu/gmp/' + url: 'https://ftpmirror.gnu.org/gnu/gmp/' regex: '/href="(?gmp-(?[^"]+)\.tar\.xz)"/' source-mirror: type: url diff --git a/config/pkg/lib/idn2.yml b/config/pkg/lib/idn2.yml index cef2a149..3b597b4d 100644 --- a/config/pkg/lib/idn2.yml +++ b/config/pkg/lib/idn2.yml @@ -3,7 +3,7 @@ idn2: artifact: source: type: filelist - url: 'https://ftp.gnu.org/gnu/libidn/' + url: 'https://ftpmirror.gnu.org/gnu/libidn/' regex: '/href="(?libidn2-(?[^"]+)\.tar\.gz)"/' metadata: license-files: [COPYING.LESSERv3] diff --git a/config/pkg/lib/libiconv.yml b/config/pkg/lib/libiconv.yml index 58cd77b0..2893679c 100644 --- a/config/pkg/lib/libiconv.yml +++ b/config/pkg/lib/libiconv.yml @@ -3,7 +3,7 @@ libiconv: artifact: source: type: filelist - url: 'https://ftp.gnu.org/gnu/libiconv/' + url: 'https://ftpmirror.gnu.org/gnu/libiconv/' regex: '/href="(?libiconv-(?[^"]+)\.tar\.gz)"/' metadata: license-files: [COPYING.LIB] diff --git a/config/pkg/lib/libunistring.yml b/config/pkg/lib/libunistring.yml index 13a66d42..5a78fa14 100644 --- a/config/pkg/lib/libunistring.yml +++ b/config/pkg/lib/libunistring.yml @@ -3,7 +3,7 @@ libunistring: artifact: source: type: filelist - url: 'https://ftp.gnu.org/gnu/libunistring/' + url: 'https://ftpmirror.gnu.org/gnu/libunistring/' regex: '/href="(?libunistring-(?[^"]+)\.tar\.gz)"/' metadata: license-files: [COPYING.LIB] diff --git a/config/pkg/lib/readline.yml b/config/pkg/lib/readline.yml index 0cb80b00..2dd25e49 100644 --- a/config/pkg/lib/readline.yml +++ b/config/pkg/lib/readline.yml @@ -3,7 +3,7 @@ readline: artifact: source: type: filelist - url: 'https://ftp.gnu.org/pub/gnu/readline/' + url: 'https://ftpmirror.gnu.org/gnu/readline/' regex: '/href="(?readline-(?[^"]+)\.tar\.gz)"/' metadata: license-files: [COPYING]