【问题标题】:Emscripten with module loaders带有模块加载器的 Emscripten
【发布时间】: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 泄露任何内容?

【问题讨论】:

    标签: javascript module emscripten


    【解决方案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 编译标志,看起来很有希望......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-07
    • 1970-01-01
    • 1970-01-01
    • 2018-02-16
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多