[知者行之始|行者知之成]C/C++程序在浏览器端运行DemoCode/*WebAssembly从入门到放弃*/
- 2020 年 2 月 25 日
- 筆記
编译器下载和配置参考[WebAssembly从入门到放弃] Emscripten1.39.4工具链的安装与简单使用。本文介绍将C程序编译后在浏览器端运行的例子。
1. 搭建服务器
服务器使用Express框架,安装参考[物联网loT]树莓派实现局域网内LED亮灭,代码如下:
// Express const express = require('express') const app = express() // public文件夹作为服务器根目录 app.use( express.static('public', { setHeaders: (res, path, stat) => { // Serve .wasm files with correct mime type if (path.endsWith('.wasm')) { res.set('Content-Type', 'application/wasm') } } }) ) // 开启服务器 app.listen( 8888, () => console.log('Server running on port 8888!') )
2. C程序及其编译
2.1 程序demo.c
其中getPoints函数返回了100个坐标点,要给js使用。
#include <time.h> #include <stdio.h> #include <stdlib.h> #include <emscripten.h> // 点集数量 #define NUM_POINTS 100 // 坐标点的数据结构 struct Point { int x; // x 坐标值 int y; // y 坐标值 }; // 坐标点存储 struct Point points[NUM_POINTS]; // 随机整数生成函数 int getRandInt(max) { return (rand() % max); } // 主函数 int main() { // 初始化伪随机数 srand(time(NULL)); // 创建点集实例 for( int i = 0; i < NUM_POINTS; i++ ) { // 设置坐标值 points[i].x = getRandInt(666); points[i].y = getRandInt(666); } // 调用JS函数并传递参数 EM_ASM({ jsDemoFun($0, $1); }, NUM_POINTS*2, 2 ); } // 返回点集数据结构给js struct Point * getPoints( int canvasWidth, int canvasHeight ) { return points; }
2.2 编译
命令行如下:
emcc demo.c -s WASM=1 -s EXPORTED_FUNCTIONS="['_main','_getPoints']" -O3 -o demo.js
EXPORTED_FUNCTIONS指定要导数的函数列表,比如getPoints函数是要导出给js调用的,需要指明;-O3表示三级优化,如不优化,编译后文件体积会很大。
3 与js交互示例
getPoints返回的是整型数组的指针,即元素首地址,也就是在内存(buffer)中的地址,使用Int32Array读取内存buffer中长度为dataLength的数据,以整型数据类型读取。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>WebAssembly Demo</title> </head> <body> <script src="demo.js"></script> <script> const jsDemoFun = ( dataLength, pointStructSize ) => { // 调用C语言里的程序_getPoints let points = new Int32Array( Module.buffer, _getPoints( 666, 888), dataLength ) // 遍历内存中的数据,逐个读取 for( let i = 0; i < points.length; i+=pointStructSize ) { // 从内存中截取数据 let point = points.slice( i, i+pointStructSize ) console.log(point); } } </script> </body> </html>
4测试
启动服务器,打开浏览器,地址栏输入127.0.0.1:8888。