翻译:云荒杯倾
本文是Emscripten-WebAssembly专栏系列文章之一,更多文章请查看专栏。
也能够去做者的博客阅读文章。
欢迎加入Wasm和emscripten技术交流群,群聊号码:939206522。html
若是只是想要入门Emscripten的话,使用Emscripten是很是简单的。本教学将教会你从命令行编译Emscripten代码的种种步骤,以及Emscripten代码中怎样使用文件和使用主要的编译优化flag。node
首先是确保你已经下载而且安装好了Emscripten。根据你的操做系统不一样,下载和安装过程稍有不一样。c++
Emscripten主要是经过emcc(Emscripten Compiler Frontend)来工做的。这是个命令行工具,它会调用其余编译须要的工具,能够将它当作是标准编译器好比gcc或者clang的命令行版本。wimdows系统的话,命令行中使用emcc,Linux下使用./emcc。git
第一次使用Emscripten,请先使用如下命令验证Emscripten是否正确安装:github
emcc -v
若是有警告发生,多是由于缺乏一些工具,请去看这个连接解决
若是没有警告或报错,就往下看。web
如今就可使用Emscripten把C/C++代码编译成JavaScript了。canvas
首先,写一个待编译为JavaScript的C文件。好比hello_world.c,像下面这样:segmentfault
#include <stdio.h> int main() { printf("hello, world!\n"); return 0; }
注:这是Emscripten提供的测试集中最简单的一个C文件。浏览器
为了编译这个C文件,你只须要在test目录下打开命令行,emcc后面跟上这个文件名就好了。less
emcc tests/hello_world.c
注:test目录是Emscripten测试集的目录。
这样就会在test目录下生成一个a.out.js文件,你可使用node运行这个a.out.js。
node a.out.js
就会在node控制台打印出hello world!了。
若是编译失败,你能够在emcc tests/hello_world.c后面加个-v,也就是变成emcc tests/hello_world.c -v ,这样呢就会有一些调试信息,你能够参考他们,找出编译失败的缘由。
Emscripten能为刚才输出的那个JavaScript生成HTML文件,你可使用-o命令指定要输出的html文件名。
emcc tests/hello_world.c -o hello.html
在浏览器打开这个hello.html。你会看到,这个HTML页面中有一块文本区域是为了显示C代码中printf()函数打印的内容。
实际上,这块区域不只能够显示文本。若是你C代码中调用了SDL的API,那么也能够在一块canvas中显示一个五彩斑斓的cube。好比,hello_world_cube.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; }
C/C++中,能够用libc库的fopen,fclose等API来访问文件
js运行在浏览器的沙盒环境中,并不能直接访问本地文件系统,不过,Emscripten模拟了一个文件系统,这样你能够在你的C/C++代码中继续使用libc的API。
你想访问的文件应该经过preload或者embedded的方式打包到Emscripten虚拟的文件系统中。
测试集中,hello_world_file.cpp展现了怎么加载一个文件。测试代码和测试文件hello_world_file.txt以下面所示:
#include <stdio.h> int main() { FILE *file = fopen("tests/hello_world_file.txt", "rb"); if (!file) { printf("cannot open file\n"); return 1; } while (!feof(file)) { char c = fgetc(file); if (c != EOF) { putchar(c); } } fclose (file); return 0; }
== This data has been read from a file. The file is readable as if it were at the same location in the filesystem, including directories, as in the local filesystem where you compiled the source. ==
下面命令是在任何编译代码运行前指定一个数据文件预加载到Emscripten的虚拟文件系统。这个方法颇有用,由于浏览器只能异步获取数据的,而原生代码(C/C++)不少都是使用的同步文件API,那么,用这个方法能够确保数据加载完成以前,编译代码(C/C++编译以后的js)不会从Emscripten的虚拟文件系统中去取数据,也就不会出错。下面是编译命令:
./emcc tests/hello_world_file.cpp -o hello.html --preload-file tests/hello_world_file.txt
运行生成的HTML,就能看到hello_world_file.txt文件的内容。
默认状况下,和gcc以及clang等编译器同样,Emscripten生成的编译代码没有通过编译优化。那么,你能够在命令行参数中使用-O1,生成轻微优化的代码。
./emcc -O1 tests/hello_world.cpp
由于编译生成a.out.js的过程实际上并不真的须要优化,因此实际上你加不加-O1,从编译时间(或者说编译速度)上,你是看不出区别的。
可是真的没区别吗?
你能够看看生成的a.out.js文件,就能发现仍是有区别的。-O1的优化有一些微小的优化而且清除了一些运行时断言,好比,在生成的代码中,printf函数,会被替换成put。
想编译优化,不只能够用-O1,还能够用-O2,-O2优化的程度更厉害。你能够试一下,它的编译代码跟-O1又有很大差异。
Emscripten给你们提供了很是多的测试用例,几乎覆盖了Emscripten的全部功能。对于开发者来讲,这是很是好的资源。
关于测试集的更多状况,能够点击了解。
本教学告诉了你使用Emscripten的第一步,就是使用命令行编译一个c/c++代码为js或者HTML。为了了解更多Emscripten,给你几个小贴士:
Emscripten主题系列文章是emscripten中文站点的一部份内容。
第一个主题介绍代码可移植性与限制
第二个主题介绍Emscripten的运行时环境
第三个主题第一篇文章介绍链接C++和JavaScript
第三个主题第二篇文章介绍embind
第四个主题介绍文件和文件系统
第六个主题介绍Emscripten如何调试代码