更多内容在【倦倦喵.cn】~
WebAssembly学习笔记(一)
编译和导入wasm模块
用Emscripten编译C/C++并使用HTML模板
让Emscripten生成WebAssembly模块、JavaScript plubming文件, 以及HTML模板文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LK77Cj5N-1670298706899)(/img/webassembly/0101.png)]
-
创建一个用于存放文件的目录: WebAssembly\Chapter 3\3.4 html_template\。
-
创建C或C++代码。
-
创建一个名为 calculate_primes.c 的文件。要做的第一件事是包含C标准库、 C标准输入和输出,以及Emscripten库的头文件。
-
#include <stdlib.h>
#include <stdio.h>
#include <emscripten.h>
-
-
将C代码编译为WebAssembly模块。
- 进入目录WebAssembly\Chapter 3\3.4 html_template\,打开一个控制台窗口,然后定位到这个目录。
- 运行以下命令可以生成WebAssembly模块、JavaScript plumbing文件和一个HTML模板。
emcc calculate_primes.c -o html_template.html
-
在Web浏览器中打开HTML文件查看结果。
- Emscripten创建的HTML文件会将任何来自模块的printf输出定向到一个文本框,这样不需要打开浏览器开发者工具,就可以在页面上看到输出。
用Emscripten生成JavaScript plumbing代码
让Emscripten生成WebAssembly模块和JavaScript plumbing文件。修改一个HTML文件或者创建一个新文件,以引用生成的 JavaScript文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOC1UpCs-1670298706900)(/img/webassembly/0102.png)]
-
创建一个用于存放文件的目录: WebAssembly\Chapter 3\3.5 js_plumbing\ 。
-
创建C或C++代码。
-
将C代码编译为WebAssembly模块。
-
进入目录 WebAssembly\Chapter 3\3.5 js_plumbing\,打开一个控制台窗口,然后定位到这个目录。
-
运行以下命令,让Emscripten创建WebAssembly 模块和JavaScript文件。
-
emcc calculate_primes.c -o js_plumbing.js
-
-
-
修改一个HTML文件或者创建一个新文件,以引用生成的 JavaScript文件。
-
←---- 这个JavaScript文件会处理WebAssembly模块的加载和实例化
-
-
在Web浏览器中打开HTML文件查看结果。
用Emscripten只生成WebAssembly文件
让Emscripten只生成WebAssembly模块。 然后创建必要的 HTML和JavaScript代码,以下载和实例化模块。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ar1LanN8-1670298706900)(/img/webassembly/0103.png)]
-
创建一个用于存放文件的目录:WebAssembly\Chapter 3\3.6 side_module\。
-
是创建C/C++代码。
-
让Emscripten只生成WebAssembly文件。
-
含优化标记-O1,如果没有指定优化标记,则Emscripten会使用默认的-O0(大写字母O和数字0),这表示不执行任何优化。
-
需要将函数Increment指定为导出函数,这样它才能够被JavaScript代码调用。为了向Emscripten编译器指示这一点,可以在命令行参数-s EXPORTED_FUNCTIONS中包含这个函数名。生成WebAssembly文件时, Emscripten会在这个函数前添加一个下划线字符,因此将函数名包含到导 出数组时,需要包含下划线字符:_Increment。
-
emcc side_module.c -s SIDE_MODULE=2 -O1
➥ -s EXPORTED_FUNCTIONS=[‘_Increment’] -o side_module.wasm
-
-
创建一个HTML文件并编写JavaScript代码从服务器请求这个文件,并让这个模块完成实例化。
-
promise与箭头函数表达式
-
JavaScript对象简写
-
WebAssembly JavaScript API概览
-
编写JavaScript代码来获取并实例化模块
-
定义一个JavaScript对象,将其命名为importObject,它有一个名为env的子对象,其中包含一个memory_base属性,这是这个模块想要导入的。这个memory_base属性会简单持有一个0值,因为我们不会动态链接这个模块。
-
创建好importObject后,就可以调用函数instantiateStreaming,传入Wasm文件的fetch方法的结果作为第一个参数,importObject作为第二个参数。
-
instantiateStreaming会返回一个promise,因此我们将设置一个处理函数作为成功回调,模块完成下载、编译并实例化后,它就会被调用。此时可以访问这个WebAssembly模块实例的导出元素并调用_Increment函数。
-
const importObject = { env: { __memory_base: 0, } }; WebAssembly.instantiateStreaming(fetch("side_module.wasm"), ➥ importObject).then(result => { const value = result.instance.exports._Increment(17); console.log(value.toString()); });
-
-
创建一个基本的HTML页面
-
<script> const importObject = { env: { __memory_base: 0, } }; WebAssembly.instantiateStreaming(fetch("side_module.wasm"), ➥ importObject).then(result => { const value = result.instance.exports._Increment(17); console.log(value.toString()); }); </script>
-
-
使用wasm模块中的函数
用C/C++创建带Emscripten plumbing的模块
-
修改C++代码。
-
Emscripten的条件编译符号与头文件
-
Emscripten提供了条件编译符号__EMSCRIPTEN__,你可以用其检测正在编译这个解决方案的是否为Emscripten。
-
#include
#include
#ifdef EMSCRIPTEN ←---- 当代码被Emscripten编译时这个符号存在
#include <emscripten.h> ←---- Emscripten库的头文件
#endif
-
-
extern "C"块
-
在C++中,函数名可以被重载(overload),因此,编译时为了确保名称的唯一性,编译器会通过添加与函数参数相关的信息来改变它。编译代码时,编译器会修改函数名,这对于想要调用某个特定函数的外部代码来说是一个问题,因为那个函数名已经不复存在了。
-
需要为函数包裹一个extern "C"块。将来要添加到这个文件中的所有函数都会放在这个块内。
-
#ifdef __cplusplus
extern “C” { ←---- 因此编译器不会在这对大括号内重命名函数
#endif
←---- WebAssembly函数将放在这里
#ifdef __cplusplus
}
#endif
-
-
-
将代码编译为WebAssembly模块。
-
在编写与模块交互的JavaScript代码时,将使用到Emscripten辅助函数ccall和UTF8ToString。
-
emcc validate.cpp -o validate.js
➥ -s EXTRA_EXPORTED_RUNTIME_METHODS=[‘ccall’,‘UTF8ToString’]
-
辅助函数ccall:帮助调用模块函数,并在字符串希望只在调用期间存在时,辅助管理这些字符串的内 存。
-
辅助函数UTF8ToString:这个函数接受一个指针,并从这个内存位置读取字符串。
-
-
创建网页。
-
创建与模块交互的JavaScript代码。
- 将生成的文件复制到HTML文件所在目录,然后创建JavaScript代码与模块交互。
用C/C++创建不使用Emscripten的模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-abg5HYV5-1670298706900)(/img/webassembly/0105.png)]