mirror of
https://github.com/php/frankenphp.git
synced 2026-03-23 16:42:13 +01:00
Closes #83 #880 #1286. Working patch for Windows support. Supports linking to the [official PHP release (TS version)](https://www.php.net/downloads.php). Includes some work from #1286 (thanks @TenHian!!) This patch allows using Visual Studio to compile the cgo code. To do so, it must be compiled with Go 1.26 (RC) with the following setup: ```powershell winget install -e --id Microsoft.VisualStudio.2022.Community --override "--passive --wait --add Microsoft.VisualStudio.Workload.NativeDesktop --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --includeRecommended" winget install -e --id GoLang.Go $env:PATH += ';C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\bin' cd c:\ gh repo clone microsoft/vcpkg .\vcpkg\bootstrap-vcpkg.bat .\vcpkg\vcpkg install pthreads brotli # build watcher Invoke-WebRequest -Uri "https://github.com/e-dant/watcher/releases/download/0.14.3/x86_64-pc-windows-msvc.tar" -OutFile "$env:TEMP\watcher.tar" tar -xf "$env:TEMP\watcher.tar" -C C:\ Rename-Item -Path "C:\x86_64-pc-windows-msvc" -NewName "watcher-x86_64-pc-windows-msvc" Remove-Item "$env:TEMP\watcher.tar" # download php Invoke-WebRequest -Uri "https://downloads.php.net/~windows/releases/archives/php-8.5.1-Win32-vs17-x64.zip" -OutFile "$env:TEMP\php.zip" Expand-Archive -Path "$env:TEMP\php.zip" -DestinationPath "C:\" Remove-Item "$env:TEMP\php.zip" # download php development package Invoke-WebRequest -Uri "https://downloads.php.net/~windows/releases/archives/php-devel-pack-8.5.1-Win32-vs17-x64.zip" -OutFile "$env:TEMP\php-devel.zip" Expand-Archive -Path "$env:TEMP\php-devel.zip" -DestinationPath "C:\" Remove-Item "$env:TEMP\php-devel.zip" $env:GOTOOLCHAIN = 'go1.26rc1' $env:CC = 'clang' $env:CXX = 'clang++' $env:CGO_CFLAGS = "-I$env:C:\vcpkg\installed\x64-windows\include -IC:\watcher-x86_64-pc-windows-msvc -IC:\php-8.5.1-devel-vs17-x64\include -IC:\php-8.5.1-devel-vs17-x64\include\main -IC:\php-8.5.1-devel-vs17-x64\include\TSRM -IC:\php-8.5.1-devel-vs17-x64\include\Zend -IC:\php-8.5.1-devel-vs17-x64\include\ext" $env:CGO_LDFLAGS = '-LC:\vcpkg\installed\x64-windows\lib -lbrotlienc -LC:\watcher-x86_64-pc-windows-msvc -llibwatcher-c -LC:\php-8.5.1-Win32-vs17-x64 -LC:\php-8.5.1-devel-vs17-x64\lib -lphp8ts -lphp8embed' # clone frankenphp and build git clone -b windows https://github.com/php/frankenphp.git cd frankenphp\caddy\frankenphp go build -ldflags '-extldflags="-fuse-ld=lld"' -tags nowatcher,nobadger,nomysql,nopgx # Tests $env:PATH += ";$env:VCPKG_ROOT\installed\x64-windows\bin;C:\watcher-x86_64-pc-windows-msvc";C:\php-8.5.1-Win32-vs17-x64" "opcache.enable=0`r`nopcache.enable_cli=0" | Out-File -Encoding ascii php.ini $env:PHPRC = Get-Location go test -ldflags '-extldflags="-fuse-ld=lld"' -tags nowatcher,nobadger,nomysql,nopgx . ``` TODO: - [x] Fix remaining skipped tests (scaling and watcher) - [x] Test if the watcher mode works as expected - [x] Automate the build with GitHub Actions --------- Signed-off-by: Marc <m@pyc.ac> Co-authored-by: Kévin Dunglas <kevin@dunglas.dev> Co-authored-by: DubbleClick <m@pyc.ac>
103 lines
2.5 KiB
Go
103 lines
2.5 KiB
Go
//go:build !nomercure
|
|
|
|
package frankenphp
|
|
|
|
// #include <stdint.h>
|
|
// #include "frankenphp.h"
|
|
// #include <php.h>
|
|
import "C"
|
|
import (
|
|
"log/slog"
|
|
"unsafe"
|
|
|
|
"github.com/dunglas/mercure"
|
|
)
|
|
|
|
type mercureContext struct {
|
|
mercureHub *mercure.Hub
|
|
}
|
|
|
|
//export go_mercure_publish
|
|
func go_mercure_publish(threadIndex C.uintptr_t, topics *C.struct__zval_struct, data *C.zend_string, private bool, id, typ *C.zend_string, retry uint64) (generatedID *C.zend_string, error C.short) {
|
|
thread := phpThreads[threadIndex]
|
|
ctx := thread.context()
|
|
fc := thread.frankenPHPContext()
|
|
|
|
if fc.mercureHub == nil {
|
|
if fc.logger.Enabled(ctx, slog.LevelError) {
|
|
fc.logger.LogAttrs(ctx, slog.LevelError, "No Mercure hub configured")
|
|
}
|
|
|
|
return nil, 1
|
|
}
|
|
|
|
u := &mercure.Update{
|
|
Event: mercure.Event{
|
|
Data: GoString(unsafe.Pointer(data)),
|
|
ID: GoString(unsafe.Pointer(id)),
|
|
Retry: retry,
|
|
Type: GoString(unsafe.Pointer(typ)),
|
|
},
|
|
Private: private,
|
|
Debug: fc.logger.Enabled(ctx, slog.LevelDebug),
|
|
}
|
|
|
|
zvalType := C.zval_get_type(topics)
|
|
switch zvalType {
|
|
case C.IS_STRING:
|
|
u.Topics = []string{GoString(unsafe.Pointer(*(**C.zend_string)(unsafe.Pointer(&topics.value[0]))))}
|
|
case C.IS_ARRAY:
|
|
ts, err := GoPackedArray[string](unsafe.Pointer(*(**C.zend_array)(unsafe.Pointer(&topics.value[0]))))
|
|
if err != nil {
|
|
if fc.logger.Enabled(ctx, slog.LevelError) {
|
|
fc.logger.LogAttrs(ctx, slog.LevelError, "invalid topics type", slog.Any("error", err))
|
|
}
|
|
|
|
return nil, 1
|
|
}
|
|
|
|
u.Topics = ts
|
|
default:
|
|
// Never happens as the function is called from C with proper types
|
|
panic("invalid topics type")
|
|
}
|
|
|
|
if err := fc.mercureHub.Publish(ctx, u); err != nil {
|
|
if fc.logger.Enabled(ctx, slog.LevelError) {
|
|
fc.logger.LogAttrs(ctx, slog.LevelError, "Unable to publish Mercure update", slog.Any("error", err))
|
|
}
|
|
|
|
return nil, 2
|
|
}
|
|
|
|
return (*C.zend_string)(PHPString(u.ID, false)), 0
|
|
}
|
|
|
|
func (w *worker) configureMercure(o *workerOpt) {
|
|
if o.mercureHub == nil {
|
|
return
|
|
}
|
|
|
|
w.mercureHub = o.mercureHub
|
|
}
|
|
|
|
// WithMercureHub sets the mercure.Hub to use to publish updates
|
|
func WithMercureHub(hub *mercure.Hub) RequestOption {
|
|
return func(o *frankenPHPContext) error {
|
|
o.mercureHub = hub
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// WithWorkerMercureHub sets the mercure.Hub in the worker script and used to dispatch hot reloading-related mercure.Update.
|
|
func WithWorkerMercureHub(hub *mercure.Hub) WorkerOption {
|
|
return func(w *workerOpt) error {
|
|
w.mercureHub = hub
|
|
|
|
w.requestOptions = append(w.requestOptions, WithMercureHub(hub))
|
|
|
|
return nil
|
|
}
|
|
}
|