C/C++編譯成.wasm文件,並使用javascript調用接口

一、C/C++編譯成.wasm

0.背景

準備好本地編譯環境Emscripten,使用emcc命令編譯的.wasm文件在js裏面調用時報這個錯誤:

CompileError: Wasm decoding failedResult = expected magic word 00 61 73 6d, found 42 43 c0 ……

沒找到處理辦法,但是找到了一種更簡單的方法–使用WebAssembly Studio在線編譯。

1、如果只是需要一個.wasm文件,創建Empty C Project

在這裏插入圖片描述

2、main.js和main.html也可以刪除

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DYrmhl1D-1590498410522)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1590496699150.png)]

3、在main.c中編寫c代碼,注意每一個函數上面需要加WASM_EXPORT

在這裏插入圖片描述

4、可以右鍵edit更改輸入、輸出文件名稱,但是注意build.ts文件輸入、輸出文件需要同步

在這裏插入圖片描述
在這裏插入圖片描述

5、最後注意保存文件!再build就編譯生成了.wasm文件

在這裏插入圖片描述
在這裏插入圖片描述

二、javascript加載.wasm文件,調用接口

1、右鍵剛剛生成的.wasm文件download下載

在這裏插入圖片描述

2、測試代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>Compile C to WebAssembly</h1>
<p>The test result can be found in console.</p>

<script>
    function loadWebAssembly(path) {
        return fetch(path)                     // 加載文件
            .then(res => res.arrayBuffer())    // 轉成 ArrayBuffer
            .then(WebAssembly.instantiate)     // 編譯 + 實例化
            .then(mod => mod.instance)         // 提取生成都模塊
    }

    loadWebAssembly('./math.wasm')
        .then(instance => {
            const add = instance.exports.add;
            const sub = instance.exports.sub;
            const mul = instance.exports.mul;
            const dev = instance.exports.dev;

            console.log('1+1 =', add(1, 1));
            console.log('1-1 =', sub(1, 1));
            console.log('1×6 =', mul(1, 6));
            console.log('9÷3 =', dev(9, 3));
        });
    
</script>
</body>
</html>

3、運行結果

在這裏插入圖片描述

4、如果失敗,將第2步的loadWebAssembly換成這個

    /**
     * 如果你直接使用上邊那個 loadWebAssembly 函數,有可能會執行失敗,因爲在 wasm 文件裏,可能還會引入一些環境變量,
     * 在實例化的同時還需要初始化內存空間和變量映射表,也就是 WebAssembly.Memory 和 WebAssembly.Table。
     * @param {String} path wasm 文件路徑
     * @param {Object} imports 傳遞到 wasm 代碼中的變量
     * @returns {Promise<WebAssembly.Instance>}
     */
    function loadWebAssembly(path, imports = {}) {
        return fetch(path)
            .then(response => response.arrayBuffer())
            .then(buffer => WebAssembly.compile(buffer))
            .then(module => {
                imports.env = imports.env || {};

                // 開闢內存空間
                imports.env.memoryBase = imports.env.memoryBase || 0;
                if (!imports.env.memory) {
                    imports.env.memory = new WebAssembly.Memory({initial: 256})
                }

                // 創建變量映射表
                imports.env.tableBase = imports.env.tableBase || 0;
                if (!imports.env.table) {
                    // 在 MVP 版本中 element 只能是 "anyfunc"
                    imports.env.table = new WebAssembly.Table({initial: 0, element: 'anyfunc'})
                }

                // 創建 WebAssembly 實例
                return new WebAssembly.Instance(module, imports)
            })
    }

5、// TODO 引入了第三方庫的c文件編譯成.wasm(求助…)

三、參考

WebAssembly 實踐:如何寫代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章