Emscripten之基础使用

Emscripten之基础使用一 前言随着 WebAssembly 技术的发展 asm js 的竞争力已经逐渐被削弱了 所以 Emscripten 进一步与 Binaryen 结合 形成基于 LLVM 构建的 WebAssembly 后端 现如今 我们已经可以通过 Emscripten 工具链直接构建 Wasm 应用了 有兴趣了解 WebAssembly 与 asm js 的可以参考以下资料 asm js 阮一峰 asm js 和 Emscripten 入

一、前言

随着WebAssembly技术的发展,asm.js的竞争力已经逐渐被削弱了,所以Emscripten进一步与Binaryen结合,形成基于LLVM构建的WebAssembly后端。现如今,我们已经可以通过Emscripten工具链直接构建Wasm应用了。

有兴趣了解WebAssembly与asm.js的可以参考以下资料:

  • asm.js

阮一峰《asm.js和Emscripten入门教程》

  • WebAssembly

胡子大哈翻译的《WebAssembly系列(一) 生动形象地介绍WebAssembly》

二、编译目标与编译流程

在Emscripten环境下,编译目标可分为asm.js与WebAssembly两种,前者生成一个js文件,后者则生成wasm文件以及对应的JS胶水代码。因为WebAssmbly是二进制格式的,体积小、执行率高,在兼容性允许的条件下,一般建议试用WebAssembly作为编译目标。

使用emcc编译C/C++代码的主要流程如下:

emcc编译流程图

C/C++代码首先通过Clang编译成LLVM Bitcode,然后再根据不同的编译目标编译为asm.js或WebAssembly。

由于内部调用Clang,因此emcc支持绝大多数的Clang选项,比如-O、-g、-s OPTIONS=VALUE(这里是根据自己需求设置,比如编译为asm.js需要设置-s WASM=0)等。除此之外,为了适应Web环境,还增加了一些特有的选项,如–pre-js YOURFILE、–post-js YOURFILE等。

emcc所有的选项列表可以通过以下指令查询:

emcc --help 

三、Emscripten的简单使用

首先我们编写一个简单的demo,保存为hello.c/hello.cc:

#include  
     int main() { 
    printf("Hello World!"); } 

因为emsdk不是安装在系统上的,所以编译操作都需要在emsdk文件夹下进行。建议在emsdk下新建一个文件夹,存放需要编译的文件或项目。

3.1 生成默认Html

cd YourFolder
emcc hello.c -o hello.html

完成之后会在当前文件夹下生成hello.html、hello.js、hello.wasm三个文件。打开hello.html,可以看到默认的页面中显示“Hello World!”。如果想自定义html页面,可以只生成asm.js或者WebAssembly,然后在Web项目中引入使用即可。

3.2 生成asm.js

Emscripten是默认生成wasm文件的,如果想使用asm.js,需要设置WASM项为0。

emcc hello.c -s WASM=0 -o hello.js 

编译之后只生成hello.js。但当编译目标为asm.js时,未对齐的内存读写可能会出现异常。关于Emscripten内存对齐的问题可以参考以下资料:《C/C++面向WebAssembly编程》。

3.3 生成WebAssembly

执行以下命令

emcc hello.c -o hello_wasm.js 

编译之后生成hello.js与hello.wasm两个文件。其中hello.wasm是Web项目中使用的WebAssembly模块,而hello.js是对应的JS胶水代码,实现了将wasm文件引入,并导出对应的函数等。

四、JS中调用C函数

在Web项目中引入asm.js或WebAssembly,C/C++代码中的main函数在加载之后会立即运行。Emscripten除了可以导出main函数,还可以导出其他C/C++函数,但是为了避免在编译时被优化器删除普通的C/C++函数,所以需要在函数前加EMSCRIPTEN_KEEPALIVE标识,提前告知编译器保留当前函数。为了方便导出,提供以下函数导出宏:

#ifndef EM_PORT_API # if defined(__EMSCRIPTEN__) # include  
     # if defined(__cplusplus) # define EM_PORT_API(rettype) extern "C" rettype EMSCRIPTEN_KEEPALIVE # else # define EM_PORT_API(rettype) rettype EMSCRIPTEN_KEEPALIVE # endif # else # if defined(__cplusplus) # define EM_PORT_API(rettype) extern "C" rettype # else # define EM_PORT_API(rettype) rettype # endif # endif #endif 

修改之前的demo,保存为say.c,代码如下:

// 此处加上EM_PORT_API宏 #include  
     EM_PORT_API(void) say_hello() { 
    printf("Hello World!"); } 

打开编译器,执行以下命令:

emcc say.c -o say.js 

这里编译目标是WebAssembly,在Web项目中可以使用以下两种方式引入使用:

  • 4.1 script标签引入使用

 <html> <head> <meta charset="utf-8"> <title>Say Hello 
     title>  
      head> <body> <script> Module = { 
      } Module.onRuntimeInitialized = function() { 
       Module._say_hello(); }  
       script> <script src="say.js"> 
        script>  
         body>  
          html> 

在Module初始化前,向Module中注入一个名为onRuntimeInitialized的方法,Emscirpten中的Runtime就绪之后,就会回调这个方法。这里使用回调的原因是因为Emscripten生成的JS胶水代码中,是使用异步加载wasm文件的,所以需要通过该方法确认Runtime准备就绪后,才执行say_hello函数。

可以观察到,如果编译时生成了JS胶水代码,那么Module中对应的C/C++导出函数,在原函数名的基础上增加了下划线“_”前缀。

注意:JS胶水代码需要与wasm文件放在同一目录下。

  • 4.2 模块引入使用

使用require引入使用前,需要在JS胶水代码底部增加:

module.exports = Module; 

在JS引入:

var MyModule = require("say.js") MyModule.onRuntimeInitialized = function() { 
    MyModule._say_hello(); } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220023.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午9:25
下一篇 2026年3月17日 下午9:25


相关推荐

  • C++ 指针常量和常量指针

    C++ 指针常量和常量指针首先在 C 目前我看到的类型声明方式 该变量的类型都是由最后几个字来确定 前面是定语 修饰词 有其他不同的欢迎指出 共同学习 比如 指针数组 是数组 数组里存的是指针 数组指针 是指针 指针指向数组 所以指针常量 首先是常量 然后是一个指针 即是该指针是一个常量 指针的值 即指向的地址不会变 常量指针 首先是指针 指针指向的是常量 该指针所指向的值是个常量 然后对于类型 const 除了 const 在类型声明的最左侧的情况 const 都修饰它左边的类型 当它在最左边时 修饰右边最近的类型

    2026年3月26日
    1
  • pushd命令「建议收藏」

    1)功能pushd命令常用于将目录加入到栈中,加入记录到目录栈顶部,并切换到该目录;若pushd命令不加任何参数,则会将位于记录栈最上面的2个目录对换位置2)语法(1)格式:pushd [目录|-N|+N]  [-n](2)选项目录  将该目录加入到栈顶,并执行"cd目录",切换到该目录+N  将第N个目录移至栈顶(从左边数起,数字从0开始)-N   将第N个目录移至栈顶(从右…

    2022年4月18日
    70
  • 查看c源码地址

    查看c源码地址https referencesou microsoft com

    2026年3月16日
    1
  • 2005年10大偏执狂技术

    2005年10大偏执狂技术1 GoogleEarth 2005 年 Google 正式推出了免费的基于卫星图片的地图软件 GoogleEarth GoogleEarth 的功能犹如该公司的在线地图服务 GoogleMap 用户可以在一副 3D 地图上放大目的地或获得驾车指南 而 GoogleEarth 采用的 3D 地图定位技术则把 GoogleMap 上的最新卫星图片推向了一个新水平 用户可以在 3D 地图上搜索特定区域 放大

    2026年3月26日
    2
  • matlab保存图片函数后突变分辨变化,MATLAB总结 – 图片保存「建议收藏」

    matlab保存图片函数后突变分辨变化,MATLAB总结 – 图片保存「建议收藏」I.Matlab中保存图片的方法1.一种是出来图形窗口后手动保存(这儿又可以分两种):1.1直接从菜单保存,有fig,eps,jpeg,gif,png,bmp等格式。1.2edit——〉copyfigure,再粘贴到其他程序。2.另一种是用命令直接保存(这里也有两种):2.1用saveas命令保存图片。saveas的三个参数:(1)图形句柄,如果图形窗口标题栏是“Figure3…

    2025年11月3日
    6
  • 分治算法详解(超详细)

    分治算法详解(超详细)原分治算法详解

    2025年6月5日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号