不了解BPC是什么的可以翻看之前的 幾個(gè)分享,也可以翻閱 知乎專欄 或者 v2ex 了解更多.
簡言之,BPC可以將PHP代碼最終轉(zhuǎn)譯成C語言,然后編譯成動(dòng)態(tài)鏈接庫或者可執(zhí)行程序,實(shí)現(xiàn) PHP Native AOT!
本文所述的所有操作都是在 Ubuntu 18.04 amd64 上完成的,但這并不是說BPC只能在 Ubuntu 18.04 上運(yùn)行.
BPC編譯器自身已驗(yàn)證過可以在 Ubuntu 18.04 / 20. 04 / 22.04 上運(yùn)行,編譯結(jié)果還可以在 Debian 12 上運(yùn)行, 參看 wordpress的例子.
下載編譯好的二進(jìn)制文件 start
加上可執(zhí)行權(quán)限 chmod +x start
運(yùn)行 mkdir /tmp/x && mv start /tmp/x && cd /tmp/x && ./start start
另外打開一個(gè)終端
~$ tree /tmp/x/
/tmp/x/
├── runtime
│?? ├── logs
│?? │?? └── workerman.log
│?? ├── views
│?? └── webman.pid
└── start
3 directories, 3 files
訪問以下url查看效果
~$ bpc
bpc/6.4.0
Usage: bpc [options] <input-files> [-- script args]
see bpc -h for help with command line options
下載安裝phptobpc 來解決BPC不支持的語法特性
phptobpc就是個(gè)phar文件,下載回來后加上可執(zhí)行權(quán)限,放到 ~/bin/
或者 /usr/local/bin/
目錄下即可.
由于是phar文件,當(dāng)然需要php解釋器,sudo apt install php-cli
即可.
~$ phptobpc
Usage: php phptobpc.php file.php
參照以下 git repo README.md 開頭的 BPC Notes 編譯安裝webman依賴
結(jié)果如下:
~$ cd /usr/local/lib/
/usr/local/lib$ ls *psr*
libpsr-container_u-4.4a.a libpsr-log_u-4.4a.a psr-container.heap psr-log.heap
libpsr-container_u-4.4a.so libpsr-log_u-4.4a.so psr-container.sch psr-log.sch
/usr/local/lib$ ls *fastroute*
fastroute.heap fastroute.sch libfastroute_u-4.4a.a libfastroute_u-4.4a.so
/usr/local/lib$ ls *monolog*
libmonolog_u-4.4a.a libmonolog_u-4.4a.so monolog.heap monolog.sch
/usr/local/lib$ ls *workerman*
libworkerman_u-4.4a.a libworkerman_u-4.4a.so workerman.heap workerman.sch
/usr/local/lib$ ls *webman*
libwebman_u-4.4a.a libwebman_u-4.4a.so webman.heap webman.sch
注意: 需要完成1,2,3步才能進(jìn)行這一步.
```shell
~$ git clone git@github.com:heguangyu5/bpc-webman.git
~$ cd bpc-webman/
~/bpc-webman$ make
...
output prologue
generate main.c
generate build.ninja
run ninja
[34/34] link ../start (statically linked)
mv start ../
make[1]: Leaving directory '~/bpc-webman/build'
~/bpc-webman$ ./start start
Workerman[./start] start in DEBUG mode
--------------------------------------------- WORKERMAN ----------------------------------------------
Workerman version:4.1.10 PHP version:7.2.19-bpc Event-Loop:\Workerman\Events\Event
---------------------------------------------- WORKERS -----------------------------------------------
proto user worker listen processes status
tcp hgy webman http://0.0.0.0:8787 16 [OK]
------------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.
```
webman-framework 詳見 git commits
src/App.php
不支持依賴注入
依賴注入需要獲取到callback或者controller每個(gè)method的參數(shù)的詳細(xì)信息,BPC目前不提供這些信息,所以依賴注入部分的代碼都給注釋掉了, @see src/App.php#L322
src/Context.php
簡化實(shí)現(xiàn)
BPC尚未實(shí)現(xiàn)SplObjectStorage
, 所以臨時(shí)使用一個(gè)array
替代了原來的代碼
BPC6.5已實(shí)現(xiàn)SplObjectStorage
,此修改已rollback
src/support/App.php
Worker::$eventLoopClass
固定為 \Workerman\Events\Event
, 不可配置
src/App.php::getController()
要求目錄及文件名全部小寫.
編譯成二進(jìn)制后,目錄和文件的概念都沒有了,所以也就不能scanDir了,根據(jù)url找到controller的邏輯必須固定下來,不能scanDir+strtolower來實(shí)現(xiàn).
Controller的文件名可以大寫,bpc-prepare.sh
會(huì)將文件名轉(zhuǎn)成小寫.
src/Config.php
src/Route.php
src/support/App.php
和第4點(diǎn)一樣,由于不能scanDir,config文件必須想個(gè)辦法明確列出來.
webman 詳見 git commits
support/helpers.php
定義了一個(gè)常量 BASE_PATH_REAL
用于當(dāng)需要讀寫硬盤文件時(shí)用 config/view.php
編譯時(shí)為了區(qū)分靜態(tài)資源文件(css/js/html/圖片等)和view文件, 將view_suffix
配置為 phtml
vendor/autoload.php
BPC不需要composer,所以需要一個(gè)手寫的 autoloader.php
參看 webman Makefile 里的編譯命令:
bpc -v \
--static \
-c bpc.conf \
-u psr-log \
-u psr-container \
-u fastroute \
-u monolog \
-u workerman \
-u webman \
-d display_errors=on \
--input-file src.list
將你項(xiàng)目的外部依賴像 psr-log/container, fastroute, monolog 等一樣,編譯成 .so/.a, 然后通過參數(shù) -u YOUR_LIB
link進(jìn)來, 然后把項(xiàng)目自身的靜態(tài)資源和php文件加到src.list
里編譯就好了.
等待BPC升級新版本.
翻閱過之前文章的網(wǎng)友應(yīng)該知道,BPC并不是我們公司的主營業(yè)務(wù),它最初是為了解決云招OurATS招聘管理系統(tǒng)本地部署而生的一個(gè) side project ,目前OurATS自身的需求已經(jīng)完善解決,所以BPC目前處在穩(wěn)定期,更新和維護(hù)要看OurATS的需求來進(jìn)行,請大家期望不要太高.
確實(shí)有需求的網(wǎng)友可以在公司層面和我們進(jìn)行深度合作,我們樂意提供相應(yīng)的技術(shù)支持.
語法特性涉及到BPC編譯器的核心部分,因此實(shí)現(xiàn)起來一般不會(huì)很快,所以能用phptobpc解決的,可以用phptobpc解決.
php擴(kuò)展開發(fā)較為容易,簡單的幾天可以開發(fā)一個(gè),復(fù)雜的需要幾周時(shí)間,比如開發(fā) event(core) 擴(kuò)展用了3天,開發(fā) mysqli 擴(kuò)展用了2周.
目前BPC有3個(gè)大的特性尚未實(shí)現(xiàn),提前知悉以免白忙一場:
trait
簡單的trait就相當(dāng)于copy paste, monolog-2.x里有用到幾個(gè)trait,就是通過代碼替換完成編譯的.
class typed properties
BPC 支持 function/method type hints,但不支持 return type (可通過phptobpc去掉).
Generator / Fiber
PHPUnit.
我們維護(hù)著一個(gè)BPC可編譯的phpunit版本: bpc-phpunit.phar-4.8.36.
使用php運(yùn)行phpunit tests沒問題,然后再用bpc編譯運(yùn)行這些tests還沒問題,那就是沒問題.
nikic-fast-route-1.3.0 和 monolog-2.x-branch 的 phpunit tests 就是使用 bpc-phpunit.phar-4.8.36 跑過的,所以可以確保沒問題.
另外,我們也有一本收費(fèi)的電子書 《PHPUnit in Action --- The Easy Way》 介紹了云招OurATS 10多年來的測試心得,有需要的可以看看.
這里說的軟件授權(quán)不是BPC編譯器自身的license,而是你自己項(xiàng)目的授權(quán).
比如你自己的項(xiàng)目中可能會(huì)有如下授權(quán)檢測代碼:
if (/* 沒有通過授權(quán)檢測 */) {
die('請購買授權(quán)后再使用');
}
BPC的解決方案是在生成的scheme代碼中隨機(jī)插入授權(quán)檢測代碼,數(shù)量可由一個(gè)參數(shù)控制,通過插入足夠多的授權(quán)檢測(比如10萬個(gè))來增加破解時(shí)間,簡單粗暴.
請參看文檔 06_Licensing
在 https://bpc.dev 上可以在線試用BPC編譯器, 已內(nèi)置了一些示例項(xiàng)目代碼, 歡迎大家試玩兒~
BPC的出發(fā)點(diǎn)在于源碼保護(hù)和軟件授權(quán),因此對性能沒那么在意,也沒有做什么編譯優(yōu)化.
這里感謝網(wǎng)友 kspade 提供的性能測試結(jié)果,供大家參考,編譯后較PHP還是有很大差距.
BPC ./start
PHP 8.0
為了減小最終生成的二進(jìn)制大小, bpc-webman//bpc.conf 里僅包含了webman用到的擴(kuò)展.
BPC已實(shí)現(xiàn)的擴(kuò)展列表見這里 bpc-php-7.2.19-tests.
還有幾個(gè)擴(kuò)展僅實(shí)現(xiàn)了一小部分函數(shù),并且沒有過phpt測試,未列出,比如 gd imagick zlib sysvsem等,這些在 bpc-release 的 tar.gz 里可以找到.
error while loading shared libraries: libargon2.so.0: cannot open shared object file: No such file or directory
解決辦法安裝
yum install epel-release
sudo yum install libargon2
然后:ldconfig -p | grep libargon2 查看發(fā)現(xiàn)已安裝
libargon2.so.1 (libc6,x86-64) => /lib64/libargon2.so.1
但是仍然報(bào)錯(cuò):把/lib64/libargon2.so.1 復(fù)制1個(gè)改名為:libargon2.so.0
然后運(yùn)行成功
error while loading shared libraries: libargon2.so.0: cannot open shared object file: No such file or directory
解決辦法安裝libargon2-0:
sudo apt-get install libargon2-0
安裝后測試成功
或許是我打包姿勢不對,但是我看了一下 很多我使用的擴(kuò)展都沒有支持 因此放棄了,而且翻閱了文檔似乎無法將指定目錄或者文件不打包操作,
實(shí)際上libargon2是可以link .a的,只是ubuntu下默認(rèn)系統(tǒng)都已經(jīng)安裝了,所以沒有加上.
編譯時(shí)可以修改 bpc.conf 的 ldflags 調(diào)整link選項(xiàng), https://github.com/heguangyu5/bpc-webman/blob/ca9680d9cd4372f512cebff12f9cb191bb830454/bpc.conf#L26
之前在編譯wordpress時(shí)嘗試過centos7,發(fā)現(xiàn)它的libc版本太低了,然后就沒再試了,你的centos是哪個(gè)版本的?
ubuntu 22.04下編譯好的可以直接放到debian 12上運(yùn)行,沒問題,其它的沒試過 .
centos7.9
centos8.2
CentOS Stream 9
Ubuntu 22.04.3 LTS
Debian 11.1
均測試了 不行 報(bào)一樣錯(cuò)誤
bpc-release里發(fā)的編譯器也是針對 ubuntu 18.04 的,要想上22.04上正確運(yùn)行,需要發(fā)一個(gè)22.04版本的BPC編譯器,然后再編譯就好了.
大佬,這個(gè)性能相對于傳統(tǒng)的fpm相比如何?
BPC不是為性能而生的,如果是追求性能的項(xiàng)目就不用考慮了.
以 wordpress 為例, ab測試 apache2 + php 8.1 101 req/s, BPC althttpd 37 req/s.
支持!