Electron 内部:将 Node 用作库
这是解释 Electron 内部机制的系列文章中的第二篇。如果你还没有阅读过,请查看有关事件循环集成的第一篇文章。
大多数人使用Node 用于服务器端应用程序,但由于 Node 的丰富 API 集和蓬勃发展的社区,它也非常适合嵌入式库。这篇文章解释了 Electron 如何将 Node 用作库。
构建系统
Node 和 Electron 都使用GYP
作为它们的构建系统。如果你想在你的应用程序中嵌入 Node,你必须也使用它作为你的构建系统。
不熟悉 GYP
?在继续阅读本文之前,请阅读本指南。
Node 的标志
Node 源代码目录中的node.gyp
文件描述了 Node 的构建方式,以及许多控制哪些 Node 部分启用以及是否打开某些配置的GYP
变量。
若要更改构建标志,你需要在项目的 .gypi
文件中设置这些变量。Node 中的 configure
脚本可以为你生成一些常用配置,例如运行 ./configure --shared
将生成一个 config.gypi
,其中包含指示 Node 构建为共享库的变量。
Electron 不使用 configure
脚本,因为它有自己的构建脚本。Node 的配置在 Electron 根源代码目录的common.gypi
文件中定义。
将 Node 与 Electron 链接
在 Electron 中,Node 通过将 GYP
变量 node_shared
设置为 true
来作为共享库进行链接,因此 Node 的构建类型将从 executable
更改为 shared_library
,并且包含 Node 的 main
入口点的源代码将不会编译。
由于 Electron 使用与 Chromium 一起提供的 V8 库,因此不会使用 Node 源代码中包含的 V8 库。这可以通过将 node_use_v8_platform
和 node_use_bundled_v8
都设置为 false
来实现。
共享库或静态库
在与 Node 链接时,有两种选择:你可以将 Node 构建为静态库并将其包含在最终的可执行文件中,或者你可以将其构建为共享库并在最终可执行文件旁边进行分发。
在 Electron 中,Node 长期以来一直作为静态库构建。这使得构建变得简单,能够实现最佳编译优化,并允许 Electron 在没有额外 node.dll
文件的情况下进行分发。
但是,在 Chrome 切换到使用BoringSSL 之后,这种情况发生了改变。BoringSSL 是OpenSSL 的一个分支,它删除了几个未使用的 API 并更改了许多现有的接口。由于 Node 仍然使用 OpenSSL,因此如果将它们一起链接,编译器会由于冲突的符号而生成许多链接错误。
Electron 无法在 Node 中使用 BoringSSL,也无法在 Chromium 中使用 OpenSSL,因此唯一的选项是切换到将 Node 构建为共享库,并将隐藏 BoringSSL 和 OpenSSL 符号 在每个组件中。
此更改给 Electron 带来了了一些积极的副作用。在此更改之前,如果你使用的是原生模块,则无法在 Windows 上重命名 Electron 的可执行文件,因为可执行文件的名称是在导入库中硬编码的。在 Node 构建为共享库之后,此限制消失了,因为所有原生模块都链接到 node.dll
,其名称不需要更改。
支持原生模块
Node 中的原生模块 通过为 Node 定义一个加载入口函数来工作,然后从 Node 中搜索 V8 和 libuv 的符号。这对嵌入者来说有点麻烦,因为默认情况下,在将 Node 构建为库时,V8 和 libuv 的符号会被隐藏,并且原生模块将无法加载,因为它们无法找到这些符号。
因此,为了使原生模块正常工作,V8 和 libuv 符号在 Electron 中被公开。对于 V8,这是通过强制 Chromium 配置文件中的所有符号都被公开 来实现的。对于 libuv,这是通过设置 BUILDING_UV_SHARED=1
定义 来实现的。
在你的应用程序中启动 Node
完成构建和与 Node 链接的所有工作后,最后一步是在你的应用程序中运行 Node。
Node 没有提供许多用于将自身嵌入其他应用程序的公共 API。通常,你只需调用node::Start
和 node::Init
即可启动 Node 的新实例。但是,如果你正在构建一个基于 Node 的复杂应用程序,你必须使用 node::CreateEnvironment
等 API 来精确控制每个步骤。
在 Electron 中,Node 以两种模式启动:在主进程中运行的独立模式,这与官方 Node 二进制文件类似;以及将 Node API 插入网页的嵌入模式。这方面的详细信息将在以后的文章中介绍。