介绍
SpiderMonkey是Firefox使用的脚本引擎,V8是Google Chrome使用的脚本引擎。这篇文章介绍了怎样在自己的C++程序中嵌入这两种脚本引擎,以及简单做了一些横向的对比。
编译
SpiderMonkey
SpiderMonkey支持1.0~1.8版本的JavaScript语法,包括ECMAScript,ECMA 263-3,以及Mozilla扩展,可选支持E4X
由于SpiderMonkey的makefile只支持GNU Make。为了便于编译,建议使用MSYS,请先准备好MSYS(http://www.mingw.org)
下载SpiderMonkey源代码(https://developer.mozilla.org/En/SpiderMonkey/1.8)
解压...
- 从“VC命令提示”进入控制台,然后进入到MSYS中,这样做的目的是为了让MSYS能使用VC的编译器。
- 在MSYS里,用cd命令进入到SpiderMonkey源代码目录中
- 输入make -f makefile.ref BUILD_OPT=1
这样就编译完成了,还算简单吧。
BUILD_OPT=1参数的作用是把SpiderMonkey编译成Release版本。
另外,默认是使用VC的运行库的(即使用-MD编译参数),如果不喜欢,可以修改src/confg目录下的*.mk文件(比如把-MD改成-MT)
对于MinGW用户,请参考这里http://jargon.ca/spidermonkey/编译
V8
不知道Google为什么把他们的脚本引擎称为V8,其宣称V8的速度远远超过SpiderMonkey,同样支持支持ECMAScript、ECMA-262-3。
下载V8源代码,需要安装SVN,命令是svn checkout http://v8.googlecode.com/svn/trunk/ v8
下载后解压...
可以在tools/visual_studio里找到工程文件,直接打开工程文件就可以编译了。
如果编译成功,可以无视下面这段。如果没搞定,请静下心来继续...
命令行编译方法
需要Python2.4以上版本(http://www.python.org )
安装scons(http://www.scons.org ),这是一个python的编译脚本软件,可以把它看作是“高级”一点的make。
- 进入“VC命令提示”
- 进入V8目录
- 设置Python路径 set path=c:/Python25;c:/Python25/Scripts;%path%
官方文档说到这一步输入scons就可以开始编译了
不过例外总是有的,比如我的VC2005就不行,一会儿说找不到cl命令,一会儿又找不到头文件-_-
我们得告诉它环境变量的值,这样写就可以了:
scons env="PATH:%path%,INCLUDE:%include%,LIB:%lib%"
默认是静态链接,静态VC库,可以这样修改编译参数
scons library=shared msvcrt=shared env=...
输入scons --help能看到更多编译参数
想在MinGW里编译,要到这里下个补丁才行:http://codereview.chromium.org/18309
注意:如果编译成动态库,使用时包含头文件v8.h之前应该先来一句 #define USING_V8_SHARED 1
对比
只是简单地比较一下脚本运行速度、脚本与宿主程序之间通信速度以及编程的简易程度。我想这也是C++编程人员关心的主要问题。
比较用的脚本:
这是一个从网上找来的计算Pi的JS脚本:
- mess="";
- Base=Math.pow(10,11);
- cellSize=Math.floor(Math.log(Base)/Math.LN10);
- a=Number.MAX_VALUE;
- MaxDiv=Math.floor(Math.sqrt(a));
- function makeArray (n, aX, Integer) {
- var i=0;
- for (i=1; i<n; i++)
- aX[i] = null;
- aX[0] = Integer;
- }
- function isEmpty (aX) {
- var empty=true
- for (i=0; i<aX.length; i++)
- if (aX[i])
- {
- empty= false;
- break;
- }
- return empty;
- }
- function Add (n, aX,aY) {
- carry=0
- for (i=n-1; i>=0; i--) {
- aX[i] += Number(aY[i])+Number(carry);
- if (aX[i]<Base)
- carry = 0;
- else {
- carry = 1;
- aX[i] =Number(aX[i])- Number(Base);
- }
- }
- }
- function Sub (n, aX,aY) {
- for (i=n-1; i>=0; i--) {
- aX[i] -= aY[i];
- if (aX[i]<0) {
- if (i>0) {
- aX[i] += Base;
- aX[i-1]--;
- }
- }
- }
- }
- function Mul (n, aX, iMult) {
- carry=0;
- for (i=n-1; i>=0; i--) {
- prod = (aX[i])*iMult;
- prod += carry;
- if (prod>=Base) {
- carry = Math.floor(prod/Base);
- prod -= (carry*Base);
- }
- else
- carry = 0;
- aX[i] = prod;
- }
- }
- function Div (n, aX, iDiv,aY) {
- carry=0;
- for (i=0; i<n; i++) {
-
- currVal = Number(aX[i])+Number(carry*Base);
-
- theDiv =Math.floor(currVal/iDiv);
-
- carry = currVal-theDiv*iDiv;
-
- aY[i] = theDiv;
- }
- }
- function arctan (iAng, n, aX) {
- iAng_squared=iAng*iAng;
- k=3;
- sign=0;
- makeArray (n, aX, 0);
- makeArray (n, aAngle, 1);
- Div (n, aAngle, iAng, aAngle);
- Add (n, aX, aAngle);
- while (!isEmpty(aAngle)) {
- Div (n, aAngle, iAng_squared, aAngle);
- Div (n, aAngle, k, aDivK);
- if (sign)
- Add (n, aX, aDivK);
- else Sub (n, aX, aDivK);
- k+=2;
- sign = 1-sign;
- }
- mess+="aArctan="+aArctan+"<br>";
- }
- function calcPI (numDec) {
- var ans="";
- t1=new Date();
- numDec=Number(numDec)+5;
- iAng=new Array(10);
- coeff=new Array(10);
- arrayLength=Math.ceil(1+numDec/cellSize);
- aPI = new Array(arrayLength);
- aArctan = new Array(arrayLength);
- aAngle=new Array(arrayLength);
- aDivK=new Array(arrayLength);
-
-
-
- coeff[0] = 4;
- coeff[1] = -1;
- coeff[2] = 0;
-
- iAng[0] = 5;
- iAng[1] = 239;
- iAng[2] = 0;
- makeArray (arrayLength, aPI, 0);
-
- makeArray(arrayLength,aAngle,0);
- makeArray(arrayLength,aDivK,0);
- for (var i=0; coeff[i]!=0; i++) {
- arctan(iAng[i], arrayLength, aArctan);
-
- Mul (arrayLength, aArctan, Math.abs(coeff[i]));
- if (coeff[i]>0)
- Add (arrayLength, aPI, aArctan);
- else
- Sub (arrayLength, aPI, aArctan);
- }
-
- Mul (arrayLength, aPI, 4);
-
-
- sPI="";
- tempPI="";
-
- for (i=0;i<aPI.length;i++)
- {
- aPI[i]=String(aPI[i]);
-
-
- if (aPI[i].length<cellSize&&i!=0)
- {
- while (aPI[i].length<cellSize)
- aPI[i]="0"+aPI[i];
- }
- tempPI+=aPI[i];
- }
-
- for (i=0;i<=numDec;i++)
- {
-
- if (i==0)
- sPI+=tempPI.charAt(i)+". ";
- else
- {
- if ((i)%50==0&&i!=0)
- sPI+=tempPI.charAt(i)+" ";
- else
- sPI+=tempPI.charAt(i);
- }
- }
-
-
- ans+=("PI ("+numDec+")="+sPI+" ");
-
- ans+=("Win PI= 3.1415926535897932384626433832795 ");
- t2=new Date();
- timeTaken=(t2.getTime()-t1.getTime())/1000;
- ans+="It took: "+timeTaken+" seconds";
- return ans;
-
- }
-
- myprint(calcPI(1000));
脚本与宿主程序之间通信速度测试脚本
- var c = new MyClass();
- t1=new Date();
-
- for(i=0; i<100000; i++)
- {
- c.push(i);
- c.pop();
- }
- t2=new Date();
- timeTaken=(t2.getTime()-t1.getTime())/1000;
- myprint("It took:",timeTaken,"seconds");
(未完待续)