带有模块加载器的 Emscripten

Posted

技术标签:

【中文标题】带有模块加载器的 Emscripten【英文标题】:Emscripten with module loaders 【发布时间】:2015-03-29 12:43:32 【问题描述】:

我正在尝试使用 Emscripten 将 C 库转换为可移植的 javascript 模块,该模块将由 AMD(例如 Require.JS)加载并提供对其功能和事物的访问:

require("vendor/mylib.js", function(mylib) 
    mylib.function1();
);

但是,我看到 Emscripten 使用大量变量污染了全局命名空间,这违背了模块应该独立且不与其他加载的模块发生冲突的前提。

所以问题是:将 Emscrpiten 与 AMD 结合使用的最佳方式是什么?

有没有办法告诉 Emscripten 不要向global 泄露任何内容?

【问题讨论】:

【参考方案1】:

emcc docs 中有 2 个命令行选项可以提供帮助,--pre-js <file>--post-js <file>。它们允许您包装生成的代码,因此允许您与 AMD 集成。

例如,你可以有一个前缀文件

// prefix.js
define(function() 
  return function(Module) 

和一个后缀文件

// postfix.js
  ;
);

您将使用类似的东西编译输出到myModule.js

emcc --pre-js prefix.js --post-js postfix.js -o myModule.js myModule.cpp

然后是 require 模块,使用 RequireJS 语法:

require(['myModule'], function(myModule) 
  myModule(... Module definition object ...);
);

下面是一个更完整的示例,在模块定义对象中设置一个画布元素。我还包括 domReady plugin 以便在 DOM 准备好时抓取元素。

<!DOCTYPE html>
<html>
  <head>
    <script src="require.js"></script>
    <script>
      require(['domReady', 'myModule'], function(domReady, myModule) 
        domReady(function() 
          myModule(
            canvas: document.getElementById('canvas_1')
          );
          myModule(
            canvas: document.getElementById('canvas_2')
          );
        );
      );
    </script>
  </head>
  <body>
    <canvas id="canvas_1"></canvas>
    <canvas id="canvas_2"></canvas>
  </body>
</html>

这样不仅可以根据您的请求保留全局命名空间,还可以让您在页面中同时拥有多个 Emscripten 支持的画布元素(如果需要)。

上面的 HTML 页面可以在 http://plnkr.co/edit/8jE3uLwrlszQuHbixU68?p=preview 看到。它加载了一个 C++ 程序:

#include <iostream>
using std::cerr;

int main() 
  cerr << "In C++ main function";

如果您加载 Plunker,那么您应该会看到两次“In C++ main function”,每个加载的模块一次。

如果您需要访问 Emscripten 修改的 Module 对象,比如调用公开的库函数,您可以执行以下操作,等待 Emscripten 本身使用 monitorRunDependencies 选项加载的所有依赖项:

require(['myModule'], function(myModule) 
  var moduleDef = 
    monitorRunDependencies: function(numberOfDependenciesRemaining) 
      if (numberOfDependenciesRemaining) return;
      // At this point we can call functions added to moduleDef
      // such as cwrap or ccall
    
  
  myModule(moduleDef);
);

【讨论】:

非常有趣,没想到像那样一起使用--pre-js--post-js... 但是我检查了Plunk 并且Module 对象存在于全局命名空间中。我怎样才能避免这种情况? @jmendeth 我怀疑我是用 Emscripten 的旧版本创建的。包含github.com/kripken/emscripten/commit/… 提交的最新版本我认为不会将Module 对象放在全局命名空间中 根据 FAQ answer,Emscripten 现在有 MODULARIZEEXPORT_NAME 编译标志,看起来很有希望......

以上是关于带有模块加载器的 Emscripten的主要内容,如果未能解决你的问题,请参考以下文章

在角度翻译中使用自定义加载器的问题

是否有用于异步 JSON 解析器的 Node 模块,它不会将整个 JSON 字符串加载到内存中?

JVM扩展之JDK9中有关类加载器的变动

JVM扩展之JDK9中有关类加载器的变动

JVM扩展之JDK9中有关类加载器的变动

检查 Webpack 中是不是已加载模块?