ci: cache Windows compiler dependencies #3
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Windows tpc build | |
| on: | |
| push: | |
| pull_request: | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: windows-tpc-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| COMPOSER_NO_INTERACTION: 1 | |
| COMPOSER_PROCESS_TIMEOUT: 0 | |
| jobs: | |
| build-tpc: | |
| name: tpc.exe (PHP ${{ matrix.php }}) | |
| runs-on: windows-2022 | |
| timeout-minutes: 90 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| php: ["8.5"] | |
| steps: | |
| - name: Checkout TypePHP | |
| uses: actions/checkout@v4 | |
| - name: Setup PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: ${{ matrix.php }} | |
| coverage: none | |
| tools: composer:v2 | |
| env: | |
| fail-fast: true | |
| phpts: nts | |
| update: true | |
| - name: Resolve PHP build environment | |
| id: php-build-env | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $phpVersion = php -r 'echo PHP_VERSION;' | |
| $phpExe = (Get-Command php).Source | |
| $phpHome = Split-Path -Parent $phpExe | |
| $archiveName = "php-devel-pack-$phpVersion-nts-Win32-vs17-x64.zip" | |
| $archive = Join-Path $env:RUNNER_TEMP $archiveName | |
| "PHP_VERSION=$phpVersion" | Out-File $env:GITHUB_ENV -Append -Encoding utf8 | |
| "PHP_HOME=$phpHome" | Out-File $env:GITHUB_ENV -Append -Encoding utf8 | |
| "PHPX_HOME=${{ github.workspace }}\vendor\swoole\phpx" | | |
| Out-File $env:GITHUB_ENV -Append -Encoding utf8 | |
| "PHP_DEVEL_ARCHIVE=$archive" | Out-File $env:GITHUB_ENV -Append -Encoding utf8 | |
| "version=$phpVersion" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8 | |
| "archive=$archive" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8 | |
| - name: Cache PHP development package | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ steps.php-build-env.outputs.archive }} | |
| key: windows-2022-php-devel-${{ steps.php-build-env.outputs.version }}-nts-vs17-x64 | |
| - name: Install matching PHP development SDK | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $phpVersion = $env:PHP_VERSION | |
| $phpHome = $env:PHP_HOME | |
| $archive = $env:PHP_DEVEL_ARCHIVE | |
| $archiveName = Split-Path -Leaf $archive | |
| $extractDir = Join-Path $env:RUNNER_TEMP "php-devel-$phpVersion" | |
| if (-not (Test-Path $archive)) { | |
| $downloaded = $false | |
| foreach ($baseUrl in @( | |
| 'https://downloads.php.net/~windows/releases', | |
| 'https://downloads.php.net/~windows/releases/archives' | |
| )) { | |
| try { | |
| Invoke-WebRequest -Uri "$baseUrl/$archiveName" -OutFile $archive | |
| $downloaded = $true | |
| break | |
| } catch { | |
| Remove-Item $archive -Force -ErrorAction SilentlyContinue | |
| } | |
| } | |
| if (-not $downloaded) { | |
| throw "Unable to download the PHP $phpVersion NTS development pack" | |
| } | |
| } | |
| Expand-Archive -Path $archive -DestinationPath $extractDir -Force | |
| $sdkSource = Get-ChildItem $extractDir -Directory | | |
| Where-Object { Test-Path (Join-Path $_.FullName 'include\main\php.h') } | | |
| Select-Object -First 1 | |
| if ($null -eq $sdkSource) { | |
| throw "The PHP development archive has an unexpected layout: $archiveName" | |
| } | |
| $sdk = Join-Path $phpHome 'SDK' | |
| $sdkInclude = Join-Path $sdk 'include' | |
| $sdkLib = Join-Path $sdk 'lib' | |
| New-Item $sdkInclude, $sdkLib -ItemType Directory -Force | Out-Null | |
| Copy-Item (Join-Path $sdkSource.FullName 'include\*') $sdkInclude -Recurse -Force | |
| Copy-Item (Join-Path $sdkSource.FullName 'lib\*') $sdkLib -Force | |
| $embedLibrary = Join-Path $phpHome 'php8embed.lib' | |
| if (-not (Test-Path $embedLibrary)) { | |
| throw "setup-php did not install php8embed.lib in $phpHome" | |
| } | |
| Copy-Item $embedLibrary $sdkLib -Force | |
| # Temporary compatibility fix for PHP packages predating php/php-src#22940. | |
| $hashHeader = Join-Path $sdkInclude 'ext\hash\php_hash.h' | |
| $hashSource = [IO.File]::ReadAllText($hashHeader) | |
| $invalidAllocation = 'char *base = ecalloc(' | |
| if ($hashSource.Contains($invalidAllocation)) { | |
| $hashSource = $hashSource.Replace( | |
| $invalidAllocation, | |
| 'char *base = (char *) ecalloc(' | |
| ) | |
| [IO.File]::WriteAllText( | |
| $hashHeader, | |
| $hashSource, | |
| [Text.UTF8Encoding]::new($false) | |
| ) | |
| } | |
| foreach ($required in @( | |
| (Join-Path $sdkInclude 'main\php.h'), | |
| (Join-Path $sdkLib 'php8.lib'), | |
| (Join-Path $sdkLib 'php8embed.lib'), | |
| (Join-Path $phpHome 'php8.dll') | |
| )) { | |
| if (-not (Test-Path $required)) { | |
| throw "Required PHP SDK file is missing: $required" | |
| } | |
| } | |
| Write-Host "Using PHP $phpVersion from $phpHome" | |
| - name: Install Composer dependencies | |
| run: composer install --prefer-dist --no-progress | |
| - name: Patch PHPX Windows CMake target ordering | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $cmakeFile = Join-Path $env:PHPX_HOME 'CMakeLists.txt' | |
| $source = [IO.File]::ReadAllText($cmakeFile).Replace("`r`n", "`n") | |
| $copyBlockPattern = '(?ms)^ # 复制 DLL 到输出目录\n file\(GLOB MPDEC_DLLS .*?^ endforeach\(\)\n' | |
| $copyBlock = [regex]::Match($source, $copyBlockPattern) | |
| if (-not $copyBlock.Success) { | |
| throw 'Unable to locate the pre-target PHPX mpdecimal copy block' | |
| } | |
| $source = $source.Remove($copyBlock.Index, $copyBlock.Length) | |
| $targetPattern = '(?ms)(add_library\(phpx SHARED \$\{SRC_FILES\}\)\nset_target_properties\(phpx PROPERTIES\n CLEAN_DIRECT_OUTPUT 1\n\)\n)' | |
| $target = [regex]::Match($source, $targetPattern) | |
| if (-not $target.Success) { | |
| throw 'Unable to locate the PHPX target declaration' | |
| } | |
| $copyBlockText = $copyBlock.Value.Replace(' # 复制 DLL 到输出目录', ' # Copy mpdecimal DLLs after the phpx target exists.') | |
| $guardedCopyBlock = "`nif (IS_WINDOWS)`n$copyBlockText" + "endif()`n" | |
| $source = $source.Insert($target.Index + $target.Length, $guardedCopyBlock) | |
| [IO.File]::WriteAllText($cmakeFile, $source, [Text.UTF8Encoding]::new($false)) | |
| $targetOffset = $source.IndexOf('add_library(phpx SHARED') | |
| $copyOffset = $source.IndexOf('add_custom_command(TARGET phpx POST_BUILD') | |
| if ($targetOffset -lt 0 -or $copyOffset -le $targetOffset) { | |
| throw 'PHPX post-build command still precedes its target declaration' | |
| } | |
| - name: Configure MSVC | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| with: | |
| arch: x64 | |
| - name: Cache GMP and MPFR | |
| id: cache-gmp-mpfr | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ runner.temp }}\typephp-cache\vcpkg-x64-windows | |
| key: windows-2022-msvc-vcpkg-gmp-mpfr-x64-v1 | |
| - name: Install GMP and MPFR | |
| if: steps.cache-gmp-mpfr.outputs.cache-hit != 'true' | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $triplet = 'x64-windows' | |
| $vcpkg = Join-Path $env:VCPKG_INSTALLATION_ROOT 'vcpkg.exe' | |
| & $vcpkg install "gmp:$triplet" "mpfr:$triplet" | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "vcpkg failed with exit code $LASTEXITCODE" | |
| } | |
| $installed = Join-Path $env:VCPKG_INSTALLATION_ROOT "installed\$triplet" | |
| $cache = Join-Path $env:RUNNER_TEMP 'typephp-cache\vcpkg-x64-windows' | |
| New-Item "$cache\include", "$cache\lib", "$cache\bin" -ItemType Directory -Force | | |
| Out-Null | |
| Copy-Item (Join-Path $installed 'include\*') "$cache\include" -Recurse -Force | |
| foreach ($library in @('gmp.lib', 'gmpxx.lib', 'mpfr.lib')) { | |
| $source = Join-Path $installed "lib\$library" | |
| if (-not (Test-Path $source)) { | |
| throw "vcpkg did not install $library" | |
| } | |
| Copy-Item $source "$cache\lib" -Force | |
| } | |
| Copy-Item (Join-Path $installed 'bin\*.dll') "$cache\bin" -Force | |
| - name: Stage GMP and MPFR | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $cache = Join-Path $env:RUNNER_TEMP 'typephp-cache\vcpkg-x64-windows' | |
| $sdkInclude = Join-Path $env:PHP_HOME 'SDK\include' | |
| $sdkLib = Join-Path $env:PHP_HOME 'SDK\lib' | |
| Copy-Item "$cache\include\*" $sdkInclude -Recurse -Force | |
| foreach ($library in @('gmp.lib', 'gmpxx.lib', 'mpfr.lib')) { | |
| $source = Join-Path $cache "lib\$library" | |
| if (-not (Test-Path $source)) { | |
| throw "The dependency cache does not contain $library" | |
| } | |
| Copy-Item $source $sdkLib -Force | |
| } | |
| Copy-Item "$cache\bin\*.dll" $env:PHP_HOME -Force | |
| - name: Cache mpdecimal | |
| id: cache-mpdecimal | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.PHPX_HOME }}\thirdparty\mpdecimal\vcbuild\dist64 | |
| key: windows-2022-msvc-mpdecimal-x64-${{ hashFiles('vendor/swoole/phpx/thirdparty/mpdecimal/**') }} | |
| - name: Build mpdecimal | |
| if: steps.cache-mpdecimal.outputs.cache-hit != 'true' | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $buildScript = Join-Path $env:PHPX_HOME 'thirdparty\mpdecimal\vcbuild\vcbuild64.bat' | |
| & cmd.exe /d /s /c "`"$buildScript`"" | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "mpdecimal build failed with exit code $LASTEXITCODE" | |
| } | |
| - name: Stage mpdecimal | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $dist = Join-Path $env:PHPX_HOME 'thirdparty\mpdecimal\vcbuild\dist64' | |
| $sdkInclude = Join-Path $env:PHP_HOME 'SDK\include' | |
| $sdkLib = Join-Path $env:PHP_HOME 'SDK\lib' | |
| Copy-Item (Join-Path $dist '*.lib') $sdkLib -Force | |
| Copy-Item (Join-Path $dist '*.dll') $sdkLib -Force | |
| Copy-Item (Join-Path $dist '*.dll') $env:PHP_HOME -Force | |
| Copy-Item (Join-Path $dist 'mpdecimal.h') $sdkInclude -Force | |
| Copy-Item (Join-Path $dist 'decimal.hh') $sdkInclude -Force | |
| - name: Build PHPX | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| $phpxBuild = Join-Path $env:PHPX_HOME 'build' | |
| $sdkLib = Join-Path $env:PHP_HOME 'SDK\lib' | |
| cmake -S $env:PHPX_HOME -B $phpxBuild -G Ninja ` | |
| -D CMAKE_BUILD_TYPE=Release ` | |
| -D BUILD_TESTS=OFF ` | |
| -D BUILD_EXT=OFF ` | |
| -D GITHUB_ACTION=ON ` | |
| -D MPDECIMAL_LIBRARY="$sdkLib\libmpdec-4.0.1.dll.lib" ` | |
| -D MPDECIMALXX_LIBRARY="$sdkLib\libmpdec++-4.0.1.dll.lib" | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "PHPX configuration failed with exit code $LASTEXITCODE" | |
| } | |
| cmake --build $phpxBuild --target phpx --parallel 2 | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "PHPX build failed with exit code $LASTEXITCODE" | |
| } | |
| foreach ($required in @( | |
| (Join-Path $env:PHPX_HOME 'lib\phpx.lib'), | |
| (Join-Path $phpxBuild 'phpx.dll') | |
| )) { | |
| if (-not (Test-Path $required)) { | |
| throw "Required PHPX build output is missing: $required" | |
| } | |
| } | |
| - name: Build tpc.exe | |
| shell: pwsh | |
| run: | | |
| php bin\tpc.php project.yml --job 1 --no-progress | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "TypePHP build failed with exit code $LASTEXITCODE" | |
| } | |
| if (-not (Test-Path 'tpc.exe')) { | |
| throw 'The compiler did not produce tpc.exe' | |
| } | |
| - name: Upload tpc.exe | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: tpc-windows-x64-php-${{ matrix.php }} | |
| if-no-files-found: error | |
| retention-days: 7 | |
| path: tpc.exe |