ターボモジュールに関する高度なトピック
このトピックでは、複雑なターボモジュールを作成するときに役立つ関連情報を紹介します。
ターボモジュールのCMAKEヘルパー
kepler_add_turbo_module_library関数はCMakeヘルパーで、これにより、Vega向けReact Nativeランタイムで使用するターボモジュールライブラリのターゲットを定義するプロセスが簡略化されます。ターボモジュールライブラリに必要な一般的な構成と最適化の設定を処理し、必要な設定と最適化を自動的に適用して、プロセスを合理化します。
このヘルパー関数には次のような利点があります。
- シンプルな構成: 定型のCMakeコードを削減し、1回の関数呼び出しに置き換えます。
- 一貫性のあるベストプラクティス: すべてのターボモジュールが同じ構成パターンに従うようにして、将来的に共通設定を一元的に展開するしくみを提供します。
- アプリケーションバイナリインターフェイス(ABI)の安定性の向上: シンボルの適切な可視性設定を自動的に適用します。
- パフォーマンスの最適化: リンク時最適化やサイズ最適化など、パフォーマンスの最適化を確実に適用します。
ターボモジュールDSOのシンボルに関する主要なコントラクト
Vegaプラットフォームのすべてのターボモジュールは、次の2つの重要な要件に従う必要があります。
- EntryPoint関数のエクスポート: ターボモジュールライブラリは、
autoLinkVegaTurboModulesV1という名前のシンボルを1つエクスポートする必要があります。このシンボルは、Vegaランタイムがターボモジュールを自動的にリンクして読み込むために使用するエントリポイントとして機能します。 - シンボルの隠蔽: ターボモジュールライブラリ内のその他のシンボルはすべて隠蔽する必要があります。これにより、ほかライブラリとのシンボルの競合が回避され、ABIの安定性が確保され、ターボモジュールの読み込み時間が短縮されます。また、多くの場合はライブラリのサイズを削減できます。
kepler_add_turbo_module_libraryヘルパーを使用すると、これらの要件が自動的に構成されるため、シンボルの可視性を手動で管理する必要がなくなります。
提供される機能
kepler_add_turbo_module_library関数は、ターボモジュールライブラリの作成を簡単にするいくつかの主な機能を提供します。これらの機能は、大きく次の3つのカテゴリーに分類されます。
共有ライブラリの作成
ヘルパー関数は、次のように共有ライブラリをサポートします。
- CMakeの標準の
add_libraryコマンドを使用して、指定された名前で共有ライブラリを作成します。 turbomoduleAPI静的ライブラリをリンクします。これにより、ターボモジュールを開発するためのC++メソッドと、必要なプラットフォームレベルの機能がライブラリに提供されます。- ライブラリターゲットを適切に設定します。手動で
add_libraryとtarget_link_librariesを使用する場合と同様の処理が行われます。
シンボルの可視性の制御
ヘルパー関数は、シンボルの可視性を自動的に構成してABIの安定性を確保します。
- すべてのシンボルのデフォルトの可視性を「隠蔽」に設定します。
autoLinkVegaTurboModulesV1シンボルのみを明示的にエクスポートするバージョンスクリプトを適用します。-fno-semantic-interpositionを使用してシンボルの割り込みを無効にし、-Bsymbolicを使用してグローバル参照のローカルバインドを適用することで、シンボルの競合を防ぎます。
パフォーマンスの最適化
ヘルパー関数は、ターボモジュールのパフォーマンスとサイズを改善するいくつかの最適化を適用します。
- パフォーマンスの向上とサイズの削減のために、リンク時最適化(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
)
## ターボモジュールライブラリを作成します。
kepler_add_turbo_module_library(MyTurboModule ${SOURCES})
よくある質問(FAQ)
Q: このヘルパー関数を使用するように既存のターボモジュールを移行する必要はありますか?
A: はい。既にターボモジュールがある場合は、このヘルパー関数を使用するように移行することを強くお勧めします。turbomoduleAPIライブラリを介して最適化フラグをINTERFACEフラグとして伝播する現在のアプローチは、将来廃止される予定です。このヘルパー関数はより広範な戦略の一部であり、戦略全体の目標は、予期しない動作につながる可能性のあるビルド設定の暗黙的な伝播を防ぎながら、ターボモジュールの構成をより明確で管理しやすいものにすることです。
Q: このヘルパー関数を使用するように既存のターボモジュールを移行するにはどうすればよいですか?
A: 移行するには、次の手順に従ってください。
- 現在のCMakeLists.txtを確認して、ターボモジュールがどのように構成されているかを理解します。
- 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
)
## すべての最適化が適用されたターボモジュールライブラリを作成します。
kepler_add_turbo_module_library(MyTurboModule ${SOURCES})
Q: このヘルパー関数でバージョンスクリプトを処理するにはどうすればよいですか? autoLinkVegaTurboModulesV1以外のシンボルを追加でエクスポートすることはできますか?
A: このヘルパー関数は、autoLinkVegaTurboModulesV1シンボルのみをエクスポートするバージョンスクリプトを自動的に適用します。既にバージョンスクリプトを使用している場合は、競合を避けるために、CMake構成から既存のバージョンスクリプトの適用箇所を削除してください。autoLinkVegaTurboModulesV1以外のシンボルを追加でエクスポートする必要がある場合は、ヘルパー関数の呼び出し後に別のバージョンスクリプトを適用できます。ただし、各スクリプトでエクスポートされるシンボルが重複しないようにしてください。追加のシンボルをエクスポートするとABIの安定性が損なわれる可能性があるため、このアプローチの使用は控えめにする必要があります。
Q: kepler_add_turbo_module_library関数にかかわる問題をデバッグするにはどうすればよいですか?
A: 生成されたコンパイルデータベース(buildディレクトリにあるcompile_commands.json)を確認して、コンパイラとリンカーのフラグを調べることができます。ヘルパー関数は、デフォルトでEXPORT_COMPILE_COMMANDS ONを有効にしてこのデータベースを作成します。IDEでデータベースを開いて、適用された正確なフラグを確認することができます。
Q: ターゲットの動作を追加するにはどうすればよいですか?
A: ヘルパー関数は既にプラットフォーム固有の動作を処理するようになっています。追加の設定が必要な場合は、ヘルパー関数の呼び出し後に追加できます。
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
スレッド
すべてのターボモジュールメソッドはJSThreadで呼び出されます。良好なパフォーマンスを維持するには、PromiseやCallback向けなどの用途にはJSThread以外の別のスレッドを適宜使用して、JSThreadをブロックしないようにすることが重要です。
固有の要件に応じて、スレッドユーティリティライブラリを使用するかstd:: threadを直接使用して、ターボモジュール用にJSThread以外の別のスレッドを作成して管理できます。
イベントハンドリング
ターボモジュールはC++からJavaScriptにイベントを送信できますが、@amzn /keplerscript-turbomodule-apiパッケージには現在、これらのイベントを処理するためのサポートが含まれていません。イベントをリッスンするには、react-nativeのNativeEventEmitterを使用します。
ターボモジュールは、組み込みのemitメソッドを使用してJavaScriptにイベントを通知できます。このメソッドは、ほとんどのターボモジュールの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();
エラー処理
ターボモジュールを実行しているときに発生する可能性のある例外の多くは、JavaScriptレイヤーにスローされます。ネイティブモジュールにラップされているJavaScript実装を使用している場合は、try/catchを使用してこれらのエラーに対処することができます。
関連トピック
Last updated: 2025年12月10日

