diff --git a/bin/spc-debug.ps1 b/bin/spc-debug.ps1 new file mode 100644 index 000000000..015dae9c9 --- /dev/null +++ b/bin/spc-debug.ps1 @@ -0,0 +1,12 @@ +$PHP_Exec = ".\runtime\php.exe" + +if (-not(Test-Path $PHP_Exec)) { + $PHP_Exec = Get-Command php.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Definition + if (-not $PHP_Exec) { + Write-Host "Error: PHP not found, you need to install PHP on your system or use 'bin/setup-runtime'." -ForegroundColor Red + exit 1 + } +} + +& "$PHP_Exec" -d xdebug.mode=debug -d xdebug.client_host=127.0.0.1 -d xdebug.client_port=9003 -d xdebug.start_with_request=yes ("bin/spc") @args +exit $LASTEXITCODE diff --git a/config/pkg/lib/brotli.yml b/config/pkg/lib/brotli.yml index 524f9ddc8..c88b93b5a 100644 --- a/config/pkg/lib/brotli.yml +++ b/config/pkg/lib/brotli.yml @@ -15,3 +15,7 @@ brotli: - libbrotlicommon - libbrotlidec - libbrotlienc + static-libs@windows: + - brotlicommon.lib + - brotlidec.lib + - brotlienc.lib diff --git a/config/pkg/lib/bzip2.yml b/config/pkg/lib/bzip2.yml index 1cd36bd7e..f9e1870d8 100644 --- a/config/pkg/lib/bzip2.yml +++ b/config/pkg/lib/bzip2.yml @@ -16,3 +16,6 @@ bzip2: - bzlib.h static-libs@unix: - libbz2.a + static-libs@windows: + - libbz2.lib + - libbz2_a.lib diff --git a/config/pkg/lib/freetype.yml b/config/pkg/lib/freetype.yml index c101a174b..df7dc22a8 100644 --- a/config/pkg/lib/freetype.yml +++ b/config/pkg/lib/freetype.yml @@ -11,6 +11,7 @@ freetype: depends: - zlib suggests: + - libpng - bzip2 - brotli headers@unix: diff --git a/config/pkg/lib/icu.yml b/config/pkg/lib/icu.yml index 43328228d..e42dcb6c3 100644 --- a/config/pkg/lib/icu.yml +++ b/config/pkg/lib/icu.yml @@ -6,11 +6,20 @@ icu: repo: unicode-org/icu match: icu4c.+-src\.tgz prefer-stable: true + binary: + windows-x86_64: { type: url, url: 'https://dl.static-php.dev/static-php-cli/deps/icu-static-windows-x64/icu-static-windows-x64.zip', extract: hosted } metadata: - license-files: [LICENSE] + license-files: ['@/icu.txt'] license: ICU + headers@windows: + - unicode lang: cpp pkg-configs: - icu-uc - icu-i18n - icu-io + static-libs@windows: + - icudt.lib + - icuin.lib + - icuio.lib + - icuuc.lib diff --git a/config/pkg/lib/libaom.yml b/config/pkg/lib/libaom.yml index 6a2dbe3cb..51d14a9b5 100644 --- a/config/pkg/lib/libaom.yml +++ b/config/pkg/lib/libaom.yml @@ -10,3 +10,5 @@ libaom: lang: cpp static-libs@unix: - libaom.a + static-libs@windows: + - aom.lib diff --git a/config/pkg/lib/libavif.yml b/config/pkg/lib/libavif.yml index c75b05c45..eaea8542a 100644 --- a/config/pkg/lib/libavif.yml +++ b/config/pkg/lib/libavif.yml @@ -16,3 +16,5 @@ libavif: - libpng static-libs@unix: - libavif.a + static-libs@windows: + - avif.lib diff --git a/config/pkg/lib/libffi-win.yml b/config/pkg/lib/libffi-win.yml new file mode 100644 index 000000000..051dfcb22 --- /dev/null +++ b/config/pkg/lib/libffi-win.yml @@ -0,0 +1,12 @@ +libffi-win: + type: library + artifact: + source: + type: git + rev: master + url: 'https://github.com/static-php/libffi-win.git' + metadata: + license-files: [LICENSE] + license: MIT + static-libs@windows: + - libffi.lib diff --git a/config/pkg/lib/libiconv-win.yml b/config/pkg/lib/libiconv-win.yml new file mode 100644 index 000000000..103acf2e9 --- /dev/null +++ b/config/pkg/lib/libiconv-win.yml @@ -0,0 +1,13 @@ +libiconv-win: + type: library + artifact: + source: + type: git + rev: master + url: 'https://github.com/static-php/libiconv-win.git' + metadata: + license-files: [source/COPYING] + license: GPL-3.0-or-later + static-libs@windows: + - libiconv.lib + - libiconv_a.lib diff --git a/config/pkg/lib/libjpeg.yml b/config/pkg/lib/libjpeg.yml index 9171ad388..cca706861 100644 --- a/config/pkg/lib/libjpeg.yml +++ b/config/pkg/lib/libjpeg.yml @@ -7,6 +7,10 @@ libjpeg: metadata: license-files: [LICENSE.md] license: IJG + suggests@windows: + - zlib static-libs@unix: - libjpeg.a - libturbojpeg.a + static-libs@windows: + - libjpeg_a.lib diff --git a/config/pkg/lib/libpng.yml b/config/pkg/lib/libpng.yml index e8831d60c..083cf430a 100644 --- a/config/pkg/lib/libpng.yml +++ b/config/pkg/lib/libpng.yml @@ -14,3 +14,6 @@ libpng: - zlib static-libs@unix: - libpng16.a + static-libs@windows: + - libpng16_static.lib + - libpng_a.lib diff --git a/config/pkg/lib/librabbitmq.yml b/config/pkg/lib/librabbitmq.yml index da4e98562..9928d331d 100644 --- a/config/pkg/lib/librabbitmq.yml +++ b/config/pkg/lib/librabbitmq.yml @@ -12,3 +12,5 @@ librabbitmq: - openssl static-libs@unix: - librabbitmq.a + static-libs@windows: + - rabbitmq.4.lib diff --git a/config/pkg/lib/libsodium.yml b/config/pkg/lib/libsodium.yml index f5a551b93..4bd41363b 100644 --- a/config/pkg/lib/libsodium.yml +++ b/config/pkg/lib/libsodium.yml @@ -13,3 +13,5 @@ libsodium: - libsodium static-libs@unix: - libsodium.a + static-libs@windows: + - libsodium.lib diff --git a/config/pkg/lib/libssh2.yml b/config/pkg/lib/libssh2.yml index 8e1d82754..2916e3a9c 100644 --- a/config/pkg/lib/libssh2.yml +++ b/config/pkg/lib/libssh2.yml @@ -20,3 +20,5 @@ libssh2: - libssh2 static-libs@unix: - libssh2.a + static-libs@windows: + - libssh2.lib diff --git a/config/pkg/lib/libwebp.yml b/config/pkg/lib/libwebp.yml index 62ddddc13..24873b127 100644 --- a/config/pkg/lib/libwebp.yml +++ b/config/pkg/lib/libwebp.yml @@ -14,3 +14,8 @@ libwebp: - libwebpdemux - libwebpmux - libsharpyuv + static-libs@windows: + - libwebp.lib + - libwebpdecoder.lib + - libwebpdemux.lib + - libsharpyuv.lib diff --git a/config/pkg/lib/libxml2.yml b/config/pkg/lib/libxml2.yml index 7e86b5af5..5ffdc8b27 100644 --- a/config/pkg/lib/libxml2.yml +++ b/config/pkg/lib/libxml2.yml @@ -12,7 +12,13 @@ libxml2: - libiconv - zlib - xz + depends@windows: + - zlib + - libiconv-win headers: - libxml2 pkg-configs: - libxml-2.0 + static-libs@windows: + - libxml2s.lib + - libxml2_a.lib diff --git a/config/pkg/lib/libyaml.yml b/config/pkg/lib/libyaml.yml index 0d39e0b1d..8cabd58fb 100644 --- a/config/pkg/lib/libyaml.yml +++ b/config/pkg/lib/libyaml.yml @@ -13,3 +13,5 @@ libyaml: - yaml.h static-libs@unix: - libyaml.a + static-libs@windows: + - yaml.lib diff --git a/config/pkg/lib/libzip.yml b/config/pkg/lib/libzip.yml index 2de69d424..3d8a375a0 100644 --- a/config/pkg/lib/libzip.yml +++ b/config/pkg/lib/libzip.yml @@ -8,9 +8,10 @@ libzip: prefer-stable: true metadata: license-files: [LICENSE] - depends@unix: + license: BSD-3-Clause + depends: - zlib - suggests@unix: + suggests: - bzip2 - xz - zstd @@ -20,3 +21,5 @@ libzip: - zipconf.h static-libs@unix: - libzip.a + static-libs@windows: + - libzip_a.lib diff --git a/config/pkg/lib/nghttp2.yml b/config/pkg/lib/nghttp2.yml index 166c33ac5..11521d5a3 100644 --- a/config/pkg/lib/nghttp2.yml +++ b/config/pkg/lib/nghttp2.yml @@ -22,3 +22,5 @@ nghttp2: - libnghttp2 static-libs@unix: - libnghttp2.a + static-libs@windows: + - nghttp2.lib diff --git a/config/pkg/lib/nghttp3.yml b/config/pkg/lib/nghttp3.yml index f9adc05b5..272172b99 100644 --- a/config/pkg/lib/nghttp3.yml +++ b/config/pkg/lib/nghttp3.yml @@ -17,3 +17,5 @@ nghttp3: - libnghttp3 static-libs@unix: - libnghttp3.a + static-libs@windows: + - nghttp3.lib diff --git a/config/pkg/lib/ngtcp2.yml b/config/pkg/lib/ngtcp2.yml index c864739a7..8984ca729 100644 --- a/config/pkg/lib/ngtcp2.yml +++ b/config/pkg/lib/ngtcp2.yml @@ -11,9 +11,6 @@ ngtcp2: license: MIT depends: - openssl - suggests: - - nghttp3 - - brotli headers: - ngtcp2 pkg-configs: @@ -22,3 +19,5 @@ ngtcp2: static-libs@unix: - libngtcp2.a - libngtcp2_crypto_ossl.a + static-libs@windows: + - ngtcp2.lib diff --git a/config/pkg/lib/onig.yml b/config/pkg/lib/onig.yml index fa06524dc..c2ef658af 100644 --- a/config/pkg/lib/onig.yml +++ b/config/pkg/lib/onig.yml @@ -13,3 +13,6 @@ onig: - oniguruma.h static-libs@unix: - libonig.a + static-libs@windows: + - onig.lib + - onig_a.lib diff --git a/config/pkg/lib/openssl.yml b/config/pkg/lib/openssl.yml index 22d065088..da02f202b 100644 --- a/config/pkg/lib/openssl.yml +++ b/config/pkg/lib/openssl.yml @@ -16,8 +16,14 @@ openssl: license: OpenSSL depends: - zlib + depends@windows: + - zlib + - jom headers: - openssl static-libs@unix: - libssl.a - libcrypto.a + static-libs@windows: + - libssl.lib + - libcrypto.lib diff --git a/config/pkg/lib/postgresql.yml b/config/pkg/lib/postgresql.yml index 1237b1846..ee78072e4 100644 --- a/config/pkg/lib/postgresql.yml +++ b/config/pkg/lib/postgresql.yml @@ -5,19 +5,25 @@ postgresql: type: ghtagtar repo: postgres/postgres match: REL_18_\d+ + binary: + windows-x86_64: { type: url, url: 'https://get.enterprisedb.com/postgresql/postgresql-16.8-1-windows-x64-binaries.zip', extract: { lib/libpq.lib: '{build_root_path}/lib/libpq.lib', lib/libpgport.lib: '{build_root_path}/lib/libpgport.lib', lib/libpgcommon.lib: '{build_root_path}/lib/libpgcommon.lib', include/libpq-fe.h: '{build_root_path}/include/libpq-fe.h', include/postgres_ext.h: '{build_root_path}/include/postgres_ext.h', include/pg_config_ext.h: '{build_root_path}/include/pg_config_ext.h', include/libpq/libpq-fs.h: '{build_root_path}/include/libpq/libpq-fs.h' } } metadata: - license-files: [COPYRIGHT] + license-files: ['@/postgresql.txt'] license: PostgreSQL - depends: + depends@unix: - libiconv - libxml2 - openssl - zlib - libedit - suggests: + suggests@unix: - icu - libxslt - ldap - zstd pkg-configs: - libpq + static-libs@windows: + - libpq.lib + - libpgport.lib + - libpgcommon.lib diff --git a/config/pkg/lib/pthreads4w.yml b/config/pkg/lib/pthreads4w.yml new file mode 100644 index 000000000..06a6245f8 --- /dev/null +++ b/config/pkg/lib/pthreads4w.yml @@ -0,0 +1,12 @@ +pthreads4w: + type: library + artifact: + source: + type: git + rev: master + url: 'https://git.code.sf.net/p/pthreads4w/code' + metadata: + license-files: [LICENSE] + license: Apache-2.0 + static-libs@windows: + - libpthreadVC3.lib diff --git a/config/pkg/lib/qdbm.yml b/config/pkg/lib/qdbm.yml index 1b46e3049..86b881d7c 100644 --- a/config/pkg/lib/qdbm.yml +++ b/config/pkg/lib/qdbm.yml @@ -10,3 +10,5 @@ qdbm: license: 'GPL-2.0-only OR LGPL-2.1-only' static-libs@unix: - libqdbm.a + static-libs@windows: + - qdbm_a.lib diff --git a/config/pkg/lib/sqlite.yml b/config/pkg/lib/sqlite.yml index fb6eecf35..442629d0c 100644 --- a/config/pkg/lib/sqlite.yml +++ b/config/pkg/lib/sqlite.yml @@ -10,3 +10,5 @@ sqlite: - sqlite3ext.h static-libs@unix: - libsqlite3.a + static-libs@windows: + - libsqlite3_a.lib diff --git a/config/pkg/lib/xz.yml b/config/pkg/lib/xz.yml index 7d0af682b..3be1815d8 100644 --- a/config/pkg/lib/xz.yml +++ b/config/pkg/lib/xz.yml @@ -14,7 +14,13 @@ xz: - libiconv headers@unix: - lzma + headers@windows: + - lzma + - lzma.h pkg-configs: - liblzma static-libs@unix: - liblzma.a + static-libs@windows: + - lzma.lib + - liblzma_a.lib diff --git a/config/pkg/lib/zlib.yml b/config/pkg/lib/zlib.yml index cf7f11ba0..b4e71364e 100644 --- a/config/pkg/lib/zlib.yml +++ b/config/pkg/lib/zlib.yml @@ -14,3 +14,6 @@ zlib: - zconf.h static-libs@unix: - libz.a + static-libs@windows: + - zlibstatic.lib + - zlib_a.lib diff --git a/config/pkg/lib/zstd.yml b/config/pkg/lib/zstd.yml index 3d76e270c..875380d1f 100644 --- a/config/pkg/lib/zstd.yml +++ b/config/pkg/lib/zstd.yml @@ -17,3 +17,5 @@ zstd: - libzstd static-libs@unix: - libzstd.a + static-libs@windows: + - zstd_static.lib diff --git a/config/pkg/target/curl.yml b/config/pkg/target/curl.yml index 4daba8c14..78064510c 100644 --- a/config/pkg/target/curl.yml +++ b/config/pkg/target/curl.yml @@ -12,6 +12,10 @@ curl: depends@unix: - openssl - zlib + depends@windows: + - zlib + - libssh2 + - nghttp2 suggests@unix: - libssh2 - brotli @@ -23,6 +27,9 @@ curl: - ldap - idn2 - krb5 + suggests@windows: + - brotli + - zstd frameworks: - CoreFoundation - CoreServices @@ -33,3 +40,5 @@ curl: - curl static-libs@unix: - libcurl.a + static-libs@windows: + - libcurl_a.lib diff --git a/config/pkg/target/jom.yml b/config/pkg/target/jom.yml new file mode 100644 index 000000000..70916bfdd --- /dev/null +++ b/config/pkg/target/jom.yml @@ -0,0 +1,7 @@ +jom: + type: target + artifact: + binary: + windows-x86_64: { type: url, url: 'https://download.qt.io/official_releases/jom/jom.zip', extract: '{pkg_root_path}/jom' } + path@windows: + - '{pkg_root_path}\jom' diff --git a/src/Package/Library/brotli.php b/src/Package/Library/brotli.php index f22b9ef29..cab05112b 100644 --- a/src/Package/Library/brotli.php +++ b/src/Package/Library/brotli.php @@ -8,11 +8,19 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; use StaticPHP\Util\FileSystem; #[Library('brotli')] class brotli { + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $package): void + { + WindowsCMakeExecutor::create($package)->build(); + // FileSystem::copy("{$package->getLibDir()}\\onig.lib", "{$package->getLibDir()}\\onig_a.lib"); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib): void diff --git a/src/Package/Library/bzip2.php b/src/Package/Library/bzip2.php index 403773dab..90fcce7c6 100644 --- a/src/Package/Library/bzip2.php +++ b/src/Package/Library/bzip2.php @@ -20,6 +20,17 @@ public function patchBeforeBuild(LibraryPackage $lib): void FileSystem::replaceFileStr($lib->getSourceDir() . '/Makefile', 'CFLAGS=-Wall', 'CFLAGS=-fPIC -Wall'); } + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $package): void + { + cmd()->cd($package->getSourceDir()) + ->exec('nmake /nologo /f Makefile.msc CFLAGS="-DWIN32 -MT -Ox -D_FILE_OFFSET_BITS=64 -nologo" clean') + ->exec('nmake /nologo /f Makefile.msc CFLAGS="-DWIN32 -MT -Ox -D_FILE_OFFSET_BITS=64 -nologo" lib'); + FileSystem::copy("{$package->getSourceDir()}\\libbz2.lib", "{$package->getLibDir()}\\libbz2.lib"); + FileSystem::copy("{$package->getSourceDir()}\\libbz2.lib", "{$package->getLibDir()}\\libbz2_a.lib"); + FileSystem::copy("{$package->getSourceDir()}\\bzlib.h", "{$package->getIncludeDir()}\\bzlib.h"); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib, PackageBuilder $builder): void diff --git a/src/Package/Library/freetype.php b/src/Package/Library/freetype.php index 6cb05a90a..8a83eb5e3 100644 --- a/src/Package/Library/freetype.php +++ b/src/Package/Library/freetype.php @@ -8,6 +8,7 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; use StaticPHP\Util\FileSystem; #[Library('freetype')] @@ -33,4 +34,18 @@ public function buildUnix(LibraryPackage $lib): void $lib->patchPkgconfPrefix(['freetype2.pc']); FileSystem::replaceFileStr("{$lib->getBuildRootPath()}/lib/pkgconfig/freetype2.pc", ' -L/lib ', " -L{$lib->getBuildRootPath()}/lib "); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->optionalPackage('libpng', ...cmake_boolean_args('FT_DISABLE_PNG', true)) + ->optionalPackage('bzip2', ...cmake_boolean_args('FT_DISABLE_BZIP2', true)) + ->optionalPackage('brotli', ...cmake_boolean_args('FT_DISABLE_BROTLI', true)) + ->addConfigureArgs('-DFT_DISABLE_HARFBUZZ=ON') + ->build(); + + // freetype.lib to libfreetype_a.lib + FileSystem::copy("{$lib->getLibDir()}\\freetype.lib", "{$lib->getLibDir()}\\libfreetype_a.lib"); + } } diff --git a/src/Package/Library/gmssl.php b/src/Package/Library/gmssl.php index 21b4ea668..7785e55a4 100644 --- a/src/Package/Library/gmssl.php +++ b/src/Package/Library/gmssl.php @@ -8,6 +8,8 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; +use StaticPHP\Util\FileSystem; #[Library('gmssl')] class gmssl @@ -18,4 +20,35 @@ public function build(LibraryPackage $lib): void { UnixCMakeExecutor::create($lib)->build(); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + $buildDir = "{$lib->getSourceDir()}\\builddir"; + + // GmSSL requires NMake Makefiles generator on Windows + WindowsCMakeExecutor::create($lib) + ->setBuildDir($buildDir) + ->setCustomDefaultArgs( + '-G "NMake Makefiles"', + '-DWIN32=ON', + '-DBUILD_SHARED_LIBS=OFF', + '-DCMAKE_BUILD_TYPE=Release', + '-DCMAKE_C_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"', + '-DCMAKE_CXX_FLAGS_RELEASE="/MT /O2 /Ob2 /DNDEBUG"', + '-DCMAKE_INSTALL_PREFIX=' . escapeshellarg($lib->getBuildRootPath()), + '-B ' . escapeshellarg($buildDir), + ) + ->toStep(1) + ->build(); + + // fix cmake_install.cmake install prefix (GmSSL overrides it internally) + $installCmake = "{$buildDir}\\cmake_install.cmake"; + FileSystem::writeFile( + $installCmake, + 'set(CMAKE_INSTALL_PREFIX "' . str_replace('\\', '/', $lib->getBuildRootPath()) . '")' . PHP_EOL . FileSystem::readFile($installCmake) + ); + + cmd()->cd($buildDir)->exec('nmake install XCFLAGS=/MT'); + } } diff --git a/src/Package/Library/libaom.php b/src/Package/Library/libaom.php index 167ef0766..7e578242b 100644 --- a/src/Package/Library/libaom.php +++ b/src/Package/Library/libaom.php @@ -8,12 +8,28 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; use StaticPHP\Toolchain\Interface\ToolchainInterface; use StaticPHP\Toolchain\ZigToolchain; #[Library('libaom')] class libaom extends LibraryPackage { + #[BuildFor('Windows')] + public function buildWin(): void + { + WindowsCMakeExecutor::create($this) + ->setBuildDir("{$this->getSourceDir()}/builddir") + ->addConfigureArgs( + '-DAOM_TARGET_CPU=generic', + '-DENABLE_TESTS=OFF', + '-DENABLE_EXAMPLES=OFF', + '-DENABLE_TOOLS=OFF', + '-DENABLE_DOCS=OFF', + ) + ->build(); + } + #[BuildFor('Darwin')] #[BuildFor('Linux')] public function buildUnix(ToolchainInterface $toolchain): void diff --git a/src/Package/Library/libavif.php b/src/Package/Library/libavif.php index 6db235e19..b8321375e 100644 --- a/src/Package/Library/libavif.php +++ b/src/Package/Library/libavif.php @@ -6,12 +6,25 @@ use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\Library; +use StaticPHP\Attribute\Package\PatchBeforeBuild; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; +use StaticPHP\Runtime\SystemTarget; +use StaticPHP\Util\FileSystem; #[Library('libavif')] class libavif { + #[PatchBeforeBuild] + public function patchBeforeBuild(LibraryPackage $lib): void + { + // workaround for libavif 1.2.0 bug: MSVC does not support empty initializer list + if (SystemTarget::getTargetOS() === 'Windows') { + FileSystem::replaceFileStr($lib->getSourceDir() . '/src/read.c', 'avifFileType ftyp = {};', 'avifFileType ftyp = { 0 };'); + } + } + #[BuildFor('Darwin')] #[BuildFor('Linux')] public function buildUnix(LibraryPackage $lib): void @@ -27,4 +40,17 @@ public function buildUnix(LibraryPackage $lib): void // patch pkgconfig $lib->patchPkgconfPrefix(['libavif.pc']); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs( + '-DAVIF_BUILD_APPS=OFF', + '-DAVIF_BUILD_TESTS=OFF', + '-DAVIF_LIBYUV=OFF', + '-DAVIF_ENABLE_GTEST=OFF', + ) + ->build(); + } } diff --git a/src/Package/Library/libffi_win.php b/src/Package/Library/libffi_win.php new file mode 100644 index 000000000..12faaabef --- /dev/null +++ b/src/Package/Library/libffi_win.php @@ -0,0 +1,47 @@ + '\win32\vs17_x64', + '16' => '\win32\vs16_x64', + default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported!"), + }; + ApplicationContext::set('libffi_win_vs_ver_dir', $vs_ver_dir); + } + + #[BuildFor('Windows')] + public function build(LibraryPackage $lib): void + { + $vs_ver_dir = ApplicationContext::get('libffi_win_vs_ver_dir'); + cmd()->cd("{$lib->getSourceDir()}{$vs_ver_dir}") + ->exec('msbuild libffi-msvc.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64'); + FileSystem::createDir($lib->getLibDir()); + FileSystem::createDir($lib->getIncludeDir()); + + FileSystem::copy("{$lib->getSourceDir()}{$vs_ver_dir}\\x64\\Release\\libffi.lib", "{$lib->getLibDir()}\\libffi.lib"); + FileSystem::copy("{$lib->getSourceDir()}{$vs_ver_dir}\\x64\\Release\\libffi.pdb", "{$lib->getLibDir()}\\libffi.pdb"); + FileSystem::copy("{$lib->getSourceDir()}\\include\\ffi.h", "{$lib->getIncludeDir()}\\ffi.h"); + FileSystem::replaceFileStr("{$lib->getIncludeDir()}\\ffi.h", '#define LIBFFI_H', "#define LIBFFI_H\n#define FFI_BUILDING"); + FileSystem::copy("{$lib->getSourceDir()}\\src\\x86\\ffitarget.h", "{$lib->getIncludeDir()}\\ffitarget.h"); + FileSystem::copy("{$lib->getSourceDir()}\\fficonfig.h", "{$lib->getIncludeDir()}\\fficonfig.h"); + } +} diff --git a/src/Package/Library/libiconv_win.php b/src/Package/Library/libiconv_win.php new file mode 100644 index 000000000..b6b0531df --- /dev/null +++ b/src/Package/Library/libiconv_win.php @@ -0,0 +1,43 @@ + '\MSVC17', + '16' => '\MSVC16', + default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"), + }; + ApplicationContext::set('vs_ver_dir', $vs_ver_dir); + } + + #[BuildFor('Windows')] + public function build(LibraryPackage $lib): void + { + $vs_ver_dir = ApplicationContext::get('vs_ver_dir'); + cmd()->cd("{$lib->getSourceDir()}{$vs_ver_dir}") + ->exec('msbuild libiconv.sln /t:Rebuild /p:Configuration=Release /p:Platform=x64'); + FileSystem::createDir($lib->getLibDir()); + FileSystem::createDir($lib->getIncludeDir()); + FileSystem::copy("{$lib->getSourceDir()}{$vs_ver_dir}\\x64\\lib\\libiconv.lib", "{$lib->getLibDir()}\\libiconv.lib"); + FileSystem::copy("{$lib->getSourceDir()}{$vs_ver_dir}\\x64\\lib\\libiconv_a.lib", "{$lib->getLibDir()}\\libiconv_a.lib"); + FileSystem::copy("{$lib->getSourceDir()}\\source\\include\\iconv.h", "{$lib->getIncludeDir()}\\iconv.h"); + } +} diff --git a/src/Package/Library/libjpeg.php b/src/Package/Library/libjpeg.php index 04f4fd254..6e06bfb70 100644 --- a/src/Package/Library/libjpeg.php +++ b/src/Package/Library/libjpeg.php @@ -8,6 +8,8 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; +use StaticPHP\Util\FileSystem; #[Library('libjpeg')] class libjpeg @@ -25,4 +27,20 @@ public function buildUnix(LibraryPackage $lib): void // patch pkgconfig $lib->patchPkgconfPrefix(['libjpeg.pc', 'libturbojpeg.pc']); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs( + '-DENABLE_SHARED=OFF', + '-DENABLE_STATIC=ON', + '-DBUILD_TESTING=OFF', + '-DWITH_JAVA=OFF', + '-DWITH_CRT_DLL=OFF', + ) + ->optionalPackage('zlib', '-DENABLE_ZLIB_COMPRESSION=ON', '-DENABLE_ZLIB_COMPRESSION=OFF') + ->build(); + FileSystem::copy("{$lib->getLibDir()}\\jpeg-static.lib", "{$lib->getLibDir()}\\libjpeg_a.lib"); + } } diff --git a/src/Package/Library/libpng.php b/src/Package/Library/libpng.php index 1d02fdd69..6a1690105 100644 --- a/src/Package/Library/libpng.php +++ b/src/Package/Library/libpng.php @@ -8,6 +8,8 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; +use StaticPHP\Util\FileSystem; #[Library('libpng')] class libpng @@ -44,4 +46,21 @@ public function buildUnix(LibraryPackage $lib): void $lib->patchPkgconfPrefix(['libpng16.pc']); $lib->patchLaDependencyPrefix(); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs( + '-DSKIP_INSTALL_PROGRAM=ON', + '-DSKIP_INSTALL_FILES=ON', + '-DPNG_STATIC=ON', + '-DPNG_SHARED=OFF', + '-DPNG_TESTS=OFF', + ) + ->build(); + + // libpng16_static.lib to libpng_a.lib + FileSystem::copy("{$lib->getLibDir()}\\libpng16_static.lib", "{$lib->getLibDir()}\\libpng_a.lib"); + } } diff --git a/src/Package/Library/librabbitmq.php b/src/Package/Library/librabbitmq.php index 2350ea5e8..03eda2a74 100644 --- a/src/Package/Library/librabbitmq.php +++ b/src/Package/Library/librabbitmq.php @@ -8,6 +8,7 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; #[Library('librabbitmq')] class librabbitmq extends LibraryPackage @@ -18,4 +19,11 @@ public function buildUnix(): void { UnixCMakeExecutor::create($this)->addConfigureArgs('-DBUILD_STATIC_LIBS=ON')->build(); } + + #[BuildFor('Windows')] + public function buildWin(): void + { + WindowsCMakeExecutor::create($this)->build(); + rename("{$this->getLibDir()}\\librabbitmq.4.lib", "{$this->getLibDir()}\\rabbitmq.4.lib"); + } } diff --git a/src/Package/Library/libsodium.php b/src/Package/Library/libsodium.php index 50d706ba4..0d4c8afef 100644 --- a/src/Package/Library/libsodium.php +++ b/src/Package/Library/libsodium.php @@ -6,12 +6,27 @@ use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\Library; +use StaticPHP\Attribute\Package\PatchBeforeBuild; +use StaticPHP\Attribute\PatchDescription; +use StaticPHP\Exception\BuildFailureException; +use StaticPHP\Exception\EnvironmentException; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; +use StaticPHP\Runtime\SystemTarget; +use StaticPHP\Util\FileSystem; +use StaticPHP\Util\System\WindowsUtil; #[Library('libsodium')] class libsodium { + #[PatchBeforeBuild] + #[PatchDescription('Replace SODIUM_STATIC define guard with unconditional #if 1 for MSVC static linking')] + public function patchBeforeBuild(LibraryPackage $lib): void + { + spc_skip_if(SystemTarget::getTargetOS() !== 'Windows', 'This patch is only for Windows builds.'); + FileSystem::replaceFileStr($lib->getSourceDir() . '\src\libsodium\include\sodium\export.h', '#ifdef SODIUM_STATIC', '#if 1'); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib): void @@ -21,4 +36,39 @@ public function build(LibraryPackage $lib): void // Patch pkg-config file $lib->patchPkgconfPrefix(['libsodium.pc'], PKGCONF_PATCH_PREFIX); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + $ver = WindowsUtil::findVisualStudio(); + $vs_ver_dir = match ($ver['major_version']) { + '17' => '\vs2022', + '16' => '\vs2019', + default => throw new EnvironmentException("Current VS version {$ver['major_version']} is not supported yet!"), + }; + + cmd()->cd("{$lib->getSourceDir()}\\builds\\msvc{$vs_ver_dir}") + ->exec('msbuild libsodium.sln /t:Rebuild /p:Configuration=StaticRelease /p:Platform=x64 /p:PreprocessorDefinitions="SODIUM_STATIC=1"'); + FileSystem::createDir($lib->getLibDir()); + FileSystem::createDir($lib->getIncludeDir()); + + // copy include + FileSystem::copyDir("{$lib->getSourceDir()}\\src\\libsodium\\include\\sodium", "{$lib->getIncludeDir()}\\sodium"); + FileSystem::copy("{$lib->getSourceDir()}\\src\\libsodium\\include\\sodium.h", "{$lib->getIncludeDir()}\\sodium.h"); + // copy lib + $ls = FileSystem::scanDirFiles("{$lib->getSourceDir()}\\bin"); + $find = false; + foreach ($ls as $file) { + if (str_ends_with($file, 'libsodium.lib')) { + FileSystem::copy($file, "{$lib->getLibDir()}\\libsodium.lib"); + $find = true; + } + if (str_ends_with($file, 'libsodium.pdb')) { + FileSystem::copy($file, "{$lib->getLibDir()}\\libsodium.pdb"); + } + } + if (!$find) { + throw new BuildFailureException("Build libsodium success, but cannot find libsodium.lib in {$lib->getSourceDir()}\\bin ."); + } + } } diff --git a/src/Package/Library/libssh2.php b/src/Package/Library/libssh2.php index f71d508ac..b41434e09 100644 --- a/src/Package/Library/libssh2.php +++ b/src/Package/Library/libssh2.php @@ -8,10 +8,22 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; #[Library('libssh2')] class libssh2 { + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs( + '-DENABLE_ZLIB_COMPRESSION=ON', + '-DBUILD_TESTING=OFF' + ) + ->build(); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib): void diff --git a/src/Package/Library/libwebp.php b/src/Package/Library/libwebp.php index 0ee4028d5..30b3826ac 100644 --- a/src/Package/Library/libwebp.php +++ b/src/Package/Library/libwebp.php @@ -8,6 +8,7 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; #[Library('libwebp')] class libwebp extends LibraryPackage @@ -41,4 +42,23 @@ public function buildUnix(): void $this->patchPkgconfPrefix(patch_option: PKGCONF_PATCH_PREFIX | PKGCONF_PATCH_LIBDIR); $this->patchPkgconfPrefix(['libsharpyuv.pc'], PKGCONF_PATCH_CUSTOM, ['/^includedir=.*$/m', 'includedir=${prefix}/include/webp']); } + + #[BuildFor('Windows')] + public function buildWin(): void + { + WindowsCMakeExecutor::create($this) + ->addConfigureArgs( + '-DWEBP_BUILD_EXTRAS=OFF', + '-DWEBP_BUILD_ANIM_UTILS=OFF', + '-DWEBP_BUILD_CWEBP=OFF', + '-DWEBP_BUILD_DWEBP=OFF', + '-DWEBP_BUILD_GIF2WEBP=OFF', + '-DWEBP_BUILD_IMG2WEBP=OFF', + '-DWEBP_BUILD_VWEBP=OFF', + '-DWEBP_BUILD_WEBPINFO=OFF', + '-DWEBP_BUILD_WEBPMUX=OFF', + '-DWEBP_BUILD_FUZZTEST=OFF', + ) + ->build(); + } } diff --git a/src/Package/Library/libxml2.php b/src/Package/Library/libxml2.php index 3f8b3e71f..108b9962f 100644 --- a/src/Package/Library/libxml2.php +++ b/src/Package/Library/libxml2.php @@ -7,12 +7,33 @@ use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; +use StaticPHP\Package\PackageInstaller; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; use StaticPHP\Util\FileSystem; #[Library('libxml2')] class libxml2 { + #[BuildFor('Windows')] + public function buildForWindows(LibraryPackage $lib, PackageInstaller $installer): void + { + $iconv_win = $installer->getLibraryPackage('libiconv-win'); + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs( + '-DLIBXML2_WITH_ICONV=ON', + "-DIconv_LIBRARY={$iconv_win->getLibDir()}", + "-DIconv_INCLUDE_DIR={$iconv_win->getIncludeDir()}", + '-DLIBXML2_WITH_ZLIB=ON', + '-DLIBXML2_WITH_PYTHON=OFF', + '-DLIBXML2_WITH_LZMA=OFF', + '-DLIBXML2_WITH_PROGRAMS=OFF', + '-DLIBXML2_WITH_TESTS=OFF', + ) + ->build(); + FileSystem::copy("{$lib->getLibDir()}\\libxml2s.lib", "{$lib->getLibDir()}\\libxml2_a.lib"); + } + #[BuildFor('Linux')] public function buildForLinux(LibraryPackage $lib): void { diff --git a/src/Package/Library/libyaml.php b/src/Package/Library/libyaml.php index 602c875c8..5334079ba 100644 --- a/src/Package/Library/libyaml.php +++ b/src/Package/Library/libyaml.php @@ -6,16 +6,44 @@ 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\Runtime\Executor\WindowsCMakeExecutor; +use StaticPHP\Runtime\SystemTarget; +use StaticPHP\Util\FileSystem; #[Library('libyaml')] class libyaml { + #[PatchBeforeBuild] + #[PatchDescription('Copy missing cmake helper files required for MSVC build (not included in libyaml git source)')] + public function patchBeforeBuild(LibraryPackage $lib): void + { + spc_skip_if(SystemTarget::getTargetOS() !== 'Windows', 'This patch is only for Windows builds.'); + // check missing files: cmake\config.h.in and .\YamlConfig.cmake.in + if (!file_exists($lib->getSourceDir() . '\cmake\config.h.in')) { + FileSystem::createDir($lib->getSourceDir() . '\cmake'); + FileSystem::copy(ROOT_DIR . '/src/globals/extra/libyaml_config.h.in', $lib->getSourceDir() . '\cmake\config.h.in'); + } + if (!file_exists($lib->getSourceDir() . '\YamlConfig.cmake.in')) { + FileSystem::copy(ROOT_DIR . '/src/globals/extra/libyaml_yamlConfig.cmake.in', $lib->getSourceDir() . '\YamlConfig.cmake.in'); + } + } + #[BuildFor('Darwin')] #[BuildFor('Linux')] public function buildUnix(LibraryPackage $lib): void { UnixAutoconfExecutor::create($lib)->configure()->make(); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs('-DBUILD_TESTING=OFF') + ->build(); + } } diff --git a/src/Package/Library/libzip.php b/src/Package/Library/libzip.php index f6ebdfea7..b1d386345 100644 --- a/src/Package/Library/libzip.php +++ b/src/Package/Library/libzip.php @@ -8,6 +8,8 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; +use StaticPHP\Util\FileSystem; #[Library('libzip')] class libzip @@ -33,4 +35,28 @@ public function buildUnix(LibraryPackage $lib): void ->build(); $lib->patchPkgconfPrefix(['libzip.pc'], PKGCONF_PATCH_PREFIX); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->optionalPackage('bzip2', ...cmake_boolean_args('ENABLE_BZIP2')) + ->optionalPackage('xz', ...cmake_boolean_args('ENABLE_LZMA')) + ->optionalPackage('openssl', ...cmake_boolean_args('ENABLE_OPENSSL')) + ->optionalPackage('zstd', ...cmake_boolean_args('ENABLE_ZSTD')) + ->addConfigureArgs( + '-DENABLE_GNUTLS=OFF', + '-DENABLE_MBEDTLS=OFF', + '-DBUILD_DOC=OFF', + '-DBUILD_EXAMPLES=OFF', + '-DBUILD_REGRESS=OFF', + '-DBUILD_TOOLS=OFF', + '-DBUILD_OSSFUZZ=OFF', + ) + ->build(); + FileSystem::copy( + $lib->getBuildRootPath() . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'zip.lib', + $lib->getBuildRootPath() . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'libzip_a.lib' + ); + } } diff --git a/src/Package/Library/nghttp2.php b/src/Package/Library/nghttp2.php index 3a85ada4a..f09659470 100644 --- a/src/Package/Library/nghttp2.php +++ b/src/Package/Library/nghttp2.php @@ -8,10 +8,26 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; #[Library('nghttp2')] class nghttp2 { + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs( + '-DENABLE_SHARED_LIB=OFF', + '-DENABLE_STATIC_LIB=ON', + '-DENABLE_STATIC_CRT=ON', + '-DENABLE_LIB_ONLY=ON', + '-DENABLE_DOC=OFF', + '-DBUILD_TESTING=OFF', + ) + ->build(); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib): void diff --git a/src/Package/Library/nghttp3.php b/src/Package/Library/nghttp3.php index 1f686b7b5..4659c5711 100644 --- a/src/Package/Library/nghttp3.php +++ b/src/Package/Library/nghttp3.php @@ -8,10 +8,26 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; #[Library('nghttp3')] class nghttp3 { + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs( + '-DENABLE_SHARED_LIB=OFF', + '-DENABLE_STATIC_LIB=ON', + '-DBUILD_STATIC_LIBS=ON', + '-DBUILD_SHARED_LIBS=OFF', + '-DENABLE_STATIC_CRT=ON', + '-DENABLE_LIB_ONLY=ON', + ) + ->build(); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib): void diff --git a/src/Package/Library/ngtcp2.php b/src/Package/Library/ngtcp2.php index 15821225b..c88b643bf 100644 --- a/src/Package/Library/ngtcp2.php +++ b/src/Package/Library/ngtcp2.php @@ -8,10 +8,27 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; #[Library('ngtcp2')] class ngtcp2 { + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->addConfigureArgs( + '-DENABLE_SHARED_LIB=OFF', + '-DENABLE_STATIC_LIB=ON', + '-DBUILD_STATIC_LIBS=ON', + '-DBUILD_SHARED_LIBS=OFF', + '-DENABLE_STATIC_CRT=ON', + '-DENABLE_LIB_ONLY=ON', + '-DENABLE_OPENSSL=ON', + ) + ->build(); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib): void @@ -26,18 +43,6 @@ public function build(LibraryPackage $lib): void ]), '--with-openssl=no' ) - ->optionalPackage('nghttp3', ...ac_with_args('libnghttp3', true)) - ->optionalPackage( - 'brotli', - fn (LibraryPackage $brotli) => implode(' ', [ - '--with-brotlidec=yes', - "LIBBROTLIDEC_CFLAGS=\"-I{$brotli->getIncludeDir()}\"", - "LIBBROTLIDEC_LIBS=\"{$brotli->getStaticLibFiles()}\"", - '--with-libbrotlienc=yes', - "LIBBROTLIENC_CFLAGS=\"-I{$brotli->getIncludeDir()}\"", - "LIBBROTLIENC_LIBS=\"{$brotli->getStaticLibFiles()}\"", - ]) - ) ->appendEnv(['PKG_CONFIG' => '$PKG_CONFIG --static']) ->configure('--enable-lib-only') ->make(); diff --git a/src/Package/Library/openssl.php b/src/Package/Library/openssl.php index 541b6145f..69297198d 100644 --- a/src/Package/Library/openssl.php +++ b/src/Package/Library/openssl.php @@ -6,13 +6,72 @@ use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\Library; +use StaticPHP\Attribute\Package\Validate; +use StaticPHP\DI\ApplicationContext; +use StaticPHP\Exception\EnvironmentException; use StaticPHP\Package\LibraryPackage; +use StaticPHP\Package\PackageBuilder; +use StaticPHP\Runtime\SystemTarget; use StaticPHP\Util\FileSystem; use StaticPHP\Util\System\LinuxUtil; +use StaticPHP\Util\System\WindowsUtil; #[Library('openssl')] class openssl { + #[Validate] + public function validate(): void + { + if (SystemTarget::getTargetOS() === 'Windows') { + global $argv; + $perl_path_native = PKG_ROOT_PATH . '\strawberry-perl-' . arch2gnu(php_uname('m')) . '-win\perl\bin\perl.exe'; + $perl = file_exists($perl_path_native) ? ($perl_path_native) : WindowsUtil::findCommand('perl.exe'); + if ($perl === null) { + throw new EnvironmentException( + 'You need to install perl first!', + "Please run \"{$argv[0]} doctor\" to fix the environment.", + ); + } + ApplicationContext::set('perl', $perl); + } + } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib, PackageBuilder $builder): void + { + $perl = ApplicationContext::get('perl'); + $cmd = cmd()->cd($lib->getSourceDir()) + ->exec( + "{$perl} Configure zlib VC-WIN64A " . + 'no-shared ' . + '--prefix=' . quote($lib->getBuildRootPath()) . ' ' . + '--with-zlib-lib=' . quote($lib->getLibDir()) . ' ' . + '--with-zlib-include=' . quote($lib->getIncludeDir()) . ' ' . + '--release ' . + 'no-legacy ' . + 'no-tests ' . + '/FS' + ); + + // patch zlib + FileSystem::replaceFileStr("{$lib->getSourceDir()}\\Makefile", 'ZLIB1', 'zlibstatic.lib'); + // patch debug: https://stackoverflow.com/questions/18486243/how-do-i-build-openssl-statically-linked-against-windows-runtime + FileSystem::replaceFileStr("{$lib->getSourceDir()}\\Makefile", '/debug', '/incremental:no /opt:icf /dynamicbase /nxcompat /ltcg /nodefaultlib:msvcrt'); + + // build + $cmd->exec("jom.exe /j{$builder->concurrency} install_dev CNF_LDFLAGS=\"/NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:msvcrt /NODEFAULTLIB:msvcrtd /DEFAULTLIB:libcmt /LIBPATH:{$lib->getLibDir()} zlibstatic.lib\""); + + // copy necessary c files + FileSystem::copy("{$lib->getSourceDir()}\\ms\\applink.c", "{$lib->getIncludeDir()}\\openssl\\applink.c"); + + // patch cmake outputs + FileSystem::replaceFileRegex( + "{$lib->getLibDir()}\\cmake\\OpenSSL\\OpenSSLConfig.cmake", + '/set\(OPENSSL_LIBCRYPTO_DEPENDENCIES .*\)/m', + 'set(OPENSSL_LIBCRYPTO_DEPENDENCIES "${OPENSSL_LIBRARY_DIR}" ws2_32.lib gdi32.lib advapi32.lib crypt32.lib user32.lib)' + ); + } + #[BuildFor('Darwin')] public function buildForDarwin(LibraryPackage $pkg): void { diff --git a/src/Package/Library/postgresql.php b/src/Package/Library/postgresql.php index 682b79e28..45c48577c 100644 --- a/src/Package/Library/postgresql.php +++ b/src/Package/Library/postgresql.php @@ -73,6 +73,11 @@ public function buildUnix(PackageInstaller $installer, PackageBuilder $builder): FileSystem::resetDir("{$this->getSourceDir()}/build"); + if ($installer->isPackageResolved('ldap')) { + $ldap_libs = clean_spaces(implode(' ', PkgConfigUtil::getLibsArray('ldap'))); + FileSystem::replaceFileStr("{$this->getSourceDir()}/configure", '-lldap', $ldap_libs); + } + // PHP source relies on the non-private encoding functions in libpgcommon.a FileSystem::replaceFileStr( "{$this->getSourceDir()}/src/common/Makefile", diff --git a/src/Package/Library/pthreads4w.php b/src/Package/Library/pthreads4w.php new file mode 100644 index 000000000..69f181f0b --- /dev/null +++ b/src/Package/Library/pthreads4w.php @@ -0,0 +1,34 @@ +cd($lib->getSourceDir()) + ->exec( + 'nmake /E /nologo /f Makefile ' . + 'DESTROOT=' . $lib->getBuildRootPath() . ' ' . + 'XCFLAGS="/MT" ' . // no dll + 'EHFLAGS="/I. /DHAVE_CONFIG_H /Os /Ob2 /D__PTW32_STATIC_LIB /D__PTW32_BUILD_INLINED" ' . + 'pthreadVC3.inlined_static_stamp' + ); + FileSystem::createDir($lib->getLibDir()); + FileSystem::createDir($lib->getIncludeDir()); + FileSystem::copy("{$lib->getSourceDir()}\\libpthreadVC3.lib", "{$lib->getLibDir()}\\libpthreadVC3.lib"); + FileSystem::copy("{$lib->getSourceDir()}\\_ptw32.h", "{$lib->getIncludeDir()}\\_ptw32.h"); + FileSystem::copy("{$lib->getSourceDir()}\\pthread.h", "{$lib->getIncludeDir()}\\pthread.h"); + FileSystem::copy("{$lib->getSourceDir()}\\sched.h", "{$lib->getIncludeDir()}\\sched.h"); + FileSystem::copy("{$lib->getSourceDir()}\\semaphore.h", "{$lib->getIncludeDir()}\\semaphore.h"); + } +} diff --git a/src/Package/Library/qdbm.php b/src/Package/Library/qdbm.php index 3b5c276c8..358846fb6 100644 --- a/src/Package/Library/qdbm.php +++ b/src/Package/Library/qdbm.php @@ -23,4 +23,15 @@ public function buildUnix(LibraryPackage $lib): void $ac->make(SystemTarget::getTargetOS() === 'Darwin' ? 'mac' : ''); $lib->patchPkgconfPrefix(['qdbm.pc']); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + cmd()->cd($lib->getSourceDir()) + ->exec('nmake /f VCMakefile'); + FileSystem::createDir($lib->getLibDir()); + FileSystem::createDir($lib->getIncludeDir()); + FileSystem::copy("{$lib->getSourceDir()}\\qdbm_a.lib", "{$lib->getLibDir()}\\qdbm_a.lib"); + FileSystem::copy("{$lib->getSourceDir()}\\depot.h", "{$lib->getIncludeDir()}\\depot.h"); + } } diff --git a/src/Package/Library/sqlite.php b/src/Package/Library/sqlite.php index ae802bfa9..a3d15f9b7 100644 --- a/src/Package/Library/sqlite.php +++ b/src/Package/Library/sqlite.php @@ -6,8 +6,11 @@ use StaticPHP\Attribute\Package\BuildFor; use StaticPHP\Attribute\Package\Library; +use StaticPHP\Attribute\Package\PatchBeforeBuild; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; +use StaticPHP\Runtime\SystemTarget; +use StaticPHP\Util\FileSystem; #[Library('sqlite')] class sqlite @@ -19,4 +22,18 @@ public function buildUnix(LibraryPackage $lib): void UnixAutoconfExecutor::create($lib)->configure()->make(); $lib->patchPkgconfPrefix(['sqlite3.pc']); } + + #[PatchBeforeBuild] + public function patchBeforeBuild(LibraryPackage $lib): void + { + spc_skip_if(SystemTarget::getTargetOS() !== 'Windows', 'This patch is only for Windows builds.'); + FileSystem::copy(ROOT_DIR . '/src/globals/extra/Makefile-sqlite', "{$lib->getSourceDir()}\\Makefile"); + } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + cmd()->cd($lib->getSourceDir()) + ->exec("nmake PREFIX={$lib->getBuildRootPath()} install-static"); + } } diff --git a/src/Package/Library/xz.php b/src/Package/Library/xz.php index 3486d4c17..44a20090f 100644 --- a/src/Package/Library/xz.php +++ b/src/Package/Library/xz.php @@ -8,6 +8,8 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; +use StaticPHP\Util\FileSystem; #[Library('xz')] class xz @@ -27,4 +29,14 @@ public function build(LibraryPackage $lib): void $lib->patchPkgconfPrefix(['liblzma.pc']); $lib->patchLaDependencyPrefix(); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib)->build(); + // copy lzma.lib to liblzma_a.lib + FileSystem::copy("{$lib->getLibDir()}\\lzma.lib", "{$lib->getLibDir()}\\liblzma_a.lib"); + // patch lzma.h: make static API always available on Windows + FileSystem::replaceFileStr("{$lib->getIncludeDir()}\\lzma.h", 'defined(LZMA_API_STATIC)', 'defined(_WIN32)'); + } } diff --git a/src/Package/Library/zlib.php b/src/Package/Library/zlib.php index 8706dfe9b..9bc9ef663 100644 --- a/src/Package/Library/zlib.php +++ b/src/Package/Library/zlib.php @@ -8,6 +8,8 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixAutoconfExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; +use StaticPHP\Util\FileSystem; #[Library('zlib')] class zlib @@ -21,4 +23,29 @@ public function build(LibraryPackage $lib): void // Patch pkg-config file $lib->patchPkgconfPrefix(['zlib.pc'], PKGCONF_PATCH_PREFIX); } + + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib)->build(); + $detect_list = [ + 'zlibstatic.lib', + 'zs.lib', + 'libzs.lib', + 'libz.lib', + ]; + foreach ($detect_list as $item) { + if (file_exists("{$lib->getLibDir()}\\{$item}")) { + FileSystem::copy("{$lib->getLibDir()}\\{$item}", "{$lib->getLibDir()}\\zlib_a.lib"); + FileSystem::copy("{$lib->getLibDir()}\\{$item}", "{$lib->getLibDir()}\\zlibstatic.lib"); + break; + } + } + FileSystem::removeFileIfExists("{$lib->getBinDir()}\\zlib.dll"); + FileSystem::removeFileIfExists("{$lib->getLibDir()}\\zlib.lib"); + FileSystem::removeFileIfExists("{$lib->getLibDir()}\\libz.dll"); + FileSystem::removeFileIfExists("{$lib->getLibDir()}\\libz.lib"); + FileSystem::removeFileIfExists("{$lib->getLibDir()}\\z.lib"); + FileSystem::removeFileIfExists("{$lib->getLibDir()}\\z.dll"); + } } diff --git a/src/Package/Library/zstd.php b/src/Package/Library/zstd.php index ab538358e..f12bf3e02 100644 --- a/src/Package/Library/zstd.php +++ b/src/Package/Library/zstd.php @@ -8,10 +8,24 @@ use StaticPHP\Attribute\Package\Library; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; #[Library('zstd')] class zstd { + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $package): void + { + WindowsCMakeExecutor::create($package) + ->setWorkingDir("{$package->getSourceDir()}/build/cmake") + ->setBuildDir("{$package->getSourceDir()}/build/cmake/build") + ->addConfigureArgs( + '-DZSTD_BUILD_STATIC=ON', + '-DZSTD_BUILD_SHARED=OFF', + ) + ->build(); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib): void diff --git a/src/Package/Target/curl.php b/src/Package/Target/curl.php index dbfa8f7a1..43a2904b7 100644 --- a/src/Package/Target/curl.php +++ b/src/Package/Target/curl.php @@ -10,6 +10,7 @@ use StaticPHP\Attribute\PatchDescription; use StaticPHP\Package\LibraryPackage; use StaticPHP\Runtime\Executor\UnixCMakeExecutor; +use StaticPHP\Runtime\Executor\WindowsCMakeExecutor; use StaticPHP\Runtime\SystemTarget; use StaticPHP\Util\FileSystem; @@ -20,7 +21,9 @@ class curl #[PatchDescription('Remove CMAKE_C_IMPLICIT_LINK_LIBRARIES and fix macOS framework detection')] public function patchBeforeBuild(LibraryPackage $lib): bool { - shell()->cd($lib->getSourceDir())->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ./CMakeLists.txt'); + if (SystemTarget::getTargetOS() !== 'Windows') { + shell()->cd($lib->getSourceDir())->exec('sed -i.save s@\${CMAKE_C_IMPLICIT_LINK_LIBRARIES}@@ ./CMakeLists.txt'); + } if (SystemTarget::getTargetOS() === 'Darwin') { FileSystem::replaceFileRegex("{$lib->getSourceDir()}/CMakeLists.txt", '/NOT COREFOUNDATION_FRAMEWORK/m', 'FALSE'); FileSystem::replaceFileRegex("{$lib->getSourceDir()}/CMakeLists.txt", '/NOT SYSTEMCONFIGURATION_FRAMEWORK/m', 'FALSE'); @@ -29,6 +32,34 @@ public function patchBeforeBuild(LibraryPackage $lib): bool return true; } + #[BuildFor('Windows')] + public function buildWin(LibraryPackage $lib): void + { + WindowsCMakeExecutor::create($lib) + ->optionalPackage('zstd', ...cmake_boolean_args('CURL_ZSTD')) + ->optionalPackage('brotli', ...cmake_boolean_args('CURL_BROTLI')) + ->addConfigureArgs( + '-DBUILD_CURL_EXE=OFF', + '-DZSTD_LIBRARY=zstd_static.lib', + '-DBUILD_TESTING=OFF', + '-DBUILD_EXAMPLES=OFF', + '-DUSE_LIBIDN2=OFF', + '-DCURL_USE_LIBPSL=OFF', + '-DUSE_WINDOWS_SSPI=ON', + '-DCURL_USE_SCHANNEL=ON', + '-DCURL_USE_OPENSSL=OFF', + '-DCURL_ENABLE_SSL=ON', + '-DUSE_NGHTTP2=ON', + '-DSHARE_LIB_OBJECT=OFF', + '-DCURL_USE_LIBSSH2=ON', + '-DENABLE_IPV6=ON', + ) + ->build(); + // move libcurl.lib to libcurl_a.lib + rename("{$lib->getLibDir()}\\libcurl.lib", "{$lib->getLibDir()}\\libcurl_a.lib"); + FileSystem::replaceFileStr("{$lib->getIncludeDir()}\\curl\\curl.h", '#ifdef CURL_STATICLIB', '#if 1'); + } + #[BuildFor('Linux')] #[BuildFor('Darwin')] public function build(LibraryPackage $lib): void diff --git a/src/StaticPHP/Artifact/ArtifactExtractor.php b/src/StaticPHP/Artifact/ArtifactExtractor.php index 4d38a84bd..8b73243a4 100644 --- a/src/StaticPHP/Artifact/ArtifactExtractor.php +++ b/src/StaticPHP/Artifact/ArtifactExtractor.php @@ -468,6 +468,9 @@ protected function extractArchive(string $filename, string $target): void if ($extname !== 'exe' && !is_dir($target)) { FileSystem::createDir($target); + if (!is_dir($target)) { + throw new FileSystemException("Failed to create target directory: {$target}"); + } } match (SystemTarget::getTargetOS()) { 'Windows' => match ($extname) { diff --git a/src/StaticPHP/Command/InstallPackageCommand.php b/src/StaticPHP/Command/InstallPackageCommand.php index 864fd3796..1185e9f93 100644 --- a/src/StaticPHP/Command/InstallPackageCommand.php +++ b/src/StaticPHP/Command/InstallPackageCommand.php @@ -4,6 +4,7 @@ namespace StaticPHP\Command; +use StaticPHP\Artifact\DownloaderOptions; use StaticPHP\DI\ApplicationContext; use StaticPHP\Package\PackageInstaller; use StaticPHP\Registry\PackageLoader; @@ -29,6 +30,7 @@ public function configure(): void return array_filter($packages, fn ($name) => str_starts_with($name, $val)); } ); + $this->getDefinition()->addOptions(DownloaderOptions::getConsoleOptions('dl')); } public function handle(): int diff --git a/src/StaticPHP/Doctor/Doctor.php b/src/StaticPHP/Doctor/Doctor.php index 1239a30c8..05f3c4a1d 100644 --- a/src/StaticPHP/Doctor/Doctor.php +++ b/src/StaticPHP/Doctor/Doctor.php @@ -147,13 +147,17 @@ private static function getLockPath(): string { if (SystemTarget::getTargetOS() === 'Windows') { $trial_ls = [ - getenv('LOCALAPPDATA') ?: ((getenv('USERPROFILE') ?: 'C:\Users\Default') . '\AppData\Local') . '\.spc-doctor.lock', + getenv('LOCALAPPDATA') ? + (getenv('LOCALAPPDATA') . '\.spc-doctor.lock') : + (((getenv('USERPROFILE') ?: 'C:\Users\Default') . '\AppData\Local') . '\.spc-doctor.lock'), sys_get_temp_dir() . '\.spc-doctor.lock', WORKING_DIR . '\.spc-doctor.lock', ]; } else { $trial_ls = [ - getenv('XDG_CACHE_HOME') ?: ((getenv('HOME') ?: '/tmp') . '/.cache') . '/.spc-doctor.lock', + getenv('XDG_CACHE_HOME') ? + (getenv('XDG_CACHE_HOME') . '/.spc-doctor.lock') + : (((getenv('HOME') ?: '/tmp') . '/.cache') . '/.spc-doctor.lock'), sys_get_temp_dir() . '/.spc-doctor.lock', WORKING_DIR . '/.spc-doctor.lock', ]; diff --git a/src/StaticPHP/Package/LibraryPackage.php b/src/StaticPHP/Package/LibraryPackage.php index aa24f057c..769612b9f 100644 --- a/src/StaticPHP/Package/LibraryPackage.php +++ b/src/StaticPHP/Package/LibraryPackage.php @@ -44,18 +44,20 @@ public function isInstalled(): bool return false; } } - foreach (PackageConfig::get($this->getName(), 'pkg-configs', []) as $pc) { - if (!str_ends_with($pc, '.pc')) { - $pc .= '.pc'; - } - if (!file_exists("{$this->getLibDir()}/pkgconfig/{$pc}")) { - return false; + if (SystemTarget::getTargetOS() !== 'Windows') { + foreach (PackageConfig::get($this->getName(), 'pkg-configs', []) as $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) { - $path = FileSystem::isRelativePath($bin) ? "{$this->getBinDir()}/{$bin}" : $bin; - if (!file_exists($path)) { - return false; + foreach (PackageConfig::get($this->getName(), 'static-bins', []) as $bin) { + $path = FileSystem::isRelativePath($bin) ? "{$this->getBinDir()}/{$bin}" : $bin; + if (!file_exists($path)) { + return false; + } } } return true; diff --git a/src/StaticPHP/Package/PackageInstaller.php b/src/StaticPHP/Package/PackageInstaller.php index 417c4e1b6..16e8f45a9 100644 --- a/src/StaticPHP/Package/PackageInstaller.php +++ b/src/StaticPHP/Package/PackageInstaller.php @@ -168,10 +168,23 @@ public function run(bool $disable_delay_msg = false): void // check download if ($this->download) { $downloaderOptions = DownloaderOptions::extractFromConsoleOptions($this->options, 'dl'); - $downloader = new ArtifactDownloader( - [...$downloaderOptions, 'source-only' => implode(',', array_map(fn ($x) => $x->getName(), $this->build_packages))], - $this->interactive + // Collect packages that have no build stage for current OS but do have a platform binary. + // These must always download binary (not source), regardless of global prefer-source setting. + $binary_only_packages = array_filter( + $this->packages, + fn ($p) => $p instanceof LibraryPackage + && !$this->isBuildPackage($p) + && !$p->hasStage('build') + && ($p->getArtifact()?->hasPlatformBinary() ?? false) ); + $dl_opts = [ + ...$downloaderOptions, + 'source-only' => implode(',', array_map(fn ($x) => $x->getName(), $this->build_packages)), + ]; + if ($binary_only_packages !== []) { + $dl_opts['binary-only'] = implode(',', array_map(fn ($x) => $x->getName(), $binary_only_packages)); + } + $downloader = new ArtifactDownloader($dl_opts, $this->interactive); $downloader->addArtifacts($this->getArtifacts())->download(); } else { logger()->notice('Skipping download (--no-download option enabled)'); @@ -310,6 +323,11 @@ public function isPackageInstalled(Package|string $package_name): bool $artifact = $package->getArtifact(); return $artifact->isBinaryExtracted(); } + // Fallback: if the download cache is missing (e.g. download failed or cache was cleared), + // still check whether the files are physically present in buildroot. + if ($package instanceof LibraryPackage) { + return $package->isInstalled(); + } return false; } @@ -716,10 +734,13 @@ private function validatePackagesBeforeBuild(): void } $is_to_build = $this->isBuildPackage($package); $has_build_stage = $package instanceof LibraryPackage && $package->hasStage('build'); - $should_use_binary = $package instanceof LibraryPackage && ($package->getArtifact()?->shouldUseBinary() ?? false); + // Use hasPlatformBinary() here (not shouldUseBinary()) because this runs before download, + // so the binary is not yet on disk. We only need to know if a binary is declared for + // the current platform in the artifact config. + $has_platform_binary = $package instanceof LibraryPackage && ($package->getArtifact()?->hasPlatformBinary() ?? false); // Check if package can neither be built nor installed - if (!$is_to_build && !$should_use_binary && !$has_build_stage) { + if (!$is_to_build && !$has_platform_binary && !$has_build_stage) { throw new WrongUsageException("Package '{$package->getName()}' cannot be installed: no build stage defined and no binary artifact available for current OS: " . SystemTarget::getCurrentPlatformString()); } } diff --git a/src/StaticPHP/Runtime/Executor/WindowsCMakeExecutor.php b/src/StaticPHP/Runtime/Executor/WindowsCMakeExecutor.php index 9e0978196..1f057f126 100644 --- a/src/StaticPHP/Runtime/Executor/WindowsCMakeExecutor.php +++ b/src/StaticPHP/Runtime/Executor/WindowsCMakeExecutor.php @@ -176,6 +176,12 @@ public function getConfigureArgsString(): string return implode(' ', array_merge($this->configure_args, $this->getDefaultCMakeArgs())); } + public function setWorkingDir(string $dir): static + { + $this->cmd = $this->cmd->cd($dir); + return $this; + } + /** * Returns the default CMake args. */ @@ -207,12 +213,12 @@ private function makeCmakeToolchainFile(): string private function initBuildDir(): void { if ($this->build_dir === null) { - $this->build_dir = "{$this->package->getSourceDir()}\\build"; + $this->build_dir = "{$this->package->getSourceRoot()}\\build"; } } private function initCmd(): void { - $this->cmd = cmd()->cd($this->package->getSourceDir()); + $this->cmd = cmd()->cd($this->package->getSourceRoot()); } } diff --git a/src/StaticPHP/Runtime/Shell/DefaultShell.php b/src/StaticPHP/Runtime/Shell/DefaultShell.php index 66dfb7ab0..272011e49 100644 --- a/src/StaticPHP/Runtime/Shell/DefaultShell.php +++ b/src/StaticPHP/Runtime/Shell/DefaultShell.php @@ -6,6 +6,7 @@ use StaticPHP\Exception\InterruptException; use StaticPHP\Exception\SPCInternalException; +use StaticPHP\Runtime\SystemTarget; use StaticPHP\Util\FileSystem; /** @@ -132,7 +133,8 @@ public function executeTarExtract(string $archive_path, string $target_path, str }; $mute = $this->console_putput ? '' : ' 2>/dev/null'; - $cmd = "tar {$compression_flag}xf {$archive_arg} --strip-components {$strip} -C {$target_arg}{$mute}"; + $tar = SystemTarget::isUnix() ? 'tar' : '"C:\\Windows\\system32\\tar.exe"'; + $cmd = "{$tar} {$compression_flag}xf {$archive_arg} --strip-components {$strip} -C {$target_arg}{$mute}"; $this->logCommandInfo($cmd); logger()->debug("[TAR EXTRACT] {$cmd}"); @@ -185,9 +187,11 @@ public function execute7zExtract(string $archive_path, string $target_path): boo }; $extname = FileSystem::extname($archive_path); + $tar = SystemTarget::isUnix() ? 'tar' : '"C:\\Windows\\system32\\tar.exe"'; + match ($extname) { 'tar' => $this->executeTarExtract($archive_path, $target_path, 'none'), - 'gz', 'tgz', 'xz', 'txz', 'bz2' => $run("{$_7z} x -so {$archive_arg} | tar -f - -x -C {$target_arg} --strip-components 1"), + 'gz', 'tgz', 'xz', 'txz', 'bz2' => $run("{$_7z} x -so {$archive_arg} | {$tar} -f - -x -C {$target_arg} --strip-components 1"), default => $run("{$_7z} x {$archive_arg} -o{$target_arg} -y{$mute}"), }; diff --git a/src/StaticPHP/Util/FileSystem.php b/src/StaticPHP/Util/FileSystem.php index 3015b4891..38a614e01 100644 --- a/src/StaticPHP/Util/FileSystem.php +++ b/src/StaticPHP/Util/FileSystem.php @@ -142,6 +142,9 @@ public static function copy(string $from, string $to): bool logger()->debug("Copying file from {$from} to {$to}"); $dst_path = FileSystem::convertPath($to); $src_path = FileSystem::convertPath($from); + if ($src_path === $dst_path) { + return true; + } if (!copy($src_path, $dst_path)) { throw new FileSystemException('Cannot copy file from ' . $src_path . ' to ' . $dst_path); } @@ -402,6 +405,7 @@ public static function isRelativePath(string $path): bool public static function replacePathVariable(string $path): string { $replacement = [ + '{build_root_path}' => BUILD_ROOT_PATH, '{pkg_root_path}' => PKG_ROOT_PATH, '{php_sdk_path}' => getenv('PHP_SDK_PATH') ? getenv('PHP_SDK_PATH') : WORKING_DIR . '/php-sdk-binary-tools', '{working_dir}' => WORKING_DIR, diff --git a/src/StaticPHP/Util/System/WindowsUtil.php b/src/StaticPHP/Util/System/WindowsUtil.php index a6df41564..b6d943be4 100644 --- a/src/StaticPHP/Util/System/WindowsUtil.php +++ b/src/StaticPHP/Util/System/WindowsUtil.php @@ -4,12 +4,15 @@ namespace StaticPHP\Util\System; +use StaticPHP\Exception\EnvironmentException; use StaticPHP\Util\FileSystem; class WindowsUtil { + private static array|false|null $vsCache = null; + /** - * Find windows program using executable name. + * Find Windows program using executable name. * * @param string $name command name (xxx.exe) * @param array $paths search path (default use env path) @@ -39,8 +42,16 @@ public static function findCommand(string $name, array $paths = []): ?string */ public static function findVisualStudio(): array|false { + if (self::$vsCache !== null) { + return self::$vsCache; + } + // call vswhere (need VS and C++ tools installed), output is json $vswhere_exec = PKG_ROOT_PATH . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'vswhere.exe'; + // detect vswhere exists, if not throw error + if (!file_exists($vswhere_exec)) { + throw new EnvironmentException('vswhere.exe not found, please run `doctor` command first'); + } $args = [ '-latest', '-format', 'json', @@ -49,13 +60,13 @@ public static function findVisualStudio(): array|false $cmd = escapeshellarg($vswhere_exec) . ' ' . implode(' ', $args); $result = f_exec($cmd, $out, $code); if ($code !== 0 || !$result) { - return false; + return self::$vsCache = false; } $json = json_decode(implode("\n", $out), true); if (!is_array($json) || count($json) === 0) { - return false; + return self::$vsCache = false; } - return [ + return self::$vsCache = [ 'version' => $json[0]['installationVersion'], 'major_version' => explode('.', $json[0]['installationVersion'])[0], 'dir' => $json[0]['installationPath'], @@ -89,6 +100,7 @@ public static function makeCmakeToolchainFile(?string $cflags = null, ?string $l $ldflags = '/nodefaultlib:msvcrt /nodefaultlib:msvcrtd /defaultlib:libcmt'; } $buildroot = str_replace('\\', '\\\\', BUILD_ROOT_PATH); + $source = str_replace('\\', '/', SOURCE_PATH); $toolchain = <<. +Copyright © 2012-2015 Dan Nicholson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + +As a special exception to the GNU General Public License, if you +distribute this file as part of a program that contains a +configuration script generated by Autoconf, you may include it under +the same distribution terms that you use for the rest of that +program. + + +(The condition for the exception is fulfilled because +ICU4C includes a configuration script generated by Autoconf, +namely the `configure` script.) + +---------------------------------------------------------------------- + +File: config.guess (only for ICU4C) + + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . + +As a special exception to the GNU General Public License, if you +distribute this file as part of a program that contains a +configuration script generated by Autoconf, you may include it under +the same distribution terms that you use for the rest of that +program. This Exception is an additional permission under section 7 +of the GNU General Public License, version 3 ("GPLv3"). + + +(The condition for the exception is fulfilled because +ICU4C includes a configuration script generated by Autoconf, +namely the `configure` script.) + +---------------------------------------------------------------------- + +File: install-sh (only for ICU4C) + + +Copyright 1991 by the Massachusetts Institute of Technology + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the name of M.I.T. not be used in advertising or +publicity pertaining to distribution of the software without specific, +written prior permission. M.I.T. makes no representations about the +suitability of this software for any purpose. It is provided "as is" +without express or implied warranty. + +---------------------------------------------------------------------- + +File: sorttable.js (only for ICU4J) + +The MIT Licence, for code from kryogenix.org + +Code downloaded from the Browser Experiments section of kryogenix.org is +licenced under the so-called MIT licence. The licence is below. + +Copyright (c) 1997-date Stuart Langridge + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/globals/licenses/postgresql.txt b/src/globals/licenses/postgresql.txt new file mode 100644 index 000000000..2f33cebbe --- /dev/null +++ b/src/globals/licenses/postgresql.txt @@ -0,0 +1,23 @@ +PostgreSQL Database Management System +(also known as Postgres, formerly known as Postgres95) + +Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/src/globals/patch/php-src-patches/cli_checks_81.patch b/src/globals/patch/php-src-patches/cli_checks_81.patch index 92d6cce5a..39ed5828b 100644 --- a/src/globals/patch/php-src-patches/cli_checks_81.patch +++ b/src/globals/patch/php-src-patches/cli_checks_81.patch @@ -20,7 +20,7 @@ index 8f05686367..c155028233 100644 REGISTER_INI_ENTRIES(); - FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0; -+ FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0 || strcmp(sapi_module.name, "micro") == 1; ++ FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0 || strcmp(sapi_module.name, "micro") == 0; zend_ffi_exception_ce = register_class_FFI_Exception(zend_ce_error); @@ -103,7 +103,7 @@ index 4287045511..eab0311d07 100644 return NULL; } - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_in = 0; fd = STDIN_FILENO; if (cli_in) { @@ -112,7 +112,7 @@ index 4287045511..eab0311d07 100644 #endif } else if (!strcasecmp(path, "stdout")) { - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_out = 0; fd = STDOUT_FILENO; if (cli_out++) { @@ -121,7 +121,7 @@ index 4287045511..eab0311d07 100644 #endif } else if (!strcasecmp(path, "stderr")) { - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_err = 0; fd = STDERR_FILENO; if (cli_err++) { @@ -130,7 +130,7 @@ index 4287045511..eab0311d07 100644 int dtablesize; - if (strcmp(sapi_module.name, "cli")) { -+ if (strcmp(sapi_module.name, "cli") || strcmp(sapi_module.name, "micro")) { ++ if (strcmp(sapi_module.name, "cli") && strcmp(sapi_module.name, "micro")) { if (options & REPORT_ERRORS) { php_error_docref(NULL, E_WARNING, "Direct access to file descriptors is only available from command-line PHP"); } diff --git a/src/globals/patch/php-src-patches/cli_checks_83.patch b/src/globals/patch/php-src-patches/cli_checks_83.patch index e94250958..db02843b4 100644 --- a/src/globals/patch/php-src-patches/cli_checks_83.patch +++ b/src/globals/patch/php-src-patches/cli_checks_83.patch @@ -20,7 +20,7 @@ index bbfe07576e..398373d577 100644 REGISTER_INI_ENTRIES(); - FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0; -+ FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0 || strcmp(sapi_module.name, "micro") == 1; ++ FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0 || strcmp(sapi_module.name, "micro") == 0; zend_ffi_exception_ce = register_class_FFI_Exception(zend_ce_error); @@ -112,7 +112,7 @@ index 8926485025..6740163bc5 100644 return NULL; } - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_in = 0; fd = STDIN_FILENO; if (cli_in) { @@ -121,7 +121,7 @@ index 8926485025..6740163bc5 100644 #endif } else if (!strcasecmp(path, "stdout")) { - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_out = 0; fd = STDOUT_FILENO; if (cli_out++) { @@ -130,7 +130,7 @@ index 8926485025..6740163bc5 100644 #endif } else if (!strcasecmp(path, "stderr")) { - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_err = 0; fd = STDERR_FILENO; if (cli_err++) { @@ -139,7 +139,7 @@ index 8926485025..6740163bc5 100644 int dtablesize; - if (strcmp(sapi_module.name, "cli")) { -+ if (strcmp(sapi_module.name, "cli") || strcmp(sapi_module.name, "micro")) { ++ if (strcmp(sapi_module.name, "cli") && strcmp(sapi_module.name, "micro")) { if (options & REPORT_ERRORS) { php_error_docref(NULL, E_WARNING, "Direct access to file descriptors is only available from command-line PHP"); } diff --git a/src/globals/patch/php-src-patches/cli_checks_84.patch b/src/globals/patch/php-src-patches/cli_checks_84.patch index 6b8ac74e1..b137c6ef4 100644 --- a/src/globals/patch/php-src-patches/cli_checks_84.patch +++ b/src/globals/patch/php-src-patches/cli_checks_84.patch @@ -20,7 +20,7 @@ index d797f5f93f..27cb05e3e4 100644 REGISTER_INI_ENTRIES(); - FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0; -+ FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0 || strcmp(sapi_module.name, "micro") == 1; ++ FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0 || strcmp(sapi_module.name, "micro") == 0; zend_ffi_exception_ce = register_class_FFI_Exception(zend_ce_error); @@ -111,7 +111,7 @@ index a5581d9ccc..98455f7b52 100644 return NULL; } - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_in = 0; fd = STDIN_FILENO; if (cli_in) { @@ -120,7 +120,7 @@ index a5581d9ccc..98455f7b52 100644 #endif } else if (!strcasecmp(path, "stdout")) { - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_out = 0; fd = STDOUT_FILENO; if (cli_out++) { @@ -129,7 +129,7 @@ index a5581d9ccc..98455f7b52 100644 #endif } else if (!strcasecmp(path, "stderr")) { - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_err = 0; fd = STDERR_FILENO; if (cli_err++) { @@ -138,7 +138,7 @@ index a5581d9ccc..98455f7b52 100644 int dtablesize; - if (strcmp(sapi_module.name, "cli")) { -+ if (strcmp(sapi_module.name, "cli") || strcmp(sapi_module.name, "micro")) { ++ if (strcmp(sapi_module.name, "cli") && strcmp(sapi_module.name, "micro")) { if (options & REPORT_ERRORS) { php_error_docref(NULL, E_WARNING, "Direct access to file descriptors is only available from command-line PHP"); } diff --git a/src/globals/patch/php-src-patches/cli_checks_85.patch b/src/globals/patch/php-src-patches/cli_checks_85.patch index cfd72550c..b8cf0fa51 100644 --- a/src/globals/patch/php-src-patches/cli_checks_85.patch +++ b/src/globals/patch/php-src-patches/cli_checks_85.patch @@ -20,7 +20,7 @@ index 10fc11f5..eb4d4175 100644 REGISTER_INI_ENTRIES(); - FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0; -+ FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0 || strcmp(sapi_module.name, "micro") == 1; ++ FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0 || strcmp(sapi_module.name, "micro") == 0; zend_ffi_exception_ce = register_class_FFI_Exception(zend_ce_error); @@ -98,7 +98,7 @@ index ea33ba49..083184b8 100644 return NULL; } - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_in = 0; fd = STDIN_FILENO; if (cli_in) { @@ -107,7 +107,7 @@ index ea33ba49..083184b8 100644 #endif } else if (!strcasecmp(path, "stdout")) { - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_out = 0; fd = STDOUT_FILENO; if (cli_out++) { @@ -116,7 +116,7 @@ index ea33ba49..083184b8 100644 #endif } else if (!strcasecmp(path, "stderr")) { - if (!strcmp(sapi_module.name, "cli")) { -+ if (!strcmp(sapi_module.name, "cli") && !strcmp(sapi_module.name, "micro")) { ++ if (!strcmp(sapi_module.name, "cli") || !strcmp(sapi_module.name, "micro")) { static int cli_err = 0; fd = STDERR_FILENO; if (cli_err++) { @@ -125,7 +125,7 @@ index ea33ba49..083184b8 100644 int dtablesize; - if (strcmp(sapi_module.name, "cli")) { -+ if (strcmp(sapi_module.name, "cli") || strcmp(sapi_module.name, "micro")) { ++ if (strcmp(sapi_module.name, "cli") && strcmp(sapi_module.name, "micro")) { if (options & REPORT_ERRORS) { php_error_docref(NULL, E_WARNING, "Direct access to file descriptors is only available from command-line PHP"); }