emscripten getting start
Emscripten是一个基于LLVM的项目,可以把C和C++代码编译成高度优化的JavaScript代码(asm.js格式),可以在web中以近乎原生的速度运行C和C++代码,而且不需要插件。
把现有的C/C++直接编译,并且可以在所有现代浏览器中运行
Emscripten把OpenGL转译成WebGL, 并且可以使用你熟悉的API开发,比如SDL, 或者直接使用html5
得益于 LLVM, Emscripten 和 asm.js,代码可以用接近原生代码的速度运行
1.About Emscripten
Emscripten是一个开源 LLVM to JavaScript 编译器. 有了Emscripten你可以:
- 把 C 和 C++ 代码编译成 JavaScript
- 把可以编译成 LLVM 字节码的其他代码编译成 JavaScript.
- 把其他语言的 C/C++ runtimes 编译成 JavaScript, 并在web中以间接方法运行这种语言 (已经被 Python 和 Lua 使用)!
2.Emscripten Toolchain
Emscripten工具链的流程图如下。核心是Emscripten编译器前端(emcc),它是标准编译器(比如gcc)的替代实现。
Emcc 使用 Clang 把 C/C++ 文件编译为 LLVM 字节码, 使用 Fastcomp (Emscripten 的编译器核心 — 一个 LLVM 后端) 来把字节码编译成 JavaScript. 输出的 JavaScript 可以被 node.js 执行, 或者嵌入 HTML 在浏览器中运行
3.Download and install
windows可以选择安装完整版的Emscripten SDK或者绿色版for Win,linux和mac用户只能下载绿色版for Unix like
我是mac用户,讲解一下绿色版的安装方法
- 下载并解压emsdk_protable并解压到某个文件夹下
- 打开终端并进入到emsdk文件夹下,然后执行下列命令
# 获取最新可用工具链的信息
./emsdk update
# 下载并安装最新的工具链
./emsdk install latest
# 让 "最新的" SDK "激活"
./emsdk activate latest
3.Mac和linux需要,吧emsdk的路径添加到PATH
# 在Linux/Mac OS X上添加emsdk的路径到PATH
source ./emsdk_env.sh
这步windows用户不需要,windows在执行
activate
命令时已经完成PATH的修改
4.使用Emscripten
在终端下输入emcc -v
,看到当前的Emscripten版本和llvm版本
4.1 hello.c
新建一个hello.c文件,在文件内添加如下内容
#include<stdio.h>
int main() {
printf("hello, world!\n");
return 0;
}
然后运行
emcc hello.c
当前文件夹下应该生成了a.out.js,可以使用node.js运行
node a.out.js
正常的话命令行中显示“hello, world!”
然后运行
emcc hello.c -o hello_world.html
当前文件夹下生成hello_world.html和hello_world.js两个文件,在浏览器中打开hello_world.html,可以看到类似这样的效果
4.2 hello_world_sdl.cpp
hello_world_sdl.cpp文件,在文件内添加如下内容
#include <stdio.h>
#include <SDL/SDL.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
extern "C" int main(int argc, char** argv) {
printf("hello, world!\n");
SDL_Init(SDL_INIT_VIDEO);
SDL_Surface *screen = SDL_SetVideoMode(256, 256, 32, SDL_SWSURFACE);
#ifdef TEST_SDL_LOCK_OPTS
EM_ASM("SDL.defaults.copyOnLock = false; SDL.defaults.discardOnLock = true; SDL.defaults.opaqueFrontBuffer = false;");
#endif
if (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
#ifdef TEST_SDL_LOCK_OPTS
// Alpha behaves like in the browser, so write proper opaque pixels.
int alpha = 255;
#else
// To emulate native behavior with blitting to screen, alpha component is ignored. Test that it is so by outputting
// data (and testing that it does get discarded)
int alpha = (i+j) % 255;
#endif
*((Uint32*)screen->pixels + i * 256 + j) = SDL_MapRGBA(screen->format, i, j, 255-i, alpha);
}
}
if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
SDL_Flip(screen);
printf("you should see a smoothly-colored square - no sharp lines but the square borders!\n");
printf("and here is some text that should be HTML-friendly: amp: |&| double-quote: |\"| quote: |'| less-than, greater-than, html-like tags: |<cheez></cheez>|\nanother line.\n");
SDL_Quit();
return 0;
}
然后运行
emcc hello_world_sdl.cpp -o hello_world_sdl.html
浏览器中打开hello_world_sdl.html可以看到类似这样的页面
4.3 hello_world_gles.cpp
新建一个hello_world_gles.cpp,添加这里的代码
编译,生成类似这个网页
4.4 glfw
新建一个glfw.c,并添加这里的代码
浏览器中打开glfw.html可以看到类似这样的页面,移动鼠标或者敲键盘,输入都能被捕捉并在下方的虚拟终端中显示
4.5 lua虚拟机
下载lua源代码,用这的也可以
将lua源码所在文件夹的名称改为lua,在这里再新建一个文件夹dist,dist和lua文件夹在同一层。进入lua文件夹,执行下面的命令
make emscripten
在dist文件夹中会生成lua.vm.js
4.5.1 在node.js中使用lua.vm.js
执行
$ npm install lua.vm.js
然后编写node.js代码
var LuaVM = require('lua.vm.js');
var l = new LuaVM.Lua.State();
l.execute('print("Hello, world")');
4.5.2 在网页中使用lua.vm.js
可以参考这个示例