Emscripten编译c/c++为WebAssembly

268 阅读3分钟

Emscripten介绍

WebAssembly是一种面向Web的二进制格式,不是一种编程语言,它是一种可移植、高性能、低级别的虚拟机。它是由W3C(万维网联盟)设计的一种新型的Web标准,旨在通过在Web浏览器中运行高性能的本机二进制代码,提供更快速、更安全的Web应用程序。

Emscripten是一个用于将C/C 代码编译为Wasm字节码的工具链。我们也可以用他来将Typescript(搭配tsc)编译成 LLVM字节码。

emsd 是一个基于Python的全平台(Windows、Mac、Linux)的开发工具,主要用于管理和使用emscripten编译器。emsdk的主要功能包括:安装、卸载emscripten以及相关工具链,切换不同版本的emscripten编译器,管理运行时模块(即.s和.js文件),支持WebAssembly生成和优化等。别外,

编译原理: Emscripten编译优化分为两个步骤

  1. 每个源文件编译成目标文件(.bc文件),通过LLVM优化
  2. 目标文件编译成js文件

中文网:emcc.zcopy.site/

安装Emscripten

安装python 3.6+

网上与Python官网的指南都很清晰明了,此处(略) .

安装git

网上与git官网的指南都很清晰明了.

安装emsdk (Emscripten安装器,工具包)

Get the emsdk source

# Get the emsdk repo
git clone https://github.com/emscripten-core/emsdk.git

# Enter that directory
cd emsdk

拉取最新代码并激活

git pull

# 记得一定要加 --system
./emsdk install --system latest

./emsdk activate latest

# Activate PATH and other environment variables in the current terminal
# in linux
# source ./emsdk_env.sh 

更新emsdk

# Fetch the latest registry of available tools.
emsdk update

# Download and install the latest SDK tools. 
# 加 --system
emsdk install --system latest

# Set up the compiler configuration to point to the "latest" SDK.
emsdk activate latest

配置emsdk和emcc环凌变量

输入

# Activate PATH and other environment variables in the current terminal
#source ./emsdk_env.sh

emsdk_env.bat

会有如下输了

Setting up EMSDK environment (suppress these messages with EMSDK_QUIET=1)
Adding directories to PATH:
PATH += D:\software\emsdk

Setting environment variables:
PATH = D:\software\emsdk;D:\tmp\emsdk;C:\Program Files\NVIDIA GPU Computing
...

EMSDK = D:/software/emsdk
Clearing existing environment variable: EMSDK_PY

根据上述我们对环境变量做如下配置: EMSDK:

image.png

PATH:

image.png

linux的话是在/etc/profile文件内

验证安装

emcc -v

到这里 Emscripten 已经成功安装完成了,配置完 PATH 后即可在全局调用此命令,接下来就可以将 C或ts(后者需要搭ts) 代码编译成 wasm 文件了。

激活其他版本

# Get list of the old versions of the tool.
./emsdk list --old

# Install the required version.
./emsdk install <name_of_tool>

# Activate required version.
./emsdk activate <name_of_tool>

更多信息:emscripten.org/docs/tools_…

用Emscripten将C/C++编译为wasm文件

配置vscode

也可以用其他工具,这时笔者主要使用vscode做该demo。

配置VS Code。如果您使用Visual Studio Code,可以按照以下步骤配置:

  1. 在VS Code中打开一个新窗口
  2. 按下F1,在命令栏中输入“C/C++: Edit Configurations”并选择它
  3. 在弹出的窗口中添加以下配置:
{
  "name": "emscripten",
  "includePath": [
    "${workspaceFolder}/**"
  ],
  "defines": [
    "_DEBUG",
    "UNICODE",
    "_UNICODE"
  ],
  "compilerPath": "C:/emsdk/emscripten/1.38.22/em++.bat",
  "cStandard": "c17",
  "cppStandard": "c++17",
  "intelliSenseMode": "windows-gcc-x64"
}

准备文件

hello.cpp

#include <stdio.h>

int main() {
  printf("hello, world!\n");
  return 0;
}

编译成js

./emcc hello.cpp

image.png

目录下会生成a.out.js and a.out.wasm两个文件

Node测试

node a.out.js

控制台会输出hello, world

更多命令

生成html - 用于测试

emcc hello.cpp -o hello.html

在浏览器打开hello.html,可看到效果。

转成wast可读文件

wasm2wat hello.wasm -o hello.wast

先编译成js + 再指定导出的的方法

准备 index.cpp 文件


int add(int x, int y) 
{
    return x + y;
}

int min(int x, int y) 
{
    if (x>y){
        return y;
    } else {
        return x
    }
}

编译

以下命令执行完将会生成 index.index.wasm两个文件。

emcc index.cpp -o index.js -s EXPORTED_FUNCTIONS='["_add","_min"]' -O3 -s wasm=1

参数说明:

EXPORTED_FUNCTIONS指的是导出的函数,需要和源文件里的函数名是相对应的(比原函数名多了一个"_"前缀
O3是编译优化等级,只有这个等级生成的wasm文件才会很小(几十字节),不加该优化选项,生成的wasm将会有几十KB。生成的时候会临时产生*.asm.js,等生成完后,会自动删掉。

编写test.js

var em_module = require('./index.js');
console.log("add:"+em_module._add(4,5));
console.log("add:"+em_module._min(5,4));

用node.js测试

Node node-test.js