Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Code change for compile on windows. Needs to modify php-src. #1286

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions docs/compile_win.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Compile From Source on windows
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Compile From Source on windows
# Compile From Source on Windows


Frankenphp could only dynamic compiled on Windows system. It is still in dev. This steps to compile blew.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Frankenphp could only dynamic compiled on Windows system. It is still in dev. This steps to compile blew.
FrankenPHP for Windows is **experimental**.
We strongly recommend using WSL2 instead of a native build.
On Windows, FrankenPHP can only dynamically linked to a patched version of PHP.


## Prepare MSYS2 and FrankenPHP source
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Prepare MSYS2 and FrankenPHP source
## Prepare MSYS2 and FrankenPHP Source


Click [msys2-x86_64-20240507.exe](https://github.com/msys2/msys2-installer/releases/download/2024-05-07/msys2-x86_64-20240507.exe) dowload and install it in `C:\`, then its `C:\msys64`. We use environment 'MSYS2 MINGW64'.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Click [msys2-x86_64-20240507.exe](https://github.com/msys2/msys2-installer/releases/download/2024-05-07/msys2-x86_64-20240507.exe) dowload and install it in `C:\`, then its `C:\msys64`. We use environment 'MSYS2 MINGW64'.
Download [msys2-x86_64-20240507.exe](https://github.com/msys2/msys2-installer/releases/download/2024-05-07/msys2-x86_64-20240507.exe) and install it in `C:\` (`C:\msys64`).
We use environment 'MSYS2 MINGW64'.


### Install basic tools
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Install basic tools
### Install Basic Tools


```bash
# mingw64/msys2 bash
pacman -S git
pacman -S vim
pacman -S make
pacman -S wget
```

### Install gcc

```bash
# mingw64/msys2 bash
# TODO: Check out that why other gcc versions are not able to compile frankenphp
pacman -U https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-gcc-13.2.0-6-any.pkg.tar.zst
```

### Setup go
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Setup go
### Setup Go


```bash
# mingw64/msys2 bash
# TODO: Better install this version
pacman -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-go-1.22.2-1-any.pkg.tar.zst
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use version 1.23 if possible


# set go env
export GO111MODULE='on'
export GOBIN='/home/you-user-name/go/bin'
export GOCACHE='/home/you-user-name/.cache/go-build'
export GOENV='/home/you-user-name/.config/go/env'
export GOROOT="/mingw64/lib/go"
export GOPATH="/home/you-user-name/go"
mkdir ~/go/bin ~/go/pkg ~/go/src
```

### Install brotli
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Install brotli
### Install Brotli

```bash
# mingw64/msys2 bash
pacman -S mingw-w64-x86_64-brotli
```

### Get Frankenphp source
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Get Frankenphp source
### Get FrankenPHP Source


```bash
# mingw64/msys2 bash
cd ~/go/src
git clone https://github.com/dunglas/frankenphp.git
cd frankenphp
git checkout win
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
git checkout win

```

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change


## Compile PHP

FrankenPHP is compatible with PHP 8.2 and superior. In dev stage, php-8.3.0 recommanded.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FrankenPHP is compatible with PHP 8.2 and superior. In dev stage, php-8.3.0 recommanded.
FrankenPHP is compatible with PHP 8.2 and superior.


### Install PHP-SDK

Recommend reference [build php on windows](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2).
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Recommend reference [build php on windows](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2).
Recommend reference [build PHP on Windows](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2).


The first step, you should install visual studio. For php-8.3.0, its visual_studio_2019(vs16). Here are some older [visual studio](https://github.com/user-attachments/files/18225924/visual_studio.zip) releases.
After visual C++ installed(may need reboot), windows terminal will provide a 'Developer PowerShell for VS 2019'. If not have windows terminal, click [windows terminal](https://aka.ms/terminal).

Then download [php-sdk-binary-tools](https://github.com/php/php-sdk-binary-tools/releases). Unzip it, remove and rename the folder under `C:\`, then its `C:\php-sdk`.

### Patch, compile, and copy to target path

Enter 'Developer PowerShell for VS 2019', then:
```
cd C:\php-sdk
.\phpsdk-vs16-x64.bat
phpsdk_buildtree phpdev
# now in C:\php-sdk\phpdev\vs16\x64
git clone -b php-8.3.0 https://github.com/php/php-src.git php-8.3.0
cd php-8.3.0
phpsdk_deps -u -b 8.3
buildconf
# basic configure
configure --with-prefix="C:\php-sdk\phpdev\vs16\x64\php-8.3.0\php" --enable-zts --enable-embed --enable-cli --disable-opcache-jit
COPY C:\msys64\home\TenHian\go\src\frankenphp\patch.php .\
COPY C:\msys64\home\TenHian\go\src\frankenphp\make_dep.bat .\
# modify php-src and Makefile generated by configure
..\..\..\..\bin\php\php.exe patch.php
make
make devel
# modifiy a header file, mv includes and dll in target paths
make_dep.bat
```

## Compile Frankenphp

Back to 'MSYS2 MINGW64'.

```bash
cp /mingw64/lib/libbrotlicommon.a /mingw64/lib/libbrotlidec.a /mingw64/lib/libbrotlienc.a /usr/local/lib
# now you should in ~/go/src/frankenphp
cd caddy/frankenphp
# TODO: compile with watcher
go build -tags nowatcher
# for clean
# go clean && go clean -cache
# for build details
# go build -tags nowatcher -x
```

Now you get frankenphp.exe in `~/go/src/frankenphp/caddy/frankenphp`

## After compile

The frankenphp.exe needs some shared libraries in the same directory to run. Like `libcrypto-3-x64.dll` `libpq.dll` `libssh2.dll` `libssl-3-x64.dll` `libwinpthread-1.dll` `nghttp2.dll` `php_openssl.dll` `php8embed.dll` `php8ts.dll`.
`libwinpthread-1.dll` in `C:\msys64\mingw64\bin`.
`libcrypto-3-x64.dll` `libpq.dll` `libssh2.dll` `libssl-3-x64.dll` `nghttp2.dll` in `C:\php-sdk\phpdev\vs16\x64\deps\bin`.
`php_openssl.dll` `php8embed.dll` `php8ts.dll` in `C:\php-sdk\phpdev\vs16\x64\php-8.3.0\x64\Release_TS`.
You could use `ldd frankenphp.exe` `ldd php8ts.dll` in 'MSYS2 MINGW64', or `dumpbin /dependents frankenphp.exe` `dumpbin /dependents php8ts.dll` in php-sdk console to see libriaries that need by frankenphp.exe.
The .dll files start with 'php_' are php extensions, you can find them in `C:\php-sdk\phpdev\vs16\x64\php-8.3.0\x64\Release_TS`. In order to use the extensions, you need to move them to the same path as frankenphp and edit php.ini in this path.

# Principle

First, the windows cgo support MinGW-w64 compiler suite is more complete. In fact all GNU C compilers are relatively ok, but almost all cgo compilation is based on MinGW-w64.
Second, PHP offical only recommand compile with Visual C++(MSVC).

So the core problem is to make Mingw-w64 compiler set could link with .dll that PHP on Windows. The `patch.php` does those work, see its comments for more details.
19 changes: 18 additions & 1 deletion frankenphp.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
#include <ext/standard/head.h>
#include <inttypes.h>
#include <php.h>
#include <php_config.h>
#ifdef PHP_WIN32
#include <config.w32.h>
#else
#include <php_config.h>
#endif
#include <php_ini.h>
#include <php_main.h>
#include <php_output.h>
Expand Down Expand Up @@ -140,7 +144,16 @@ static void frankenphp_worker_request_shutdown() {
SG(rfc1867_uploaded_files) = NULL;
}

// TODO: Conditional compilation here is to ensure that it will compile under windows.
// I need to see more PHP version to make visibility attributes and linkage
// modifiers clear.
// On PHP-8.3.0 windows, `php_import_environment_variables` could be pointed to
// `void _php_import_environment_variables(zval *array_ptr);`
#ifndef PHP_WIN32
PHPAPI void get_full_env(zval *track_vars_array) {
#else
void get_full_env(zval *track_vars_array) {
#endif
struct go_getfullenv_return full_env = go_getfullenv(thread_index);

for (int i = 0; i < full_env.r1; i++) {
Expand Down Expand Up @@ -807,6 +820,8 @@ static void set_thread_name(char *thread_name) {
pthread_setname_np(thread_name);
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
pthread_set_name_np(pthread_self(), thread_name);
#elif defined(__MINGW64__)
pthread_setname_np(pthread_self(), thread_name);
#endif
}

Expand Down Expand Up @@ -851,6 +866,7 @@ static void *php_thread(void *arg) {
}

static void *php_main(void *arg) {
#ifndef __MINGW64__
/*
* SIGPIPE must be masked in non-Go threads:
* https://pkg.go.dev/os/signal#hdr-Go_programs_that_use_cgo_or_SWIG
Expand All @@ -863,6 +879,7 @@ static void *php_main(void *arg) {
perror("failed to block SIGPIPE");
exit(EXIT_FAILURE);
}
#endif

set_thread_name("php-main");

Expand Down
13 changes: 9 additions & 4 deletions frankenphp.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ package frankenphp
//
// We also set these flags for hardening: https://github.com/docker-library/php/blob/master/8.2/bookworm/zts/Dockerfile#L57-L59

// TODO: Add windows CFLAGS -Wall -Werror

// #cgo darwin pkg-config: libxml-2.0
// #cgo CFLAGS: -Wall -Werror
// #cgo unix CFLAGS: -Wall -Werror
// #cgo CFLAGS: -I/usr/local/include -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib
// #cgo linux CFLAGS: -D_GNU_SOURCE
// #cgo darwin LDFLAGS: -L/opt/homebrew/opt/libiconv/lib -liconv
// #cgo linux LDFLAGS: -lresolv
// #cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lphp -ldl -lm -lutil
// #cgo windows CFLAGS: -D_WINDOWS -DWINDOWS=1 -DZEND_WIN32=1 -DPHP_WIN32=1 -DWIN32 -D_MBCS -D_USE_MATH_DEFINES -DNDebug -DNDEBUG -DZEND_DEBUG=0 -DZTS=1 -DFD_SETSIZE=256
// #cgo windows CFLAGS: -IC:/msys64/usr/local/include -IC:/msys64/usr/local/include/php -IC:/msys64/usr/local/include/php/main -IC:/msys64/usr/local/include/php/TSRM -IC:/msys64/usr/local/include/php/Zend -IC:/msys64/usr/local/include/php/ext -IC:/msys64/usr/local/include/php/ext/date/lib -IC:/msys64/usr/local/include/php/main/win32
// #cgo darwin LDFLAGS: -L/opt/homebrew/opt/libiconv/lib -L/usr/lib -liconv -lphp -ldl -lm -lutil
// #cgo linux LDFLAGS: -L/usr/lib -lresolv -lphp -ldl -lm -lutil
// #cgo windows LDFLAGS: -LC:/msys64/usr/local/lib -lphp8ts -lphp8embed -lbrotlicommon -lbrotlidec -lbrotlienc
// #cgo LDFLAGS: -L/usr/local/lib
// #include <stdlib.h>
// #include <stdint.h>
// #include <php_variables.h>
Expand Down
37 changes: 37 additions & 0 deletions make_dep.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@echo off

REM process php.h
set "php_h_path=.\x64\Release_TS\php-8.3.0-devel-vs16-x64\include\main\php.h"
if exist "%php_h_path%" (
echo Updating pid_t definition in %php_h_path%...
powershell -Command "(Get-Content '%php_h_path%' | ForEach-Object { $_ -replace '^typedef int pid_t;', 'typedef long long pid_t;' }) | Set-Content '%php_h_path%'"
) else (
echo File %php_h_path% does not exist.
)

REM copy include
set "src_include_dir=.\x64\Release_TS\php-8.3.0-devel-vs16-x64\include"
set "dest_include_dir=C:\msys64\usr\local\include\php"

if not exist "%dest_include_dir%" (
echo Creating directory %dest_include_dir%...
mkdir "%dest_include_dir%"
)

echo Copying folders from %src_include_dir% to %dest_include_dir%...
xcopy "%src_include_dir%\*" "%dest_include_dir%\" /E /I /Y

REM copy php8ts.dll php8embed.dll
set "src_php_dll_dir=.\x64\Release_TS"
set "dest_lib_dir=C:\msys64\usr\local\lib"

if not exist "%dest_lib_dir%" (
echo Creating directory %dest_lib_dir%...
mkdir "%dest_lib_dir%"
)

echo Copying php8ts.dll and php8embed.dll to %dest_lib_dir%...
copy "%src_php_dll_dir%\php8ts.dll" "%dest_lib_dir%\" /Y
copy "%src_php_dll_dir%\php8embed.dll" "%dest_lib_dir%\" /Y

echo Done!
59 changes: 59 additions & 0 deletions patch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
/* --------------------------------
This script aim to modify the php-8.3.0 source code to achieve two things:
1. Remove specifics that are supported by msvc but not by mingw-w64-gcc;
2. Modify the Makefile so that could get php8embeded.dll.
--------------------------------*/

$file_path = 'Zend/zend_portability.h';
$content = file_get_contents($file_path);
$content = str_replace('__assume(c)', 'assert(c)', $content);
$content = str_replace('__vectorcall', '__fastcall', $content);
$content = str_replace('__forceinline', 'inline', $content);
file_put_contents($file_path, $content);
echo "process Zend/zend_portability.h done;\n";

$directories = ['ext/hash/murmur', 'ext/hash/xxhash', 'ext/opcache/jit/vtune', 'win32'];
foreach ($directories as $dir) {
$files = scandir($dir);
foreach ($files as $file) {
if (is_file($dir . '/' . $file)) {
$file_path = $dir . '/' . $file;

$content = file_get_contents($file_path);
$new_content = str_replace('__forceinline', 'inline', $content);

if ($content !== $new_content) {
file_put_contents($file_path, $new_content);
echo "\"__forceinline\" in $file_path has been replace by \"inline\"\n";
}
}
}
}
echo "Replace __forceinline in assigned directory done;\n";

$file_path = 'sapi/embed/php_embed.h';
$content = file_get_contents($file_path);
$old_code = '#ifndef PHP_WIN32
#define EMBED_SAPI_API SAPI_API
#else
#define EMBED_SAPI_API
#endif';
$new_code = '#ifndef __MINGW64__
#define EMBED_SAPI_API __declspec(dllexport)
#else
#define EMBED_SAPI_API __declspec(dllimport)
#endif';
$content = str_replace($old_code, $new_code, $content);
file_put_contents($file_path, $content);
echo "Process sapi/embed/php_embed.h done;\n";

$file_path = 'Makefile';
$content = file_get_contents($file_path);
$content = str_replace('php.exe php8embed.lib', 'php.exe php8embed.dll', $content);
$content = str_replace('php8embed.lib: $(BUILD_DIR)\php8embed.lib', 'php8embed.dll: $(BUILD_DIR)\php8embed.dll', $content);
$content = str_replace('$(BUILD_DIR)\php8embed.lib:', '$(BUILD_DIR)\php8embed.dll:', $content);
$content = str_replace('$(MAKE_LIB)', '@"$(LINK)"', $content);
$content = str_replace('/nologo /out:$(BUILD_DIR)\php8embed.lib', '/nologo /DLL /out:$(BUILD_DIR)\php8embed.dll', $content);
file_put_contents($file_path, $content);
echo "Process Makefile done;\n";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
echo "Process Makefile done;\n";
echo "Process Makefile done;\n";

Loading