Last active
June 13, 2024 08:57
-
-
Save Muffinman/9075b659a06e8799f3672ee7d803ba9f to your computer and use it in GitHub Desktop.
MacOS 14 PHP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 272da51bfd562f5b9847c1b41eaa5d7018058490 Mon Sep 17 00:00:00 2001 | |
From: Manuel Kress <[email protected]> | |
Date: Fri, 1 Mar 2024 17:47:21 +0100 | |
Subject: [PATCH] Use ITIMER_REAL for timeout handling on MacOS / Apple Silicon | |
system | |
setitimer(ITIMER_PROF) fires too early on MacOS 14 when running on Apple | |
Silicon. See https://openradar.appspot.com/radar?id=5583058442911744. | |
Fixes GH-12814 | |
Closes GH-13567 | |
--- | |
NEWS | 2 ++ | |
Zend/zend_execute_API.c | 6 ++++-- | |
2 files changed, 6 insertions(+), 2 deletions(-) | |
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c | |
index c7f814138d00d..fa126f959b3ed 100644 | |
--- a/Zend/zend_execute_API.c | |
+++ b/Zend/zend_execute_API.c | |
@@ -1533,7 +1533,9 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ | |
t_r.it_value.tv_sec = seconds; | |
t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0; | |
-# if defined(__CYGWIN__) || defined(__PASE__) | |
+# if defined(__CYGWIN__) || defined(__PASE__) || (defined(__aarch64__) && defined(__APPLE__)) | |
+ // ITIMER_PROF is broken in Apple Silicon system with MacOS >= 14 | |
+ // See https://openradar.appspot.com/radar?id=5583058442911744. | |
setitimer(ITIMER_REAL, &t_r, NULL); | |
} | |
signo = SIGALRM; | |
@@ -1597,7 +1599,7 @@ void zend_unset_timeout(void) /* {{{ */ | |
no_timeout.it_value.tv_sec = no_timeout.it_value.tv_usec = no_timeout.it_interval.tv_sec = no_timeout.it_interval.tv_usec = 0; | |
-# if defined(__CYGWIN__) || defined(__PASE__) | |
+# if defined(__CYGWIN__) || defined(__PASE__) || (defined(__aarch64__) && defined(__APPLE__)) | |
setitimer(ITIMER_REAL, &no_timeout, NULL); | |
# else | |
setitimer(ITIMER_PROF, &no_timeout, NULL); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Download formula | |
curl https://gist.github.com/Muffinman/9075b659a06e8799f3672ee7d803ba9f/raw/e31e42baa88db21b0764a46dc17e8f87dacb0872/php.rb | |
# Install custom formula | |
brew install --build-from-source ./php.rb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Php < Formula | |
desc "General-purpose scripting language" | |
homepage "https://www.php.net/" | |
# Should only be updated if the new version is announced on the homepage, https://www.php.net/ | |
url "https://www.php.net/distributions/php-8.3.8.tar.xz" | |
mirror "https://fossies.org/linux/www/php-8.3.8.tar.xz" | |
sha256 "aea358b56186f943c2bbd350c9005b9359133d47e954cfc561385319ae5bb8d7" | |
license "PHP-3.01" | |
revision 1 | |
livecheck do | |
url "https://www.php.net/downloads" | |
regex(/href=.*?php[._-]v?(\d+(?:\.\d+)+)\.t/i) | |
end | |
bottle do | |
root_url "https://ghcr.io/v2/shivammathur/php" | |
sha256 arm64_sonoma: "d3615ea3b58564334a00d447d3d4f33770e56c74d041b69258d81c592b582e27" | |
sha256 arm64_ventura: "eca3ddde0ca92364e5996a65fafeb7429a0faf8eacccc9efd5487d5eb0dd1680" | |
sha256 arm64_monterey: "7fe7b1d0f6972cc5d34194ff7077dc11c2bb36beff0527a63fc795a192738ce9" | |
sha256 ventura: "27a80fa5e1f71b21f84b8b89604f5c40ac3345f1fd0c76e449579eb9772873f1" | |
sha256 monterey: "0c8e979d1000c87e017aac7eae1eae9a357dae35eef8db0f6a6419e921ac12e5" | |
sha256 x86_64_linux: "3f158d3a3f2d86088e53763fdb7516684ae8ce4f48f1f7c9701f9df492a3201e" | |
end | |
head do | |
url "https://github.com/php/php-src.git", branch: "master" | |
depends_on "bison" => :build # bison >= 3.0.0 required to generate parsers | |
depends_on "re2c" => :build # required to generate PHP lexers | |
end | |
depends_on "httpd" => [:build, :test] | |
depends_on "pkg-config" => :build | |
depends_on "apr" | |
depends_on "apr-util" | |
depends_on "argon2" | |
depends_on "aspell" | |
depends_on "autoconf" | |
depends_on "curl" | |
depends_on "freetds" | |
depends_on "gd" | |
depends_on "gettext" | |
depends_on "gmp" | |
depends_on "icu4c" | |
depends_on "krb5" | |
depends_on "libpq" | |
depends_on "libsodium" | |
depends_on "libzip" | |
depends_on "oniguruma" | |
depends_on "openldap" | |
depends_on "openssl@3" | |
depends_on "pcre2" | |
depends_on "sqlite" | |
depends_on "tidy-html5" | |
depends_on "unixodbc" | |
uses_from_macos "xz" => :build | |
uses_from_macos "bzip2" | |
uses_from_macos "libedit" | |
uses_from_macos "libffi", since: :catalina | |
uses_from_macos "libxml2" | |
uses_from_macos "libxslt" | |
uses_from_macos "zlib" | |
on_macos do | |
# PHP build system incorrectly links system libraries | |
patch :DATA | |
end | |
# Remove with 8.3.9 | |
patch do | |
url "https://raw.githubusercontent.com/shivammathur/php-builder/595dc3f/config/patches/8.3/0045-method-visibility-issue.patch?full_index=1" | |
sha256 "2947d7ad1a54af20c935ec7d804bb45aec8d9e66b7f6a693a26b1ce0f2ed0a35" | |
end | |
# Remove with 8.3.9 | |
patch do | |
url "https://gist.github.com/Muffinman/9075b659a06e8799f3672ee7d803ba9f/raw/41d68c0b95ba0f9e4d012308e8666ecc36c139ed/fix-macos-ITIMER_PROF-php8.3.patch" | |
sha256 "1174e6e55329595cb8ceb4d7aa737378da0bf1420b7d1fac4f5ac6a773f4070d" | |
end | |
def install | |
# buildconf required due to system library linking bug patch | |
system "./buildconf", "--force" | |
inreplace "configure" do |s| | |
s.gsub! "APACHE_THREADED_MPM=`$APXS_HTTPD -V 2>/dev/null | grep 'threaded:.*yes'`", | |
"APACHE_THREADED_MPM=" | |
s.gsub! "APXS_LIBEXECDIR='$(INSTALL_ROOT)'`$APXS -q LIBEXECDIR`", | |
"APXS_LIBEXECDIR='$(INSTALL_ROOT)#{lib}/httpd/modules'" | |
s.gsub! "-z `$APXS -q SYSCONFDIR`", | |
"-z ''" | |
end | |
# Update error message in apache sapi to better explain the requirements | |
# of using Apache http in combination with php if the non-compatible MPM | |
# has been selected. Homebrew has chosen not to support being able to | |
# compile a thread safe version of PHP and therefore it is not | |
# possible to recompile as suggested in the original message | |
inreplace "sapi/apache2handler/sapi_apache2.c", | |
"You need to recompile PHP.", | |
"Homebrew PHP does not support a thread-safe php binary. " \ | |
"To use the PHP apache sapi please change " \ | |
"your httpd config to use the prefork MPM" | |
inreplace "sapi/fpm/php-fpm.conf.in", ";daemonize = yes", "daemonize = no" | |
config_path = etc/"php/#{version.major_minor}" | |
# Prevent system pear config from inhibiting pear install | |
(config_path/"pear.conf").delete if (config_path/"pear.conf").exist? | |
# Prevent homebrew from hardcoding path to sed shim in phpize script | |
ENV["lt_cv_path_SED"] = "sed" | |
# system pkg-config missing | |
ENV["KERBEROS_CFLAGS"] = " " | |
if OS.mac? | |
ENV["SASL_CFLAGS"] = "-I#{MacOS.sdk_path_if_needed}/usr/include/sasl" | |
ENV["SASL_LIBS"] = "-lsasl2" | |
else | |
ENV["SQLITE_CFLAGS"] = "-I#{Formula["sqlite"].opt_include}" | |
ENV["SQLITE_LIBS"] = "-lsqlite3" | |
ENV["BZIP_DIR"] = Formula["bzip2"].opt_prefix | |
end | |
# Each extension that is built on Mojave needs a direct reference to the | |
# sdk path or it won't find the headers | |
headers_path = "=#{MacOS.sdk_path_if_needed}/usr" if OS.mac? | |
# `_www` only exists on macOS. | |
fpm_user = OS.mac? ? "_www" : "www-data" | |
fpm_group = OS.mac? ? "_www" : "www-data" | |
args = %W[ | |
--prefix=#{prefix} | |
--localstatedir=#{var} | |
--sysconfdir=#{config_path} | |
--with-config-file-path=#{config_path} | |
--with-config-file-scan-dir=#{config_path}/conf.d | |
--with-pear=#{pkgshare}/pear | |
--enable-bcmath | |
--enable-calendar | |
--enable-dba | |
--enable-exif | |
--enable-ftp | |
--enable-fpm | |
--enable-gd | |
--enable-intl | |
--enable-mbregex | |
--enable-mbstring | |
--enable-mysqlnd | |
--enable-pcntl | |
--enable-phpdbg | |
--enable-phpdbg-readline | |
--enable-shmop | |
--enable-soap | |
--enable-sockets | |
--enable-sysvmsg | |
--enable-sysvsem | |
--enable-sysvshm | |
--with-apxs2=#{Formula["httpd"].opt_bin}/apxs | |
--with-bz2#{headers_path} | |
--with-curl | |
--with-external-gd | |
--with-external-pcre | |
--with-ffi | |
--with-fpm-user=#{fpm_user} | |
--with-fpm-group=#{fpm_group} | |
--with-gettext=#{Formula["gettext"].opt_prefix} | |
--with-gmp=#{Formula["gmp"].opt_prefix} | |
--with-iconv#{headers_path} | |
--with-kerberos | |
--with-layout=GNU | |
--with-ldap=#{Formula["openldap"].opt_prefix} | |
--with-libxml | |
--with-libedit | |
--with-mhash#{headers_path} | |
--with-mysql-sock=/tmp/mysql.sock | |
--with-mysqli=mysqlnd | |
--with-ndbm#{headers_path} | |
--with-openssl | |
--with-password-argon2 | |
--with-pdo-dblib=#{Formula["freetds"].opt_prefix} | |
--with-pdo-mysql=mysqlnd | |
--with-pdo-odbc=unixODBC,#{Formula["unixodbc"].opt_prefix} | |
--with-pdo-pgsql=#{Formula["libpq"].opt_prefix} | |
--with-pdo-sqlite | |
--with-pgsql=#{Formula["libpq"].opt_prefix} | |
--with-pic | |
--with-pspell=#{Formula["aspell"].opt_prefix} | |
--with-sodium | |
--with-sqlite3 | |
--with-tidy=#{Formula["tidy-html5"].opt_prefix} | |
--with-unixODBC | |
--with-xsl | |
--with-zip | |
--with-zlib | |
] | |
if OS.mac? | |
args << "--enable-dtrace" | |
args << "--with-ldap-sasl" | |
args << "--with-os-sdkpath=#{MacOS.sdk_path_if_needed}" | |
else | |
args << "--disable-dtrace" | |
args << "--without-ldap-sasl" | |
args << "--without-ndbm" | |
args << "--without-gdbm" | |
end | |
system "./configure", *args | |
system "make" | |
system "make", "install" | |
# Allow pecl to install outside of Cellar | |
extension_dir = Utils.safe_popen_read("#{bin}/php-config", "--extension-dir").chomp | |
orig_ext_dir = File.basename(extension_dir) | |
inreplace bin/"php-config", lib/"php", prefix/"pecl" | |
%w[development production].each do |mode| | |
inreplace "php.ini-#{mode}", %r{; ?extension_dir = "\./"}, | |
"extension_dir = \"#{HOMEBREW_PREFIX}/lib/php/pecl/#{orig_ext_dir}\"" | |
end | |
# Use OpenSSL cert bundle | |
openssl = Formula["openssl@3"] | |
%w[development production].each do |mode| | |
inreplace "php.ini-#{mode}", /; ?openssl\.cafile=/, | |
"openssl.cafile = \"#{openssl.pkgetc}/cert.pem\"" | |
inreplace "php.ini-#{mode}", /; ?openssl\.capath=/, | |
"openssl.capath = \"#{openssl.pkgetc}/certs\"" | |
end | |
config_files = { | |
"php.ini-development" => "php.ini", | |
"php.ini-production" => "php.ini-production", | |
"sapi/fpm/php-fpm.conf" => "php-fpm.conf", | |
"sapi/fpm/www.conf" => "php-fpm.d/www.conf", | |
} | |
config_files.each_value do |dst| | |
dst_default = config_path/"#{dst}.default" | |
rm dst_default if dst_default.exist? | |
end | |
config_path.install config_files | |
unless (var/"log/php-fpm.log").exist? | |
(var/"log").mkpath | |
touch var/"log/php-fpm.log" | |
end | |
end | |
def post_install | |
pear_prefix = pkgshare/"pear" | |
pear_files = %W[ | |
#{pear_prefix}/.depdblock | |
#{pear_prefix}/.filemap | |
#{pear_prefix}/.depdb | |
#{pear_prefix}/.lock | |
] | |
%W[ | |
#{pear_prefix}/.channels | |
#{pear_prefix}/.channels/.alias | |
].each do |f| | |
chmod 0755, f | |
pear_files.concat(Dir["#{f}/*"]) | |
end | |
chmod 0644, pear_files | |
# Custom location for extensions installed via pecl | |
pecl_path = HOMEBREW_PREFIX/"lib/php/pecl" | |
pecl_path.mkpath | |
ln_s pecl_path, prefix/"pecl" unless (prefix/"pecl").exist? | |
extension_dir = Utils.safe_popen_read("#{bin}/php-config", "--extension-dir").chomp | |
php_basename = File.basename(extension_dir) | |
php_ext_dir = opt_prefix/"lib/php"/php_basename | |
# fix pear config to install outside cellar | |
pear_path = HOMEBREW_PREFIX/"share/pear" | |
cp_r pkgshare/"pear/.", pear_path | |
{ | |
"php_ini" => etc/"php/#{version.major_minor}/php.ini", | |
"php_dir" => pear_path, | |
"doc_dir" => pear_path/"doc", | |
"ext_dir" => pecl_path/php_basename, | |
"bin_dir" => opt_bin, | |
"data_dir" => pear_path/"data", | |
"cfg_dir" => pear_path/"cfg", | |
"www_dir" => pear_path/"htdocs", | |
"man_dir" => HOMEBREW_PREFIX/"share/man", | |
"test_dir" => pear_path/"test", | |
"php_bin" => opt_bin/"php", | |
}.each do |key, value| | |
value.mkpath if /(?<!bin|man)_dir$/.match?(key) | |
system bin/"pear", "config-set", key, value, "system" | |
end | |
system bin/"pear", "update-channels" | |
%w[ | |
opcache | |
].each do |e| | |
ext_config_path = etc/"php/#{version.major_minor}/conf.d/ext-#{e}.ini" | |
extension_type = (e == "opcache") ? "zend_extension" : "extension" | |
if ext_config_path.exist? | |
inreplace ext_config_path, | |
/#{extension_type}=.*$/, "#{extension_type}=#{php_ext_dir}/#{e}.so" | |
else | |
ext_config_path.write <<~EOS | |
[#{e}] | |
#{extension_type}="#{php_ext_dir}/#{e}.so" | |
EOS | |
end | |
end | |
end | |
def caveats | |
<<~EOS | |
To enable PHP in Apache add the following to httpd.conf and restart Apache: | |
LoadModule php_module #{opt_lib}/httpd/modules/libphp.so | |
<FilesMatch \\.php$> | |
SetHandler application/x-httpd-php | |
</FilesMatch> | |
Finally, check DirectoryIndex includes index.php | |
DirectoryIndex index.php index.html | |
The php.ini and php-fpm.ini file can be found in: | |
#{etc}/php/#{version.major_minor}/ | |
EOS | |
end | |
service do | |
run [opt_sbin/"php-fpm", "--nodaemonize"] | |
run_type :immediate | |
keep_alive true | |
error_log_path var/"log/php-fpm.log" | |
working_dir var | |
end | |
test do | |
assert_match(/^Zend OPcache$/, shell_output("#{bin}/php -i"), | |
"Zend OPCache extension not loaded") | |
# Test related to libxml2 and | |
# https://github.com/Homebrew/homebrew-core/issues/28398 | |
assert_includes (bin/"php").dynamically_linked_libraries, | |
(Formula["libpq"].opt_lib/shared_library("libpq", 5)).to_s | |
system "#{sbin}/php-fpm", "-t" | |
system "#{bin}/phpdbg", "-V" | |
system "#{bin}/php-cgi", "-m" | |
# Prevent SNMP extension to be added | |
refute_match(/^snmp$/, shell_output("#{bin}/php -m"), | |
"SNMP extension doesn't work reliably with Homebrew on High Sierra") | |
begin | |
port = free_port | |
port_fpm = free_port | |
expected_output = /^Hello world!$/ | |
(testpath/"index.php").write <<~EOS | |
<?php | |
echo 'Hello world!' . PHP_EOL; | |
var_dump(ldap_connect()); | |
EOS | |
main_config = <<~EOS | |
Listen #{port} | |
ServerName localhost:#{port} | |
DocumentRoot "#{testpath}" | |
ErrorLog "#{testpath}/httpd-error.log" | |
ServerRoot "#{Formula["httpd"].opt_prefix}" | |
PidFile "#{testpath}/httpd.pid" | |
LoadModule authz_core_module lib/httpd/modules/mod_authz_core.so | |
LoadModule unixd_module lib/httpd/modules/mod_unixd.so | |
LoadModule dir_module lib/httpd/modules/mod_dir.so | |
DirectoryIndex index.php | |
EOS | |
(testpath/"httpd.conf").write <<~EOS | |
#{main_config} | |
LoadModule mpm_prefork_module lib/httpd/modules/mod_mpm_prefork.so | |
LoadModule php_module #{lib}/httpd/modules/libphp.so | |
<FilesMatch \\.(php|phar)$> | |
SetHandler application/x-httpd-php | |
</FilesMatch> | |
EOS | |
(testpath/"fpm.conf").write <<~EOS | |
[global] | |
daemonize=no | |
[www] | |
listen = 127.0.0.1:#{port_fpm} | |
pm = dynamic | |
pm.max_children = 5 | |
pm.start_servers = 2 | |
pm.min_spare_servers = 1 | |
pm.max_spare_servers = 3 | |
EOS | |
(testpath/"httpd-fpm.conf").write <<~EOS | |
#{main_config} | |
LoadModule mpm_event_module lib/httpd/modules/mod_mpm_event.so | |
LoadModule proxy_module lib/httpd/modules/mod_proxy.so | |
LoadModule proxy_fcgi_module lib/httpd/modules/mod_proxy_fcgi.so | |
<FilesMatch \\.(php|phar)$> | |
SetHandler "proxy:fcgi://127.0.0.1:#{port_fpm}" | |
</FilesMatch> | |
EOS | |
pid = fork do | |
exec Formula["httpd"].opt_bin/"httpd", "-X", "-f", "#{testpath}/httpd.conf" | |
end | |
sleep 3 | |
assert_match expected_output, shell_output("curl -s 127.0.0.1:#{port}") | |
Process.kill("TERM", pid) | |
Process.wait(pid) | |
fpm_pid = fork do | |
exec sbin/"php-fpm", "-y", "fpm.conf" | |
end | |
pid = fork do | |
exec Formula["httpd"].opt_bin/"httpd", "-X", "-f", "#{testpath}/httpd-fpm.conf" | |
end | |
sleep 3 | |
assert_match expected_output, shell_output("curl -s 127.0.0.1:#{port}") | |
ensure | |
if pid | |
Process.kill("TERM", pid) | |
Process.wait(pid) | |
end | |
if fpm_pid | |
Process.kill("TERM", fpm_pid) | |
Process.wait(fpm_pid) | |
end | |
end | |
end | |
end | |
__END__ | |
diff --git a/build/php.m4 b/build/php.m4 | |
index 3624a33a8e..d17a635c2c 100644 | |
--- a/build/php.m4 | |
+++ b/build/php.m4 | |
@@ -425,7 +425,7 @@ dnl | |
dnl Adds a path to linkpath/runpath (LDFLAGS). | |
dnl | |
AC_DEFUN([PHP_ADD_LIBPATH],[ | |
- if test "$1" != "/usr/$PHP_LIBDIR" && test "$1" != "/usr/lib"; then | |
+ if test "$1" != "$PHP_OS_SDKPATH/usr/$PHP_LIBDIR" && test "$1" != "/usr/lib"; then | |
PHP_EXPAND_PATH($1, ai_p) | |
ifelse([$2],,[ | |
_PHP_ADD_LIBPATH_GLOBAL([$ai_p]) | |
@@ -470,7 +470,7 @@ dnl | |
dnl Add an include path. If before is 1, add in the beginning of INCLUDES. | |
dnl | |
AC_DEFUN([PHP_ADD_INCLUDE],[ | |
- if test "$1" != "/usr/include"; then | |
+ if test "$1" != "$PHP_OS_SDKPATH/usr/include"; then | |
PHP_EXPAND_PATH($1, ai_p) | |
PHP_RUN_ONCE(INCLUDEPATH, $ai_p, [ | |
if test "$2"; then | |
diff --git a/configure.ac b/configure.ac | |
index 36c6e5e3e2..71b1a16607 100644 | |
--- a/configure.ac | |
+++ b/configure.ac | |
@@ -190,6 +190,14 @@ PHP_ARG_WITH([libdir], | |
[lib], | |
[no]) | |
+dnl Support systems with system libraries/includes in e.g. /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk. | |
+PHP_ARG_WITH([os-sdkpath], | |
+ [for system SDK directory], | |
+ [AS_HELP_STRING([--with-os-sdkpath=NAME], | |
+ [Ignore system libraries and includes in NAME rather than /])], | |
+ [], | |
+ [no]) | |
+ | |
PHP_ARG_ENABLE([rpath], | |
[whether to enable runpaths], | |
[AS_HELP_STRING([--disable-rpath], |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment