V8

V8をソースコードからビルドしてみるテスト。

V8のビルドにはdepot_toolsが必要なのであらかじめcloneしておく。

1
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

cloneしたディレクトリをPATHに追加しておく。下記のコマンドが動作すればOK。

1
$ gclient

続いてV8のソースコードをcloneする。

1
$ git clone https://chromium.googlesource.com/v8/v8.git

V8のディレクトリに移動し、

1
$ gclient sync

を実行する。あとはmakeするだけなのだが、コンパイラにclangを使うにはあらかじめ次のように設定しておく。

1
2
3
4
5
6
7
8
9
export CXX=`which clang++`
export CC=`which clang`
export CPP="`which clang` -E"
export LINK=`which clang++`
export CXX_host=`which clang++`
export CC_host=`which clang`
export CPP_host="`which clang` -E"
export LINK_host=`which clang++`
export GYP_DEFINES="clang=1"

以上の準備が整ったところで、あとは

1
$ make native

でビルドが始まる。makeのターゲットにnativeを指定すると、ホストマシンのアーキテクチャをターゲットとしたリリースビルドが指定される。手もとのMacBook Proで大体25分くらいで完了した。結果はoutディレクトリに出力されており、例えばout/native/shellを実行するとV8を組み込んだサンプルシェルが起動する。

1
2
3
$ out/native/shell
V8 version 3.32.0 (candidate) [sample shell]
>

以上の手順含め詳細は下記サイトに説明がある。

BuildingWithGYP

Atom Shell で Hello world

Atom Shell を使っておそらく本来の使われ方ではないプログラムを作成してみる。以下のような Node.js プログラムを普通に実行することができる模様。

hello.js
1
2
console.log("hello, world");
process.exit(0);

最後の process.exit(0) を書かないとプロセスが終了しない。 実行するときは引数に JavaScript ファイルを指定すればよい。

実行結果
1
2
$ ./out/Release/Atom.app/Contents/MacOS/Atom hello.js
hello, world

require でロードしたモジュールも普通に使うことができる。

cpus.js
1
2
3
var os = require('os');
console.log(os.cpus());
process.exit(0);
実行結果
1
2
3
4
5
6
7
8
9
10
11
12
13
$ ./out/Release/Atom.app/Contents/MacOS/Atom cpus.js
[ { model: 'Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz',
speed: 1700,
times: { user: 4692350, nice: 0, sys: 3321620, idle: 38701300, irq: 0 } },
{ model: 'Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz',
speed: 1700,
times: { user: 2480960, nice: 0, sys: 1154690, idle: 43077500, irq: 0 } },
{ model: 'Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz',
speed: 1700,
times: { user: 4196740, nice: 0, sys: 2200760, idle: 40315740, irq: 0 } },
{ model: 'Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz',
speed: 1700,
times: { user: 2333780, nice: 0, sys: 1036880, idle: 43342400, irq: 0 } } ]

本来のデスクトップアプリケーションを目的としたプログラムのチュートリアルは下記ドキュメントにある。

ちょっと試してみたけど、main.js から HTML の DOM を操作することはできないんだろうか。よくわからない…。

Atom Shell をビルドする

GitHub が最近オープンソースで公開した Atom というエディタが話題になっているが、それに使われているフレームワークが Atom Shell というものらしい。GitHub の README.md によると JavaScript や HTML や CSS といった Web テクノロジでクロスプラットフォームなデスクトップアプリケーションが作れるフレームワークなのだそうだ。以前から Microsoft Windows でも HTA (HTML Application) という HTML + JScript/VBScript でデスクトップアプリケーションが作れる技術があったが、あのノリなのかもしれない。もっとも HTA は Internet Explorer 限定だったけど。

試しにソースコードを clone してビルドしてみる。とはいってもドキュメントの通りに進めるだけだった。まずはソースツリーを clone する。

1
2
$ git clone https://github.com/atom/atom-shell.git
$ cd atom-shell

ビルドに必要なものはすべて bootstrap.py を実行することでそろえてくれるようだ。

1
$ ./script/bootstrap.py

あとは build.py を実行するだけ。

1
$ ./script/build.py

最後に test.py を実行して完了!

1
$ cd ./script/test.py

out/Release/Atom.app/Contents/MacOS/Atom に実行ファイルが生成される。

グローバル変数をクロージャで包む

暇つぶしにリーダブルコードを読んでいたら、JavaScript のコードでグローバル変数で名前空間を汚染しないようにするために、クロージャを利用する例が掲載されていた。クロージャの使い方としてこれは知らなかったのでなるほどと感心してしまった。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var closure = (function () {
var is_called = false;
return function (name) {
if (!is_called) {
console.log("first call with " + name);
is_called = true;
}
else {
console.log("finished");
}
};
}());
closure("foo")
closure("foo")
closure("foo")

ある関数が複数回呼ばれたときに最初の一回のみ関数を実行したい場合、クロージャを使わないなら is_called というグローバル変数で一回目のコールかどうかを管理する。この例はそのグローバル変数をクロージャで包んで外部の名前空間に流出しないようにしている。

実行結果
1
2
3
first call with foo
finished
finished

Common Lisp で書いてみるとこんな感じ。

1
2
3
4
5
6
7
8
9
10
11
12
13
(defparameter *closure* nil)
(setf *closure* (let ((is-called nil))
#'(lambda (name)
(cond ((null is-called)
(format t "first called with ~a~%" name)
(setf is-called t))
(t
(format t "finished~%"))))))
(funcall *closure* "foo")
(funcall *closure* "foo")
(funcall *closure* "foo")