从 0 写个微小的 Javascript 运行时(04) - 添加一个自定义的模块/库

代码

github.com/zizifn/toy-...

代码一般会按照一篇文章一个branch。这样方便大家查看。

从文件读取脚本

在上一篇文章中,我们已经可以执行简单的脚本了。但是这个脚本是写死在代码里面的。为了运行方便,让我们从文件读取js脚本。

代码和详细解释如下,为了简洁,我就不做异常处理了。

c 复制代码
int main(int argc, char** argv)
{
    .....
    uint8_t *script_str;
    size_t script_len;
    // 利用 C 语言的文件读取函数读取文件内容
    script_str = js_load_file(ctx, &script_len, filename);
    // 运行读取的 js 脚本
    ret = JS_Eval(ctx, script_str, script_len, filename, JS_EVAL_TYPE_MODULE);
    ......
}

运行 js 脚本

随便创建一个js文件,比如 test.js,内容如下:

js 复制代码
console.log(`hello world!! 1 + 2 = ${1+2}`);

如果遇到编译问题,建议重新 build 运行。

bash 复制代码
mkdir build
cd build
cmake ..
make
./toyjsruntime ./src/test.js

如果你是使用 Clion,可以直接点击 main.c提示的运行按钮, 并配置相应的项目参数。

这样我们的 js runtime 就可以直接执行 js 文件了。

Hello World 本地 C 模块

此时我们的 js runtime 基本上和 js 引擎的能力一样,除了能执行 js 脚本之外,什么也做不了。它现在什么模块都没有,比如nodejs 的 fs 模块,http 模块等等。

接下来,我们将实现一个简单的本地模块,这个模块可以返回机器的 memory 信息。

那么,我们应该怎么做呢?

  1. 编写一个 C 函数,这个函数返回机器的 memory 信息
  2. 创建一个模块,这个模块包含这个函数
  3. 把这个模块注册到 js runtime 里面
  4. 在 js 里面调用这个函数

编写模块

获取机器内存信息

这里不同操作系统获取机器内存信息的方式不同,这里我们只实现 linux 下的获取内存信息。

github.com/zizifn/toy-...

c 复制代码
static JSValue js_memory(JSContext *ctx, JSValueConst this_val,
                       int argc, JSValueConst *argv){

// 我们只需要从 /proc/meminfo 文件读取信息就可以了,具体处理string的方式可以参考代码
FILE *file = fopen("/proc/meminfo", "r");
// MemTotal:        7036148 kB
// MemFree:         3082528 kB  
.....

}

创建并且注册模块

github.com/zizifn/toy-...

c 复制代码
static const JSCFunctionListEntry js_test_funcs[] = {
    // 声明一个函数,这个函数的名字是 memory,参数是 1 个,函数指针是 js_memory
    JS_CFUNC_DEF("memory", 1, js_memory ),
};

static int js_test_init(JSContext *ctx, JSModuleDef *m){
    // 这个类似 js 里面的 export
    return JS_SetModuleExportList(ctx, m, js_test_funcs,
            countof(js_test_funcs));
}

JSModuleDef *js_init_module_test(JSContext *ctx, const char *module_name)
{
    JSModuleDef *m;
    // 创建一个模块,包含这个模块有多少方法或者变量
    m = JS_NewCModule(ctx, module_name, js_test_init);
    if (!m)
        return NULL;
    // 注册这个模块到 quickjs 的运行时。由于quickjs 设计,这个看似重复的操作是必须的。
    JS_AddModuleExportList(ctx, m, js_test_funcs, countof(js_test_funcs));
    return m;
}

这样我们就完成了,怎么把一个 C 函数映射到 js 里面。这就是在nodejs里面经常说的 binding

修改 main.c

c 复制代码
int main(int argc, char** argv)
{
    .....
    // 注册模块
    js_init_module_test(ctx, "toyjsruntime:test");
    .....
}

在 js 里面调用这个模块

js 复制代码
import { memory } from 'toyjsruntime:test';
console.log(memory());
相关推荐
北极糊的狐2 分钟前
若依项目vue前端启动键入npm run dev 报错:不是内部或外部命令,也不是可运行的程序或批处理文件。
前端·javascript·vue.js
星火开发设计3 分钟前
C++ 输入输出流:cin 与 cout 的基础用法
java·开发语言·c++·学习·算法·编程·知识
玖釉-6 分钟前
探索连续细节层次(Continuous LOD):深入解析 NVIDIA 的 nv_cluster_lod_builder
c++·windows·图形渲染
sayang_shao24 分钟前
C++ ONNX Runtime 与 Python Ultralytics 库实现 YOLOv8 模型检测的区别
c++·python·yolo
LXS_35731 分钟前
STL - 函数对象
开发语言·c++·算法
专注于ai算法的踩坑小达人38 分钟前
C++变量全面总结
c++·qt
阿猿收手吧!1 小时前
【C++】atmoic原子操作与并发安全全解析
开发语言·c++·安全
有诺千金1 小时前
VUE3入门很简单(4)---组件通信(props)
前端·javascript·vue.js
2501_944711431 小时前
Vue-路由懒加载与组件懒加载
前端·javascript·vue.js
凯子坚持 c1 小时前
C++基于微服务脚手架的视频点播系统---客户端(1)
开发语言·c++·微服务