as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

高级Turbo模块主题

高级Turbo模块主题

本主题提供了在创建复杂的Turbo模块时有用的其他信息。

Turbo模块CMAKE帮助程序

kepler_add_turbo_module_library函数是一个CMake帮助程序,它简化了定义Turbo模块库目标的过程,以便将其用于适用于Vega的React Native运行时。它处理Turbo模块库所需的常见配置和优化设置,通过自动应用必要的设置和优化来简化流程。

此帮助程序函数具有以下优点:

  • 简化的配置: 通过单个函数调用精简了CMake样板代码
  • 一致的最佳实践: 确保所有Turbo模块都遵循相同的配置模式,并为将来推出通用设置提供一个中心位置
  • 提高了应用二进制接口 (ABI) 稳定性: 自动应用正确的符号可见性设置
  • 优化的性能: 确保应用诸如链接时间和大小优化之类的性能优化

Turbo模块DSO的关键符号合约

Vega平台上的所有Turbo模块都必须遵守两个关键要求:

  1. 导出EntryPoint函数: Turbo模块库必须导出一个名为autoLinkVegaTurboModulesV1的单一符号。这个符号是Vega运行时用来自动链接和加载您的Turbo模块的入口点。
  2. 隐藏符号可见性: Turbo模块库中的所有其他符号都应隐藏。这样可以防止与其他库发生符号冲突,确保ABI稳定,缩短Turbo模块加载时间,并且在许多情况下可以减小库的大小。

kepler_add_turbo_module_library帮助程序会自动为您配置这些要求,从而无需手动进行符号可见性管理。

提供的功能

kepler_add_turbo_module_library函数提供了多个关键功能,可简化Turbo模块库的创建。这些功能分为三个主要类别。

创建共享库

帮助程序函数提供对共享库的支持,如下所示:

  • 使用标准的CMake add_library命令创建具有指定名称的共享库。
  • turbomoduleAPI静态库链接到该库,该静态库提供开发Turbo模块所需的C++方法,以及必要的平台级功能。
  • 处理库目标的正确设置,类似于手动使用add_librarytarget_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模块以使用这个帮助程序函数?

答: 请按照以下步骤进行迁移:

  1. 查看您当前的CMakeLists.txt以了解您的Turbo模块的配置方式
  2. 确保CMakeLists.txt中有find_package(turbomoduleAPI CONFIG REQUIRED)
  3. 将您的add_library调用和所有后续配置替换为单个kepler_add_turbo_module_library调用
  4. 删除之前用于管理autoLinkVegaTurboModulesV1导出的版本脚本(.map文件)
  5. 测试您的构建以确保一切正常

以下示例显示了迁移前后的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,例如用于PromiseCallback时。

根据具体要求,可以使用线程实用工具库,甚至直接使用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解决这些错误。

创建Turbo模块


Last updated: 2025年12月10日