@react-native-gpui /爱马仕
固定的 爱马仕 引擎
React - Native -gpui,以React Native发布自己的引擎的方式打包
我们编译的public头文件,加上预构建的VM和 hermesc 编译器
对于我们支持的每个平台。
的一部分 react-native-gpui, macOS, Windows和Linux的React Native。
安装
创建的应用 npx @react-native-gpui/cli init 已经依赖它了。在现有的应用程序中:
npm install @react-native-gpui/hermes
第一次构建应用程序时,从匹配的GitHub版本下载平台的引擎二进制文件。
该文件的其余部分描述了如何构建和维护包。
构建
这里的所有内容都是从一次提交构建的,记录在 package.json:
"hermes": {
"repository": "https://github.com/facebook/hermes",
"commit": "10a40b5f1de81d007cba6afe567c4ba7a0b45f5d"
}
布局
| 路径 | 目录 |
|---|---|
API/, public/, include/ | 我们编译的上游头文件,字节对字节(如下) |
bin/<platform>-<arch>/ | 预构建的VM和编译器(未提交;已获取或已构建) |
desktop/node-api-exports.txt | 每一个 napi_*/node_api_* 为导出的虚拟机命名,每行一个 |
patches/ | 在构建之前应用于固定提交的补丁 |
scripts/fetch-binaries.mjs | 将一个CI构件或发布下载到 bin/ 并进行验证 |
desktop/node-api-exports.txt 列出虚拟机导出的Node-API名称。在Windows上
插件无法从全局作用域解析这些符号- DLL导入名称
它来自的文件-所以应用程序的可执行文件重新导出每一个,转发
来 hermesvm.dll. 列表是生成转发的来源,和
desktop/node-api-exports.test.js 从安装的库中重新生成它
当两者意见不一致时失败。碰撞赫尔墨斯后恢复:
dumpbin /exports bin/win32-x64/hermesvm.dll | # keep the napi_* / node_api_* rows
只提供针对VM进行编译所需的头文件。一切
其他在上游 include/ 是虚拟机内部共享库不导出。
API/{hermes,jsi,napi,hermes_abi}/**/*.h:其中的每个上游报头 文件夹(hermes.h,调试器和CDP报头是React Native的检查器 用途,hermes_napi.h、JSI和Hermes ABI)。来源和工具API/而未使用的API/hermes_sandbox不是卖主的。public/hermes/Public/*.h:配置和导出头文件hermes.h包括。include/hermes/napi/Node-API的C头文件hermes_napi.h包括,与上游的VENDORED.md.
构建是根据React Native的JSI (ReactCommon/jsi); API/jsi
只保留API文件夹,以便与上游匹配。
Node-API插件
引擎拥有加载库存的Node-API的一半 .node 文件。构建
使 HERMES_ENABLE_NAPI,因此VM自己实现Node-API: libhermesvm
出口的 napi_* 和 node_api_* 符号,和一个插件链接
nothing -它的导入解析已经加载到VM的任何内容。
desktop/HermesNodeAddons.cpp 为每个插件创建一个Node-API环境
hermes_napi_create_env 并加载文件 hermes_napi_load_module,
将导出作为JSI值返回。 desktop/HermesNodeApiHost.cpp 提供了
环境需要的主机回调: post_work, cancel_work, post_task
和 fatal_exception. post_task 异步工作回调跳转到JS
穿过 CallInvoker所以,核心是 _requireNodeLibrary 全球、路径
解析、每个运行时缓存和错误消息保持与引擎无关。
插件中缺失的符号表面为 dlerror() 字符串,它是什么
命名一个需要libuv (uv_default_loop)而不是Node-API。
窗户
Windows没有 dlopen 没有全局符号作用域,所以这里有两点不同
两者都是由 patches/0002-windows-load-node-api-modules.patch:
- 虚拟机加载a
.node文件,LoadLibraryExW和GetProcAddress而不是 的dlopen/dlsym,将路径转换为UTF-16并使用LOAD_WITH_ALTERED_SEARCH_PATH所以附带兄弟DLL的插件可以找到它; - 故障负载升高
Failed to load module: <reason>,在那里<reason>是 系统文本GetLastError()从FormatMessageW. 这就是要传达的信息 它告诉用户需要一个插件uv_*,或者是在没有节点的情况下建造的 延迟加载钩子(一个缺失)node.exe进口)。
这个补丁也会上升 InitFunc/initFunc 以上 #ifdef. 上游声明
他们在里面 #else 并关闭条件句 后 共享的尾巴,等等
Windows代码创建导出对象,调用入口点和
返回被编译出来;函数从末尾掉下来并返回一个
不确定的值,表面为 napi_invalid_arg 对于每个插件。
不像 0001 这个补丁并不是一个选项:它是制造引擎的东西
能够在Windows上加载插件。 scripts/build-hermes-windows.ps1 适用于
每一个补丁 patches/ 配置前,请检查 git apply --check
首先,报告它所应用的,所以总是从一个干净的检出构建
匹配固定提交加上这些更改。
bin/ 被忽略,所以一个新的克隆有头文件,但没有二进制文件:
| 平台 | 文件 |
|---|---|
darwin-arm64, darwin-x64 | libhermesvm.dylib, hermesc |
linux-x64, linux-arm64 | libhermesvm.so, hermesc |
win32-x64, win32-arm64 | hermesvm.dll, hermesvm.lib, hermesc.exe |
获取二进制文件
# latest successful hermes-engine workflow run (needs an authenticated gh)
npm run fetch-binaries
# a specific run, a release tag, or an artifact you downloaded by hand
node scripts/fetch-binaries.mjs --run 123456789
node scripts/fetch-binaries.mjs --tag hermes-10a40b5
node scripts/fetch-binaries.mjs --from ~/Downloads/hermes-darwin-arm64.zip
# check what is present: the host platform, or every platform
npm run verify-binaries
node scripts/fetch-binaries.mjs --verify --all
获取的二进制文件是从固定提交构建的 加上每一个补丁
patches/:工作流在配置前应用它们。本地脚本可以
相同,所以两者一致。
自己构建
.github/workflows/hermes-engine.yml 构建所有六个目标并上传一个
每个平台的工件。相同的构建通过repo脚本在本地运行:
scripts/build-hermes-macos.sh # builds universal, then lipo -thin per arch
scripts/build-hermes-linux.sh # linux-x64
scripts/build-hermes-windows.ps1 # win32-x64, run from a Developer PowerShell
每个脚本都期望在固定的提交(覆盖)中进行facebook/hermes签出
与 RN_GPUI_HERMES_SOURCE_DIR),并在HEAD不匹配时发出警告。
构建标志从 package.json的 hermes.buildFlags:
HERMES_ENABLE_NAPI=ON
HERMES_ENABLE_DEBUGGER=ON
HERMES_ENABLE_INTL=ON
HERMES_ICU_RUNTIME_LOAD=ON
HERMES_ICU_HEADERS_DIR=packages/hermes/third_party/icu
HERMES_ENABLE_TEST_SUITE=OFF
HERMES_BUILD_APPLE_FRAMEWORK=OFF
Intl
HERMES_ENABLE_INTL=ON 公开 Intl.Collator, Intl.NumberFormat 和
Intl.DateTimeFormat (加上 Intl.getCanonicalLocales, formatToParts,和
toLocale* / localeCompare 原型方法)。别着的爱马仕没有
Intl.PluralRules, ListFormat, RelativeTimeFormat 或者 Segmenter.
每个平台使用一个后端(patches/0003-intl-on-the-system-icu.patch)
针对ICU的C API编写,在第一次需要ICU时加载,因此
引擎船没有ICU数据和链接没有ICU:
| 平台 | ICU加载 | 最低 |
|---|---|---|
| macOS | /usr/lib/libicucore.A.dylib | 操作系统的ICU (64+) |
| 窗户 | icu.dll 从System32系统 | Windows 10 1903 (ICU 64) |
| Linux | libicui18n.so.N, N从100降到64,与 libicuuc | ICU 64 |
RN_GPUI_ICU_VERSION 强制使用一个Linux版本,并且 0 关闭装载
这种退路是可以测试的。如果没有可用的ICU,虚拟机仍然启动:它记录一个
警告, Intl 保持定义,数字格式为纯JavaScript数字,
日期如UTC中的ISO 8601,字符串按代码单元比较,以及大小写映射覆盖
ASCII。
它所编译的ICU头文件是在 third_party/icu (ICU 76.1,
未修改,仅用于签名)。后端只调用ICU 64的函数
有; uloc_openAvailableByType 和 ucal_getCanonicalTimeZoneID 是可选的。
NumberFormat 根据已解析的选项构建ICU编号框架
格式与 unumf_*,样式(十进制,货币,百分比,单位),数字,
分组、紧凑和科学记数法; signDisplay, roundingMode 和
trailingZeroDisplay 来自ICU本身。
scripts/intl-smoke.js 的断言。 hermes-engine 工作流运行
在每个平台上,在Linux上针对ICU 70, ICU 74和没有ICU。
许可证
麻省理工学院。看到 许可证. Hermes是麻省理工学院授权的Meta平台公司。