Emscripten
Emscriptrn
但实质上

环境配置
我们使用
# 也可以直接拉取代码
$ git clone https://github.com/emscripten-core/emsdk.git
$ ./emsdk update
$ ./emsdk install latest
# 如果出现异常使用 ./emsdk install sdk-1.37.12-64bit
# https://github.com/kripken/emscripten/issues/5272
安装完毕后激活响应环境即可以进行编译:
$ ./emsdk activate latest
$ source ./emsdk_env.sh# you can add this line to your .bashrc
到这里基本环境已经配置完毕,我们可以对简单的
int counter = 100;
int count() {
counter += 1;
return counter;
}
$ emcc counter.c -s WASM=1 -s SIDE_MODULE=1 -o counter.wasm
# 如果出现以下错误,则是由如下参数
# WebAssembly Link Error: import object field 'DYNAMICTOP_PTR' is not a Number
emcc counter.c -O1 -s WASM=1 -s SIDE_MODULE=1 -o counter.wasm
这样我们就得到了

使用Docker
如果在本地执行上述搭建步骤时一直失败,可以改用
# 拉取 Docker 镜像
docker pull 42ua/emsdk
# 执行编译操作
docker run --rm -v $(pwd):/home/src 42ua/emsdk emcc hello_world.c
对应的
FROM ubuntu
RUN \
apt-get update && apt-get install -y build-essential \
cmake python2.7 python nodejs-legacy default-jre git-core curl && \
apt-get clean && \
\
cd ~/ && \
curl -sL https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | tar xz && \
cd emsdk-portable/ && \
./emsdk update && \
./emsdk install -j1 latest && \
./emsdk activate latest && \
\
rm -rf ~/emsdk-portable/clang/tag-*/src && \
find . -name "*.o" -exec rm {} \; && \
find . -name "*.a" -exec rm {} \; && \
find . -name "*.tmp" -exec rm {} \; && \
find . -type d -name ".git" -prune -exec rm -rf {} \; && \
\
apt-get -y --purge remove curl git-core cmake && \
apt-get -y autoremove && apt-get clean
# http://docs.docker.com/engine/reference/run/#workdir
WORKDIR /home/src
编译命令如下所示,如果本地安装好了
$ docker run --rm -v $(pwd):/home/src 42ua/emsdk emcc counter.c -s WASM=1 -s SIDE_MODULE=1 -o counter.wasm
编译参数
- -O1、-O2、-O3、-Oz、-Os、
-g 等:编译优化,具体可参考Emscripten 官网相关章节; - -s ENVIRONMENT:设定编译代码的可执行环境,默认值为
"web,work,node" ; - -s SINGLE_FILE:是否将
ASM.js 或WebAssembly 代码以Base64 的方式嵌入到JavaScript 胶水代码中,可取值0/1 ; - -s WASM:是否编译为
WebAssembly 代码,0 编译为ASM.js ,1 编译为WebAssembly ; - -s FETCH:是否启用
Fetch 模块,可取值0/1 ; - -s DISABLE_EXCEPTION_CATCHING:禁止生成异常捕获代码,可取值
0/1 ; - -s ERROR_ON_UNDEFINED_SYMBOLS:编译时出现
Undefined Symbols 后是否退出,可取值0/1 ; -s EXIT_RUNTIME: 执行完毕main
函数后是否退出,可取值0/1 ;- -s FILESYSTEM:是否启用
File System 模块,可取值0/1 ; - -s INVOKE_RUN:是否执行
C/C++ 的main
函数,可取值0/1 ; - -s ASSERTIONS:是否给运行时增加断言,可取值
0/1 ; - -s TOTAL_MEMORY:总的可用内存使用数,可取以
16777216 为基数的整数值; - -s ALLOW_MEMORY_GROWTH:当可用内存不足时,是否自动增长,可取值
0/1 ; - -s EXPORTED_FUNCTIONS:暴露的函数列表名称;
- -s LEGACY_VM_SUPPORT:是否增加部分兼容函数以兼容低版本浏览器(iOS9、老版本
Chrome 等) ,可取值0/1 ; - -s MEM_INIT_METHOD:是否将
.mem 文件以Base64 的方式嵌入到JavaScript 胶水代码中,可取值0/1 ; - -s ELIMINATE_DUPLICATE_FUNCTIONS:将重复函数进行自动剔除,可取值
0/1 ; - –
closure: 是否使用Google Closure 进行最终代码的压缩,可取值0/1 ; - –llvm-lto:是否进行
LLVM 的链接时优化,可取值0-3 ; - –memory-init-file:同
-s MEM_INIT_METHOD ;
Hello World
我们先以打印
#include <stdio.h>
int main() {
printf("Hello World!\n");
return 0;
}
使用相关的
> emcc main.c -o hello.html
执行完毕后你将得到三个文件代码,分别是:
- hello.html
- hello.js:相关的胶水代码,包括加载
WASM 文件并执行调用等相关逻辑 - hello.wasm:编译得到的核心
WebAssembly 执行文件
如果我们想要让
> emcc main.c
第三方库
在我们的日常的业务开发中相关程序是不可能如此简单的。除了我们自己的操作逻辑外,我们还会依赖于非常多商用或开源的第三方库及框架。比如在数据通信及交换中我们往往会使用到
首先我们下载相关的源码放置在我们项目的
cmake_minimum_required(VERSION 3.15) # 根据你的需求进行修改
project(sample C)
set(CMAKE_C_STANDARD 11) # 根据你的C编译器支持情况进行修改
set(CMAKE_EXECUTABLE_SUFFIX ".html") # 编译生成.html
include_directories(vendor) # 使得我们能引用第三方库的头文件
add_subdirectory(vendor/cJSON)
add_executable(sample main.c)
# 设置Emscripten的编译链接参数,我们等等会讲到一些常用参数
set_target_properties(sample PROPERTIES LINK_FLAGS "-s EXIT_RUNTIME=1")
target_link_libraries(sample cjson) # 将第三方库与主程序进行链接
#include <stdio.h>
#include "cJSON/cJSON.h"
int main() {
const char jsonstr[] = "{\"data\":\"Hello World!\"}";
cJSON *json = cJSON_Parse(jsonstr);
const cJSON *data = cJSON_GetObjectItem(json, "data");
printf("%s\n", cJSON_GetStringValue(data));
cJSON_Delete(json);
return 0;
}
由于我们使用了
> mkdir build
> cd build
> emcmake cmake ..
> emmake make
我们创建了一个
WASM 的调试
对于开发的
#include <stdio.h>
int main() {
printf("Hello World!");
return 0;
}
然后我们使用
> emcc -g4 main.c -o main.wasm # -g4可生成对应的sourcemap信息
接着打开
Links
- https://web.dev/webassembly-threads/ Using WebAssembly threads from C, C++ and Rust