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