在C++程序中嵌入quickjs实现C++和javascript互相调用

quickjs是一个C++实现的轻量级javascript解析引擎,可以嵌入到C++程序中,实现C++和js代码的交互。

以下基于quickjs-ng这一社区分支实现样例代码演示利用quickjs编写程序进行C++和js互相调用,支持linux和windows。

代码结构

quickjs_demo- quickjs-0.5.0 - main.cpp        # C++主执行程序- main.js         # js执行程序- sample.hpp      # C++模块代码,供js调用- sample.js       # js模块代码,供C++调用- CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)project(quickjs_demo)set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)if (WIN32)add_definitions(-D_CRT_SECURE_NO_WARNINGS-D_WINSOCK_DEPRECATED_NO_WARNINGS)
elseif (UNIX)add_compile_options(-fPIC-O3)
endif()add_subdirectory(./quickjs-0.5.0)include_directories(./quickjs-0.5.0)# build host executable
file(GLOB SRCmain.cpp
)add_executable(${PROJECT_NAME} ${SRC})target_link_libraries(${PROJECT_NAME} qjs
)

基本原理为

  • C++调用js:在C++中启动js运行时,加载js代码执行,可以返回js执行结果在C++中继续处理
  • js调用C++:仍然在C++中启动js运行时,将C++定义的代码模块注册,加载js代码执行,调用注册好的C++模块,返回的结果可以在js中继续处理

基于这样的机制,就可以做到在C++的程序框架中C++与js双向交互,实现很多纯C++或者纯js达不到的效果,例如代码热更新以及安全隔离,这种机制目前其实在金融数据分析系统和游戏引擎中广泛使用。

C++调用js

sample.js

const a = 3;
const b = 5;function my_func(x, y, text)
{// the input params type, x is int, y is double, text is string, return z is double// console.log("my_func with params:", x, y, text);let z = x * y + (b - a);return z;
}

C++代码

void cpp_call_js_test()
{std::cout << "--- cpp call js test ---" << std::endl;// init js runtime and contextJSRuntime* rt = JS_NewRuntime();JSContext* ctx = JS_NewContext(rt);// define global js objectJSValue global_obj = JS_GetGlobalObject(ctx);// load js scriptstd::string js_file = "./sample.js";std::ifstream in(js_file); std::ostringstream sin; sin << in.rdbuf(); std::string script_text = sin.str();std::cout << "script text: " << std::endl;std::cout << script_text << std::endl;// run scriptstd::cout << "script run: " << std::endl;JSValue script = JS_Eval(ctx, script_text.c_str(), script_text.length(), "sample", JS_EVAL_TYPE_GLOBAL);if (!JS_IsException(script)){int x = 7;double y = 8.9;std::string text = "called from cpp";JSValue js_x = JS_NewInt32(ctx, x);JSValue js_y = JS_NewFloat64(ctx, y);JSValue js_text = JS_NewString(ctx, text.c_str());JSValue js_result;JSValue my_func = JS_GetPropertyStr(ctx, global_obj, "my_func");if (JS_IsFunction(ctx, my_func)){JSValue params[] = {js_x, js_y, js_text};// call js functionjs_result = JS_Call(ctx, my_func, JS_UNDEFINED, 3, params);if (!JS_IsException(js_result)){double result = 0.0;JS_ToFloat64(ctx, &result, js_result);std::cout << "my_func result: " << result << std::endl;}elsestd::cerr << "JS_Call failed" << std::endl;}JS_FreeValue(ctx, my_func);JS_FreeValue(ctx, js_result);JS_FreeValue(ctx, js_text);JS_FreeValue(ctx, js_y);JS_FreeValue(ctx, js_x);}elsestd::cerr << "JS_Eval failed" << std::endl;// close js runtime and contextJS_FreeValue(ctx, global_obj);JS_FreeContext(ctx);JS_FreeRuntime(rt);
}

js调用C++

sample.hpp

#include <iostream>
#include "quickjs.h"#define JS_INIT_MODULE js_init_module
#define countof(x) (sizeof(x) / sizeof((x)[0]))// define native variable and function
const int a = 3;
const int b = 5;static double my_func(int x, double y, const char* text)
{std::cout << "my_func with params: " << x << ", " << y << ", " << text << std::endl;double z = x * y + (b - a);return z;
}// define quickjs C function
static JSValue js_my_func(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{std::cout << "js_my_func, argc: " << argc << std::endl;if (argc != 3)return JS_EXCEPTION;int a = 0;double b = 0.0;if (JS_ToInt32(ctx, &a, argv[0]))return JS_EXCEPTION;if (JS_ToFloat64(ctx, &b, argv[1]))return JS_EXCEPTION;if (!JS_IsString(argv[2]))return JS_EXCEPTION;const char* text = JS_ToCString(ctx, argv[2]);double z = my_func(a, b, text);std::cout << "a: " << a << ", b: " << b << ", text: " << text << ", z: " << z << std::endl;return JS_NewFloat64(ctx, z);
}// define function entry list
static const JSCFunctionListEntry js_my_funcs[] = 
{JS_CFUNC_DEF("my_func", 3, js_my_func),
};static int js_my_init(JSContext *ctx, JSModuleDef *m)
{return JS_SetModuleExportList(ctx, m, js_my_funcs, countof(js_my_funcs));
}JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
{JSModuleDef *m;m = JS_NewCModule(ctx, module_name, js_my_init);if (!m)return NULL;JS_AddModuleExportList(ctx, m, js_my_funcs, countof(js_my_funcs));return m;
}

main.js

let a = 7;
let b = 8.9;
let text = "called from js";// call cpp function
let result = my_func(a, b, text);
// console.log("my_func result: ", result);

C++代码

void js_call_cpp_test()
{std::cout << "--- js call cpp test ---" << std::endl;// init js runtime and contextJSRuntime* rt = JS_NewRuntime();JSContext* ctx = JS_NewContext(rt);// define global js objectJSValue global_obj = JS_GetGlobalObject(ctx); // register C++ function to current contextJSValue func_val = JS_NewCFunction(ctx, js_my_func, "my_func", 1); if (JS_IsException(func_val))std::cerr << "JS_NewCFunction failed" << std::endl;if (JS_DefinePropertyValueStr(ctx, global_obj, "my_func", func_val, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)std::cerr << "JS_DefinePropertyValue failed" << std::endl;std::string js_file = "./main.js";std::ifstream in(js_file); std::ostringstream sin; sin << in.rdbuf(); std::string script_text = sin.str();std::cout << "script text: " << std::endl;std::cout << script_text << std::endl;std::cout << "script run: " << std::endl;JSValue script = JS_Eval(ctx, script_text.c_str(), script_text.length(), "main", JS_EVAL_TYPE_GLOBAL);if (JS_IsException(script))std::cerr << "JS_Eval failed" << std::endl;// close js runtime and contextJS_FreeContext(ctx);JS_FreeRuntime(rt);
}

主程序

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "quickjs.h"
#include "quickjs-libc.h"
#include "sample.hpp"// void cpp_call_js_test();
// ...// void js_call_cpp_test();
//  ...int main()
{// test cpp call js scriptcpp_call_js_test();// test js call cpp modulejs_call_cpp_test();return 0;
}

执行结果

--- cpp call js test ---
script text: 
const a = 3;
const b = 5;function my_func(x, y, text)
{// the input params type, x is int, y is double, text is string, return z is double// console.log("my_func with params:", x, y, text);let z = x * y + (b - a);return z;
}
script run: 
my_func result: 64.3
--- js call cpp test ---
script text: 
let a = 7;
let b = 8.9;
let text = "called from js";// call cpp function
let result = my_func(a, b, text);
// console.log("my_func result: ", result);
script run: 
js_my_func, argc: 3
my_func with params: 7, 8.9, called from js
a: 7, b: 8.9, text: called from js, z: 64.3

记得要将sample.js和main.js拷贝到执行目录

备注:

  • 由于quickjs的执行环境比较轻量级,在js代码里不能使用console.log等浏览器支持的内置函数,如果要打印日志,可以在C++中封装函数模块给js调用
  • 需要在支持C++20的编译器下使用,如果编译不过,建议升级gcc或msvc

源码

quickjs_demo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/37856.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cesium大屏-vue3注册全局组件

1.需求 说明&#xff1a;产品经理要求开发人员在地图大屏上面随意放置组件&#xff0c;并且需要通过数据库更改其组件大小&#xff0c;位置等&#xff1b;适用于大屏组件中场站视角、任意位置标题等。 2.实现 2.1GlobalComponents.vue 说明&#xff1a;containerList可以通…

python基础语法 004-2流程控制- for遍历

1 遍历 1.1 什么是遍历&#xff1f; 可以遍历的元素&#xff1a;字符串、列表、元组、字典、集合字符串是可以进行for 循环。&#xff08;容器对象&#xff0c;序列&#xff09;可迭代对象iterable 例子&#xff1a; 1 &#xff09;、for遍历字符串&#xff1a; name xiao…

RK3568驱动指南|第十五篇 I2C-第167章 I2C上拉电阻

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

SpringBoot实现图片添加水印

提示&#xff1a;今日完成图片添加水印功能 后续可能还会继续完善这个功能 文章目录 目录 文章目录 前端部分 后端 Xml Controller层 Sercive层 Service实现层 Config配置层 application.properties 文件后缀名获取 常量定义 前端部分 <!DOCTYPE html> <htm…

WIN11,如何同时连接有线网络与WLAN无线网络

之前写了两篇文章&#xff0c;一篇是双网卡多网卡时win11如何设置网卡优先级_多网卡设置网卡优先级-CSDN博客 另一篇是win11 以太网和WLAN冲突 连接网线时导致WiFi掉线 解决_win11 以太网和wifi不能同时生效-CSDN博客 这篇是对上面两篇的补充&#xff1a;主要解决电脑重启后&…

语音芯片TD5580,USB小音响芯片—拓达半导体

有时候电脑的声卡会出现损坏的问题&#xff0c;给我们的生活带来了很多麻烦。这时候&#xff0c;我们就需要一款方便易用的产品来解决声卡问题。USB声卡小音响就是为了解决这个问题而设计的一款便捷的产品。它不仅可以作为一个小音响&#xff0c;让您在工作和娱乐的时候享受高品…

docker-compose搭建minio对象存储服务器

docker-compose搭建minio对象存储服务器 最近想使用oss对象存储进行用户图片上传的管理&#xff0c;了解了一下例如aliyun或者腾讯云的oss对象存储服务&#xff0c;但是呢涉及到对象存储以及经费有限的缘故&#xff0c;决定自己手动搭建一个oss对象存储服务器&#xff1b; 首先…

烧结银到底有多牛?欢迎咨询SHAREX善仁新材研究院

烧结银到底有多牛&#xff1f;欢迎咨询SHAREX善仁新材研究院 在当今日新月异的科技浪潮中&#xff0c;材料科学以其独特的魅力引领着人类探索未知领域的步伐。在众多前沿材料中&#xff0c;烧结银凭借其卓越的性能和广泛的应用前景&#xff0c;逐渐崭露头角&#xff0c;成为科…

创建XCOM窗体和跳转连接

Xcom 窗体&#xff1a; (groupBox组合框&#xff0c;comboBox下拉框) xcom代码&#xff1a; namespace _01_作业 {// 1kb 1024B 1200B// 1MB public partial class Form1 : Form{public List<string> botelv new List<string> { "600","1200&…

Unix Network Programming Episode 96

‘socketpair’ Function The socketpair function creates two sockets that are then connected together. This function applies only to Unix domain sockets. #include <sys/socket.h> int socketpair(int family, int type, int protocol, int sockfd[2]);POSIX…

(十七)如何学习统计学基础知识(学习路线)

统计学是数据科学的基本支柱。统计学的目的是帮助你理解数据并从中得出有意义的结论。在数据科学中&#xff0c;统计学在理解数据模式和趋势、做出预测和检验假设方面起着至关重要的作用。 (一) 数据科学统计学习路线图 本文为学习统计学并将其应用于数据科学提供了清晰、结构化…

如何使用 SPM 插件从 Pkl 配置文件生成 Swift 接口

文章目录 前言示例展示 Pkl 配置生成 Swift 绑定手动安装和使用 pkl-gen-swift创建 SPM 命令插件加载 Pkl 配置总结前言 Pkl(全称为 Pickle)是苹果推出的一种全新的专用于配置的编程语言。它允许开发人员通过类型和内置验证安全、直观地设计数据模型。 作为苹果语言,Pkl 有…

Python容器 之 列表--下标和切片

列表的切片 得到是 新的列表字符串的切片 得到是 新的字符串 如果下标 不存在会报错 list1 [1, 3.14, "hello", False] print(list1)# 获取 列表中 第一个数据 print(list1[0]) # 1# 获取列表中的最后一个数据 print(list1[-1]) # [False]# 获取中间两个数 即 3.1…

3.2ui功能讲解之graph页面

本节重点介绍 : graph页面target页面flags页面status页面tsdb-status页面 访问地址 $ip:9090 graph页面 autocomplete 可以补全metrics tag信息或者 内置的关键字 &#xff0c;如sum聚合函数table查询 instante查询&#xff0c; 一个点的查询graph查询调整分辨率 resolutio…

记录:有趣的C#多元运算符 ? : 表达式写法

有时候用 if //...Whatre you she wanna go else if //...do do do else //...and i know something just like this... 感觉代码太多了怎么优雅的、高端的替换&#xff1f; 看个高端的栗子菊&#xff1a; LedCOM["parity"] ledData[4] "N" ? …

Study--Oracle-05-Oracler体系结构

一、oracle 体系概览 Oracle数据库的体系结构通常包括以下主要组件&#xff1a; 1、实例&#xff08;Instance&#xff09;&#xff1a;运行数据库的软件环境&#xff0c;包括内存结构&#xff08;SGA&#xff09;和进程结构&#xff08;Background Processes and User Proces…

Django 一对多关系

1&#xff0c;创建 Django 应用 Test/app9 django-admin startapp app9 2&#xff0c;注册应用 Test/Test/settings.py 3&#xff0c;添加应用路由 Test/Test/urls.py from django.contrib import admin from django.urls import path, includeurlpatterns [path(admin/,…

《每天5分钟用Flask搭建一个管理系统》 第10章:前端集成

第10章&#xff1a;前端集成 10.1 前端技术概述 前端技术指的是构建Web应用用户界面所使用的技术&#xff0c;包括HTML、CSS和JavaScript。现代Web开发中&#xff0c;前端框架如React、Vue.js和Angular等被广泛使用。 10.2 AJAX与Flask的集成 AJAX&#xff08;Asynchronous…

数据资产安全策略的定制化之道:深入了解各企业独特需求,量身打造个性化的数据资产保护方案,确保数据安全无虞,助力企业稳健发展

目录 一、引言 二、企业数据资产安全现状分析 &#xff08;一&#xff09;数据安全风险多样化 &#xff08;二&#xff09;传统安全措施难以满足需求 &#xff08;三&#xff09;企业数据资产安全意识亟待提高 三、定制化数据资产安全策略的重要性 &#xff08;一&#…

natvicat为什么连不上linux上的mysql?

老规矩&#xff0c;废话不多说&#xff0c;直接上教程。 号外&#xff0c;数据库管理工具领域的知名品牌Navicat&#xff0c;推出其免费版本——Navicat Premium Lite&#xff0c;用户可从Navicat官网下载体验这款软件。 https://www.navicat.com.cn/download/navicat-premium-…