安装

Mac 上最便捷的安装方式当然是通过 Homebrew:

$ brew install emscripten

安装好之后讲道理就已经自动配置好一切,然后 emcc 命令便可用了。

下面看非 Homebrew 安装的方式。

通过官方 WebAssembly - Developer’s Guide 提供的安装配置步骤进行环境相关设置。这里以 macOS 为例。

下载工具链

通过 clone emscripten 仓库到本地进行工具链(toolchain)的下载安装。

$ git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk

安装及配置

执行安装:

$ ./emsdk install latest

激活工具链,生成相应环境配置:

$ ./emsdk activate latest
`./emsdk activate latest` 命令的输出
$ ./emsdk activate latest
Writing .emscripten configuration file to user home directory /Users/wayou/
The Emscripten configuration file /Users/wayou/.emscripten has been rewritten with the following contents: import os

LLVM_ROOT = '/Users/wayou/dev/emsdk/fastcomp/fastcomp/bin'

BINARYEN_ROOT = '/Users/wayou/dev/emsdk/fastcomp'

NODE_JS = '/Users/wayou/dev/emsdk/node/8.9.1_64bit/bin/node'

SPIDERMONKEY_ENGINE = ''

V8_ENGINE = ''

TEMP_DIR = '/var/folders/qr/dlqjq3zj10xgf2xfx3mybn500000gn/T'

COMPILER_ENGINE = NODE_JS

JS_ENGINES = [NODE_JS] To conveniently access the selected set of tools from the command line, consider adding the following directories to PATH, or call 'source ./emsdk_env.sh' to do this for you. /Users/wayou/dev/emsdk:/Users/wayou/dev/emsdk/fastcomp/emscripten:/Users/wayou/dev/emsdk/node/8.9.1_64bit/bin

Set the following tools as active:

releases-fastcomp-3b8cff670e9233a6623563add831647e8689a86b-64bit

node-8.9.1-64bit

小贴士:其中 install 过程会从 https://chromium.googlesource.comhttps://storage.googleapis.comhttps://s3.amazonaws.com 域下载东西,所以最好在命令行配置科学 上网,否则安装会失败。

环境变量

通过执行以下命令添加相应命令及目录到环境变量以方便调用:

$ source ./emsdk_env.sh --build=Release

如果进行到这一步发生如下错误:

$ source ./emsdk_env.sh --build=Release
./emsdk_env.sh (line 19): Missing end to balance this if statement
if [ "$SRC" = "" ]; then
^
from sourcing file ./emsdk_env.sh
called on standard input source: Error while reading file './emsdk_env.sh'

这多半是因为你用的 shell 是 fish 语法不兼容的原因。

两个解决办法:

$ bash ./emsdk_env.sh
  • 因为其也提供了对应的 .fish 脚本,所以,也可以直接选择运行该 fish 脚本来解决上面语法报错的问题:
$ source ./emsdk_env.fish

执行成功的输出:

$ source ./emsdk_env.fish
Adding directories to PATH:
PATH += /Users/wayou/dev/emsdk Setting environment variables:

EMSDK = /Users/wayou/dev/emsdk

EM_CONFIG = /Users/wayou/.emscripten

检查安装

完成上面步骤后,可通过运行 emcc --version 命令查看是否安装成功:

$ emcc --version
`emcc --version` 命令的输出
$ emcc --version
cache:INFO: generating system asset: is_vanilla.txt... (this will be cached in "/Users/wayou/.emscripten_cache/is_vanilla.txt" for subsequent builds)
cache:INFO: - ok
emcc (Emscripten gcc/clang-like replacement) 1.38.33 (commit 0490c5f7aaf0e61aafd3b4cfe22cc56b803026b1)
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

如果执行 emcc 时报如下错误:

$ emcc --version
emscripten requires python 2.7.12 or above

大概率是 macOS 自带的是老版本的 Python2,而 emcc 需要 Python3。解决办法有很多,这里说一个。

尝试过在命令的配置文件中添加 alias 配置 aliast python=python3,是不生效的,但可以将 emcc 命令配置 alias 显式指定使用 python3 来启动。将如下配置添加到相应 shell 的配置文件中,以 fish 为例其配置文件为 ~/.config/fish/config.fish:

alias emcc="python3 /Users/wayou/Documents/dev/github/emsdk/fastcomp/emscripten/emcc"
alias em++="python3 /Users/wayou/Documents/dev/github/emsdk/fastcomp/emscripten/em++"
alias emrun="python3 /Users/wayou/Documents/dev/github/emsdk/fastcomp/emscripten/emrun"

根据官方文档的描述:

use em++ to force compilation as C++

--Emscripten Tutorial

em++ 用于编译 c++ 代码,所以这里将 em++ 也添加上了。

这里同时也将 emrun 添加上了别名,方便后面使用它来启动本地服务以调试。

小贴士:新开命令行窗口或重启命令行后,需要重新执行 source 命令,可将其添加到你所使用的命令行的配置文件中,.bash_profile.zshrc,或 .

以 fish 为例:

~/.config/fish/config.fish.fish

source "/Users/wayou/dev/emsdk/emsdk_env.fish";

这样每次启动命令行后 emcc 都是可用状态。

编译及运行

安装配置完成后,便可以尝试编译并运行一个简单的 demo 程序了。

一些注意点:

  • 运行 emcc 时需要指定 -s WASM=1 参数,否则默认情况下其输出为 asm.js
  • 除了生成 Wasm 二进制文件及对应的 JavaScript 封装,如果还想要生成一个可直接查看的 HTML 页面,可在输出时指定一个后缀为 .html 的文件。
  • 实际运行时不能直接打开这个生成的 HTML 文件,因为 file:/// 协议不支持跨域,所以需要本地启一个服务器来查看。

编写 Hello World

创建 hello.c 文件并输出以下内容:

hello.c

#include <stdio.h>
int main(int argc, char ** argv) {
printf("Hello, world!\n");
}

编译

执行以下命令进行编译:

$ emcc hello.c -s WASM=1 -o hello.html

运行

通过工具链中提供的 smrun 来开启一个本地服务器以查看刚刚生成的程序:

$ emrun --no_browser --port 8080 .

当然,使用其他任意 server 也是可以的,比如 Python 的:

$ python -m http.server 8080

启动成功后浏览器访问 http://localhost:8080/hello.html。不出意外你会看到页面中 Emscripten 的控制台展示了 Hello, world!

WebAssembly Hello Wrold 运行效果

但用 emrun 的好处在于它已经处理好了 .wasm 文件的返回类型为 Content-type: application/wasm,而其他 server 可能需要额外的配置,否则默认情况下 .wasm 文件返回到浏览器时其 Content-Type 不对会报错。

调用 C++ 中的方法

下面来看如何在 JavaScript 中调用 C++ 定义的方法。

默认情况下,Emscripten 编译后的代码只包含 main 方法相关的调用,其他无关的代码将会在编译时去掉。可通过在方法名前加 EMSCRIPTEN_KEEPALIVE 来防止需要导出的方法被去掉。

将以下代码放入 hello.c 并保存。

#include <stdio.h>
#include <emscripten/emscripten.h> int main(int argc, char ** argv) {

printf("Hello World\n");

}

ifdef __cplusplus

extern "C" {

endif

void EMSCRIPTEN_KEEPALIVE myFunction(int argc, char ** argv) {

printf("MyFunction Called\n");

}

ifdef __cplusplus

}

endif

此时编译需要加上 NO_EXIT_RUNTIME 参数,否则默认情况下 C++ 模块中 main 方法返回后程序就结束了。

执行以下命令编译代码:

$ emcc -o hello3.html hello3.c -O3 -s WASM=1 -s NO_EXIT_RUNTIME=1  -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']"

打开在发生的 hello.html,在第一个 <script> 标签开始前加上一个按钮:

<button class="mybutton">Run myFunction</button>

添加以下点击调用逻辑到第一个 <script> 代码块的末尾:

document.querySelector(".mybutton").addEventListener("click", function() {
alert("check console");
var result = Module.ccall(
"myFunction", // name of C function
null, // return type
null, // argument types
null // arguments
);
});

再次启动服务器运行后,点击页面中按钮在控制台观察输出。

JavaScript 中调用 C++ 方法的示例

相关资源

WebAssembly 上手的更多相关文章

  1. 快速上手最棒的网格框架ag-Grid

    由于对aggrid由衷的感谢, 又忍不住写了一篇软文来推广它(其实主要是为了弥补我把enterprise版扣下来后内心的愧疚...) ag-Grid是速度最快,功能最丰富的JavaScript dat ...

  2. ASP.NET Core Blazor 初探之 Blazor WebAssembly

    最近Blazor热度很高,传说马上就要发布正式版了,做为微软脑残粉,赶紧也来凑个热闹,学习一下. Blazor Blazor是微软在ASP.NET Core框架下开发的一种全新的Web开发框架.Bla ...

  3. 【重榜?】.NET 6 Preview 1 开箱上手!带你尝试新版本更新!

    目录 跨平台 UI 应用 Blazor 桌面应用 System.CommandLine 其它更新 ASP.NET Core 最近 .NET 6 Preview 1 发布了,.NET 统一是此版本的核心 ...

  4. 【Python五篇慢慢弹】快速上手学python

    快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...

  5. Impress.js上手 - 抛开PPT、制作Web 3D幻灯片放映

    前言: 如果你已经厌倦了使用PPT设置路径.设置时间.设置动画方式来制作动画特效.那么Impress.js将是你一个非常好的选择. 用它制作的PPT将更加直观.效果也是嗷嗷美观的. 当然,如果用它来装 ...

  6. ECharts数据图表系统? 5分钟上手!

    目录: 前言 简介 方法一:模块化单文件引入(推荐) 方法二:标签式单文件引入 [前言] 最近在捣鼓各种插件各种框架,发现这个ECharts还是比较不错的,文档也挺全的,还是中文的,给大家推荐一下. ...

  7. 快速上手Unity原生Json库

    现在新版的Unity(印象中是从5.3开始)已经提供了原生的Json库,以前一直使用LitJson,研究了一下Unity用的JsonUtility工具类的使用,发现使用还挺方便的,所以打算把项目中的J ...

  8. Masonry介绍与使用实践:快速上手Autolayout

    1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时代 w ...

  9. [译]:Xamarin.Android开发入门——Hello,Android Multiscreen快速上手

    原文链接:Hello, Android Multiscreen Quickstart. 译文链接:Hello,Android Multiscreen快速上手 本部分介绍利用Xamarin.Androi ...

随机推荐

  1. MySQL-子查询,派生表,通用表达式

    MySQL-子查询 MySQL子查询是嵌套在另一个查询中的查询. MySQL子查询还可以嵌套在另一个子查询中. MySQL子查询称为内部查询,而包含子查询的查询称为外部查询. 查询返回在位于美国(US ...

  2. dm385和8127的区别

    DM385/DM8127在ITS智能交通中的应用分析德州仪器(TI)自推出DM385和DM8127视频处理器在业界反响很大特别是深圳安博会上展出的1080P60帧高清效果之后很多龙头企业也跃 ...

  3. JavaScript总结01

    1 JavaScript 与 Java 的关系? 雷锋和雷峰塔的关系JavaScript和Java都与sun公司有合作,是借势Java 2 JavaScript 的特点是什么? 脚本语言(一种轻量级的 ...

  4. Linux在终端启动程序关闭终端不退出的方法

    一般情况下关闭终端时,那么在这个终端中启动的后台程序也会终止,要使终端关闭后,后台程序保持执行,使用这个指令: nohup 命令 & 如:nohup ./studio.sh & 网上其 ...

  5. python-----文件自动归类

    如何移动文件? →  使用内置模块来实现 归类的规则是什么? → 手动(预设文件夹)/ 自动(创建文件夹) import shutil import os path = './' #由于这里是相对路径 ...

  6. Ural1099 Work Scheduling 一般图的最大匹配

    Ural1099 给定无向图, 求最大匹配. 在寻找增广路的过程中,可能出现一个奇环,这时候把奇环收缩,成为一朵“花”,并在新图上继续增广. 为了记录匹配关系,需要在花中寻找路径,每一条增广路径都可以 ...

  7. MySQL5.7修改字符集

    本人安装的mysql版本是5.7.20,安装好mysql后就要对字符集进行修改了,于是照着网上的大部分教程说的去安装目录找一个my-default.ini文件,然后重命名为my.ini,再对其进修改字 ...

  8. COCI2012 TOY

    有m种物品,n个箱子之中装着若干物品.问取出一些箱子后,所有m种物品都被选出的方案数. m<=20,n<=106 这道题很妙啊 深刻地利用了容斥 看到n=20,我们就想到了状压和容斥. 怎 ...

  9. 【152】C# 操作 Excel 杂记

    前面写了一篇博文是关于 C# 操作 Excel 的文章,但是里面有些中规中矩,搞的我不知道怎么写了,所以另开一帖.. 注意:基本应用如下所示! //首先是引用 using Excel = Micros ...

  10. bzoj 1755: [Usaco2005 qua]Bank Interest【模拟】

    原来强行转int可以避免四舍五入啊 #include<iostream> #include<cstdio> using namespace std; int r,y; doub ...