diff --git a/.github/patches/phpx-windows-mpdecimal-target.patch b/.github/patches/phpx-windows-mpdecimal-target.patch new file mode 100644 index 00000000..853cfe23 --- /dev/null +++ b/.github/patches/phpx-windows-mpdecimal-target.patch @@ -0,0 +1,36 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 897706d..b4d85ec 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -355,14 +355,6 @@ if (IS_WINDOWS) + INTERFACE_INCLUDE_DIRECTORIES "${PHP_SDK_DIR}/include;${MPDECIMAL_DIR}/libmpdec++" + ) + +- # 复制 DLL 到输出目录 +- file(GLOB MPDEC_DLLS "${PHP_LIBRARY_DIR}/libmpdec-4.0.1.dll" "${PHP_LIBRARY_DIR}/libmpdec++-4.0.1.dll") +- foreach(_dll ${MPDEC_DLLS}) +- add_custom_command(TARGET phpx POST_BUILD +- COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_dll}" $ +- COMMENT "Copying ${_dll} to output" +- ) +- endforeach() + else() + # Linux/macOS: 内置编译 mpdecimal + libmpdec++ + message(STATUS "Using bundled mpdecimal with uint128") +@@ -419,6 +411,16 @@ set_target_properties(phpx PROPERTIES + CLEAN_DIRECT_OUTPUT 1 + ) + ++if (IS_WINDOWS) ++ # Register post-build commands only after the phpx target exists. ++ file(GLOB MPDEC_DLLS "${PHP_LIBRARY_DIR}/libmpdec-4.0.1.dll" "${PHP_LIBRARY_DIR}/libmpdec++-4.0.1.dll") ++ foreach(_dll ${MPDEC_DLLS}) ++ add_custom_command(TARGET phpx POST_BUILD ++ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_dll}" $ ++ COMMENT "Copying ${_dll} to output") ++ endforeach() ++endif() ++ + if (IS_WINDOWS) + target_link_libraries(phpx PRIVATE + ${PHP_LIBRARY} diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml new file mode 100644 index 00000000..490306fa --- /dev/null +++ b/.github/workflows/windows-build.yml @@ -0,0 +1,233 @@ +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.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 + tools: composer:v2 + env: + fail-fast: true + phpts: nts + update: true + + - name: Install matching PHP development SDK + 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 + $extractDir = Join-Path $env:RUNNER_TEMP "php-devel-$phpVersion" + $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" + } + } + + "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 + 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: git apply --directory=vendor/swoole/phpx .github/patches/phpx-windows-mpdecimal-target.patch + + - name: Configure MSVC + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Install GMP and MPFR + 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" + $sdkInclude = Join-Path $env:PHP_HOME 'SDK\include' + $sdkLib = Join-Path $env:PHP_HOME 'SDK\lib' + Copy-Item (Join-Path $installed 'include\*') $sdkInclude -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 $sdkLib -Force + } + Copy-Item (Join-Path $installed 'bin\*.dll') $env:PHP_HOME -Force + + - name: Build mpdecimal + 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" + } + + $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 diff --git a/examples/jni/TUTORIAL.md b/examples/jni/TUTORIAL.md index 52dfe38d..e1b36138 100644 --- a/examples/jni/TUTORIAL.md +++ b/examples/jni/TUTORIAL.md @@ -7,7 +7,7 @@ 本文将介绍如何使用`Java`的`JNI`接口,实现在 `PHP` 代码中直接调用 `Java` 类库 —— 创建 `Java` 对象、调用方法、读写字段,就像在 `Java` 代码中操作一样自然。 1. 本实例程序的代码全部由 `DeepSeek-4-Pro` 生成,耗时约为`50分钟` -2. GitHub: +2. GitHub: ## 准备工作