◆ PHP で JavaScript を実行するライブラリ
◆ pecl でインストールすると v8 のファイル足りないとかでエラー
  ◆ v8-devel 等インストールしてもダメ
◆ 結局 v8 と v8js 両方を自分でコンパイルしていくことになった

PHP で JavaScript (V8) を使うライブラリ v8js を使ったときのメモ
雑すぎて自分でもよくわからない……けど実際にやってみればなんとなくこのことか ってわかりそうなので残しとく



公式サイトによると

> 要件
> PHP 5.3.3 以降、そして V8 のライブラリとヘッダを適切なパスにインストールしておかなければなりません

なのに 5.6 だと

[user@fedora]~% sudo pecl install v8js
pecl/v8js requires PHP (version >= 7.0), installed version is 5.6.29

7 が必要!

7.1 があったのでインスト

[user@fedora]~% phpbrew install 7.1
[user@fedora]~% phpbrew switch 7.1

初回インストはビルドに必要なものがないと色々エラーでるのでいわれたものの devel をインストする

sudo, dir phpbrewだと権限ある

autoconf, v8

https://github.com/phpv8/v8js/issues/216

glib2-devel



V8 5.6~ はこの手順みたい

# Install required dependencies
sudo apt-get install build-essential git python libglib2.0-dev

cd /tmp

# Install depot_tools first (needed for source checkout)
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=`pwd`/depot_tools:"$PATH"

# Download v8
fetch v8
cd v8

# (optional) If you'd like to build a certain version:
git checkout 5.6.326.12
gclient sync

# Setup GN
tools/dev/v8gen.py -vv x64.release
echo is_component_build = true >> out.gn/x64.release/args.gn

# Build
ninja -C out.gn/x64.release/

# Install to /opt/v8/
sudo mkdir -p /opt/v8/{lib,include}
sudo cp out.gn/x64.release/lib*.so out.gn/x64.release/*_blob.bin /opt/v8/lib/
sudo cp -R include/* /opt/v8/include/

gclient --force

gyp

ninja


libtinfo が見つからない場合

dnf provides */libtinfo.so.5
ncurses-compat-libs-6.0-6.20160709.fc25.i686 : Ncurses compatibility libraries
リポジトリ : fedora
ncurses-compat-libs-6.0-6.20160709.fc25.x86_64 : Ncurses compatibility libraries
リポジトリ : fedora

dnf install ncurses-compat-libs




使ってみる

[user@fedora]~/v8js% php -a
Interactive shell

php > new V8Js();
php > $v8->executeString('print("Ja" + "va" + `Script`)');
JavaScript

snapshot の処理から続行

$snapshot = V8Js::createSnapshot('
const a = 100
const obj = {x:1, y:2}
');

$v8 = new V8Js('PHP', [], [], true, $snapshot);
$v8->val = 10;
var_dump(
$v8->executeString('
obj.x += a + PHP.val
obj.y += a + PHP.val
obj
')
);
object(V8Object)#4 (2) {
["x"]=>
int(111)
["y"]=>
int(112)
}

グローバルオブジェクト

$snapshot = V8Js::createSnapshot('
const a = 100
const obj = {x:1, y:2}
');

$phpobj = new StdClass();
$phpobj->p = 1000;

$v8 = new V8Js('pphp', ['val' => 10], [], true, $snapshot);
$v8->prop = $phpobj;
var_dump($v8->executeString("(function(){return this})()"));
object(V8Object)#3 (6) {
["exit"]=>
object(V8Function)#4 (0) {
}
["sleep"]=>
object(V8Function)#5 (0) {
}
["print"]=>
object(V8Function)#6 (0) {
}
["var_dump"]=>
object(V8Function)#7 (0) {
}
["require"]=>
object(V8Function)#8 (0) {
}
["pphp"]=>
object(V8Js)#2 (1) {
["prop"]=>
object(stdClass)#1 (1) {
["p"]=>
int(1000)
}
}
}

グローバルに第一引数の名前のオブジェクトが作られ $v8 のプロパティが入る

snapshot 作るタイミングで実行されてる

$snapshot = V8Js::createSnapshot('
const date = new Date()
');

sleep(10);

$v8 = new V8Js('PHP', [], [], true, $snapshot);
var_dump($v8->executeString('[date.toJSON(), new Date().toJSON()]'));
array(2) {
[0]=>
string(24) "2016-12-19T10:00:26.112Z"
[1]=>
string(24) "2016-12-19T10:00:36.133Z"
}

toLocaleString

#
# Fatal error in , line 0
# Failed to create ICU date format, are ICU data files missing?
#

==== C stack trace ===============================

/opt/v8/lib/libv8_libbase.so(+0xf73e) [0x7fe90261773e]
/opt/v8/lib/libv8_libbase.so(V8_Fatal+0xdf) [0x7fe9026156ff]
/opt/v8/lib/libv8.so(+0x569070) [0x7fe8f6643070]
/opt/v8/lib/libv8.so(+0x723e32) [0x7fe8f67fde32]
[0x2edc718bcac2]



https://github.com/phpv8/v8js/commit/12ac47d695f0a52e9ac150260ea604c5d256891d

ReadMe が更新されてわかりやすくなってた
もう少し早かったらよかったのに

まとめ

sudo dnf install php python
sudo dnf install ncurses-compat-libs # fedora25 なら

fedora25 だと libtinfo がみつからないので ncurses の compat-libs を入れて対処
error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory


/tmp が 1G だと足りないみたい
fatal: write error: No space left on device

/ の容量がある /var/tmp にする

cd /var/tmp

v8 コンパイル


ソース準備

git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=`pwd`/depot_tools:"$PATH"
fetch v8
cd v8
git checkout 5.6.326.12
gclient sync

component 設定

[root@fedora v8]# tools/dev/v8gen.py -vv x64.release -- is_component_build=true
################################################################################
/usr/bin/python -u tools/mb/mb.py gen -f infra/mb/mb_config.pyl -m developer_default -b x64.release out.gn/x64.release

Writing """\
is_debug = false
target_cpu = "x64"
""" to /opt/v8/out.gn/x64.release/args.gn.

/opt/v8/buildtools/linux64/gn gen out.gn/x64.release --check
Done. Made 87 targets from 52 files in 239ms
################################################################################
Appending """
is_component_build=true
""" to /opt/v8/out.gn/x64.release/args.gn.


[root@fedora v8]# ninja -C out.gn/x64.release/
(1時間くらい)
[root@fedora v8]# mkdir -p /opt/v8/{lib,include}
[root@fedora v8]# cp out.gn/x64.release/lib*.so out.gn/x64.release/*_blob.bin /opt/v8/lib/
[root@fedora v8]# cp -R include/* /opt/v8/include/
[root@fedora v8]# tree /opt/v8/
/opt/v8/
├── include
│   ├── DEPS
│   ├── OWNERS
│   ├── libplatform
│   │   ├── DEPS
│   │   ├── libplatform-export.h
│   │   ├── libplatform.h
│   │   └── v8-tracing.h
│   ├── v8-debug.h
│   ├── v8-experimental.h
│   ├── v8-inspector-protocol.h
│   ├── v8-inspector.h
│   ├── v8-platform.h
│   ├── v8-profiler.h
│   ├── v8-testing.h
│   ├── v8-util.h
│   ├── v8-version.h
│   ├── v8.h
│   └── v8config.h
└── lib
├── libicui18n.so
├── libicuuc.so
├── libv8.so
├── libv8_libbase.so
├── libv8_libplatform.so
├── natives_blob.bin
└── snapshot_blob.bin

3 directories, 24 files

いらないの消す

[root@fedora v8]# rm -rf /var/tmp/v8/

v8js コンパイル


事前に必要なもの

dnf install php-devel # phpize のインスト
dnf install gcc-c++ # ↓のとおり

2 つ目はコマンドの 「./configure --with-v8js=/opt/v8」 で↓がでるなら必要
とりあえず入れておけば良いと思う

checking whether we are using the GNU C++ compiler... no
checking whether g++ accepts -g... no
checking how to run the C++ preprocessor... /lib/cpp
configure: error: in `/tmp/v8js':
configure: error: C++ preprocessor "/lib/cpp" fails sanity check

v8js をコンパイルするコマンド

cd /tmp
git clone https://github.com/phpv8/v8js.git
cd v8js
phpize
./configure --with-v8js=/opt/v8
make
make test
sudo make install

インストール後に extension に追加する

[root@fedora v8js]# make install
Installing shared extensions: /usr/lib64/php/modules/

[root@fedora ~]# micro /etc/php.d/20-v8js.ini
[root@fedora ~]# cat /etc/php.d/20-v8js.ini
; Enable v8js extension module
extension=v8js.so

php > $v8 = new V8Js();
php > $v8->executeString("var a = 10");
php > $v8->executeString("print(a)");
10

php > V8
V8Function V8JsException V8JsTimeLimitException
V8Generator V8JsMemoryLimitException V8Object
V8Js V8JsScriptException

php > $v8 = new V8Js();
php > var_dump($v8->executeString('{a:1}'));
int(1)
php > $v8 = new V8Js();
php > var_dump($v8->executeString('({a:1})'));
object(V8Object)#1 (1) {
["a"]=>
int(1)
}

php > echo V8Js::V8_VERSION;
5.6.326.12

php > var_dump($v8->executeString('({function: a=>b,generatorfn:function*(){}})'));
object(V8Object)#1 (2) {
["function"]=>
object(V8Function)#3 (0) {
}
["generatorfn"]=>
object(V8Function)#4 (0) {
}
}

php > var_dump($v8->executeString('({function: a=>b,generator:(function*(){})()})'));
object(V8Object)#1 (2) {
["function"]=>
object(V8Function)#4 (0) {
}
["generator"]=>
object(V8Generator)#3 (0) {
}
}