- 首先下载emscripten
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
- 安装最新版并激活
emsdk install latest
emsdk activate latest
激活cmake工具链
emsdk activate latest-upstream
- 在emscripten安装目录中找到Emscripten.cmake并集成到cmake项目中
打开Visual Studio 2022,创建一个名称为EmscriptenTest的cmake项目
编辑CMakeLists.txt文件
# CMakeList.txt: EmscriptenTest 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)
set(CMAKE_TOOLCHAIN_FILE "D:/CppPkg/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake")
# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)
cmake_policy(SET CMP0141 NEW)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()
project ("EmscriptenTest")
# 将源代码添加到此项目的可执行文件。
add_executable (EmscriptenTest "EmscriptenTest.cpp" "util.cpp")
add_library(util STATIC util.cpp)
set_target_properties(util PROPERTIES SUFFIX ".wasm")
set_target_properties(util PROPERTIES LINK_FLAGS "--bind -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME='UtilModule' -s EXPORTED_FUNCTIONS='[\"_add\",\"_sub\"]'")
if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET EmscriptenTest PROPERTY CXX_STANDARD 20)
endif()
# TODO: 如有需要,请添加测试并安装目标。
其中
set_target_properties(util PROPERTIES LINK_FLAGS "--bind -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME='UtilModule' -s EXPORTED_FUNCTIONS='[\"_add\",\"_sub\"]'")
这行代码表示我要在util.cpp导出add函数和sub函数。
- 编写util.cpp代码
这是util.cpp代码的内容:
extern "C" {
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
}
EmscriptenTest.cpp是main函数入口,就随便写个空的main函数就行了,因为这个用不到。
EmscriptenTest.cpp的内容:
#include <iostream>
#include <stdio.h>
int main() {
return 0;
}
- 重新构建cmke缓存以及代码生成
点击visual studio 的顶部的菜单栏的“项目”选项,点击“删除缓存并重新配置”,
然后点击菜单栏中的“生成”,点击“全部重新生成”。
在\EmscriptenTest项目的 out/build/x64-debug 目录下会生成如下的libutil.wasm文件。
打开cmd窗口进入到out/build/x64-debug 目录下
执行命令:
emcc libutil.wasm -o libutil.js ^
-s EXPORT_NAME="UtilModule" ^
-s MODULARIZE=1 ^
-s "EXPORTED_FUNCTIONS=['_add','_sub']"
如果找不到emcc命令,请搜索emcc.bat文件在哪里,并配置Emscripten里面的emcc.bat文件所在目录的环境变量。
那么这时候呢,libutil.wasm 也会被重新覆盖生成,并且会得到一个libutil.js。这个命令一定要执行,才可以生成正确的libutil.asm,我们这里不使用libutil.js,仅使用libutil.wasm即可。
如下图,这个libutil.wasm文件确实变了,这是一个有效的wasm文件。
把这个libutil.wasm文件拷贝到你的nodejs项目中。
这是nodejs项目中的main.js文件的内容:
// 加载 WebAssembly 模块
const fs = require('fs');
const { promisify } = require('util');
const { instantiate } = require('node:vm');
const readFileAsync = promisify(fs.readFile);
async function main() {
try {
// 读取 libutil.wasm 文件
const wasmBuffer = await readFileAsync('libutil.wasm');
// 实例化 WebAssembly 模块
const { instance } = await WebAssembly.instantiate(wasmBuffer, {});
// 调用导出的 C++ 函数
const resultAdd = instance.exports.add(10, 5);
console.log("Addition result:", resultAdd);
const resultSub = instance.exports.sub(10, 5);
console.log("Subtraction result:", resultSub);
} catch (error) {
console.error('Error:', error);
}
}
main();
这是我的package.json文件:
{
"name": "nodedevtest",
"version": "1.0.0",
"description": "A minimal Electron application",
"main": "main.js",
"scripts": {
"start": "node main.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.6.8",
"electron": "^30.0.1",
"pixi.js": "^8.1.0",
"request": "^2.88.2"
}
}
这意味着我会用node main.js命令来执行这个main.js代码。
运行之后会得到10+5等于15的结果。
- 调试结果
通过调试发现,确实调用了C++的函数,10+5等于15