能否通过QuickJS从C语言调用CommonJS模块中的函数?
解决QuickJS访问CommonJS模块函数的问题
要在C/C++中通过QuickJS访问CommonJS模块内的函数,核心是利用QuickJS的模块加载能力,直接获取模块的导出对象,而非依赖全局作用域。具体步骤如下:
1. 以模块模式执行代码
使用JS_Eval时指定JS_EVAL_TYPE_MODULE参数,将CommonJS模块代码作为模块执行,此时返回的JSValue就是模块的命名空间对象。
2. 获取模块导出对象
模块的导出内容会挂载在模块对象的exports属性上,通过JS_GetPropertyStr即可获取导出对象。
3. 调用导出的函数
从导出对象中拿到目标函数后,就可以用JS_Call执行函数,参数和普通函数调用一致。
示例代码
/* 假设ctx是已初始化的有效JSContext */ const char *module_code = "module.exports = { add: (a, b) => a + b };"; // 以模块模式执行CommonJS代码 JSValue module_result = JS_Eval(ctx, module_code, strlen(module_code), "<module>", JS_EVAL_TYPE_MODULE); // 异常检查:模块加载失败时处理 if (JS_IsException(module_result)) { JSValue err = JS_GetException(ctx); char *err_str = JS_ToCString(ctx, err); fprintf(stderr, "模块加载失败: %s\n", err_str); JS_FreeCString(ctx, err_str); JS_FreeValue(ctx, err); JS_FreeValue(ctx, module_result); return; } // 获取模块的exports对象 JSValue exports = JS_GetPropertyStr(ctx, module_result, "exports"); // 获取导出的add函数 JSValue add_func = JS_GetPropertyStr(ctx, exports, "add"); // 准备调用参数 JSValue arg1 = JS_NewInt32(ctx, 5); JSValue arg2 = JS_NewInt32(ctx, 3); JSValue args[] = {arg1, arg2}; // 调用函数,this绑定到exports对象 JSValue call_result = JS_Call(ctx, add_func, exports, 2, args); // 处理返回值 if (!JS_IsException(call_result)) { int32_t res; if (JS_ToInt32(ctx, &res, call_result) == 0) { printf("add(5, 3) = %"PRIi32"\n", res); // 输出: add(5, 3) = 8 } } else { // 处理函数调用异常 JSValue err = JS_GetException(ctx); char *err_str = JS_ToCString(ctx, err); fprintf(stderr, "函数调用失败: %s\n", err_str); JS_FreeCString(ctx, err_str); JS_FreeValue(ctx, err); } // 释放所有JSValue资源 JS_FreeValue(ctx, call_result); JS_FreeValue(ctx, arg1); JS_FreeValue(ctx, arg2); JS_FreeValue(ctx, add_func); JS_FreeValue(ctx, exports); JS_FreeValue(ctx, module_result);
注意事项
- 编译QuickJS时需确保启用模块支持(开启
CONFIG_MODULE编译选项)。 - 如果模块依赖NodeJS内置模块(如
fs、path),需在QuickJS中实现对应的模块加载器,或用esbuild将所有依赖打包为单文件模块,避免外部依赖问题。 - 对于复杂模块,需注意模块的依赖解析和加载顺序,QuickJS兼容ES模块规范,esbuild转换后的CommonJS模块可直接加载。
内容的提问来源于stack exchange,提问作者ijustlovemath
相关产品推荐
相关产品推荐

