高级Turbo模块主题
本主题提供了在创建复杂的Turbo模块时有用的其他信息。
Turbo模块CMAKE帮助程序
kepler_add_turbo_module_library函数是一个CMake帮助程序,它简化了定义Turbo模块库目标的过程,以便将其用于适用于Vega的React Native运行时。它处理Turbo模块库所需的常见配置和优化设置,通过自动应用必要的设置和优化来简化流程。
此帮助程序函数具有以下优点:
- 简化的配置: 通过单个函数调用精简了CMake样板代码
- 一致的最佳实践: 确保所有Turbo模块都遵循相同的配置模式,并为将来推出通用设置提供一个中心位置
- 提高了应用二进制接口 (ABI) 稳定性: 自动应用正确的符号可见性设置
- 优化的性能: 确保应用诸如链接时间和大小优化之类的性能优化
Turbo模块DSO的关键符号合约
Vega平台上的所有Turbo模块都必须遵守两个关键要求:
- 导出EntryPoint函数: Turbo模块库必须导出一个名为
autoLinkVegaTurboModulesV1的单一符号。这个符号是Vega运行时用来自动链接和加载您的Turbo模块的入口点。 - 隐藏符号可见性: Turbo模块库中的所有其他符号都应隐藏。这样可以防止与其他库发生符号冲突,确保ABI稳定,缩短Turbo模块加载时间,并且在许多情况下可以减小库的大小。
kepler_add_turbo_module_library帮助程序会自动为您配置这些要求,从而无需手动进行符号可见性管理。
提供的功能
kepler_add_turbo_module_library函数提供了多个关键功能,可简化Turbo模块库的创建。这些功能分为三个主要类别。
创建共享库
帮助程序函数提供对共享库的支持,如下所示:
- 使用标准的CMake
add_library命令创建具有指定名称的共享库。 - 将
turbomoduleAPI静态库链接到该库,该静态库提供开发Turbo模块所需的C++方法,以及必要的平台级功能。 - 处理库目标的正确设置,类似于手动使用
add_library和target_link_libraries所做的设置。
符号可见性控制
帮助程序函数自动配置符号可见性以确保ABI的稳定性:
- 将所有符号的默认可见性设置为“隐藏”
- 应用仅显式导出
autoLinkVegaTurboModulesV1符号的版本脚本 - 使用
-fno-semantic-interposition禁用符号插入,并使用-Bsymbolic应用全局引用的局部绑定以防止符号冲突
性能优化
帮助程序函数应用了多项优化来改善Turbo模块的性能和大小:
- 启用链路时间优化 (LTO) 以获得更好的性能和更小的二进制文件大小
- 通过对未使用的部分进行垃圾回收来应用大小优化
用法
要使用kepler_add_turbo_module_library函数,请将以下内容添加到您的CMakeLists.txt中。
## 使用“kepler_add_turbo_module_library”需要使用TMAPI程序包
find_package(turbomoduleAPI CONFIG REQUIRED)
## 定义源文件
set(SOURCES
AutoLinkInit.cpp
MyTurboModule.cpp
)
## 创建Turbo模块库
kepler_add_turbo_module_library(MyTurboModule ${SOURCES})
常见问题解答
问: 我应该迁移我现有的Turbo模块以使用这个帮助程序函数吗?
答: 是。如果您已有Turbo模块,强烈建议您迁移到此帮助程序函数。目前通过turbomoduleAPI库将优化标记作为INTERFACE标记传播的方法在未来将被删除。此帮助程序函数是更广泛策略的一部分,该策略旨在为Turbo模块提供更明确、更可维护的配置,同时避免隐式传播构建设置,从而导致意外行为。
问: 我应该如何迁移现有的Turbo模块以使用这个帮助程序函数?
答: 请按照以下步骤进行迁移:
- 查看您当前的CMakeLists.txt以了解您的Turbo模块的配置方式
- 确保CMakeLists.txt中有
find_package(turbomoduleAPI CONFIG REQUIRED)行 - 将您的
add_library调用和所有后续配置替换为单个kepler_add_turbo_module_library调用 - 删除之前用于管理
autoLinkVegaTurboModulesV1导出的版本脚本(.map文件) - 测试您的构建以确保一切正常
以下示例显示了迁移前后的CMake配置。
之前(手动配置)
## 查找turbomoduleAPI程序包
find_package(turbomoduleAPI CONFIG REQUIRED)
## 定义源文件
set(SOURCES
AutoLinkInit.cpp
MyTurboModule.cpp
)
## 创建共享库
add_library(MyTurboModule ${SOURCES})
## 链接到turbomoduleAPI库
target_link_libraries(MyTurboModule PRIVATE turbomoduleAPI::turbomoduleAPI)
## 应用版本脚本,以便仅允许导出稳定符号。
target_link_options(MyTurboModule PRIVATE -Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/MyTurboModule_symbols.map)
之后(使用帮助程序)
## 查找turbomoduleAPI程序包
find_package(turbomoduleAPI CONFIG REQUIRED)
## 定义源文件
set(SOURCES
AutoLinkInit.cpp
MyTurboModule.cpp
)
## 创建应用所有优化的Turbo模块库
kepler_add_turbo_module_library(MyTurboModule ${SOURCES})
问: 如何使用这个帮助程序函数处理版本脚本? 我可以导出autoLinkVegaTurboModulesV1之外的其他符号吗?
答: 帮助程序函数会自动应用仅导出autoLinkVegaTurboModulesV1符号的版本脚本。如果您已经在使用版本脚本,请从CMake配置中移除现有的版本脚本应用程序,以避免冲突。如果您需要导出autoLinkVegaTurboModulesV1之外的其他符号,则可以在调用帮助程序函数后应用其他版本脚本,但要确保每个脚本导出的符号之间没有重叠之处。应谨慎使用这种方法,因为导出其他符号可能会损害ABI的稳定性。
问: 如何调试kepler_add_turbo_module_library函数的问题?
答: 您可以检查生成的编译数据库(在构建目录中的compile_commands.json)以检查正在使用的编译器和链接器标记。默认情况下,帮助程序函数启用EXPORT_COMPILE_COMMANDS ON,这样将创建此数据库。您可以使用IDE打开数据库,查看应用的确切标记。
问: 如何添加其他目标行为?
答: 帮助程序函数已经处理了特定于平台的行为。如果您需要其他设置,可以在调用帮助程序函数后添加它们:
kepler_add_turbo_module_library(MyTurboModule ${SOURCES})
target_compile_definitions(MyTurboModule PRIVATE MY_CUSTOM_DEFINE=1)
符号检查
要从Vega SDK获取llvm-nm工具路径,请使用以下命令:
> find "$(vega native toolchain aarch64)" -name llvm-nm
~/vega/sdk/vega-sdk/main/0.23.5229/workspace/App/NativeRuntime/build/private/toolchain/aarch64/mac/bin/llvm-nm
使用以下命令列出符号:
> ~/vega/sdk/vega-sdk/main/0.23.5229/workspace/App/NativeRuntime/build/private/toolchain/aarch64/mac/bin/llvm-nm -C -D --defined-only build/aarch64-release/lib/libMyTurboModule.so
00000000000cf408 T autoLinkKeplerTurboModulesV1
线程
所有Turbo模块方法都在JSThread上调用。为了保持良好的性能,必须避免阻塞JSThread,只要有益处就使用单独的非JSThread,例如用于Promise或Callback时。
根据具体要求,可以使用线程实用工具库,甚至直接使用std::thread为Turbo模块创建和管理单独的非JSThread。
事件处理
Turbo模块可以将事件从C++发送到JavaScript,但是@amzn/keplerscript-turbomodule-api程序包目前不支持处理这些事件。要侦听事件,可以使用react-native中的NativeEventEmitter。
Turbo模块可以使用内置的emit方法向JavaScript发送事件信号,该方法接受大多数Turbo模块C++类型作为有效负载。在JSThread上(即,没有创建新的线程来发出事件)时,应改为使用emitSync。
void SampleTurboModule::testEmit(std::string eventName) {
std::thread([self = this, eventName]() {
JSObject payload{};
payload["StringValue"] = "JSObject的stringMessage";
payload["intValue"] = 123;
payload["doubleValue"] = 45.67;
self->emit(eventName, payload);
}).detach();
}
JavaScript端可以注册为使用NativeEventEmitter来接收事件。以下示例以实现JavaScript层中的说明为基础。
import { NativeEventEmitter } from 'react-native';
import PingerModule from './NativePinger';
class Pinger {
__eventEmitter: NativeEventEmitter = null;
constructor() {
this.__eventEmitter = new NativeEventEmitter();
}
testEmit: (key: string) => {
const eventName = 'SampleEvent';
const subscription = this.__eventEmitter.addListener(
eventName,
(args) => {
console.log('From JS: addListener ', args);
}
);
SampleTurboModule.testEmit(eventName); // 这会发出“SampleEvent”,该事件将触发以上订阅
subscription.remove(); // 确保对订阅进行清理
}
...
}
export default new Pinger();
错误处理
运行Turbo模块时可能遇到的许多异常均抛出到JavaScript层中。如果有一个封装在原生模块上的JavaScript实现,则可以使用try/catch解决这些错误。
相关主题
Last updated: 2025年12月10日

