在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.pswp.cn/web/37856.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37856.shtml
英文地址,請注明出處:http://en.pswp.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-…