当前位置: 首页 > news >正文

尝试MuJS

目录

前言

正文

安装

运行

看看官网案例——Hello, world!

看看案例中使用的函数的含义

js_newstate

js_newcfunction

js_setglobal

js_dostring

总体流程

看看官网案例——Configuration file

看看函数含义

js_dofile

js_getglobal就不必细说了

js_tonumber

读取前面的index.js

自定义console

下一个案例——Object manipulation

js_setproperty函数


前言

看到油管上一位大佬使用MuJS,简单来试试,学习一下。

MuJS is a lightweight Javascript interpreter designed for embedding in other software to extend them with scripting capabilities.

视频网址如下,如果能访问到。

https://www.youtube.com/watch?v=4kuxeEnFVYw&list=PLpM-Dvs8t0VYMyfbX11yAd7VAHPILM0kvhttps://www.youtube.com/watch?v=4kuxeEnFVYw&list=PLpM-Dvs8t0VYMyfbX11yAd7VAHPILM0kv

MuJS下载网址。

Index of /downloadshttps://mujs.com/downloads/

MuJShttps://mujs.com/

对于环境,笔者其实很少使用linux,但是笔者windows中有wsl,就在wsl中使用

正文

安装

下载mujs-1.3.7.tar.gz,即

wget https://mujs.com/downloads/mujs-1.3.7.tar.gz

解压

tar -xzvf mujs-1.3.7.tar.gz

进入mujs-1.3.7目录,使用make构建

make

如果构建失败,很可能是网络问题。

在build/debug目录下,生成了三个文件

libmujs.o  mujs  mujs-pp

因为MuJS 只实现ECMA-262,直白的说,mujs可以看成一个ES5引擎。没有let之类的的东西。

运行

在mujs-1.3.7目录下新建一个test目录,然后在其中创建一个js文件

vim index.js

内容如下

let a=1;
let b=2;
console.log(a+b);

运行,结果如下

/mujs-1.3.7/test$ ../build/debug/mujs ./index.js
SyntaxError: ./index.js:1: unexpected token: (identifier) (expected ';')

报错。

修改文件内容

var a=1;
var b=2;
console.log(a+b);

没问题

/mujs-1.3.7/test$ ../build/debug/mujs ./index.js
3

看看官网案例——Hello, world!

在test目录下新建一个test.c文件,其中内容如下

#include <stdio.h>
#include <mujs.h>static void hello(js_State *J)
{const char *name = js_tostring(J, 1);printf("Hello, %s!\n", name);js_pushundefined(J);
}int main(int argc, char **argv)
{js_State *J = js_newstate(NULL, NULL, JS_STRICT);js_newcfunction(J, hello, "hello", 1);js_setglobal(J, "hello");js_dostring(J, "hello('world');");js_freestate(J);
}

这是官网的案例,具体含义先不慌,该如何运行这个test.c文件,

可以使用gcc编译。同时考虑到位置是在test目录下,结合前面的内容,因此,编译命令如下

gcc -I.. test.c ../build/debug/libmujs.o -o test -lm
片段含义
gcc调用 GNU 编译器集合。
-I..把上一级目录(..)加入头文件搜索路径,使 #include <mujs.h> 能找到。
test.c要编译的源文件。
../build/debug/libmujs.o已经编译好的 MuJS 目标文件,里面包含了 js_newstatejs_dostring 等函数的实现。
-o test指定输出可执行文件名叫 test
-lm链接数学库。

结果如下

/mujs-1.3.7/test$ gcc -I.. test.c ../build/debug/libmujs.o -o test -lm
/mujs-1.3.7/test$ ./test
Hello, world!

打印了hello world,没问题。

看看案例中使用的函数的含义

js_newstate

首先,先在mujs-1.3.7目录下搜索一下关于这个函数的定义

 grep -rn js_newst

...

mujs.h:52:js_State *js_newstate(js_Alloc alloc, void *actx, int flags);

...

可以发现其中的定义在mujs.h中,且在52行

进去看看,可以发现一些东西

js_State * js_newstate(js_Alloc alloc, void *context, int flags)

/* State constructor flags */
enum {
        JS_STRICT = 1,
};

根据英文意思,大致可以猜测参数的意思。

参数说明
alloc内存分配器
context给分配器携带的用户数据
flags ES5 的模式。

总之,说白了,这就是一个new,初始化

js_newcfunction

位置如下

mujs.h:175:void js_newcfunction(js_State *J, js_CFunction fun, const char *name, int length);

参数意思如下

参数含义
J解释器实例。
funC 函数指针,必须符合签名 void fun(js_State *J)
name函数名。
length形参个数,传 0 表示“可变参数”,1 就告诉 MuJS 这个函数期望 1 个实参。

说白了,“C 函数 → JS 函数

js_setglobal

mujs.h:140:void js_setglobal(js_State *J, const char *name);

参数意思如下

参数含义
J解释器实例。
name全局变量名。

说白了,将注册的函数变成全局的

js_dostring

mujs.h:60:int js_dostring(js_State *J, const char *source);

参数含义
J解释器实例。
sourceJS 源码字符串

说白了,执行js

总体流程

了解了几个函数的意思,大致明白代码在干什么了。

首先,自定义一个c语言函数

然后,变成js函数,

接着,注册成全局函数,

最后,执行。

哈哈哈哈,这个过程有点熟悉,和Webassembly类似。当然,二者还是不一样。

项目本质常见用途
MuJS一个 轻量级 JavaScript 解释器(C 库)。在 C/C++、嵌入式、桌面、服务端 脚本化,类似 Lua。
WebAssembly一种 低级字节码格式(不是语言)。让 C/C++/Rust 等代码以接近原生速度在 浏览器 或 Node.js 里运行。

看看官网案例——Configuration file

js_dofile(J, "config.js")js_getglobal(J, "foo");
foo = js_tonumber(J, -1);
js_pop(J, 1);

从名字中,可以大致明白,应该是读取js文件,获取全局,转化成c变量,弹出栈顶。

表示疑惑???修改一些东西,运行一下再说

在test目录下新建file.c和config.js文件。

其中file.c的内容如下

#include<stdio.h>
#include<mujs.h>
int main(void){js_State *J = js_newstate(NULL, NULL, 0);int res=js_dofile(J, "config.js");printf("res = %d\n",res);js_getglobal(J, "foo");double foo = js_tonumber(J, -1);js_pop(J, 1);printf("foo = %.0f\n", foo);
}

其中config.js的内容如下

var foo=10;

编译并运行

/mujs-1.3.7/test$ gcc -I.. file.c ../build/debug/libmujs.o -o file -lm
/mujs-1.3.7/test$ ./file
res = 0
foo = 10

没问题。

看看函数含义

js_dofile

mujs.h:61:int js_dofile(js_State *J, const char *filename);

参数说明
J解释器实例。
filename待执行的 .js 文件路径。

这个js_dofile包含“读文件 → 编译 → 执行” 。

返回值是int,说明可以知道执行的结果,从上面看来,0是成功了,1就是失败的

js_getglobal就不必细说了

js_tonumber

mujs.h:205:double js_tonumber(js_State *J, int idx);

具体含义

参数含义
J解释器实例。
idx栈索引(正数从底往上,负数从顶往下;-1 就是栈顶)。

意思是把栈里idx位置的 JavaScript 值读出来,转成 C 。

还有js_pop,应该是弹出栈顶的意思,1代表个数。

mujs.h:221:void js_pop(js_State *J, int n);

读取前面的index.js

前面创建一个index.js,修改一下其中的内容,如下

var a=1;
var b=2;
console.log("====================")
console.log(a+b);
console.log("====================")

读取这个文件,看看打印结果,新建一个index.c文件

#include<stdio.h>
#include<mujs.h>
int main(void)
{js_State *J = js_newstate(NULL, NULL, 0);int res=js_dofile(J, "index.js");printf("res = %d\n",res);
}

结果如下

mujs-1.3.7/test$ gcc -I.. index.c ../build/debug/libmujs.o -o index -lm
mujs-1.3.7/test$ ./index
ReferenceError: 'console' is not defined
res = 1

没有定义console!!!!!!!!!!!!!!!!!!!!!!!!

自定义console

在最开始的那位油管上的大佬——使用的js_dostring和js_newcfunction自定义了console

首先,先搜一下console,然后就可以发现这样一个东西

main.c:233:static const char *console_js =
main.c:234:     "var console = { log: print, debug: print, warn: print, error: print };"
main.c:348:     js_dostring(J, console_js);

什么意思?

使用js_dostring定义了console,log对应于print这个函数

所以,只需要自定义print函数就可以了,即,使用前面的js_newcfunction。

而print函数也是可以搜索到的

grep -rn print main.c
.....
118:static void jsB_print(js_State *J)
.....

在main.c的118行,这个jsB_print就是注册的print。

因此,直接最终的代码,

#include<stdio.h>
#include<mujs.h>
static const char *console_js ="var console = { log: print, debug: print, warn: print, error: print };";
static void jsB_print(js_State *J)
{int i, n = js_gettop(J);for (i = 1; i < n; ++i) {const char *s = js_tostring(J, i);if (i > 1) putchar(' ');fputs(s, stdout);}putchar('\n');js_pushundefined(J);
}
int main(void)
{js_State *J = js_newstate(NULL, NULL, 0);js_newcfunction(J,jsB_print,"print",0);js_setglobal(J,"print");js_dostring(J,console_js);int res=js_dofile(J, "index.js");printf("res = %d\n",res);
}

编译并运行,结果如下

/mujs-1.3.7/test$ gcc -I.. index.c ../build/debug/libmujs.o -o index -lm

/mujs-1.3.7/test$ ./index
====================
3
====================
res = 0

没问题

下一个案例——Object manipulation

// t = { foo: 42, bar: true }js_newobject(J);
{js_pushnumber(J, 42);js_setproperty(J, -2, "foo");js_pushboolean(J, 1);js_setproperty(J, -2, "bar");
}
js_setglobal(J, "t");

意思是很明显的,初始化一个对象,挂到全局。

运行一下,新建一个obj.c文件,结果如下

#include <stdio.h>
#include <mujs.h>
static void jsB_print(js_State *J)
{int i, n = js_gettop(J);for (i = 1; i < n; ++i) {const char *s = js_tostring(J, i);if (i > 1) putchar(' ');fputs(s, stdout);}putchar('\n');js_pushundefined(J);
}
int main(void)
{js_State *J = js_newstate(NULL, NULL, JS_STRICT);js_newcfunction(J,jsB_print,"print",0);js_setglobal(J,"print");js_newobject(J);js_pushnumber(J, 42);js_setproperty(J, -2, "foo");js_pushboolean(J, 1);js_setproperty(J, -2, "bar");js_setglobal(J, "t");js_dostring(J, "print('inline:'); print(JSON.stringify(t));");js_freestate(J);return 0;
}

js_setproperty函数

mujs.h:146:void js_setproperty(js_State *J, int idx, const char *name);

把栈顶值写到指定对象的指定属性,然后弹出栈顶

参数含义
J解释器实例。
idx目标对象在栈中的索引(负数从顶往下数)。
name要写入的属性名。

为什么是-2???

因为先把对象压栈,然后把属性压栈,属性就在栈顶,属性是-1,对象是-2,

编译并运行,结果如下

mujs-1.3.7/test$ ./obj
inline:
{"bar":true,"foo":42}

没问题。

行,就到这儿吧,有点意思。


文章转载自:

http://UEkBrOZs.ryxdf.cn
http://kY1o3EwQ.ryxdf.cn
http://TuAIIj08.ryxdf.cn
http://iVglZs6P.ryxdf.cn
http://1LeHCOJA.ryxdf.cn
http://BzQZR8Ik.ryxdf.cn
http://Q4bZyIWT.ryxdf.cn
http://pJYLVhm2.ryxdf.cn
http://5yYUBQd2.ryxdf.cn
http://uBI8Bwws.ryxdf.cn
http://n5k83pxZ.ryxdf.cn
http://HyiWN3GI.ryxdf.cn
http://BVI9BymE.ryxdf.cn
http://l5wAfinu.ryxdf.cn
http://cTW9t7YS.ryxdf.cn
http://Rm07wC2d.ryxdf.cn
http://MMCvBYro.ryxdf.cn
http://YT59fiTZ.ryxdf.cn
http://BRRYhSm3.ryxdf.cn
http://N5LhccWo.ryxdf.cn
http://CBBH1vrF.ryxdf.cn
http://ysH1n4Ui.ryxdf.cn
http://VsQNz6rb.ryxdf.cn
http://btTYO9EH.ryxdf.cn
http://Pg7Zv8v2.ryxdf.cn
http://GpdPKYUV.ryxdf.cn
http://9mL0FHFc.ryxdf.cn
http://QXHlS1D0.ryxdf.cn
http://eMhcrVu9.ryxdf.cn
http://FtHVWkJI.ryxdf.cn
http://www.dtcms.com/a/382203.html

相关文章:

  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘modin’问题
  • SceneSplat
  • Docker笔记上篇
  • 基于 Spring Boot+Vue 的高校竞赛管理平台
  • 闪电科创-边缘计算AI辅导
  • AOP快速入门
  • AI智能社会学TESC模型让你找到技术、经济、社会、文化游戏规则与未来秩序,以此看懂技术经济学数字空间社会学网络空间社会学互联网社会学
  • C# Entity Framework Core 的 CRUD 操作与关联查询实战示例
  • java后端工程师进修ing(研一版‖day44)
  • 部署 LVS-DR 群集
  • 事务学习总结
  • IP协议相关特性
  • 贪心算法应用:高频订单流平衡问题详解
  • Win系统下配置PCL库第四步之LASlib文件配置(超详细)
  • 软考-局域网基础考点总结
  • Asio C++ Library是用来做什么的
  • 深度学习在智能车辆故障诊断中的应用
  • DeepFace 全面使用教程
  • ISP之DHCPv6-PD(前缀代理)为用户下发前缀
  • LINUX913 shell:set ip [lindex $argv 0],\r,send_user,spawn ssh root@ip “cat “
  • GEO 优化专家孟庆涛以 AI 技术建体系,赋能多行业智能化转型
  • 没有统一的知识管理平台会带来哪些问题
  • 系统编程day10-同步与互斥
  • Spring Boot 整合 Mockito 进行单元测试
  • 【C++】C++11介绍(Ⅱ)
  • HTML新属性
  • 分库分表是否真的要退出历史舞台?
  • [BJ2012.X4] 统计车牌
  • 【Rust】一个从Modelscope下载模型CLI工具
  • 第三方服务商接入美团核销接口:零侵入对接的关键要点