PHP编译器BPC6.4发布,成功编译webman,二进制打包源码保护软件授权All in One!

heguangyu5

不了解BPC是什么的可以翻看之前的 几个分享,也可以翻阅 知乎专栏 或者 v2ex 了解更多.

简言之,BPC可以将PHP代码最终转译成C语言,然后编译成动态链接库或者可执行程序,实现 PHP Native AOT!

how BPC works

0. 前置说明

本文所述的所有操作都是在 Ubuntu 18.04 amd64 上完成的,但这并不是说BPC只能在 Ubuntu 18.04 上运行.

BPC编译器自身已验证过可以在 Ubuntu 18.04 / 20. 04 / 22.04 上运行,编译结果还可以在 Debian 12 上运行, 参看 wordpress的例子.

1. 快速体验二进制版的webman

  1. 下载编译好的二进制文件 start

  2. 加上可执行权限 chmod +x start

  3. 运行 mkdir /tmp/x && mv start /tmp/x && cd /tmp/x && ./start start

  4. 另外打开一个终端

    ~$ tree /tmp/x/
    /tmp/x/
    ├── runtime
    │   ├── logs
    │   │   └── workerman.log
    │   ├── views
    │   └── webman.pid
    └── start
    
    3 directories, 3 files
  5. 访问以下url查看效果

2. 亲自动手编译webman

  1. 参看文档下载安装 BPC

    ~$ bpc
    bpc/6.4.0
    Usage: bpc [options] <input-files> [-- script args]
    see bpc -h for help with command line options
  2. 下载安装phptobpc 来解决BPC不支持的语法特性

    phptobpc就是个phar文件,下载回来后加上可执行权限,放到 ~/bin/ 或者 /usr/local/bin/ 目录下即可.

    由于是phar文件,当然需要php解释器,sudo apt install php-cli 即可.

    ~$ phptobpc 
    Usage: php phptobpc.php file.php
  3. 参照以下 git repo README.md 开头的 BPC Notes 编译安装webman依赖

    1. psr-log-1.1.4
    2. psr-container-2.0.1
    3. nikic-fast-route-1.3.0
    4. monolog-2.x-branch
    5. workerman-4.1-branch
    6. webman-framework

    结果如下:

    ~$ 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
  4. 编译运行webman

注意: 需要完成1,2,3步才能进行这一步.

```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.
```

4. 关于webman代码调整的说明

webman-framework 详见 git commits

  1. src/App.php 不支持依赖注入

    依赖注入需要获取到callback或者controller每个method的参数的详细信息,BPC目前不提供这些信息,所以依赖注入部分的代码都给注释掉了, @see src/App.php#L322

  2. src/Context.php 简化实现

    BPC尚未实现SplObjectStorage, 所以临时使用一个array替代了原来的代码

    BPC6.5已实现SplObjectStorage,此修改已rollback

  3. src/support/App.php Worker::$eventLoopClass 固定为 \Workerman\Events\Event, 不可配置

  4. src/App.php::getController() 要求目录及文件名全部小写.

    编译成二进制后,目录和文件的概念都没有了,所以也就不能scanDir了,根据url找到controller的逻辑必须固定下来,不能scanDir+strtolower来实现.

    Controller的文件名可以大写,bpc-prepare.sh会将文件名转成小写.

  5. src/Config.php src/Route.php src/support/App.php 和第4点一样,由于不能scanDir,config文件必须想个办法明确列出来.

webman 详见 git commits

  1. support/helpers.php 定义了一个常量 BASE_PATH_REAL 用于当需要读写硬盘文件时用
  2. config/view.php 编译时为了区分静态资源文件(css/js/html/图片等)和view文件, 将view_suffix 配置为 phtml
  3. vendor/autoload.php BPC不需要composer,所以需要一个手写的 autoloader.php

5. 下一步: 如何编译我自己的项目?

参看 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

将你项目的外部依赖像 psr-log/container, fastroute, monolog 等一样,编译成 .so/.a, 然后通过参数 -u YOUR_LIB link进来, 然后把项目自身的静态资源和php文件加到src.list里编译就好了.

6. 关于BPC不支持的语法特性和扩展怎么解决?

等待BPC升级新版本.

翻阅过之前文章的网友应该知道,BPC并不是我们公司的主营业务,它最初是为了解决云招OurATS招聘管理系统本地部署而生的一个 side project ,目前OurATS自身的需求已经完善解决,所以BPC目前处在稳定期,更新和维护要看OurATS的需求来进行,请大家期望不要太高.

确实有需求的网友可以在公司层面和我们进行深度合作,我们乐意提供相应的技术支持.

语法特性涉及到BPC编译器的核心部分,因此实现起来一般不会很快,所以能用phptobpc解决的,可以用phptobpc解决.

php扩展开发较为容易,简单的几天可以开发一个,复杂的需要几周时间,比如开发 event(core) 扩展用了3天,开发 mysqli 扩展用了2周.

目前BPC有3个大的特性尚未实现,提前知悉以免白忙一场:

  1. trait

    简单的trait就相当于copy paste, monolog-2.x里有用到几个trait,就是通过代码替换完成编译的.

  2. class typed properties

    BPC 支持 function/method type hints,但不支持 return type (可通过phptobpc去掉).

  3. Generator / Fiber

7. 如何保障编译后的程序运行没问题?

PHPUnit.

我们维护着一个BPC可编译的phpunit版本: bpc-phpunit.phar-4.8.36.

使用php运行phpunit tests没问题,然后再用bpc编译运行这些tests还没问题,那就是没问题.

nikic-fast-route-1.3.0monolog-2.x-branch 的 phpunit tests 就是使用 bpc-phpunit.phar-4.8.36 跑过的,所以可以确保没问题.

另外,我们也有一本收费的电子书 《PHPUnit in Action --- The Easy Way》 介绍了云招OurATS 10多年来的测试心得,有需要的可以看看.

8. 关于软件授权

这里说的软件授权不是BPC编译器自身的license,而是你自己项目的授权.

比如你自己的项目中可能会有如下授权检测代码:

if (/* 没有通过授权检测 */) {
    die('请购买授权后再使用');
}

BPC的解决方案是在生成的scheme代码中随机插入授权检测代码,数量可由一个参数控制,通过插入足够多的授权检测(比如10万个)来增加破解时间,简单粗暴.

请参看文档 06_Licensing

9. BPC Playground

https://bpc.dev 上可以在线试用BPC编译器, 已内置了一些示例项目代码, 欢迎大家试玩儿~

BPC Playground

10. 关于性能

BPC的出发点在于源码保护和软件授权,因此对性能没那么在意,也没有做什么编译优化.

这里感谢网友 kspade 提供的性能测试结果,供大家参考,编译后较PHP还是有很大差距.

BPC ./start

PHP 8.0

11. 关于扩展

为了减小最终生成的二进制大小, bpc-webman//bpc.conf 里仅包含了webman用到的扩展.

BPC已实现的扩展列表见这里 bpc-php-7.2.19-tests.

还有几个扩展仅实现了一小部分函数,并且没有过phpt测试,未列出,比如 gd imagick zlib sysvsem等,这些在 bpc-release 的 tar.gz 里可以找到.

1672 8 7
8个评论

Tinywan

支持!

  • 暂无评论
walkor

太牛了

  • 暂无评论
JackDx

关注

  • 暂无评论
kspade

centos 测试失败提示:

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 查看发现已安装

libargon2.so.1 (libc6,x86-64) => /lib64/libargon2.so.1

但是仍然报错:把/lib64/libargon2.so.1 复制1个改名为:libargon2.so.0

然后运行成功

Debian 11.1 64bit 测试报错

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

安装后测试成功

  • kspade 2023-10-08

    最后我进行打包自己的webman 项目。不行嗷嗷报错,太多错误了。

    或许是我打包姿势不对,但是我看了一下 很多我使用的扩展都没有支持 因此放弃了,而且翻阅了文档似乎无法将指定目录或者文件不打包操作,

  • heguangyu5 2023-10-08

    实际上libargon2是可以link .a的,只是ubuntu下默认系统都已经安装了,所以没有加上.

    编译时可以修改 bpc.conf 的 ldflags 调整link选项, https://github.com/heguangyu5/bpc-webman/blob/ca9680d9cd4372f512cebff12f9cb191bb830454/bpc.conf#L26

    之前在编译wordpress时尝试过centos7,发现它的libc版本太低了,然后就没再试了,你的centos是哪个版本的?

    ubuntu 22.04下编译好的可以直接放到debian 12上运行,没问题,其它的没试过 .

  • heguangyu5 2023-10-08

    具体要编译哪些文件是要明确列出来的,也就是白名单,不是黑名单.

    扩展不支持一般问题不大,确有需要开发就是了.

  • kspade 2023-10-08

    centos7.9
    centos8.2
    CentOS Stream 9
    Ubuntu 22.04.3 LTS
    Debian 11.1
    均测试了 不行 报一样错误

  • kspade 2023-10-08

    当然安装一下就解决了,只不过这不是很友好

  • heguangyu5 2023-10-08

    bpc-release里发的编译器也是针对 ubuntu 18.04 的,要想上22.04上正确运行,需要发一个22.04版本的BPC编译器,然后再编译就好了.

  • heguangyu5 2023-10-08

    但目前我们自己用的情况下,就锁定 ubuntu 18.04 了.

  • kspade 2023-10-08

    如果局限于指定系统平台 以及版本 那就很难受了

Jinson

大佬,收藏了

  • 暂无评论
mofei

赞个👍🏻,一般性能够用了!

  • 暂无评论
shiyun

收藏、关注👍

  • 暂无评论
掌柜

大佬,这个性能相对于传统的fpm相比如何?

  • heguangyu5 2023-11-27

    BPC不是为性能而生的,如果是追求性能的项目就不用考虑了.

    以 wordpress 为例, ab测试 apache2 + php 8.1 101 req/s, BPC althttpd 37 req/s.

  • 掌柜 2023-11-27

    感谢解答

heguangyu5

1540
积分
0
获赞数
0
粉丝数
2022-11-24 加入
🔝