[知者行之始|行者知之成]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。