ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

麒麟V10源码编译PHP 8.3完整指南:从依赖准备到Nginx对接

麒麟V10源码编译PHP 8.3完整指南:从依赖准备到Nginx对接 1. 先搞清楚需求为什么要在麒麟V10(Sword)上自己编译PHP1.1 麒麟Kylin Linux Advanced Server V10系统的真实身份在开始之前先看看这套系统到底是什么。Kylin Linux Advanced Server V10 (Sword) 是用于服务器场景的Linux发行版命令习惯和包管理跟RHEL 8/CentOS 8这一系非常接近有yum/dnf可以用系统下面也是glibc、gcc、systemd这一套标准组件。也就是说你在CentOS 8上积累的编译排查经验大部分可以直接迁移过来。我第一次在这套系统上装PHP时也有点犹豫怕麒麟有自己特殊的东西。实际用下来除了软件源里某些包名、版本跟CentOS不完全一样其余操作思路几乎一致。特别是在内网、离线环境或者需要定制PHP扩展的时候源码编译反而是最稳、最可控的路径。很多人问为什么不用yum或者dnf直接装原因很简单麒麟自带的仓库里PHP版本偏旧有些还是7.x甚至更老的版本对于需要跑现代框架、要用较新语法特性的项目来说自带的版本可能不够。另一个场景是多版本共存一台机器要同时跑PHP 7.4和PHP 8.3各自独立目录源码编译是天然合适的方案。1.2 编译安装 vs 仓库安装怎么选对比项yum/dnf安装源码编译安装版本控制由系统仓库决定通常偏保守自己选版本紧跟官方稳定版扩展定制可安装仓库提供模块灵活度一般configure阶段直接决定编译哪些扩展安装目录分散在/usr/bin、/etc等位置--prefix指定统一目录卸载方便升级维护dnf update即可简单需要重新编译但可控性高依赖管理大部分自动解决需要自己确保-devel包齐全生产安全有发布方测试过的二进制依赖编译参数和系统环境需要严格测试我个人倾向线上老项目、对性能要求不极端的用yum装默认PHP够用但如果你要跑Symfony/Laravel新版本、要做opcache调优、要自己编译Swoole这类扩展或者需要在同一台机器上隔离多个版本源码编译是更合理的选择。1.3 这篇文章适合谁来参考如果你正准备在一台新的麒麟V10服务器上把PHP从源码装起来并且后续要跟Nginx对接那么这篇文章可以给你一条完整路线。不需要你有特别强的C语言背景只要会敲命令、能看懂终端报错跟着步骤走就能装出来。当然我也要说清楚编译安装最大的坑不是“不会敲命令”而是“依赖东缺西缺”。你会发现 configure 和 make 过程中报的最多错误都是缺某个头文件。所以这部分我会把依赖、参数、坑位都写到尽量让你少走几趟弯路。2. 环境准备和配置方案动手前先抓好基础2.1 用一条命令摸清系统家底编译之前先确认系统版本、架构、CPU核数和可用内存避免后面 make 的时候内存爆炸。cat /etc/os-release uname -m nproc free -h gcc --versionuname -m的输出很关键。x86_64 是常见架构arm64 会显示 aarch64。麒麟V10有大量ARM版本很多人在ARM机器上直接抄x86的编译参数结果依赖包名字不一样或者某些扩展编译失败。命令里的nproc是CPU核数决定了后面make -j用多少并行任务free -h看内存内存小于2GB的时候编译要保守一些。系统里如果没有gcc后面安装依赖时一并装上不需要提前单独处理。按理说麒麟服务器版会自带基础开发工具但如果是一台裁剪过的内网机器可能连make都没有。2.2 依赖库和编译工具链一次性装全这一步最容易偷懒但也是后面报错最少的保证。编译PHP需要两样东西编译工具链以及PHP各种扩展所依赖的开发头文件。dnf install -y gcc gcc-c make autoconf libtool automake pkg-config m4 dnf install -y pcre2-devel zlib-devel libxml2-devel openssl-devel curl-devel bzip2-devel sqlite-devel dnf install -y libjpeg-devel libpng-devel freetype-devel libwebp-devel oniguruma-devel如果你的麒麟系统把dnf屏蔽了换成yum install也可以包名完全一样。这些包分别干什么我简要说明一下pcre2-devel是PHP正则表达式底层所使用的PCRE2库头文件libxml2-devel提供XML解析能力PHP 8基本强制依赖它openssl-devel用于HTTPS、加密函数等curl-devel提供cURL扩展oniguruma-devel是mbstring多字节字符串处理的依赖。libjpeg/libpng/freetype则是给GD图像扩展用的如果不需要图片处理可以暂时不装但大多数Web应用早晚会用到。有些精简系统可能缺少bzip2-devel、sqlite-devel这两个不装也不影响基础运行但根据你的项目情况提前装掉避免PHP configure时又说找不到库。总体原则宁可多装不要缺装一个编译周期很耗时反复重新configure更痛苦。2.3 下载PHP源码包顺手校验完整性源码包建议下载一个稳定版本。我这边以 PHP 8.3 系列为例在干净环境里编译稳定性和兼容性都表现不错。下载目录推荐放到/usr/local/src不要放在/home下避免权限和路径问题。cd /usr/local/src wget https://www.php.net/distributions/php-8.3.10.tar.gz sha256sum php-8.3.10.tar.gz tar -zxvf php-8.3.10.tar.gz cd php-8.3.10sha256sum是很多人忽略的习惯。官网每发布一个源码包都会给一个hash值下载后自己算一下确认没有被修改或原包没损坏。编译环境里用损坏包很坑往往make到一半才报莫名其妙的“内部错误”实际是压缩包本身有问题。如果你在内网环境不能访问外网那就从内部软件仓库拿到源码包同样算一遍hash再解压。2.4 configure参数怎么选每个都讲清楚configure是编译安装的重头戏也是最容易出现“选择困难症”的地方。我的习惯是先想清楚这个PHP要不要跑PHP-FPM要接什么数据库要不要图像处理然后按需配置。下面是一套覆盖大多数Web场景的配置./configure --prefix/usr/local/php \ --with-config-file-path/usr/local/php/etc \ --enable-fpm \ --with-fpm-userwww \ --with-fpm-groupwww \ --enable-mbstring \ --enable-zip \ --enable-bcmath \ --enable-pcntl \ --enable-sockets \ --enable-opcache \ --with-openssl \ --with-curl \ --with-zlib \ --with-bz2 \ --with-mysqlimysqlnd \ --with-pdo-mysqlmysqlnd \ --with-jpeg \ --with-freetype \ --with-webp \ --enable-gd参数逐个拆解--prefix/usr/local/php是把PHP装到独立目录所有文件都放在这里后续升级或者不想用了直接删目录再清理PATH就行不污染系统目录。--with-config-file-path指定php.ini的位置默认路径在不同系统上变化多端很容易出现“装了PHP却找不到配置”的情况所以显式指定。--enable-fpm是编译PHP-FPM这是Nginx需要的关键组件。配合--with-fpm-user和--with-fpm-group指定PHP-FPM进程运行身份。生产环境一般不用root跑PHP所以后面要新建一个www用户。--enable-mbstring、--enable-zip、--enable-bcmath、--enable-pcntl、--enable-sockets都是日常高频扩展。mbstring不用多说中文字符串处理zip用于打包解压bcmath处理高精度数字pcntl和sockets是很多后台任务、消息队列可能用到的opcache是官方字节码缓存必须开提升性能非常明显。数据库方面--with-mysqlimysqlnd和--with-pdo-mysqlmysqlnd都使用mysqlnd驱动不用依赖libmysqlclient省心。GD库则按需配置jpeg、freetype、webp支持大多数图片处理都会用到。这里有个重要的原则configure参数不是越多越好没用的扩展会增加编译时间和潜在风险。如果暂时用不到gd可以先把GD相关参数删掉如果项目不需要pcntl也可以去掉。等到后面需要再单独编译扩展反而更灵活。3. 完整编译安装流程从零跑到Nginx3.1 先创建PHP-FPM运行用户我用的是独立运行用户一个习惯操作是groupadd www useradd -M -s /sbin/nologin -g www www-M 表示不创建home目录-s 指定为不可登录shell这样即使PHP被攻击攻击者也很难用这个账号直接登进系统。很多新手会跳过这一步直接用root跑PHP-FPM虽然能跑但安全上风险相当大。如果你后面编译Nginx也要用www用户同一个账号可以直接复用。3.2 configure、make、make install的完整过程进入源码目录后先执行上文给出的 configure 命令。这一步主要检查依赖是否齐全正常情况下会输出一长串“creating cache”“checking for...”之类的内容最后出现config.status: creating ...和一句话Thank you for using PHP。如果中途报错先不要慌排查表我放在下一大节。configure完成之后当前目录已经生成了Makefile。接下来先确认核数nproc make -j4-j后面的数字不是越大越好。编译PHP时每个编译进程都会占用内存比如-j4在4核服务器上很有可能同时跑4个cc进程每个进程占用几十甚至上百MB如果总内存只有2G容易直接卡死。内存充足时用-j$(nproc)确实快但保守起见2G内存的机器用make -j2更稳。整个编译过程一般需要10到20分钟ARM机器会更久。出现一堆gcc调用和一个Build complete.就说明make成功了。这一步最常见失败原因是virtual memory exhausted就是内存不足解决办法是关掉一些并行任务或者临时扩大swap。make成功之后继续make install这一步会把编译好的二进制、库文件复制到/usr/local/php下。结束后验证一下/usr/local/php/bin/php -v能打印PHP版本号说明主体已经落地。3.3 初始化php.ini和php-fpm.conf源码包里默认带两个php.ini模板php.ini-development适合本地调试php.ini-production适合线上环境。我强烈建议生产用production模板然后按需调几个参数。cp php.ini-production /usr/local/php/etc/php.ini cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf cp /usr/local/php/etc/php-fpm.d/www.conf.default /usr/local/php/etc/php-fpm.d/www.conf需要注意改完php.ini之后要确认PHP能读到它。用php --ini查看/usr/local/php/bin/php --ini如果返回的路径不是/usr/local/php/etc/php.ini再回头检查configure时是否写了--with-config-file-path最好也检查环境变量PHP_INI_SCAN_DIR有没有干扰。php-fpm.conf默认会include同目录php-fpm.d/*.conf所以核心池配置在www.conf中。编辑www.conf找到这几行改成自己想要的user www group www listen /var/run/php-fpm/php83.sock listen.owner www listen.group www listen.mode 0660这里我选的是Unix Socket而不是TCP 9000端口。同一台机器上的Nginx走socket比走TCP更快也少暴露一个端口。如果以后要跨机器通信再改成listen 127.0.0.1:9000。创建socket目录并给权限mkdir -p /var/run/php-fpm chown www:www /var/run/php-fpm然后用php-fpm -t检查配置语法/usr/local/php/sbin/php-fpm -t显示test is successful就可以启动了。3.4 做成一键管理的systemd服务直接php-fpm也能跑但重启、开机自启不方便。我一般会写一个systemd unit。vim /etc/systemd/system/php-fpm.service内容如下[Unit] DescriptionPHP FastCGI Process Manager Afternetwork.target [Service] Typeforking ExecStart/usr/local/php/sbin/php-fpm ExecReload/bin/kill -USR2 $MAINPID ExecStop/bin/kill -QUIT $MAINPID PrivateTmptrue [Install] WantedBymulti-user.target然后执行systemctl daemon-reload systemctl enable --now php-fpm systemctl status php-fpmTypeforking 是因为php-fpm启动后会自己转入后台运行配合ExecStart正好。如果启动不了先跑一次/usr/local/php/sbin/php-fpm -F看前台日志一般比abstract报错更明确。3.5 Nginx配置让PHP真正对外跑起来Nginx本身不会解析PHP它通过fastcgi协议把请求转给PHP-FPM。先在Nginx配置里建一个server块。server { listen 80; server_name _; root /var/www/html; index index.php index.html; location ~ \.php$ { fastcgi_pass unix:/var/run/php-fpm/php83.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }fastcgi_pass的地址必须和php-fpm的listen保持一致。如果你用的是TCP就写fastcgi_pass 127.0.0.1:9000;。SCRIPT_FILENAME是Nginx把请求的文件路径告诉PHP-FPM的关键参数写错了很容易出现File not found。写完后重载Nginxnginx -t nginx -s reload然后在网站根目录放一个index.php内容写?php phpinfo();打开浏览器访问服务器IP看到PHP信息页说明整套流程已经通了。看到信息页后记得把这个临时文件删掉避免泄露环境信息。4. 编译过程常见问题和排查记录4.1 configure阶段报错速查表configure阶段报错通常是最容易解决的因为错误信息已经把缺失的包名写在脸上了。报错关键词实际原因解决命令No package libxml-2.0 found缺libxml2开发包dnf install -y libxml2-develNo package openssl found缺openssl开发包dnf install -y openssl-develNo package libcurl found缺curl开发包dnf install -y curl-develCannot find pcre.h / pcre2.h缺PCRE或PCRE2dnf install -y pcre2-develoniguruma.h not foundmbstring依赖缺失dnf install -y oniguruma-develPlease reinstall the libzip distribution缺zip扩展依赖dnf install -y libzip-develbz2 not found缺bzip2开发包dnf install -y bzip2-devellibjpeg / freetype / webp not foundGD相关开发包缺失dnf install -y libjpeg-devel freetype-devel libwebp-devel需要注意的是某些麒麟内网源可能没有libzip-devel这种情况可以先用dnf search libzip确认一下。如果没有可以临时去掉--enable-zip后面用PECL单独补。4.2 make阶段遇到“内存不足”和“编译中断”make阶段最常见的问题是virtual memory exhausted: Cannot allocate memory这种通常是因为make -j并行任务太多内存被多个cc进程吃光了。先free -h看内存然后降到make -j1试试。如果内存还是不够可以临时加swapdd if/dev/zero of/swapfile bs1M count4096 chmod 600 /swapfile mkswap /swapfile swapon /swapfile编译完再swapoff清理掉。这种方法应急可以不建议长期依赖swap跑生产。还有一种情况是网络下载源安装的源码包本身不完整导致某个C文件缺失make直接报No such file or directory。重新解压再编译即可不必怀疑自己的参数。4.3 php-fpm启动失败和Nginx 502php-fpm启动失败先运行/usr/local/php/sbin/php-fpm -t如果报ERROR: unable to bind listening socket大概率是socket目录不存在或者权限不对。解决办法就是我在3.3节写的提前创建目录并chown给www。如果php-fpm明明在跑Nginx却返回502最可能是两个原因fastcgi_pass地址跟php-fpm的listen不一致。TCP和socket写混了肯定502。Nginx的worker进程或PHP-FPM socket文件权限设置不对。Nginx worker用nginx用户跑PHP-FPM用www用户跑socket文件的listen.owner/group就必须配好否则nginx没权限访问。还有一个坑是SELinux。麒麟V10某些安全模式下Nginx访问Unix Socket会被拦截。临时验证可以用setsebool -P httpd_can_network_connect 1具体策略名可能因版本不同有区别最好用getsebool | grep httpd_can_network查看支持项。生产环境不要简单setenforce 0而是要按策略放行。4.4 扩展加载路径和PATH环境变量混用问题很多人在源码编译完PHP后敲php -v发现还是旧版本。这是因为系统PATH里还有之前装的PHP路径比如/usr/bin/php。解决方式有三种修改/etc/profile或使用绝对路径或把/usr/local/php/bin和/usr/local/php/sbin加到PATH最前面。export PATH/usr/local/php/bin:/usr/local/php/sbin:$PATH想永久生效就写进/etc/profile.d/php.sh。结合之前说的扩展问题如果php -m里看不到 mysqli、pdo_mysql先检查编译参数是否正确再检查php --ini里的extension_dir路径确认要加载的.so文件是否真的存在。大多数情况下编译参数对就不需要额外改php.ini。4.5 ARM64架构上需要额外留神的事麒麟V10有很大一批机器是arm64也就是uname -m输出aarch64。在ARM上编译PHP绝大多数源码本身没问题但有几个细节下载的源码包要对应官方对ARM的兼容支持目前PHP主线版本都是支持的。如果某些扩展依赖的第三方库没有arm64版本的二进制包可能需要通过源码编译这些库比x86多一步。ARM上编译时间比x86长建议用make -j2或-j4更稳妥。别拿x86机器上编译好的PHP二进制直接拷到ARM机器绝大多数不能跑。5. 最后分享几点实战经验和建议编译安装PHP这件事我第一次做的时候也被各种依赖问题折磨了一天。后来养成一个习惯每次configure之前先把dnf groupinstall Development Tools装上再单独把上面列出的-devel包补齐。这一步能把一半的报错提前消灭掉。另一个经验是编译参数写进一个Shell脚本保存好。比如在/usr/local/src/build-php.sh里记录configure命令和依赖清单。操作系统升级、换机器、给同事复现环境时直接跑脚本不用每次重新回忆参数。我后来维护的多台PHP服务器都是通过对脚本的目录结构和配置路径统一管理升级PHP版本也就变成了“换源码包改版本号重跑脚本”这么简单。如果后续还需要安装Nginx、MySQL等组件建议把端口、运行用户、日志路径都提前规划好别等全部装完再发现用户冲突、目录权限互相影响。最后再提醒一点源码编译出来的PHP体积比较大生产环境一定要在部署前做一轮性能测试和opcache参数调整别装完直接扛线上流量。编译只是开始线上的事还在后面。
返回列表