模块对象

Module 是一个全局 JavaScript 对象,具有 Emscripten 生成的代码在其执行的不同阶段调用的属性。

开发人员可以提供 Module 的实现来控制代码的执行。例如,要定义 Emscripten 的通知消息的显示方式,开发人员需要实现 Module.print 属性。

当 Emscripten 应用程序启动时,它会查看 Module 对象上的值并应用它们。请注意,在启动后更改值通常无效;在启用 ASSERTIONS 的构建中,您将遇到错误。

注意

Module 也用于以安全的方式提供对 Emscripten API 函数的访问(例如 ccall())。任何导出(使用 EXPORTED_FUNCTIONS 用于编译的函数,或 EXPORTED_RUNTIME_METHODS 用于像 ccall 这样的运行时方法)的函数或运行时方法都可以在 Module 对象上访问,而不会因为压缩而改变名称,并且优化器将确保保持函数存在(并且不会将其删除为未使用的)。请参阅 相关的 FAQ 条目.

创建 Module 对象

使用 emcc 的 pre-js 选项 添加 JavaScript 代码来定义(或扩展)具有您所需行为的 Module 对象。

仅生成 JavaScript(与生成 HTML 相反)时,默认情况下不会创建 Module 对象,行为完全由开发人员定义。例如,使用以下代码创建 Module 对象会导致程序的所有通知都成为对 alert() 的调用。

var Module = {
  'print': function(text) { alert('stdout: ' + text) },
  'printErr': function(text) { alert('stderr: ' + text) }
};

重要

如果您对代码运行 Closure 编译器(可选,可以通过 --closure 1 完成),则需要在 Module 的属性周围使用引号,如上面的示例所示。此外,您需要在编译后的代码和 Module 的声明一起运行 closure — 这将为 --pre-js 文件自动完成。

在生成 HTML 时,Emscripten 会创建一个具有默认方法的 Module 对象(请参阅 src/shell.html)。在这种情况下,您应该再次使用 --pre-js,但这次您向现有Module 对象添加属性,例如

Module['print'] = function(text) { alert('stdout: ' + text) };

请注意,一旦主 JavaScript 文件收到 Module 对象,它将在此时查找 Module['print'] 等等,并相应地使用它们。稍后更改其值可能不会被注意到。

编译设置

INCOMING_MODULE_JS_API 编译器设置控制在发出的 JS 中支持哪些 Module 属性。此列表默认情况下包含常用的内容。

将此设置为您的应用程序所需的最小列表将节省 JS 代码大小。例如,如果您不使用任何 Module 属性,您可以使用 -sINCOMING_MODULE_JS_API=[] 进行构建。或者,如果您只使用几个,可以列出它们,例如:-sINCOMING_MODULE_JS_API=print,printErr.

影响执行

以下 Module 属性会影响代码执行。设置它们以自定义行为。

Module.arguments

命令行参数。 arguments 的值包含如果编译后的代码检查 argcargv 所返回的值。

Module.buffer

允许您提供自己的 ArrayBufferSharedArrayBuffer 作为内存使用。

注意

这仅在 -sWASM=0 时支持。请参阅 Module.wasmMemory 以了解 WebAssembly 支持。

Module.wasmMemory

允许您提供自己的 WebAssembly.Memory 作为内存使用。用于初始化内存的属性应与编译器选项匹配。

例如,如果您将 INITIAL_MEMORY 设置为 8MB 且不使用内存增长,那么您提供的 wasmMemory(如果有)应该同时将 'initial''maximum' 设置为 128(由于 WASM 页面大小为 64KB)。

Module.locateFile

如果设置,此方法将在运行时需要加载文件时被调用,例如 .wasm WebAssembly 文件、.mem 内存初始化文件或由文件打包程序生成的的文件。该函数接收构建过程中配置的文件的相对路径以及一个 prefix(指向主 JavaScript 文件目录的路径),并应返回实际 URL。这使您可以将文件包或 .mem 文件等托管在与 JavaScript 文件目录不同的位置(默认情况下,预期它们在同一个目录下),例如,如果您想将它们托管在 CDN 上。

注意

prefix 可能是一个空字符串,如果在加载主 JavaScript 之前调用 locateFile。例如,这可能发生在事先加载文件包或内存初始化文件的情况下(可能来自 HTML,在它加载主 JavaScript 之前)。

注意

几个 Module.*PrefixURL 选项已被弃用,取而代之的是 locateFile,其中包括 memoryInitializerPrefixURLpthreadMainPrefixURLcdInitializerPrefixURLfilePackagePrefixURL。要更新您的代码,例如如果您使用的是 Module.memoryInitializerPrefixURL 等于 "https://mycdn.com/memory-init-dir/",那么您可以用类似下面的内容替换它

Module['locateFile'] = function(path, prefix) {
  // if it's a mem init file, use a custom dir
  if (path.endsWith(".mem")) return "https://mycdn.com/memory-init-dir/" + path;
  // otherwise, use the default, the prefix (JS file's dir) + the path
  return prefix + path;
}
Module.logReadFiles

如果设置,stderr 将在读取任何文件时记录。

Module.printWithColors

控制 Emscripten 运行时库是否尝试以颜色打印。目前,这仅影响 sanitizers。

如果未设置,如果使用 node 打印到终端,颜色将被启用。

如果设置为 true,颜色将始终在可能的情况下使用。如果设置为 false,颜色将永远不会使用。

Module.onAbort

如果设置,此函数将在发生异常程序终止时被调用。这可能由于直接调用 C 方法 abort()、从 JavaScript 调用或由于致命问题(例如在启动期间无法获取必要的文件(例如 Wasm 二进制文件)等)而发生。在调用此函数后,程序将终止(即,您无法使用它来尝试执行其他操作而不是停止;这里没有恢复的可能性)。

Module.onRuntimeInitialized

如果设置,此函数在运行时完全初始化时调用,也就是说,当编译后的代码可以安全运行时,这发生在任何异步启动操作完成之后(例如异步 WebAssembly 编译、文件预加载等)。(等待此函数调用的另一种方法是等待 main() 被调用。)

Module.noExitRuntime

如果 noExitRuntime 设置为 true,运行时在 run 完成后不会关闭。关闭运行时会调用关闭回调,例如 atexit 调用。如果您想在 run() 完成后继续使用代码,则需要设置此选项。如果您使用暗示您希望运行时不关闭的 API 命令(例如 emscripten_set_main_loop),则此选项将自动为您设置。

Module.noInitialRun

如果 noInitialRun 设置为 truemain() 不会自动调用(您可以稍后手动调用)。程序仍然会调用全局初始化器,设置内存初始化等。

Module.preInit

一个函数(或函数数组),必须在全局初始化器运行之前调用,但在 JavaScript 运行时基本初始化之后。这通常用于 文件系统操作.

Module.preinitializedWebGLContext

如果使用 -sGL_PREINITIALIZED_CONTEXT 设置进行构建,您可以将 Module.preinitializedWebGLContext 设置为预先创建的 WebGL 上下文实例,它将在 C/C++ 端初始化 WebGL 时使用。在 C/C++ 代码加载之前或与之并行,在页面上预先创建 GL 上下文对于执行 GL 端加载(着色器编译、纹理加载等)非常有用,也可以在加载任何编译代码之前或与之并行检测 WebGL 特性支持,例如 GL 版本或压缩纹理支持。

Module.preRun

一个函数数组,在调用 run() 之前但定义和设置环境之后调用,包括全局初始化器。这很有用,例如,使用 文件系统 API 设置目录和文件 - 因为这需要在加载文件系统 API 之后但程序开始运行之前发生。

注意

如果代码需要影响全局初始化器,则应使用 preInit 运行。

Module.print

当向标准输出(stdout)打印内容时调用。

Module.printErr

当向标准错误(stderr)打印内容时调用。

Module.mainScriptUrlOrBlob

允许 pthread 工作线程或 WASM 工作线程从 URL 或 blob 中独立加载主应用程序模块 JavaScript 文件(例如 main.js)。pthread 工作线程或 WASM 工作线程的创建需要加载主应用程序模块 JavaScript 文件(例如 main.js)。默认情况下,它们从 main.js 的 URL 加载 main.js 的内容。但是,如果 main.js 文件是从 Blob 中加载的,则无法访问 main.js 的 URL。此外,当 main.js 被 Node.JS 模块捆绑器(例如 webpack)捆绑时,该脚本的 URL 可能不正确,webpack 捆绑器后的 URL 将导致错误的 URL,例如 main.chunk.js

其他方法

Module.destroy(obj)

此方法应用于销毁使用 WebIDL 绑定 在 JavaScript 中创建的 C++ 对象。如果未调用此方法,对象可能会被垃圾回收,但其析构函数不会被调用。

参数
  • obj – 要销毁的 JavaScript 包装的 C++ 对象。

Module.getPreloadedPackage()

如果您希望手动管理 .data 文件包的下载以实现自定义缓存、进度报告和错误处理行为,您可以实现 Module.getPreloadedPackage = function(remotePackageName, remotePackageSize) 回调函数,以将数据文件的内容提供给文件加载脚本。此回调函数的返回值应为包含下载的文件数据内容的 Arraybuffer。有关示例,请参见文件 test/manual_download_data.html 和测试 browser.test_preload_file_with_manual_data_download

Module.instantiateWasm()

在针对 WebAssembly 时,Module.instantiateWasm 是一个可选的用户实现的回调函数,Emscripten 运行时会调用它来执行 WebAssembly 实例化操作。回调函数将被调用,带有两个参数,importssuccessCallbackimports 是一个 JS 对象,包含实例化时需要传递给 WebAssembly 模块的所有函数导入,并且一旦实例化,此回调函数应使用生成的 WebAssembly 实例对象调用 successCallback()

实例化可以同步或异步执行。此函数的返回值应包含实例化的 WebAssembly 模块的 exports 对象,或者如果实例化是异步执行的,则包含一个空字典对象 {},或者如果实例化失败,则包含 false

通过此函数覆盖 WebAssembly 实例化过程在您有其他自定义异步启动操作或下载(可以与 WebAssembly 编译并行执行)时非常有用。实现此回调允许并行执行所有这些操作。有关此结构如何在实践中工作的示例,请参见文件 test/manual_wasm_instantiate.html 和测试 browser.test_manual_wasm_instantiate

注意

如果使用 Module.instantiateWasm 覆盖 WebAssembly 实例化,则目前不支持消毒器或源地图。在启用源地图或消毒器时提供 Module.instantiateWasm 会阻止 WebAssembly 实例化完成。

Module.onCustomMessage()

当使用 PROXY_TO_WORKER = 1 编译时(参见 settings.js),此回调(应在客户端和工作线程的 Module 对象上实现)允许在 Web 工作线程和主线程之间发送自定义消息和数据(使用在 proxyClient.jsproxyWorker.js 中定义的 postCustomMessage 函数)。

Module.fetchSettings()

覆盖从网络获取 Wasm 模块时使用的默认设置对象。此属性应为字符串,默认值为 { credentials: 'same-origin' }