TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
449 lines
17 KiB
449 lines
17 KiB
name: Windows x64
|
|
|
|
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: Build - PHP ${{ matrix.php }} ZTS
|
|
runs-on: windows-2022
|
|
timeout-minutes: 90
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
php: ["8.4", "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
|
|
extensions: zip
|
|
tools: composer:v2
|
|
env:
|
|
fail-fast: true
|
|
phpts: ts
|
|
update: true
|
|
|
|
- name: Resolve PHP build environment
|
|
id: php-build-env
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$phpVersion = php -r 'echo PHP_VERSION;'
|
|
if (-not $phpVersion.StartsWith('${{ matrix.php }}.')) {
|
|
throw "setup-php installed PHP $phpVersion, expected ${{ matrix.php }}.x"
|
|
}
|
|
$threadSafety = php -r 'echo PHP_ZTS ? "zts" : "nts";'
|
|
if ($threadSafety -ne 'zts') {
|
|
throw "setup-php installed $threadSafety PHP, expected zts"
|
|
}
|
|
$zipAvailable = php -r 'echo class_exists("ZipArchive") ? "yes" : "no";'
|
|
if ($zipAvailable -ne 'yes') {
|
|
throw 'setup-php did not enable the ZipArchive extension required by package.php'
|
|
}
|
|
$phpExe = (Get-Command php).Source
|
|
$phpHome = Split-Path -Parent $phpExe
|
|
$archiveName = "php-devel-pack-$phpVersion-Win32-vs17-x64.zip"
|
|
$archive = Join-Path $env:RUNNER_TEMP $archiveName
|
|
|
|
"PHP_VERSION=$phpVersion" | Out-File $env:GITHUB_ENV -Append -Encoding utf8
|
|
"PHP_THREAD_SAFETY=$threadSafety" | 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
|
|
"thread_safety=$threadSafety" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
|
|
"archive=$archive" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
|
|
|
|
- name: Cache PHP development package
|
|
id: cache-php-devel
|
|
uses: actions/cache/restore@v4
|
|
with:
|
|
path: ${{ steps.php-build-env.outputs.archive }}
|
|
key: windows-2022-php-devel-${{ steps.php-build-env.outputs.version }}-${{ steps.php-build-env.outputs.thread_safety }}-vs17-x64
|
|
|
|
- name: Install matching PHP development SDK
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$phpVersion = $env:PHP_VERSION
|
|
$phpHome = $env:PHP_HOME
|
|
$threadSafety = $env:PHP_THREAD_SAFETY
|
|
$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 ZTS 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
|
|
|
|
$coreLibrary = 'php8ts.lib'
|
|
$runtimeLibrary = 'php8ts.dll'
|
|
|
|
# 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 $coreLibrary),
|
|
(Join-Path $sdkLib 'php8embed.lib'),
|
|
(Join-Path $phpHome $runtimeLibrary)
|
|
)) {
|
|
if (-not (Test-Path $required)) {
|
|
throw "Required PHP SDK file is missing: $required"
|
|
}
|
|
}
|
|
|
|
Write-Host "Using PHP $phpVersion from $phpHome"
|
|
|
|
- name: Save PHP development package
|
|
if: steps.cache-php-devel.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v4
|
|
with:
|
|
path: ${{ steps.php-build-env.outputs.archive }}
|
|
key: ${{ steps.cache-php-devel.outputs.cache-primary-key }}
|
|
|
|
- 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/restore@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: Save GMP and MPFR
|
|
if: steps.cache-gmp-mpfr.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v4
|
|
with:
|
|
path: ${{ runner.temp }}\typephp-cache\vcpkg-x64-windows
|
|
key: ${{ steps.cache-gmp-mpfr.outputs.cache-primary-key }}
|
|
|
|
- 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/restore@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'
|
|
$buildDirectory = Split-Path -Parent $buildScript
|
|
Push-Location $buildDirectory
|
|
try {
|
|
& cmd.exe /d /s /c vcbuild64.bat
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "mpdecimal build failed with exit code $LASTEXITCODE"
|
|
}
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
|
|
- name: Save mpdecimal
|
|
if: steps.cache-mpdecimal.outputs.cache-hit != 'true'
|
|
uses: actions/cache/save@v4
|
|
with:
|
|
path: ${{ env.PHPX_HOME }}\thirdparty\mpdecimal\vcbuild\dist64
|
|
key: ${{ steps.cache-mpdecimal.outputs.cache-primary-key }}
|
|
|
|
- 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: Run Windows smoke tests
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$env:PATH = "$env:PHPX_HOME\build;$env:PATH"
|
|
& .\tpc.exe tests\windows\smoke\project.yml --job 1 --no-progress
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Windows smoke project compilation failed with exit code $LASTEXITCODE"
|
|
}
|
|
|
|
$smokeExe = Join-Path '${{ github.workspace }}' 'tests\windows\smoke\windows_smoke.exe'
|
|
if (-not (Test-Path $smokeExe)) {
|
|
throw "Windows smoke executable was not generated: $smokeExe"
|
|
}
|
|
|
|
$processInfo = [Diagnostics.ProcessStartInfo]::new()
|
|
$processInfo.FileName = $smokeExe
|
|
$processInfo.ArgumentList.Add('zts')
|
|
$processInfo.UseShellExecute = $false
|
|
$processInfo.RedirectStandardOutput = $true
|
|
$processInfo.RedirectStandardError = $true
|
|
|
|
$process = [Diagnostics.Process]::new()
|
|
$process.StartInfo = $processInfo
|
|
if (-not $process.Start()) {
|
|
throw 'Unable to start the Windows smoke executable'
|
|
}
|
|
$stdout = $process.StandardOutput.ReadToEnd()
|
|
$stderr = $process.StandardError.ReadToEnd()
|
|
$process.WaitForExit()
|
|
|
|
Write-Host "Windows smoke stdout: $stdout"
|
|
Write-Host "Windows smoke stderr: $stderr"
|
|
Write-Host "Windows smoke exit code: $($process.ExitCode)"
|
|
if ($process.ExitCode -ne 0) {
|
|
throw "Windows smoke executable failed with exit code $($process.ExitCode)"
|
|
}
|
|
if ($stdout.Trim() -ne 'windows-smoke-ok:zts') {
|
|
throw "Unexpected Windows smoke output: $stdout"
|
|
}
|
|
|
|
- name: Package tested Windows compiler
|
|
if: startsWith(github.ref, 'refs/tags/') && matrix.php == '8.5'
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
composer install --no-dev --prefer-dist --no-progress --classmap-authoritative
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Production Composer install failed with exit code $LASTEXITCODE"
|
|
}
|
|
$env:TYPEPHP_PACKAGE_VERSION = $env:GITHUB_REF_NAME
|
|
php package.php
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Windows packaging failed with exit code $LASTEXITCODE"
|
|
}
|
|
|
|
$packages = @(Get-ChildItem 'tpc_v*_windows_*.zip' -File)
|
|
if ($packages.Count -ne 1) {
|
|
throw "Expected one Windows release package, found $($packages.Count)"
|
|
}
|
|
|
|
- name: Upload Windows release package
|
|
if: startsWith(github.ref, 'refs/tags/') && matrix.php == '8.5'
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: release-windows-x64-php-${{ matrix.php }}-zts
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
path: tpc_v*_windows_*.zip
|
|
|
|
- name: Upload Windows build outputs
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: tpc-windows-x64-php-${{ matrix.php }}-zts
|
|
if-no-files-found: warn
|
|
retention-days: 7
|
|
path: |
|
|
tpc.exe
|
|
tests/windows/smoke/windows_smoke.exe
|
|
tests/windows/smoke/build/**/*.cc
|
|
tests/windows/smoke/build/**/*.h
|
|
tests/windows/smoke/build/**/*.rsp
|
|
|