WebAssembly和Emscripten入门简介
通过不断的学习WebAssembly开发技术,可以帮助开发人员在Web平台上构建更快、更安全、更可移植的应用程序。
01
初识WebAssembly
WebAssembly,简称 WASM ,是一种新的低级二进制格式,它可以在所有主流的浏览器中使用,包括 Chrome,Firefox,Edge和Safari。WebAssembly最初由Mozilla、Google、微软和其他技术公司推出,它的目标是通过提供一种高性能、可移植和安全的方式来扩展Web平台,以便开发人员可以在Web上构建更加复杂和功能更加强大的应用程序。
WebAssembly与JavaScript不同,它是一种二进制格式,而不是文本格式,它需要使用虚拟机来解释字节码,同时提供与Web技术的交互。WebAssembly可以将C/C++、Rust等语言编写的代码编译成字节码格式,然后在浏览器中运行。WebAssembly可以通过使用JavaScript的API调用,也可以在WebAssembly模块之间进行通信。WebAssembly可以更快地加载、解析和执行,从而提供更好的性能和更低的内存占用。
02
Emscripten开发入门
WebAssembly需要将C/C++、Rust等语言编写的代码编译成字节码格式,然后在浏览器中运行。Emscripten是一个将C/C++代码转换为WebAssembly的工具集,是WebAssembly技术的重要推动者之一。Emscripten的核心是一个将LLVM字节码转换为JavaScript或WebAssembly字节码的编译器,称为LLVM到JavaScript的编译器。该编译器可以将C/C++代码编译为LLVM字节码,然后通过LLVM到JavaScript编译器将字节码转换为JavaScript或WebAssembly代码。通过利用Emscripten工具,开发者可以使用C/C++等语言来开发Web应用,利用WebAssembly的高性能、低资源消耗、跨平台等优势来提升Web应用的性能和用户体验。
使用Emscripten开发编译流程大致如下:
#01
Emscripten安装
安装Emscripten需要使用emsdk脚本,emsdk脚本是基于python语言开发的,安装前需要确认有以下依赖项:`git`,`python`,`Node.js`。
安装步骤如下:
在终端中输入以下命令
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
git pull
./emsdk install latest
./emsdk activate latest
配置环境变量
source ./emsdk_env.sh
安装完成后的目录
安装结束后进行版本校验,查看版本信息
emcc -v
#02
Hello, Emscripten
接下来我们开始Emscripten开始之旅,新建一个`hello.cpp`文件,代码如下:
// hello.cpp
#include
using namespace std;
int main() {
cout << "Hello, World!" << endl;
return 0;
}
切换到当前工程目录,在控制台使用`emcc`命令生成wasm文件,通过`-o`选项指定输出文件:
emcc hello.cpp -o hello.js
编译完成后在目录中会生成`hello.js`文件和`hello.wasm`文件。
被编译成WebAssembly后的C/C++代码是不能直接运行的,需要通过浏览器加载运行。
在同一个目录,我们继续新建一个`hello.html`文件,并引入`hello.js`文件:
在浏览器中打开`hello.html`文件,在开发者面板中的Console中能够看到`hello.cpp`的输出内容。
WebAssembly是一种跨平台的字节码,不仅可以在浏览器中运行,也可以在node环境中运行:
#03
WebAssembly和JavaScript交互
如果要实现一个实用功能的WebAssembly模块,必然需要提供能够和外部交互的函数接口。包括JavaScript调用C/C++函数功能,C/C++函数调用JavaScript方法,以及C/C++函数和JavaScript交换数据等需求。
Emscripten编译生成的js文件是一种胶水代码,用来加载WebAssembly模块和导出相关函数。生成的js代码中有一个全局对象Module,该全局对象是Emscripten的核心,负责WebAssembly模块的载入、创建初始化等,以及对C/C++函数进行封装等功能。在之前`hello.js`中有对`hello.cpp`中的`main`函数的封装代码如下:
Emscripten会对封装导出的函数前面加上下划线,`main()`函数会被封装成`_main()`。我们可以在浏览器控制台中直接使用`_main()`函数。
#04
JavaScript调用C/C++函数
接下来我们新建一个export.cpp文件,代码如下:
我们定义了一个`EM_PORT_API`的宏定义,用来统一C和C++环境,方便用来导出函数。其中`__EMSCRIPTEN__`是用来识别Emscripten环境,`__cplusplus`是用来判断C++代码,`EMSCRIPTEN_KEEPALIVE`是Emscripten的宏定义,用来优化编译的。
切换到工程目录,在控制台使用emcc命令生成wasm文件:
目录中生成文件:`export.js`和`export.wasm`。继续在浏览器中测试我们的代码,新建一个`export.html`文件,代码如下:
WebAssembly实例是通过方法createWasm()异步创建的,有可能js文件加载后,Emscripten运行环境没有准备好,我们需要通过建立一种Emscripten运行时准备就绪的机制。一种简单的方法就是使用onRuntimeInitialized回调方法,在这个回调方法中运行WebAssembly Module导出的方法。
通过运行浏览器,我们可以在控制台查看JavaScript调用C++代码的结果:
#05
C/C++函数调用JavaScript方法
反过来,我们也可以在C/C++函数调用JavaScript方法。首先需要创建一个`call_js.cpp`文件,代码如下:
我们在`call_js.cpp`文件中声明了`js_add`和`js_console_log`两个函数,这两个函数/方法的具体实现是在js文件中。接着新建一个`mylibrary.js`文件,代码如下:
按照在C++文件中声明的方法签名,在js文件中实现了`js_add`和`js_console_log`的方法功能,并合并注入到`LibraryManager.library`中。`LibraryManager.library`对象可以简单理解为是JavaScript注入到C/C++中的运行时库。
在控制台使用emcc命令生成wasm文件,需要使用`--js-library`链接外部的js文件:
继续新建一个`call_js.html`文件用来测试代码,在浏览器查看我们的运行结果。
浏览器的运行结果如下:
03
总结
我们简单的展示了C/C++和JavaScript函数之间通过WebAssembly的相互调用,在这里并没有涉及到复杂的数据交换和相关的内存模型操作。WebAssembly是一个强大的Web应用技术,可以为Web应用程序提供更好的性能和更多强大的功能。Emscripten是一个用来开发WebAssembly应用的强大工具集。通过不断的学习WebAssembly开发技术,可以帮助开发人员在Web平台上构建更快、更安全、更可移植的应用程序。
















































































