QuickJS快速体验:在C程序代码中调用JS脚本并执行

发布时间:2024年01月21日

前言

JS(JavaScript)是一种轻量级的面向对象的编程语言,目前使用非常广泛,既能在浏览器中使用,也能在服务器端作为后台(借助node.s),并且由于其是解释型语言,不需要提前编译,所以它就有了一个特别大的优势,它支持热更新(可以实现极其轻量级的OTA),所以这些年在嵌入式Linux中,有很多场景也开始引入了JS。不过JS也有缺点,因为是解释性语言,所以执行效率相比二进制编译语言,比如C,相对低。本文主要介绍借助QuickJS来体验一下再C程序代码中如何调用JS代码。
QuickJS是一种在嵌入式平台上应用比较广泛的JS引擎。

在Ubuntu上安装quickJS

1. 下载QuickJS源码

wget https://bellard.org/quickjs/quickjs-2024-01-13.tar.xz

2. 解压quickjs源码

tar -xJf quickjs-2024-01-13.tar.xz

3. 安装quickjs

sudo make
......
sudo make install

安装成功后,会在/usr/local/lib/quickjs 目录下安装libquickjs.a 文件,在/usr/local/include/quickjs下包含其头文件。

C调用JS脚本demo程序

使用JS实现的计算器脚本 calculator.js

// calculator.js 文件内容
function calculate(a, b, operation) {
    switch(operation) {
      case '+': return a + b;
      case '-': return a - b;
      case '*': return a * b;
      case '/': return a / b || 'Error: Division by zero'; // 注意,这里做了除数为零的判断
      default: return 'Error: Invalid operation';
    }
  }

C 调用JS demo

test.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <quickjs/quickjs-libc.h>

int main(int argc, char *argv[]) 
{
    JSRuntime* rt;
    JSContext* ctx;
    JSValue global_obj, script, result;

    // 初始化QuickJS运行时和上下文
    rt = JS_NewRuntime();
    ctx = JS_NewContext(rt);
    
    // 注册全局对象
    global_obj = JS_GetGlobalObject(ctx);

    // 读取并执行JavaScript脚本文件
    FILE *fp = fopen("calculator.js", "r");
    if (!fp) {
        fprintf(stderr, "Failed to open script file: calculator.js\n");
        exit(EXIT_FAILURE);
    }

    fseek(fp, 0, SEEK_END);
    long script_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    char *script_text = malloc(script_size + 1);
    fread(script_text, script_size, 1, fp);
    script_text[script_size] = '\0'; // 添加结束符

    fclose(fp);

    script = JS_Eval(ctx, script_text, script_size, "calculator.js", JS_EVAL_TYPE_GLOBAL);
    if (JS_IsException(script)) {
        fprintf(stderr, "Error evaluating JavaScript function from calculator.js: %s\n", JS_ToCString(ctx, script));
        goto fail;
    }

    // 创建JavaScript函数参数
    //double num1 = 10, num2 = 2;
    double num1 = atof(argv[1]);
    double num2 = atof(argv[3]);
    ///const char* op = "+";  // 这里可以更换为加减乘除符号
    const char* op = argv[2];
    JSValue arg1 = JS_NewFloat64(ctx, num1);
    JSValue arg2 = JS_NewFloat64(ctx, num2);
    JSValue operation = JS_NewString(ctx, op);

    // 创建JavaScript函数调用
    JSValue calculator_fn;
    calculator_fn = JS_GetPropertyStr(ctx, global_obj, "calculate"); // 获取calculate函数
    if (JS_IsFunction(ctx, calculator_fn)) {
        JSValue argv[] = {arg1, arg2, operation};
        result = JS_Call(ctx, calculator_fn, JS_UNDEFINED, 3, argv); // 调用函数
        if (JS_IsException(result)) {
            printf("Error executing JavaScript function\n");
        } else {
            double calculated_result;
            if (JS_ToFloat64(ctx, &calculated_result, result) < 0) {
                printf("Conversion to float64 failed\n");
            } else {
                printf("Result: %.2f\n", calculated_result);
            }
        }
    } else {
        printf("calculate function not found or is not a function\n");
    }

    // 清理
    fail:
    JS_FreeValue(ctx, result);
    JS_FreeValue(ctx, calculator_fn);
    JS_FreeValue(ctx, operation);
    JS_FreeValue(ctx, arg2);
    JS_FreeValue(ctx, arg1);
    JS_FreeValue(ctx, global_obj);
    JS_FreeContext(ctx);
    JS_FreeRuntime(rt);
    free(script_text);

    return 0;
}

编译构建

gcc -o test test.c -L/usr/local/lib/quickjs -lquickjs -lpthread -lm

特别注意:因为quickJS引用了数学相关的C库,所以我们需要添加-lm,否则会宝很多错

demo执行结果:

/opt/test/quickJs-test$ ./test 12 + 34
Result: 46.00

结束语

本文介绍了在ubuntu平台上,使用C代码调用JS脚本的demo流程,对于嵌入式工程师来说,js提供了一种新的思路,我们不一定非要OTA来升级程序,也可以通过JS的热更新机制来实现程序的升级,当然,这个前提是JS能够满足使用场景,比如执行效率,内存等。

文章来源:https://blog.csdn.net/u012351051/article/details/135736069
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。