Skip to content

fix(frankenphp): build a working static binary on Windows#1201

Open
m-this wants to merge 2 commits into
crazywhalecc:v3from
m-this:fix/v3-frankenphp-windows-static
Open

fix(frankenphp): build a working static binary on Windows#1201
m-this wants to merge 2 commits into
crazywhalecc:v3from
m-this:fix/v3-frankenphp-windows-static

Conversation

@m-this

@m-this m-this commented Jul 6, 2026

Copy link
Copy Markdown

The frankenphp Windows target did not link. Three fixes:

  • -mthreads: for cgo builds Go passes this MinGW-only flag to the C compiler (golang/go#16932), and Clang >= 20 rejects it for the MSVC target. A small wrapper strips the flag, and only kicks in when the detected Clang refuses it.
  • Missing system libs: secur32 (InitSecurityInterfaceA) and pathcch (PathCchCanonicalizeEx, referenced by php8embed since PHP 8.5) are now linked, for both frankenphp and the embed test.
  • zend_atomic_bool_{load,store}: frankenphp only references these via __imp_, so their objects never got pulled from php8embed.lib. Forced in with /INCLUDE.

Tested on windows-latest with PHP 8.5 (ZTS): the resulting frankenphp.exe runs version/build-info and serves a PHP page via php-server.

Related to #1100.

Workflow used to build and test the binary
name: Check FrankenPHP Windows build

on:
  workflow_dispatch:
    inputs:
      version:
        description: php version
        default: '8.5'
        type: string
      extensions:
        description: extensions to compile (comma separated)
        default: 'bcmath,ctype,curl,dom,filter,fileinfo,iconv,mbstring,opcache,openssl,pdo,pdo_sqlite,phar,session,simplexml,sockets,sqlite3,tokenizer,xml,xmlreader,xmlwriter,zip,zlib'
        type: string
  push:
    paths:
      - src/Package/Target/php/frankenphp.php
      - .github/workflows/frankenphp-windows-check.yml

env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  PHP_VER: ${{ inputs.version || '8.5' }}
  EXTS: ${{ inputs.extensions || 'bcmath,ctype,curl,dom,filter,fileinfo,iconv,mbstring,opcache,openssl,pdo,pdo_sqlite,phar,session,simplexml,sockets,sqlite3,tokenizer,xml,xmlreader,xmlwriter,zip,zlib' }}

jobs:
  build:
    name: frankenphp ${{ inputs.version || '8.5' }} on Windows x86_64
    runs-on: windows-latest
    timeout-minutes: 180
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.4'
      - run: composer update --no-dev --classmap-authoritative
      # FrankenPHP requires Go >= 1.26; make sure the runner's older Go cannot shadow it
      - uses: actions/setup-go@v6
        with:
          go-version: stable
          cache: false
      - run: go version
      - run: ./bin/spc doctor --auto-fix
      - run: ./bin/spc download --with-php="$env:PHP_VER" --for-extensions="$env:EXTS" --for-libs=nghttp2 --ignore-cache-sources=php-src --retry 5
      - name: Build php-embed
        run: ./bin/spc build:php-embed --enable-zts "--with-libs=nghttp2,pthreads4w" "$env:EXTS"
      - name: Inspect php8embed.lib for zend_atomic_bool_store
        run: |
          $lib = Get-ChildItem -Recurse -Filter php8embed.lib | Select-Object -First 1
          Write-Host "lib: $($lib.FullName)"
          $dumpbin = (Get-ChildItem "C:/Program Files/Microsoft Visual Studio/*/*/VC/Tools/MSVC/*/bin/HostX64/x64/dumpbin.exe" | Select-Object -First 1).FullName
          & $dumpbin /SYMBOLS $lib.FullName | Select-String "zend_atomic_bool_store|InitSecurityInterface|PathCchCanonicalize" | Select-Object -First 20
      - name: Build frankenphp
        run: ./bin/spc build:frankenphp --enable-zts --with-libs=nghttp2 "$env:EXTS"
      - name: Test binary
        run: |
          $bin = Get-ChildItem -Recurse -Filter frankenphp.exe | Select-Object -First 1
          & $bin.FullName version
          & $bin.FullName build-info
      - uses: actions/upload-artifact@v7
        if: always()
        with:
          name: frankenphp-windows-x86_64
          path: buildroot/bin/frankenphp.exe
          if-no-files-found: ignore
      - uses: actions/upload-artifact@v7
        if: failure()
        with:
          name: spc-logs
          path: log/

Three issues prevented the frankenphp Windows target from linking:

- Go passes the MinGW-only -mthreads flag to the C compiler for cgo builds
  (golang/go#16932); Clang >= 20 rejects it for the MSVC target. Wrap Clang
  to strip the flag when it is refused.
- secur32 (InitSecurityInterfaceA) and pathcch (PathCchCanonicalizeEx,
  referenced by php8embed since PHP 8.5) were not linked.
- zend_atomic_bool_{load,store} are only referenced via __imp_, so their
  objects were never pulled from php8embed.lib; force them in with /INCLUDE.

The embed smoke test needed pathcch too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants