diff --git a/.github/workflows/precompile-php.yml b/.github/workflows/precompile-php.yml index 54b39814..46e20c90 100644 --- a/.github/workflows/precompile-php.yml +++ b/.github/workflows/precompile-php.yml @@ -2,28 +2,35 @@ name: Precompile PHP on: push: - branches: [main, develop] - paths: - - .github/workflows/precompile-php.yml - - build-configs/** - - scripts/get-php-versions.ts - - scripts/check-php-updates.ts + branches: [main] schedule: # Check for updates daily at 2 AM UTC - cron: '0 2 * * *' workflow_dispatch: inputs: + php_version: + description: PHP version to build (leave empty for auto-detection) + required: false + type: string + php_config: + description: PHP build configuration + required: true + default: laravel-mysql + type: choice + options: + - laravel-mysql + - laravel-postgres + - laravel-sqlite + - api-only + - enterprise + - wordpress + - full-stack force_rebuild: - description: Force rebuild even if no new versions + description: Force rebuild even if no updates required: false default: false type: boolean -env: - REGISTRY_URL: ghcr.io - REGISTRY_USERNAME: ${{ github.actor }} - REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} - jobs: # First job: Check if we need to rebuild based on new PHP versions check-for-updates: @@ -68,7 +75,7 @@ jobs: get-php-versions: needs: check-for-updates runs-on: ubuntu-latest - if: needs.check-for-updates.outputs.rebuild_needed == 'true' || github.event.inputs.force_rebuild == 'true' + if: needs.check-for-updates.outputs.rebuild_needed == 'true' || github.event.inputs.force_rebuild == 'true' || github.event.inputs.php_version != '' outputs: php_versions: ${{ steps.get-versions.outputs.php_versions }} steps: @@ -83,937 +90,640 @@ jobs: - name: Get PHP versions from ts-pkgx id: get-versions run: | - # Get dynamic PHP versions using our custom script - PHP_VERSIONS=$(bun scripts/get-php-versions.ts | grep "JSON output for GitHub Actions:" -A 1 | tail -1) + if [ -n "${{ github.event.inputs.php_version }}" ]; then + # Use specific version if provided + PHP_VERSIONS='["${{ github.event.inputs.php_version }}"]' + else + # Get dynamic PHP versions using our custom script + PHP_VERSIONS=$(bun scripts/get-php-versions.ts | grep "JSON output for GitHub Actions:" -A 1 | tail -1) + fi echo "php_versions=$PHP_VERSIONS" >> $GITHUB_OUTPUT echo "๐Ÿ” Dynamic PHP versions: $PHP_VERSIONS" - # Job to provide feedback when no rebuild is needed - no-rebuild-needed: - needs: check-for-updates - runs-on: ubuntu-latest - if: needs.check-for-updates.outputs.rebuild_needed == 'false' && github.event.inputs.force_rebuild != 'true' - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: No rebuild needed - run: | - echo "โœ… No rebuild needed" - echo "Reason: ${{ needs.check-for-updates.outputs.reason }}" - echo "Current versions: ${{ needs.check-for-updates.outputs.current_versions }}" - echo "Latest versions: ${{ needs.check-for-updates.outputs.latest_versions }}" - echo "" - echo "The workflow will skip building since no new PHP versions are available." - echo "To force a rebuild, use the 'force_rebuild' input parameter." - - # Matrix strategy for building across different platforms and configurations - build-matrix: + build: needs: [check-for-updates, get-php-versions] - runs-on: ${{ matrix.os }} - if: needs.check-for-updates.outputs.rebuild_needed == 'true' || github.event.inputs.force_rebuild == 'true' + if: needs.check-for-updates.outputs.rebuild_needed == 'true' || github.event.inputs.force_rebuild == 'true' || github.event.inputs.php_version != '' strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, macos-13] # Include Intel Mac - php_version: ${{ fromJSON(needs.get-php-versions.outputs.php_versions) }} - config: [laravel-mysql, laravel-postgres, laravel-sqlite, api-only, enterprise, wordpress, full-stack] + php_version: ${{ fromJson(needs.get-php-versions.outputs.php_versions) }} + config: + - laravel-mysql + - laravel-postgres + - laravel-sqlite + - api-only + - enterprise + - wordpress + - full-stack + os: + - ubuntu-latest + - macos-14 + - macos-15 + - macos-15-intel + - windows-latest include: - # Add Windows later if needed - os: ubuntu-latest platform: linux arch: x86_64 - - os: macos-latest + - os: macos-14 + platform: darwin + arch: x86_64 + - os: macos-15 platform: darwin arch: arm64 - - os: macos-13 + - os: macos-15-intel platform: darwin arch: x86_64 - exclude: - # Skip some combinations to reduce build time - - os: macos-13 - config: api-only - # WordPress mainly used on Linux - - os: macos-13 - config: wordpress + - os: windows-latest + platform: win32 + arch: x86_64 + + runs-on: ${{ matrix.os }} steps: - - name: Checkout repository + - name: Checkout code uses: actions/checkout@v4 - - name: Set up build environment - run: | - echo "Building PHP ${{ matrix.php_version }} for ${{ matrix.platform }}-${{ matrix.arch }}" - echo "Configuration: ${{ matrix.config }}" - echo "BINARY_NAME=php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }}" >> $GITHUB_ENV - echo "BUILD_DIR=${{ github.workspace }}/build" >> $GITHUB_ENV - echo "OUTPUT_DIR=${{ github.workspace }}/binaries" >> $GITHUB_ENV - - - name: Install Bun + - name: Setup Bun uses: oven-sh/setup-bun@v2 - - - name: Use cached node_modules - uses: actions/cache@v4 with: - path: node_modules - key: node-modules-${{ hashFiles('**/bun.lock') }} - restore-keys: | - node-modules- - - - name: Install Dependencies - run: bun install + bun-version: latest - - name: Install build dependencies (Ubuntu) + - name: Install build dependencies (Linux) if: matrix.platform == 'linux' run: | - # Install PHP dependencies via apt-get (alternative to launchpad) - echo "๐Ÿ”ง Installing PHP dependencies via apt-get..." - echo "๐Ÿ” Debug info:" - echo " - Platform: linux" - echo " - Architecture: $(uname -m)" - sudo apt-get update sudo apt-get install -y \ - build-essential \ - autoconf \ - automake \ - libtool \ - pkg-config \ - bison \ - re2c \ - libxml2-dev \ - libssl-dev \ - libcurl4-openssl-dev \ - libpng-dev \ - libjpeg-dev \ - libfreetype6-dev \ - libonig-dev \ - libzip-dev \ - libsqlite3-dev \ - libpq-dev \ - libreadline-dev \ - libbz2-dev \ - libgmp-dev \ - libldap2-dev \ - libsasl2-dev \ - libxslt1-dev \ - libicu-dev \ - libsodium-dev \ - zlib1g-dev + build-essential autoconf automake libtool pkg-config bison re2c \ + libxml2-dev libssl-dev libcurl4-openssl-dev libpng-dev libjpeg-dev \ + libfreetype6-dev libonig-dev libzip-dev libpq-dev libreadline-dev \ + libbz2-dev libgmp-dev libldap2-dev libxslt1-dev libicu-dev \ + libsodium-dev zlib1g-dev libsqlite3-dev libenchant-2-dev \ + libtidy-dev libsnmp-dev libgd-dev libwebp-dev libc-client-dev \ + libkrb5-dev libedit-dev libargon2-dev libffi-dev \ + libmcrypt-dev libmhash-dev libpcre3-dev libexpat1-dev \ + libc-ares-dev libnghttp2-dev libpsl-dev libidn2-dev \ + librtmp-dev libssh2-1-dev libgssapi-krb5-2 libkrb5-dev \ + gettext libgettext-ocaml-dev - name: Install build dependencies (macOS) if: matrix.platform == 'darwin' run: | - # Install PHP dependencies via Homebrew (alternative to launchpad) - echo "๐Ÿ”ง Installing PHP dependencies via Homebrew..." - echo "๐Ÿ” Debug info:" - echo " - Platform: darwin" - echo " - Architecture: $(uname -m)" - - # Install dependencies with quiet output to reduce warnings - brew install --quiet \ - autoconf \ - automake \ - libtool \ - pkg-config \ - bison \ - re2c \ - libxml2 \ - openssl@3 \ - curl \ - libpng \ - jpeg \ - freetype \ - oniguruma \ - libzip \ - postgresql@17 \ - libpq \ - readline \ - bzip2 \ - gmp \ - openldap \ - libxslt \ - icu4c \ - libsodium \ - zlib \ - libiconv \ - gettext - - # Verify readline installation - echo "Checking readline installation:" - ls -la $(brew --prefix readline)/include/readline/readline.h || echo "readline.h not found in expected location" - ls -la $(brew --prefix readline)/lib/libreadline.* || echo "libreadline not found in expected location" - - # Verify PostgreSQL installation - echo "Checking PostgreSQL installation:" - ls -la $(brew --prefix libpq)/include/libpq-fe.h || echo "libpq-fe.h not found in expected location (libpq)" - ls -la $(brew --prefix libpq)/lib/libpq.* || echo "libpq not found in expected location (libpq)" - which pg_config || echo "pg_config not found in PATH" - - # Verify bzip2 installation - echo "Checking bzip2 installation:" - ls -la $(brew --prefix bzip2)/include/bzlib.h || echo "bzlib.h not found in expected location" - ls -la $(brew --prefix bzip2)/lib/libbz2.* || echo "libbz2 not found in expected location" - - # Verify gettext installation - echo "Checking gettext installation:" - ls -la $(brew --prefix gettext)/include/libintl.h || echo "libintl.h not found in expected location" - ls -la $(brew --prefix gettext)/lib/libintl.* || echo "libintl not found in expected location" - - # Verify OpenLDAP installation - echo "Checking OpenLDAP installation:" - ls -la $(brew --prefix openldap)/include/ldap.h || echo "ldap.h not found in expected location" - ls -la $(brew --prefix openldap)/lib/libldap.* || echo "libldap not found in expected location" - ls -la $(brew --prefix openldap)/lib/liblber.* || echo "liblber not found in expected location" - echo "OpenLDAP include directory contents:" - ls -la $(brew --prefix openldap)/include/ | head -10 - echo "OpenLDAP lib directory contents:" - ls -la $(brew --prefix openldap)/lib/ | head -10 - - # Create symlinks to help PHP find readline, bzip2, gettext, and openldap - echo "Creating symlinks for readline, bzip2, gettext, and openldap:" - sudo mkdir -p /usr/local/include/readline /usr/local/lib - sudo ln -sf $(brew --prefix readline)/include/readline/readline.h /usr/local/include/readline/readline.h - sudo ln -sf $(brew --prefix readline)/include/readline/history.h /usr/local/include/readline/history.h - sudo ln -sf $(brew --prefix readline)/lib/libreadline.* /usr/local/lib/ - sudo ln -sf $(brew --prefix bzip2)/include/bzlib.h /usr/local/include/bzlib.h - sudo ln -sf $(brew --prefix bzip2)/lib/libbz2.* /usr/local/lib/ - sudo ln -sf $(brew --prefix gettext)/include/libintl.h /usr/local/include/libintl.h - sudo ln -sf $(brew --prefix gettext)/lib/libintl.* /usr/local/lib/ - sudo ln -sf $(brew --prefix openldap)/include/ldap.h /usr/local/include/ldap.h - sudo ln -sf $(brew --prefix openldap)/lib/libldap.* /usr/local/lib/ - sudo ln -sf $(brew --prefix openldap)/lib/liblber.* /usr/local/lib/ - - - name: Create build configuration - run: | - mkdir -p ${{ env.BUILD_DIR }} ${{ env.OUTPUT_DIR }} - - # Determine libpq prefix only on macOS (avoid brew on Linux) - PG_PREFIX="" - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - PG_PREFIX="$(brew --prefix libpq)" + # macOS: Let Launchpad handle all dependencies + echo "๐Ÿ“ฆ macOS build will use Launchpad for all dependencies" + echo "๐Ÿš€ Installing PHP dependencies via Launchpad first..." + + # Pre-install dependencies to ensure they're available + echo "๐Ÿ”ง Pre-installing dependencies via Launchpad..." + bun run launchpad install php --deps-only + + # Wait for dependencies to be fully installed + echo "โณ Waiting for dependency installation to complete..." + sleep 10 + + # Debug: Check what was actually installed + echo "๐Ÿ” Checking installed dependencies..." + echo "๐Ÿ“ .local directory structure (first level):" + find "$HOME/.local" -maxdepth 2 -type d | sort | head -20 + + echo "๐Ÿ” Looking for pkg-config specifically..." + find "$HOME/.local" -name "*pkg*" -type f 2>/dev/null | head -10 || echo "No pkg-related files found" + + echo "๐Ÿ” Looking for freedesktop.org directory..." + find "$HOME/.local" -path "*freedesktop*" -type d 2>/dev/null | head -5 || echo "No freedesktop.org directories found" + + # Debug: Check if pkg-config is available + echo "๐Ÿ” Checking for pkg-config..." + if command -v pkg-config >/dev/null 2>&1; then + echo "โœ… pkg-config found: $(which pkg-config)" + echo "๐Ÿ“‹ pkg-config version: $(pkg-config --version)" + else + echo "โŒ pkg-config not found in PATH" + echo "๐Ÿ” Searching for pkg-config in .local..." + find "$HOME/.local" -name "pkg-config" -type f 2>/dev/null || echo "No pkg-config found in .local" fi - # Create configuration based on matrix config - case "${{ matrix.config }}" in - "laravel-mysql") - # For PHP 8.1, disable intl extension to avoid ICU4C C++17 issues - if [[ "${{ matrix.php_version }}" == 8.1* ]]; then - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-exif --enable-bcmath --with-pdo-mysql --with-mysqli --with-curl --with-openssl --enable-gd --with-zip --with-readline --with-libxml --with-zlib" - else - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-intl --enable-exif --enable-bcmath --with-pdo-mysql --with-mysqli --with-curl --with-openssl --enable-gd --with-zip --with-readline --with-libxml --with-zlib" - fi - ;; - "laravel-postgres") - # For PHP 8.1, disable intl extension to avoid ICU4C C++17 issues - if [[ "${{ matrix.php_version }}" == 8.1* ]]; then - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-exif --enable-bcmath --with-pdo-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-curl --with-openssl --enable-gd --with-zip --with-readline --with-libxml --with-zlib" - else - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-intl --enable-exif --enable-bcmath --with-pdo-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-curl --with-openssl --enable-gd --with-zip --with-readline --with-libxml --with-zlib" - fi - ;; - "laravel-sqlite") - # For PHP 8.1, disable intl extension to avoid ICU4C C++17 issues - if [[ "${{ matrix.php_version }}" == 8.1* ]]; then - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-exif --enable-bcmath --with-pdo-sqlite --with-sqlite3 --with-curl --with-openssl --enable-gd --with-zip --with-readline --with-libxml --with-zlib" - else - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-intl --enable-exif --enable-bcmath --with-pdo-sqlite --with-sqlite3 --with-curl --with-openssl --enable-gd --with-zip --with-readline --with-libxml --with-zlib" - fi - ;; - "api-only") - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-bcmath --with-pdo-mysql --with-mysqli --with-curl --with-openssl --with-zip --with-libxml --with-zlib" - ;; - "enterprise") - # For PHP 8.1, disable intl extension to avoid ICU4C C++17 issues - if [[ "${{ matrix.php_version }}" == 8.1* ]]; then - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-exif --enable-bcmath --with-pdo-mysql --with-pdo-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-pdo-sqlite --with-mysqli --with-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-sqlite3 --with-curl --with-openssl --enable-gd --enable-soap --enable-sockets --with-zip --with-bz2 --with-readline --with-libxml --with-zlib --enable-pcntl --enable-posix --with-gettext --with-gmp --with-ldap --with-xsl --with-sodium" - else - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-intl --enable-exif --enable-bcmath --with-pdo-mysql --with-pdo-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-pdo-sqlite --with-mysqli --with-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-sqlite3 --with-curl --with-openssl --enable-gd --enable-soap --enable-sockets --with-zip --with-bz2 --with-readline --with-libxml --with-zlib --enable-pcntl --enable-posix --with-gettext --with-gmp --with-ldap --with-xsl --with-sodium" - fi - ;; - "wordpress") - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-exif --with-pdo-mysql --with-mysqli --with-curl --with-openssl --enable-gd --with-zip --with-libxml --with-zlib" - ;; - "full-stack") - # Comprehensive configuration with all major database drivers and extensions for local testing - # For PHP 8.1, disable intl extension to avoid ICU4C C++17 issues - if [[ "${{ matrix.php_version }}" == 8.1* ]]; then - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-exif --enable-bcmath --enable-calendar --enable-ftp --enable-sysvmsg --enable-sysvsem --enable-sysvshm --enable-wddx --with-pdo-mysql --with-pdo-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-pdo-sqlite --with-mysqli --with-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-sqlite3 --with-curl --with-openssl --enable-gd --enable-soap --enable-sockets --with-zip --with-bz2 --with-readline --with-libxml --with-zlib --enable-pcntl --enable-posix --with-gettext --with-gmp --with-ldap --with-xsl --with-sodium --with-iconv --enable-fileinfo --enable-json --enable-phar --enable-filter --enable-hash --enable-session --enable-tokenizer --enable-ctype --enable-dom --enable-simplexml --enable-xml --enable-xmlreader --enable-xmlwriter --enable-shmop" - else - EXTENSIONS="--enable-cli --enable-fpm --enable-mbstring --enable-opcache --enable-intl --enable-exif --enable-bcmath --enable-calendar --enable-ftp --enable-sysvmsg --enable-sysvsem --enable-sysvshm --enable-wddx --with-pdo-mysql --with-pdo-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-pdo-sqlite --with-mysqli --with-pgsql${PG_PREFIX:+=$PG_PREFIX} --with-sqlite3 --with-curl --with-openssl --enable-gd --enable-soap --enable-sockets --with-zip --with-bz2 --with-readline --with-libxml --with-zlib --enable-pcntl --enable-posix --with-gettext --with-gmp --with-ldap --with-xsl --with-sodium --with-iconv --enable-fileinfo --enable-json --enable-phar --enable-filter --enable-hash --enable-session --enable-tokenizer --enable-ctype --enable-dom --enable-simplexml --enable-xml --enable-xmlreader --enable-xmlwriter --enable-shmop" - fi - ;; - esac + # Debug: Check if ICU libraries are available + echo "๐Ÿ” Checking for ICU libraries..." + if [ -d "$HOME/.local/unicode.org" ]; then + echo "โœ… ICU libraries found at: $HOME/.local/unicode.org" + ls -la "$HOME/.local/unicode.org/" + if [ -f "$HOME/.local/unicode.org"/*/lib/pkgconfig/icu-uc.pc ]; then + echo "โœ… ICU pkgconfig files found" + find "$HOME/.local/unicode.org" -name "*.pc" -type f | head -5 + else + echo "โŒ ICU pkgconfig files not found" + fi + else + echo "โŒ ICU libraries not found" + fi - echo "CONFIGURE_EXTENSIONS=$EXTENSIONS" >> $GITHUB_ENV + # Debug: Check libxml2 libraries + echo "๐Ÿ” Checking for libxml2 libraries..." + if [ -d "$HOME/.local/gnome.org/libxml2" ]; then + echo "โœ… libxml2 libraries found at: $HOME/.local/gnome.org/libxml2" + ls -la "$HOME/.local/gnome.org/libxml2/" + if [ -f "$HOME/.local/gnome.org/libxml2"/*/lib/pkgconfig/libxml-2.0.pc ]; then + echo "โœ… libxml2 pkgconfig files found" + find "$HOME/.local/gnome.org/libxml2" -name "libxml-2.0.pc" -type f + else + echo "โŒ libxml2 pkgconfig files not found" + fi + else + echo "โŒ libxml2 libraries not found" + fi - - name: Set macOS specific paths - if: matrix.platform == 'darwin' - run: | - # Set paths for Homebrew dependencies including keg-only packages - # Use a more organized approach to avoid duplicates - PKG_CONFIG_PATHS=( - "$(brew --prefix)/lib/pkgconfig" - "$(brew --prefix openssl@3)/lib/pkgconfig" - "$(brew --prefix libxml2)/lib/pkgconfig" - "$(brew --prefix icu4c)/lib/pkgconfig" - "$(brew --prefix zlib)/lib/pkgconfig" - "$(brew --prefix postgresql@17)/lib/pkgconfig" - "$(brew --prefix libpq)/lib/pkgconfig" - "$(brew --prefix bzip2)/lib/pkgconfig" - "$(brew --prefix gettext)/lib/pkgconfig" - "$(brew --prefix openldap)/lib/pkgconfig" - ) - PKG_CONFIG_PATH_JOINED=$(IFS=:; echo "${PKG_CONFIG_PATHS[*]}") - echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH_JOINED" >> $GITHUB_ENV - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH_JOINED" - - PATH_PATHS=( - "$(brew --prefix bison)/bin" - "$(brew --prefix)/bin" - "$(brew --prefix libpq)/bin" - "$(brew --prefix postgresql@17)/bin" - "$(brew --prefix gettext)/bin" - ) - PATH_JOINED=$(IFS=:; echo "${PATH_PATHS[*]}") - echo "PATH=$PATH_JOINED:$PATH" >> $GITHUB_ENV - export PATH="$PATH_JOINED:$PATH" - - LDFLAGS_PATHS=( - "-L$(brew --prefix)/lib" - "-L$(brew --prefix openssl@3)/lib" - "-L$(brew --prefix zlib)/lib" - "-L$(brew --prefix libiconv)/lib" - "-L$(brew --prefix libpq)/lib" - "-L$(brew --prefix bzip2)/lib" - "-L$(brew --prefix gettext)/lib" - "-L$(brew --prefix openldap)/lib" - ) - LDFLAGS_JOINED=$(IFS=' '; echo "${LDFLAGS_PATHS[*]}") - echo "LDFLAGS=$LDFLAGS_JOINED" >> $GITHUB_ENV - export LDFLAGS="$LDFLAGS_JOINED" - - CPPFLAGS_PATHS=( - "-I$(brew --prefix)/include" - "-I$(brew --prefix openssl@3)/include" - "-I$(brew --prefix zlib)/include" - "-I$(brew --prefix libiconv)/include" - "-I$(brew --prefix libpq)/include" - "-I$(brew --prefix bzip2)/include" - "-I$(brew --prefix gettext)/include" - "-I$(brew --prefix openldap)/include" - ) - CPPFLAGS_JOINED=$(IFS=' '; echo "${CPPFLAGS_PATHS[*]}") - echo "CPPFLAGS=$CPPFLAGS_JOINED" >> $GITHUB_ENV - export CPPFLAGS="$CPPFLAGS_JOINED" - echo "CXXFLAGS=-std=c++17 -stdlib=libc++" >> $GITHUB_ENV - export CXXFLAGS="-std=c++17 -stdlib=libc++" - - # Set readline-specific paths - echo "READLINE_CFLAGS=-I$(brew --prefix readline)/include" >> $GITHUB_ENV - echo "READLINE_LIBS=-L$(brew --prefix readline)/lib -lreadline" >> $GITHUB_ENV - export READLINE_CFLAGS="-I$(brew --prefix readline)/include" - export READLINE_LIBS="-L$(brew --prefix readline)/lib -lreadline" - - # Ensure libpq is linked for pg_config availability (keg-only) - brew link libpq --force || true - - # Check if PostgreSQL is available and working - echo "Debug: Checking PostgreSQL availability:" - echo " PATH: $PATH" - echo " Checking pg_config:" - which pg_config || echo " pg_config not found in PATH" - pg_config --version 2>/dev/null || echo " pg_config version check failed" - echo " Checking libpq-fe.h:" - ls -la $(brew --prefix libpq)/include/libpq-fe.h 2>/dev/null || echo " libpq-fe.h not found" - echo " Checking libpq installation:" - ls -la $(brew --prefix libpq)/include/ 2>/dev/null | head -5 || echo " libpq include directory not found" - ls -la $(brew --prefix libpq)/lib/ 2>/dev/null | head -5 || echo " libpq lib directory not found" - - if which pg_config >/dev/null 2>&1 && [[ -f "$(brew --prefix libpq)/include/libpq-fe.h" ]]; then - echo "PostgreSQL found and working" - echo "POSTGRESQL_AVAILABLE=true" >> $GITHUB_ENV + # Debug: Check PATH and PKG_CONFIG_PATH + echo "๐Ÿ” Environment check:" + echo "PATH includes unicode.org: $(echo $PATH | grep -o unicode.org || echo 'NO')" + echo "PATH includes freedesktop.org: $(echo $PATH | grep -o freedesktop.org || echo 'NO')" + echo "PKG_CONFIG_PATH: ${PKG_CONFIG_PATH:-'NOT SET'}" + + # Debug: Check if Launchpad environment script exists + echo "๐Ÿ” Checking for Launchpad environment..." + if [ -f "$HOME/.local/launchpad.sh" ]; then + echo "โœ… Launchpad environment script found" + echo "๐Ÿ“‹ Sourcing environment to check paths..." + source "$HOME/.local/launchpad.sh" + echo "PATH after sourcing: ${PATH:0:200}..." + echo "PKG_CONFIG_PATH after sourcing: ${PKG_CONFIG_PATH:-'NOT SET'}" else - echo "PostgreSQL not found or not working, will disable PostgreSQL support" - echo "POSTGRESQL_AVAILABLE=false" >> $GITHUB_ENV + echo "โŒ Launchpad environment script not found" fi - - name: Download and extract PHP source + - name: Install build dependencies (Windows) + if: matrix.platform == 'win32' run: | - cd ${{ env.BUILD_DIR }} - # Temporarily modify PATH to prioritize system binaries over launchpad binaries - # This prevents conflicts with launchpad-installed binaries that may have library dependencies - export PATH="/usr/bin:/usr/local/bin:/bin:$PATH" - # Use system curl instead of launchpad curl to avoid library conflicts - curl -fsSL "https://www.php.net/distributions/php-${{ matrix.php_version }}.tar.gz" -o php.tar.gz - tar -xzf php.tar.gz - cd php-${{ matrix.php_version }} - echo "PHP_SOURCE_DIR=${{ env.BUILD_DIR }}/php-${{ matrix.php_version }}" >> $GITHUB_ENV - - - name: Configure PHP build + # Windows: Install Visual Studio Build Tools and dependencies for PHP compilation + choco install visualstudio2022buildtools --package-parameters "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --includeOptional --passive" + choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' + choco install git + # Install additional dependencies needed for PHP extensions + echo "Windows build dependencies installed for PHP compilation" + + - name: Setup Launchpad Environment (macOS) + if: matrix.platform == 'darwin' + shell: bash run: | - cd ${{ env.PHP_SOURCE_DIR }} - - # Create installation directory - INSTALL_PREFIX="${{ env.OUTPUT_DIR }}/${{ env.BINARY_NAME }}" - mkdir -p "$INSTALL_PREFIX" - - # Configure with platform-specific options - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - # On macOS, use Homebrew-installed libraries - # Set environment variables for readline detection - export CPPFLAGS="$CPPFLAGS -I$(brew --prefix readline)/include" - export LDFLAGS="$LDFLAGS -L$(brew --prefix readline)/lib" - export LIBS="$LIBS -lreadline" - - # Set PostgreSQL environment variables and PATH - export PGSQL_CFLAGS="-I$(brew --prefix libpq)/include" - export PGSQL_LIBS="-L$(brew --prefix libpq)/lib -lpq" - export PATH="$(brew --prefix libpq)/bin:$(brew --prefix postgresql@17)/bin:$PATH" - - # Set bzip2 environment variables - export BZIP2_CFLAGS="-I$(brew --prefix bzip2)/include" - export BZIP2_LIBS="-L$(brew --prefix bzip2)/lib -lbz2" - - # Set gettext environment variables - export GETTEXT_CFLAGS="-I$(brew --prefix gettext)/include" - export GETTEXT_LIBS="-L$(brew --prefix gettext)/lib -lintl" - - # Check if both LDAP libraries are available - echo "Debug: Checking for lber library:" - ls -la $(brew --prefix openldap)/lib/liblber.* 2>/dev/null || echo " lber library not found" - echo "Debug: Checking for ldap library:" - ls -la $(brew --prefix openldap)/lib/libldap.* 2>/dev/null || echo " ldap library not found" - - if [[ -f "$(brew --prefix openldap)/lib/liblber.dylib" ]] && [[ -f "$(brew --prefix openldap)/lib/libldap.dylib" ]]; then - echo "Both LDAP libraries found, enabling LDAP support" - LDAP_AVAILABLE=true + # Find and setup Launchpad environment variables + echo "๐Ÿ”ง Setting up Launchpad environment for macOS build..." + + # Store original PATH to preserve system tools + echo "ORIGINAL_PATH=$PATH" >> $GITHUB_ENV + + # Find all Launchpad binary directories that should be added to PATH + LAUNCHPAD_PATHS="" + + # Find pkg-config binary - search broadly first + echo "๐Ÿ” Searching for pkg-config binary..." + PKG_CONFIG_BINARY=$(find "$HOME/.local" -name "pkg-config" -type f 2>/dev/null | head -1) + if [ -n "$PKG_CONFIG_BINARY" ]; then + PKG_CONFIG_DIR=$(dirname "$PKG_CONFIG_BINARY") + echo "โœ… Found pkg-config at: $PKG_CONFIG_DIR" + LAUNCHPAD_PATHS="$PKG_CONFIG_DIR" + else + echo "โŒ pkg-config binary not found in .local" + echo "๐Ÿ” Checking if pkg-config exists in system PATH..." + if command -v pkg-config >/dev/null 2>&1; then + echo "โœ… pkg-config found in system PATH: $(which pkg-config)" else - echo "LDAP libraries not found, disabling LDAP support" - LDAP_AVAILABLE=false - # Remove LDAP from CONFIGURE_EXTENSIONS - export CONFIGURE_EXTENSIONS=$(echo "$CONFIGURE_EXTENSIONS" | sed 's/--with-ldap//g' | sed 's/ */ /g') - echo "Updated CONFIGURE_EXTENSIONS: $CONFIGURE_EXTENSIONS" + echo "โŒ pkg-config not found anywhere" fi + fi - # Set OpenLDAP environment variables (only if libraries are available) - if [[ "$LDAP_AVAILABLE" == "true" ]]; then - export LDAP_CFLAGS="-I$(brew --prefix openldap)/include" - export LDAP_LIBS="-L$(brew --prefix openldap)/lib -lldap -llber" - echo "Debug: LDAP_CFLAGS=$LDAP_CFLAGS" - echo "Debug: LDAP_LIBS=$LDAP_LIBS" - else - # Clear LDAP environment variables if not available - unset LDAP_CFLAGS - unset LDAP_LIBS - echo "Debug: LDAP environment variables cleared" + # Find other essential Launchpad tools that might override system tools + # We'll be more selective to avoid overriding system tools + SED_BINARY=$(find "$HOME/.local" -path "*/gnu.org/sed/*/bin/sed" -type f 2>/dev/null | head -1) + if [ -n "$SED_BINARY" ]; then + SED_DIR=$(dirname "$SED_BINARY") + echo "โœ… Found sed at: $SED_DIR" + # Only add sed if we have other tools too, to avoid conflicts + if [ -n "$LAUNCHPAD_PATHS" ]; then + LAUNCHPAD_PATHS="$LAUNCHPAD_PATHS:$SED_DIR" fi + fi + + # Set the combined Launchpad paths (these will be prepended to PATH later) + if [ -n "$LAUNCHPAD_PATHS" ]; then + echo "LAUNCHPAD_BINARY_PATHS=$LAUNCHPAD_PATHS" >> $GITHUB_ENV + echo "โœ… Launchpad binary paths: $LAUNCHPAD_PATHS" + else + echo "LAUNCHPAD_BINARY_PATHS=" >> $GITHUB_ENV + echo "โŒ No Launchpad binary paths found - PATH will not be modified" + fi - # Set C++ standard based on PHP version - # PHP 8.4+ requires C++17, earlier versions may work with C++14 - PHP_MAJOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f1) - PHP_MINOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f2) - - if [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -ge 2 ]]; then - # PHP 8.2+ requires C++17 - export CXXFLAGS="-std=c++17 -stdlib=libc++" - echo "Using C++17 for PHP ${{ matrix.php_version }}" - elif [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -eq 1 ]]; then - # PHP 8.1 configure step requires C++14, but build step will need C++17 for ICU4C - export CXXFLAGS="-std=c++14 -stdlib=libc++" - echo "Using C++14 for PHP ${{ matrix.php_version }} (configure step only)" + # Setup comprehensive PKG_CONFIG_PATH + PKG_PATHS=$(find "$HOME/.local" -name "pkgconfig" -type d 2>/dev/null | tr '\n' ':') + if [ -n "$PKG_PATHS" ]; then + echo "LAUNCHPAD_PKG_CONFIG_PATH=$PKG_PATHS" >> $GITHUB_ENV + echo "โœ… PKG_CONFIG_PATH setup with $(echo "$PKG_PATHS" | tr ':' '\n' | wc -l) directories" + fi + + - name: Build PHP + shell: bash + env: + PHP_VERSION: ${{ matrix.php_version }} + PHP_CONFIG: ${{ matrix.config }} + TARGET_PLATFORM: ${{ matrix.platform }} + TARGET_ARCH: ${{ matrix.arch }} + BUILD_DIR: ${{ github.workspace }}/build + OUTPUT_DIR: ${{ github.workspace }}/binaries + # Environment for all platforms - will handle PATH logic in shell script + PKG_CONFIG_PATH: ${{ matrix.platform == 'darwin' && env.LAUNCHPAD_PKG_CONFIG_PATH || env.PKG_CONFIG_PATH }} + run: | + # Setup PATH for macOS with Launchpad tools + if [ "${{ matrix.platform }}" = "darwin" ]; then + echo "๐Ÿ”ง Setting up macOS environment..." + + # Preserve original PATH + ORIGINAL_PATH="$PATH" + echo "โœ… Original PATH: ${ORIGINAL_PATH:0:100}..." + + # Add Launchpad binary paths to PATH if they exist + if [ -n "${LAUNCHPAD_BINARY_PATHS:-}" ] && [ "${LAUNCHPAD_BINARY_PATHS}" != "NOT SET" ]; then + export PATH="$LAUNCHPAD_BINARY_PATHS:$ORIGINAL_PATH" + echo "โœ… Updated PATH with Launchpad binaries: ${LAUNCHPAD_BINARY_PATHS}" else - # Earlier PHP versions can use C++14 - export CXXFLAGS="-std=c++14 -stdlib=libc++" - echo "Using C++14 for PHP ${{ matrix.php_version }}" + echo "โŒ No Launchpad binary paths found - using original PATH" fi - # Keep CFLAGS clean for C compiler - export CFLAGS="" - export CPPFLAGS="$CPPFLAGS" - echo "Set C++ flags for configure step" - echo "CXXFLAGS: $CXXFLAGS" - echo "CFLAGS: $CFLAGS" - echo "CPPFLAGS: $CPPFLAGS" - - # Ensure we're using clang++ on macOS - if command -v clang++ >/dev/null 2>&1; then - export CC=clang - export CXX=clang++ - echo "Using clang/clang++ compilers" - echo "CC: $CC" - echo "CXX: $CXX" - fi + echo "โœ… Final PATH: ${PATH:0:100}..." + echo "โœ… PKG_CONFIG_PATH: ${PKG_CONFIG_PATH:-'NOT SET'}" - # Verify C++ support based on PHP version - if [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -ge 4 ]]; then - echo "Testing C++17 support before configure:" - echo '#include ' > test_cpp.cpp - echo 'int main() { std::enable_if_t x = 0; return x; }' >> test_cpp.cpp - if clang++ -std=c++17 -stdlib=libc++ test_cpp.cpp -o test_cpp 2>/dev/null; then - echo "C++17 support confirmed before configure" - rm -f test_cpp.cpp test_cpp + # Verify essential system tools are available + echo "๐Ÿ”ง Checking essential system tools..." + for tool in curl tar gzip grep tr find wc head; do + if command -v $tool >/dev/null 2>&1; then + echo "โœ… $tool: $(which $tool)" else - echo "C++17 support test failed before configure" - rm -f test_cpp.cpp test_cpp + echo "โŒ $tool: NOT FOUND" fi - elif [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -eq 1 ]]; then - echo "Testing C++14 support before configure (PHP 8.1 configure step):" - echo '#include ' > test_cpp.cpp - echo 'int main() { typename std::enable_if::type x = 0; return x; }' >> test_cpp.cpp - if clang++ -std=c++14 -stdlib=libc++ test_cpp.cpp -o test_cpp 2>/dev/null; then - echo "C++14 support confirmed before configure" - rm -f test_cpp.cpp test_cpp + done + + # Verify pkg-config is accessible + echo "๐Ÿ”ง Checking pkg-config..." + if command -v pkg-config >/dev/null 2>&1; then + echo "โœ… pkg-config is accessible: $(which pkg-config)" + echo "โœ… pkg-config version: $(pkg-config --version)" + + # Test libxml-2.0 specifically + if pkg-config --exists libxml-2.0; then + echo "โœ… libxml-2.0 package found via pkg-config" + echo "๐Ÿ“‹ libxml-2.0 cflags: $(pkg-config --cflags libxml-2.0)" else - echo "C++14 support test failed before configure" - rm -f test_cpp.cpp test_cpp + echo "โŒ libxml-2.0 package not found via pkg-config" + echo "๐Ÿ” Available packages: $(pkg-config --list-all | head -10)" fi else - echo "Testing C++14 support before configure:" - echo '#include ' > test_cpp.cpp - echo 'int main() { typename std::enable_if::type x = 0; return x; }' >> test_cpp.cpp - if clang++ -std=c++14 -stdlib=libc++ test_cpp.cpp -o test_cpp 2>/dev/null; then - echo "C++14 support confirmed before configure" - rm -f test_cpp.cpp test_cpp - else - echo "C++14 support test failed before configure" - rm -f test_cpp.cpp test_cpp - fi + echo "โŒ pkg-config not accessible" + echo "๐Ÿ” Searching for pkg-config in .local..." + find "$HOME/.local" -name "pkg-config" -type f 2>/dev/null | head -3 || echo "No pkg-config binaries found" fi - - # Try to find readline.h and set the path explicitly - READLINE_PATH=$(brew --prefix readline) - if [[ -f "$READLINE_PATH/include/readline/readline.h" ]]; then - echo "Found readline.h at $READLINE_PATH/include/readline/readline.h" - EXTRA_CONFIG="--with-iconv=$(brew --prefix libiconv) --with-readline=$READLINE_PATH" - else - echo "readline.h not found, disabling readline support" - EXTRA_CONFIG="--with-iconv=$(brew --prefix libiconv) --disable-readline" - fi - - # Check if PostgreSQL is available and working - echo "Debug: POSTGRESQL_AVAILABLE=$POSTGRESQL_AVAILABLE" - if [[ "$POSTGRESQL_AVAILABLE" == "true" ]]; then - echo "PostgreSQL found and working" - else - if [[ "${{ matrix.config }}" == "laravel-postgres" ]]; then - echo "โŒ PostgreSQL not available; cannot build laravel-postgres binary on this runner" - exit 1 - fi - echo "PostgreSQL not found or not working, will disable PostgreSQL support for non-postgres configs" - # Remove PostgreSQL extensions from CONFIGURE_EXTENSIONS - export CONFIGURE_EXTENSIONS=$(echo "$CONFIGURE_EXTENSIONS" | sed 's/--with-pdo-pgsql//g' | sed 's/--with-pgsql//g' | sed 's/ */ /g') - echo "Updated CONFIGURE_EXTENSIONS: $CONFIGURE_EXTENSIONS" - # Also disable PostgreSQL in the configuration - EXTRA_CONFIG="$EXTRA_CONFIG --disable-pgsql --disable-pdo-pgsql" - fi - else - # On Linux, use system-installed libraries - # System libraries should be available via apt-get installation - echo "Using system libraries installed via apt-get" - EXTRA_CONFIG="" fi - echo "Configuring PHP with:" - echo " Extensions: ${{ env.CONFIGURE_EXTENSIONS }}" - echo " Prefix: $INSTALL_PREFIX" - echo " Extra config: $EXTRA_CONFIG" - - # Debug: Check readline installation on macOS - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - echo "Debug: Checking readline installation on macOS:" - echo " READLINE_CFLAGS: $READLINE_CFLAGS" - echo " READLINE_LIBS: $READLINE_LIBS" - echo " CPPFLAGS: $CPPFLAGS" - echo " LDFLAGS: $LDFLAGS" - echo " Checking if readline.h exists:" - find $(brew --prefix) -name "readline.h" 2>/dev/null || echo " No readline.h found" - - echo "Debug: Checking PostgreSQL installation on macOS:" - echo " PGSQL_CFLAGS: $PGSQL_CFLAGS" - echo " PGSQL_LIBS: $PGSQL_LIBS" - echo " PATH: $PATH" - echo " Checking if pg_config is available:" - which pg_config || echo " pg_config not found in PATH" - pg_config --version 2>/dev/null || echo " pg_config version check failed" - echo " Checking if libpq-fe.h exists:" - find $(brew --prefix) -name "libpq-fe.h" 2>/dev/null || echo " No libpq-fe.h found" - fi + # Run the build script with properly configured environment + bun run scripts/build-php.ts - # Check if libcurl is found via pkg-config - if pkg-config --exists libcurl; then - echo "libcurl found via pkg-config" - CURL_CONFIG="" - else - echo "libcurl not found via pkg-config, using system curl" - CURL_CONFIG="" + - name: Create tarball (Unix) + if: matrix.platform != 'win32' + run: | + # Ensure binaries directory exists and check for builds + if [ ! -d "binaries" ]; then + echo "โŒ Binaries directory not found" + ls -la + exit 1 fi - # Build the final configure extensions based on availability - FINAL_EXTENSIONS="${{ env.CONFIGURE_EXTENSIONS }}" + cd binaries + BINARY_NAME="php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }}" - # If PostgreSQL is not available, remove PostgreSQL extensions - if [[ "${{ matrix.platform }}" == "darwin" ]] && [[ "$POSTGRESQL_AVAILABLE" != "true" ]]; then - echo "Removing PostgreSQL extensions from configure command" - FINAL_EXTENSIONS=$(echo "$FINAL_EXTENSIONS" | sed 's/--with-pdo-pgsql//g' | sed 's/--with-pgsql//g' | sed 's/ */ /g') - echo "Final extensions: $FINAL_EXTENSIONS" - fi - - # Set PHP version variables for C++ standard selection - PHP_MAJOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f1) - PHP_MINOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f2) - - echo "Configure environment:" - echo " CXXFLAGS: $CXXFLAGS" - echo " CFLAGS: $CFLAGS" - echo " CPPFLAGS: $CPPFLAGS" - echo " PHP Version: ${{ matrix.php_version }} (Major: $PHP_MAJOR_VERSION, Minor: $PHP_MINOR_VERSION)" - - # Test C++17 support before configure - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - echo "Testing C++17 support before configure:" - echo '#include ' > test_cpp17.cpp - echo 'int main() { std::enable_if_t x = 0; return x; }' >> test_cpp17.cpp - if clang++ -std=c++17 -stdlib=libc++ test_cpp17.cpp -o test_cpp17 2>/dev/null; then - echo "C++17 support confirmed before configure" - rm -f test_cpp17.cpp test_cpp17 - else - echo "C++17 support test failed before configure" - rm -f test_cpp17.cpp test_cpp17 - fi - fi + echo "๐Ÿ” Looking for binary directory: $BINARY_NAME" + ls -la - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - # Set environment variables for configure - if [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -ge 2 ]]; then - export CXXFLAGS="-std=c++17 -stdlib=libc++" - echo "Set C++17 for configure: $CXXFLAGS" - elif [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -eq 1 ]]; then - # PHP 8.1 configure step uses C++14 (PHP requirement) - export CXXFLAGS="-std=c++14 -stdlib=libc++" - echo "Set C++14 for PHP 8.1 configure: $CXXFLAGS" - else - export CXXFLAGS="-std=c++14 -stdlib=libc++" - echo "Set C++14 for configure: $CXXFLAGS" + if [ -d "$BINARY_NAME" ]; then + # Create metadata file if it doesn't exist + if [ ! -f "$BINARY_NAME/metadata.json" ]; then + echo '{"php_version":"${{ matrix.php_version }}","platform":"${{ matrix.platform }}","arch":"${{ matrix.arch }}","config":"${{ matrix.config }}","built_at":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' > "$BINARY_NAME/metadata.json" fi - export CFLAGS="" - export CPPFLAGS="$CPPFLAGS" - - # Also set CC and CXX explicitly - export CC=clang - export CXX=clang++ - echo "Set CC=$CC, CXX=$CXX" - fi - # Run configure with explicit environment - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - CXXFLAGS="$CXXFLAGS" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" CC="$CC" CXX="$CXX" ./configure \ - --prefix="$INSTALL_PREFIX" \ - --with-config-file-path="$INSTALL_PREFIX/lib" \ - --with-config-file-scan-dir="$INSTALL_PREFIX/lib/conf.d" \ - --disable-debug \ - --enable-shared \ - --with-pic \ - $FINAL_EXTENSIONS \ - $EXTRA_CONFIG \ - $CURL_CONFIG + # Create tarball + tar -czf "$BINARY_NAME.tar.gz" "$BINARY_NAME" + echo "โœ… Created tarball: $BINARY_NAME.tar.gz" + ls -lh "$BINARY_NAME.tar.gz" else - ./configure \ - --prefix="$INSTALL_PREFIX" \ - --with-config-file-path="$INSTALL_PREFIX/lib" \ - --with-config-file-scan-dir="$INSTALL_PREFIX/lib/conf.d" \ - --disable-debug \ - --enable-shared \ - --with-pic \ - $FINAL_EXTENSIONS \ - $EXTRA_CONFIG \ - $CURL_CONFIG - fi - - # Check the generated Makefile for C++ flags - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - echo "Checking Makefile for C++ flags:" - grep -E "CXXFLAGS|CXX|std=" Makefile | head -10 || echo "No C++ flags found in Makefile" + echo "โŒ Binary directory not found: $BINARY_NAME" + echo "Available directories:" + ls -la + exit 1 fi - - name: Build PHP + - name: Create tarball (Windows) + if: matrix.platform == 'win32' run: | - cd ${{ env.PHP_SOURCE_DIR }} - - # Use all available CPU cores for faster builds - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - JOBS=$(sysctl -n hw.ncpu) - # Set C++ standard based on PHP version for build - PHP_MAJOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f1) - PHP_MINOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f2) - - if [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -ge 2 ]]; then - export CXXFLAGS="-std=c++17 -stdlib=libc++" - echo "Set C++17 flags for macOS build" - elif [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -eq 1 ]]; then - # PHP 8.1 needs C++17 for ICU4C compilation - export CXXFLAGS="-std=c++17 -stdlib=libc++" - echo "Set C++17 flags for PHP 8.1 (ICU4C compatibility)" - else - export CXXFLAGS="-std=c++14 -stdlib=libc++" - echo "Set C++14 flags for macOS build" - fi - - # Keep CFLAGS clean for C compiler - export CFLAGS="" - export CPPFLAGS="$CPPFLAGS" - else - JOBS=$(nproc) - fi + # Ensure binaries directory exists and check for builds + if (-not (Test-Path -Path "binaries" -PathType Container)) { + Write-Host "โŒ Binaries directory not found" + Get-ChildItem + exit 1 + } - echo "Building PHP with $JOBS parallel jobs" - echo "CXXFLAGS: $CXXFLAGS" - echo "CFLAGS: $CFLAGS" - echo "CPPFLAGS: $CPPFLAGS" - - # Show what compiler is being used - echo "Compiler being used:" - which gcc || which clang || echo "No compiler found" - echo "C++ compiler:" - which g++ || which clang++ || echo "No C++ compiler found" - - # Show compiler version and flags - echo "Compiler info:" - which gcc || which clang || echo "No compiler found" - gcc --version 2>/dev/null || clang --version 2>/dev/null || echo "Could not get compiler version" - - # Check available C++ standards - echo "Checking available C++ standards:" - if command -v clang++ >/dev/null 2>&1; then - echo "Available C++ standards for clang++:" - clang++ --help | grep -E "std=" || echo "Could not determine available standards" - fi + cd binaries + $BINARY_NAME = "php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }}" + + Write-Host "๐Ÿ” Looking for binary directory: $BINARY_NAME" + Get-ChildItem + + if (Test-Path -Path $BINARY_NAME -PathType Container) { + # Create metadata file if it doesn't exist + if (-not (Test-Path -Path "$BINARY_NAME\metadata.json")) { + $metadata = @{ + php_version = "${{ matrix.php_version }}" + platform = "${{ matrix.platform }}" + arch = "${{ matrix.arch }}" + config = "${{ matrix.config }}" + built_at = (Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ") + } | ConvertTo-Json + $metadata | Out-File -FilePath "$BINARY_NAME\metadata.json" -Encoding UTF8 + } + + # Create zip archive (Windows equivalent of tarball) + Compress-Archive -Path $BINARY_NAME -DestinationPath "$BINARY_NAME.zip" -Force + Write-Host "โœ… Created archive: $BINARY_NAME.zip" + Get-ChildItem "$BINARY_NAME.zip" | Format-List Name, Length + } else { + Write-Host "โŒ Binary directory not found: $BINARY_NAME" + Write-Host "Available directories:" + Get-ChildItem + exit 1 + } - # Test C++ support based on PHP version - PHP_MAJOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f1) - PHP_MINOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f2) - - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - if [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -ge 2 ]]; then - echo "Testing C++17 support:" - echo '#include ' > test_cpp.cpp - echo 'int main() { std::enable_if_t x = 0; return x; }' >> test_cpp.cpp - if clang++ -std=c++17 -stdlib=libc++ test_cpp.cpp -o test_cpp 2>/dev/null; then - echo "C++17 support confirmed" - rm -f test_cpp.cpp test_cpp - else - echo "C++17 support test failed" - rm -f test_cpp.cpp test_cpp - fi - elif [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -eq 1 ]]; then - echo "Testing C++17 support for PHP 8.1 (ICU4C compatibility):" - echo '#include ' > test_cpp.cpp - echo 'int main() { std::enable_if_t x = 0; return x; }' >> test_cpp.cpp - if clang++ -std=c++17 -stdlib=libc++ test_cpp.cpp -o test_cpp 2>/dev/null; then - echo "C++17 support confirmed for PHP 8.1" - rm -f test_cpp.cpp test_cpp - else - echo "C++17 support test failed for PHP 8.1" - rm -f test_cpp.cpp test_cpp - fi - else - echo "Testing C++14 support:" - echo '#include ' > test_cpp.cpp - echo 'int main() { typename std::enable_if::type x = 0; return x; }' >> test_cpp.cpp - if clang++ -std=c++14 -stdlib=libc++ test_cpp.cpp -o test_cpp 2>/dev/null; then - echo "C++14 support confirmed" - rm -f test_cpp.cpp test_cpp + - name: Test PHP Binary (Unix) + if: matrix.platform != 'win32' + run: | + BINARY_NAME="php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }}" + if [ -f "binaries/$BINARY_NAME/bin/php" ]; then + echo "โœ… PHP binary created successfully" + binaries/$BINARY_NAME/bin/php --version + echo "๐Ÿ“‹ All available extensions:" + binaries/$BINARY_NAME/bin/php -m + + # Define essential extensions that MUST be present + REQUIRED_EXTENSIONS=( + "Core" "date" "hash" "json" "pcre" "Reflection" "SPL" "standard" + "mbstring" "iconv" "filter" "ctype" "tokenizer" "session" "fileinfo" + "phar" "dom" "xml" "xmlreader" "xmlwriter" "simplexml" + "curl" "openssl" "zip" "zlib" "calendar" "ftp" "pcntl" "posix" + "shmop" "sockets" "exif" "bcmath" "bz2" "gettext" "readline" + ) + + # Define Zend extensions that need special checking + ZEND_EXTENSIONS=("opcache") + + # Test each required extension + echo "๐Ÿงช Testing essential extensions..." + MISSING_EXTENSIONS=() + for ext in "${REQUIRED_EXTENSIONS[@]}"; do + EXT_LOADED=$(binaries/$BINARY_NAME/bin/php -r "echo extension_loaded('$ext') ? '1' : '0';") + if [ "$EXT_LOADED" = "1" ]; then + echo "โœ… $ext: LOADED" else - echo "C++14 support test failed" - rm -f test_cpp.cpp test_cpp + echo "โŒ $ext: MISSING" + MISSING_EXTENSIONS+=("$ext") fi - fi - fi + done - # Pass compiler flags explicitly to make - if [[ "${{ matrix.platform }}" == "darwin" ]]; then - PHP_MAJOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f1) - PHP_MINOR_VERSION=$(echo "${{ matrix.php_version }}" | cut -d. -f2) - - if [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -ge 2 ]]; then - echo "Making with explicit C++17 flags:" - echo " CXXFLAGS: -std=c++17 -stdlib=libc++" - echo " CFLAGS: (empty)" - echo " CPPFLAGS: $CPPFLAGS" - make -j$JOBS CXXFLAGS="-std=c++17 -stdlib=libc++" CFLAGS="" CPPFLAGS="$CPPFLAGS" - elif [[ "$PHP_MAJOR_VERSION" -eq 8 && "$PHP_MINOR_VERSION" -eq 1 ]]; then - echo "Making with explicit C++17 flags for PHP 8.1 (ICU4C compatibility):" - echo " CXXFLAGS: -std=c++17 -stdlib=libc++" - echo " CFLAGS: (empty)" - echo " CPPFLAGS: $CPPFLAGS" - - # Force update Makefile for PHP 8.1 to use C++17 - echo "Updating Makefile for PHP 8.1 C++17 compatibility..." - sed -i.bak 's/-std=c++14/-std=c++17/g' Makefile 2>/dev/null || echo "No C++14 flags found in Makefile to replace" - sed -i.bak 's/-std=gnu++14/-std=gnu++17/g' Makefile 2>/dev/null || echo "No gnu++14 flags found in Makefile to replace" - - # Set environment variables to force C++17 - export CXXFLAGS="-std=c++17 -stdlib=libc++" - export CFLAGS="" - export CC=clang - export CXX=clang++ - echo "Final CXXFLAGS: $CXXFLAGS" - - # Also update the Makefile to force C++17 for all compilation rules - echo "Forcing C++17 in all Makefile compilation rules..." - sed -i.bak 's/$(CXX) $(CFLAGS_CXX) $(CXXFLAGS) $(CPPFLAGS_CXX) $(CPPFLAGS) -c/$(CXX) $(CFLAGS_CXX) -std=c++17 -stdlib=libc++ $(CXXFLAGS) $(CPPFLAGS_CXX) $(CPPFLAGS) -c/g' Makefile 2>/dev/null || echo "Could not update Makefile compilation rules" - - # Show what C++ flags are in the Makefile after all updates - echo "C++ flags in Makefile after all updates:" - grep -E "std=" Makefile | head -10 || echo "No std flags found in Makefile" - - # Set system-wide C++17 flags - export CXXFLAGS="-std=c++17 -stdlib=libc++" - export CFLAGS="" - export CPPFLAGS="$CPPFLAGS" - export CC=clang - export CXX=clang++ - - # Test C++17 compilation before building - echo "Testing C++17 compilation before build:" - echo '#include ' > test_cpp17.cpp - echo 'int main() { std::enable_if_t x = 0; std::is_same_v y = true; return 0; }' >> test_cpp17.cpp - if clang++ -std=c++17 -stdlib=libc++ test_cpp17.cpp -o test_cpp17 2>/dev/null; then - echo "C++17 compilation test passed" - rm -f test_cpp17.cpp test_cpp17 + # Test Zend extensions separately + for ext in "${ZEND_EXTENSIONS[@]}"; do + EXT_LOADED=$(binaries/$BINARY_NAME/bin/php -r "echo function_exists('opcache_get_status') ? '1' : '0';") + if [ "$EXT_LOADED" = "1" ]; then + echo "โœ… $ext: LOADED" else - echo "C++17 compilation test failed" - rm -f test_cpp17.cpp test_cpp17 + echo "โŒ $ext: MISSING" + MISSING_EXTENSIONS+=("$ext") fi + done - # Use a more aggressive approach - override the compiler - echo "Using aggressive C++17 enforcement..." - - # Create a wrapper script that forces C++17 - echo '#!/bin/bash' > cxx17_wrapper.sh - echo 'exec clang++ -std=c++17 -stdlib=libc++ "$@"' >> cxx17_wrapper.sh - chmod +x cxx17_wrapper.sh + # Check if any essential extensions are missing + if [ ${#MISSING_EXTENSIONS[@]} -gt 0 ]; then + echo "โŒ Critical extensions missing: ${MISSING_EXTENSIONS[*]}" + echo "This build is incomplete and will cause issues with Composer and Laravel." + exit 1 + fi - # Use the wrapper script as the C++ compiler - make -j$JOBS CXXFLAGS="-std=c++17 -stdlib=libc++" CFLAGS="" CPPFLAGS="$CPPFLAGS" CC="clang" CXX="./cxx17_wrapper.sh" + # Test phar extension functionality specifically + echo "๐Ÿงช Testing phar extension functionality..." + PHAR_LOADED=$(binaries/$BINARY_NAME/bin/php -r 'echo extension_loaded("phar") ? "1" : "0";') + if [ "$PHAR_LOADED" = "1" ]; then + echo "โœ… Phar extension is loaded" + # Test phar creation (essential for Composer) + echo "๐Ÿงช Testing phar creation..." + echo 'addFromString("test.txt", "Hello World"); + echo "โœ… Phar creation successful\n"; + unlink("test.phar"); + } catch (Exception $e) { + echo "โŒ Phar creation failed: " . $e->getMessage() . "\n"; + exit(1); + } + } else { + echo "โŒ Phar extension not loaded\n"; + exit(1); + } + ?>' > test_phar_create.php + binaries/$BINARY_NAME/bin/php -d phar.readonly=0 test_phar_create.php + rm test_phar_create.php else - echo "Making with explicit C++14 flags:" - echo " CXXFLAGS: -std=c++14 -stdlib=libc++" - echo " CFLAGS: (empty)" - echo " CPPFLAGS: $CPPFLAGS" - make -j$JOBS CXXFLAGS="-std=c++14 -stdlib=libc++" CFLAGS="" CPPFLAGS="$CPPFLAGS" + echo "โŒ Phar extension not loaded - this will break Composer!" + exit 1 fi + + # Test Composer compatibility + echo "๐Ÿงช Testing Composer compatibility..." + echo '' > test_composer_compat.php + binaries/$BINARY_NAME/bin/php test_composer_compat.php + rm test_composer_compat.php + + echo "โœ… All PHP binary tests passed successfully!" else - make -j$JOBS + echo "โŒ PHP binary not found" + exit 1 fi - - name: Install PHP + - name: Test PHP Binary (Windows) + if: matrix.platform == 'win32' run: | - cd ${{ env.PHP_SOURCE_DIR }} - make install - - # Verify installation - INSTALL_PREFIX="${{ env.OUTPUT_DIR }}/${{ env.BINARY_NAME }}" - "$INSTALL_PREFIX/bin/php" --version - "$INSTALL_PREFIX/bin/php" -m # Show loaded modules - - # Generate a default php.ini to ensure DB extensions are enabled by default - echo "Generating default php.ini for configuration: ${{ matrix.config }}" - EXT_DIR=$("$INSTALL_PREFIX/bin/php-config" --extension-dir 2>/dev/null || echo "") - PHP_INI_DIR="$INSTALL_PREFIX/lib" - mkdir -p "$PHP_INI_DIR" - PHP_INI="$PHP_INI_DIR/php.ini" - { - echo "; Launchpad php.ini (auto-generated in CI)" - echo "memory_limit = 512M" - echo "max_execution_time = 300" - echo "upload_max_filesize = 64M" - echo "post_max_size = 64M" - echo "display_errors = On" - echo "error_reporting = E_ALL" - if [ -n "$EXT_DIR" ]; then - echo "extension_dir = \"$EXT_DIR\"" - fi - case "${{ matrix.config }}" in - "laravel-postgres") - echo "extension=pdo_pgsql" - echo "extension=pgsql" - ;; - "laravel-mysql") - echo "extension=pdo_mysql" - echo "extension=mysqli" - ;; - "laravel-sqlite") - echo "extension=pdo_sqlite" - echo "extension=sqlite3" - ;; - "enterprise"|"full-stack") - echo "extension=pdo_pgsql" - echo "extension=pgsql" - echo "extension=pdo_mysql" - echo "extension=mysqli" - echo "extension=pdo_sqlite" - echo "extension=sqlite3" - ;; - *) - : - ;; - esac - } > "$PHP_INI" - echo "Created $PHP_INI" - - - name: Create binary package - run: | - cd ${{ env.OUTPUT_DIR }} - - # Create metadata file - cat > ${{ env.BINARY_NAME }}/metadata.json << EOF - { - "php_version": "${{ matrix.php_version }}", - "platform": "${{ matrix.platform }}", - "architecture": "${{ matrix.arch }}", - "configuration": "${{ matrix.config }}", - "built_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", - "built_by": "GitHub Actions", - "commit": "${{ github.sha }}", - "extensions": "$(echo '${{ env.CONFIGURE_EXTENSIONS }}' | tr ' ' '\n' | grep -E '^--(enable|with)-' | sed 's/^--[^-]*-//' | sort | tr '\n' ',' | sed 's/,$//')" + $BINARY_NAME = "php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }}" + $phpExeRoot = "binaries\$BINARY_NAME\php.exe" + $phpExeBin = "binaries\$BINARY_NAME\bin\php.exe" + $PHP = if (Test-Path -Path $phpExeRoot -PathType Leaf) { $phpExeRoot } elseif (Test-Path -Path $phpExeBin -PathType Leaf) { $phpExeBin } else { $null } + Write-Host "Checking for binary at: $PHP" + + # List all files in the binary directory to verify structure + Write-Host "๐Ÿ“‚ Binary directory structure:" + Get-ChildItem -Path "binaries\$BINARY_NAME" -Recurse | Format-Table Name, Length, LastWriteTime + + # Check if the PHP binary exists + if ($PHP -and (Test-Path -Path $PHP -PathType Leaf)) { + Write-Host "โœ… PHP binary exists at expected location" + + # Get file size to verify it's a real binary (not just a placeholder) + $fileSize = (Get-Item $PHP).Length + Write-Host "๐Ÿ“Š PHP binary size: $fileSize bytes" + + # Test PHP version and extensions + Write-Host "๐Ÿงช Testing PHP binary..." + & $PHP --version + Write-Host "๐Ÿ“‹ All available extensions:" + & $PHP -m + + # Define essential extensions that MUST be present + $REQUIRED_EXTENSIONS = @( + "Core", "date", "hash", "json", "pcre", "Reflection", "SPL", "standard", + "mbstring", "iconv", "filter", "ctype", "tokenizer", "session", "fileinfo", + "phar", "dom", "xml", "xmlreader", "xmlwriter", "simplexml", + "curl", "openssl", "zip", "zlib", "calendar", "ftp", + "shmop", "sockets", "exif", "bcmath", "bz2", "gettext", "readline" + ) + + # Define Zend extensions that need special checking + $ZEND_EXTENSIONS = @("opcache") + + # Test each required extension + Write-Host "๐Ÿงช Testing essential extensions..." + $MISSING_EXTENSIONS = @() + foreach ($ext in $REQUIRED_EXTENSIONS) { + $extLoaded = & $PHP -r "echo extension_loaded('$ext') ? '1' : '0';" + if ($extLoaded -eq "1") { + Write-Host "โœ… $ext`: LOADED" + } else { + Write-Host "โŒ $ext`: MISSING" + $MISSING_EXTENSIONS += $ext + } + } + + # Test Zend extensions separately + foreach ($ext in $ZEND_EXTENSIONS) { + $extLoaded = & $PHP -r "echo function_exists('opcache_get_status') ? '1' : '0';" + if ($extLoaded -eq "1") { + Write-Host "โœ… $ext`: LOADED" + } else { + Write-Host "โŒ $ext`: MISSING" + $MISSING_EXTENSIONS += $ext + } + } + + # Check if any essential extensions are missing + if ($MISSING_EXTENSIONS.Count -gt 0) { + Write-Host "โŒ Critical extensions missing: $($MISSING_EXTENSIONS -join ', ')" + Write-Host "This build is incomplete and will cause issues with Composer and Laravel." + exit 1 + } + + # Test phar extension functionality specifically + Write-Host "๐Ÿงช Testing phar extension functionality..." + $pharLoaded = & $PHP -r 'echo extension_loaded("phar") ? "1" : "0";' + if ($pharLoaded -eq "1") { + Write-Host "โœ… Phar extension is loaded" + # Test phar creation (essential for Composer) + Write-Host "๐Ÿงช Testing phar creation..." + $pharTest = & $PHP -d phar.readonly=0 -r 'try { $p = new Phar("test.phar"); $p->addFromString("t.txt", "x"); echo "OK"; unlink("test.phar"); } catch (Exception $e) { echo "ERR: ".$e->getMessage(); exit(1); }' + if ($pharTest -eq "OK") { + Write-Host "โœ… Phar creation successful" + } else { + Write-Host "โŒ Phar creation failed: $pharTest" + exit 1 + } + } else { + Write-Host "โŒ Phar extension not loaded - this will break Composer!" + exit 1 + } + + # Test Composer compatibility + Write-Host "๐Ÿงช Testing Composer compatibility..." + $composerTestContent = "" + $composerTestContent | Out-File -FilePath "test_composer_compat.php" -Encoding UTF8 + & $PHP "test_composer_compat.php" + Remove-Item "test_composer_compat.php" + + # Check if this is likely a real binary based on file size + if ($fileSize -gt 1000000) { + Write-Host "โœ… PHP binary appears to be a real Windows binary (file size: $fileSize bytes)" + + # Check for DLLs which should be present in a real PHP distribution + $dllCount = (Get-ChildItem -Path "binaries\$BINARY_NAME" -Filter "*.dll" -Recurse).Count + Write-Host "Found $dllCount DLL files in the PHP distribution" + + if ($dllCount -gt 10) { + Write-Host "โœ… PHP distribution contains expected DLL files" + } else { + Write-Host "โš ๏ธ PHP distribution contains fewer DLL files than expected" + } + } else { + Write-Host "โš ๏ธ PHP binary is smaller than expected, might be a placeholder" + } + + Write-Host "โœ… All PHP binary tests passed successfully!" + } else { + Write-Host "โŒ PHP binary not found at expected location" + Write-Host "Directory contents:" + if (Test-Path -Path "binaries\$BINARY_NAME") { + Get-ChildItem -Path "binaries\$BINARY_NAME" -Recurse + } else { + Write-Host "Binary directory does not exist" + } + exit 1 } - EOF - - # Create tarball - tar -czf ${{ env.BINARY_NAME }}.tar.gz ${{ env.BINARY_NAME }}/ - # Show package info - echo "Created package: ${{ env.BINARY_NAME }}.tar.gz" - ls -lh ${{ env.BINARY_NAME }}.tar.gz - - - name: Upload binary artifact + - name: Upload PHP Binary (Unix) + if: matrix.platform != 'win32' uses: actions/upload-artifact@v4 with: - name: ${{ env.BINARY_NAME }} - path: ${{ env.OUTPUT_DIR }}/${{ env.BINARY_NAME }}.tar.gz - retention-days: 90 + name: php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }} + path: binaries/php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }}.tar.gz + retention-days: 30 - - name: Upload to GitHub Container Registry (Linux) - if: github.event_name == 'push' && github.ref == 'refs/heads/main' && matrix.platform == 'linux' - run: | - echo ${{ secrets.GITHUB_TOKEN }} | docker login ${{ env.REGISTRY_URL }} -u ${{ env.REGISTRY_USERNAME }} --password-stdin - - # Create a simple Dockerfile for the binary - cd ${{ env.OUTPUT_DIR }} - cat > Dockerfile << EOF - FROM scratch - COPY ${{ env.BINARY_NAME }}.tar.gz /php-binary.tar.gz - EOF - - # Build and push - IMAGE_TAG="${{ env.REGISTRY_URL }}/${{ github.repository_owner }}/php-binaries:${{ env.BINARY_NAME }}" - docker build -t "$IMAGE_TAG" . - docker push "$IMAGE_TAG" + - name: Upload PHP Binary (Windows) + if: matrix.platform == 'win32' + uses: actions/upload-artifact@v4 + with: + name: php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }} + path: binaries/php-${{ matrix.php_version }}-${{ matrix.platform }}-${{ matrix.arch }}-${{ matrix.config }}.zip + retention-days: 30 # Release job to create GitHub releases with binaries create-release: - needs: [check-for-updates, build-matrix, get-php-versions] + needs: [check-for-updates, build, get-php-versions] runs-on: ubuntu-latest if: ((github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'workflow_dispatch') && (needs.check-for-updates.outputs.rebuild_needed == 'true' || github.event.inputs.force_rebuild == 'true') @@ -1055,14 +765,15 @@ jobs: echo "๐Ÿ” Current directory structure:" ls -la echo "" - echo "๐Ÿ” Looking for tar.gz files:" - find . -name "*.tar.gz" -type f + echo "๐Ÿ” Looking for binary files (tar.gz and zip):" + find . -name "*.tar.gz" -type f -o -name "*.zip" -type f echo "" # Create a temporary JSON array file echo "[]" > binaries_array.json - # Find all tar.gz files recursively and process them + # Process tar.gz files (Unix binaries) + echo "Processing Unix binaries (.tar.gz files)..." for tarball in $(find . -name "*.tar.gz" -type f); do filename=$(basename "$tarball") size=$(stat -c%s "$tarball" 2>/dev/null || stat -f%z "$tarball") @@ -1116,6 +827,70 @@ jobs: mv temp_array.json binaries_array.json done + # Process zip files (Windows binaries) + echo "Processing Windows binaries (.zip files)..." + for zipfile in $(find . -name "*.zip" -type f); do + filename=$(basename "$zipfile") + size=$(stat -c%s "$zipfile" 2>/dev/null || stat -f%z "$zipfile") + + echo "Processing: $filename (size: $size bytes)" + + # Parse the binary name to extract components + # Expected format: php-8.4.11-win32-x86_64-laravel-mysql.zip + binary_name=$(echo "$filename" | sed 's/\.zip$//') + + # Extract components from binary name + if [[ "$binary_name" =~ ^php-([^-]+)-([^-]+)-([^-]+)-(.+)$ ]]; then + php_version="${BASH_REMATCH[1]}" + platform="${BASH_REMATCH[2]}" + architecture="${BASH_REMATCH[3]}" + configuration="${BASH_REMATCH[4]}" + else + # Fallback if pattern doesn't match + php_version="unknown" + platform="unknown" + architecture="unknown" + configuration="unknown" + fi + + # Try to extract metadata from zip if possible + # This is more complex with zip files, so we'll use a simpler approach + # Create a temporary directory + temp_dir="temp_extract_$RANDOM" + mkdir -p "$temp_dir" + + # Try to extract just the metadata file + unzip -q -j "$zipfile" "*/metadata.json" -d "$temp_dir" 2>/dev/null || echo '{}' > "$temp_dir/metadata.json" + + # Create JSON object for this binary + binary_json=$(jq -n \ + --arg filename "$filename" \ + --arg size "$size" \ + --arg php_version "$php_version" \ + --arg platform "$platform" \ + --arg architecture "$architecture" \ + --arg configuration "$configuration" \ + --arg built_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + --arg extensions "$(cat "$temp_dir/metadata.json" | jq -r '.extensions // ""' 2>/dev/null || echo '')" \ + '{ + filename: $filename, + size: ($size | tonumber), + php_version: $php_version, + platform: $platform, + architecture: $architecture, + configuration: $configuration, + built_at: $built_at, + extensions: $extensions + }') + + # Add this binary to the array using jq + jq --argjson binary "$binary_json" '. += [$binary]' binaries_array.json > temp_array.json + mv temp_array.json binaries_array.json + + # Clean up temp directory + rm -rf "$temp_dir" + done + # Create the final manifest with proper structure and sorted binaries jq --arg version "$(date +%Y.%m.%d)" \ --arg built_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ @@ -1135,11 +910,13 @@ jobs: cat manifest.json echo "" echo "๐Ÿ“Š Summary:" - echo " - Total binaries found: $(find . -name "*.tar.gz" -type f | wc -l)" + echo " - Unix binaries found: $(find . -name "*.tar.gz" -type f | wc -l)" + echo " - Windows binaries found: $(find . -name "*.zip" -type f | wc -l)" + echo " - Total binaries found: $(find . -name "*.tar.gz" -o -name "*.zip" -type f | wc -l)" echo " - Manifest file size: $(stat -c%s manifest.json 2>/dev/null || stat -f%z manifest.json) bytes" - name: Create GitHub Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2.3.3 with: tag_name: binaries-${{ github.run_number }} name: PHP Binaries - Build ${{ github.run_number }} @@ -1148,7 +925,7 @@ jobs: > This release contains precompiled PHP binaries optimized for modern PHP usage - - **Platforms**: Linux (x86_64), macOS (ARM64 & Intel) + - **Platforms**: Linux (x86_64), macOS (ARM64 & Intel), Windows (x86_64) - **PHP Versions**: ${{ steps.format-versions.outputs.php_versions_string }} - **Configuration Options**: - `laravel-mysql`: Laravel applications using MySQL or MariaDB @@ -1168,6 +945,7 @@ jobs: See `manifest.json` for detailed information about each binary. files: | binaries/**/*.tar.gz + binaries/**/*.zip binaries/manifest.json draft: false prerelease: false