From 463cff54539783cc56574e5af97b62f7517f4e82 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 1 Jun 2024 10:12:30 +0900 Subject: [PATCH 1/2] Provide an option to set compiled library file path --- flutter_ffi_plugin/bin/src/message.dart | 3 ++- flutter_ffi_plugin/lib/rinf.dart | 16 +++++++++++++--- flutter_ffi_plugin/lib/src/interface_os.dart | 4 ++++ flutter_ffi_plugin/lib/src/interface_web.dart | 4 ++++ flutter_ffi_plugin/lib/src/load_os.dart | 12 ++++++++++++ flutter_ffi_plugin/lib/src/load_web.dart | 11 ++++++++++- 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/flutter_ffi_plugin/bin/src/message.dart b/flutter_ffi_plugin/bin/src/message.dart index 0353d83df..87bbfe14d 100644 --- a/flutter_ffi_plugin/bin/src/message.dart +++ b/flutter_ffi_plugin/bin/src/message.dart @@ -504,7 +504,8 @@ hash_map.insert( import 'dart:typed_data'; import 'package:rinf/rinf.dart'; -Future initializeRust() async { +Future initializeRust({String? compiledLibPath}) async { + setCompiledLibPath(compiledLibPath); await prepareInterface(handleRustSignal); startRustLogic(); } diff --git a/flutter_ffi_plugin/lib/rinf.dart b/flutter_ffi_plugin/lib/rinf.dart index 4b5af0ebe..debb3802b 100755 --- a/flutter_ffi_plugin/lib/rinf.dart +++ b/flutter_ffi_plugin/lib/rinf.dart @@ -6,6 +6,16 @@ import 'src/exports.dart'; export 'src/interface.dart' show RustSignal; +/// Sets the exact file path of the dynamic library +/// compiled from the `hub` crate. +/// On the web, this function sets the path to the JavaScript module +/// that needs to be loaded. +/// This function might not be necessary for major platforms +/// but can be useful when the app runs on embedded devices. +void setCompiledLibPath(String? path) { + setCompiledLibPathExtern(path); +} + /// Prepares the native interface /// needed to communicate with Rust. Future prepareInterface(HandleRustSignal handleRustSignal) async { @@ -18,9 +28,9 @@ void startRustLogic() async { } /// Terminates all Rust tasks. -/// Doing so before closing the Flutter app -/// can prevent potential memory errors that may occur -/// when Rust attempts to send data after the Dart VM has been turned off. +/// Calling this function before closing the Flutter app +/// can prevent potential resource leaks that may occur +/// if the Rust side is abruptly terminated. /// Please note that on the web, this function does not have any effect, /// as tasks are managed by the JavaScript runtime, not Rust. void stopRustLogic() async { diff --git a/flutter_ffi_plugin/lib/src/interface_os.dart b/flutter_ffi_plugin/lib/src/interface_os.dart index 938d869cd..7407ed6b7 100644 --- a/flutter_ffi_plugin/lib/src/interface_os.dart +++ b/flutter_ffi_plugin/lib/src/interface_os.dart @@ -7,6 +7,10 @@ import 'dart:isolate'; import 'interface.dart'; import 'dart:convert'; +void setCompiledLibPathExtern(String? path) { + setDynamicLibPath(path); +} + Future prepareInterfaceExtern( HandleRustSignal handleRustSignal, ) async { diff --git a/flutter_ffi_plugin/lib/src/interface_web.dart b/flutter_ffi_plugin/lib/src/interface_web.dart index 05035d43a..97642a4a8 100644 --- a/flutter_ffi_plugin/lib/src/interface_web.dart +++ b/flutter_ffi_plugin/lib/src/interface_web.dart @@ -7,6 +7,10 @@ import 'interface.dart'; import 'dart:async'; import 'dart:convert'; +void setCompiledLibPathExtern(String? path) { + setJsLibPath(path); +} + Future prepareInterfaceExtern( HandleRustSignal handleRustSignal, ) async { diff --git a/flutter_ffi_plugin/lib/src/load_os.dart b/flutter_ffi_plugin/lib/src/load_os.dart index 870bd9ff8..2b1189663 100644 --- a/flutter_ffi_plugin/lib/src/load_os.dart +++ b/flutter_ffi_plugin/lib/src/load_os.dart @@ -1,9 +1,21 @@ import 'dart:io' as io; import 'dart:ffi'; +String? dynamicLibPath; final rustLibrary = loadRustLibrary(); +void setDynamicLibPath(String? path) { + dynamicLibPath = path; +} + DynamicLibrary loadRustLibrary() { + // Use provided dynamic library path if possible. + final path = dynamicLibPath; + if (path != null) { + return DynamicLibrary.open(path); + } + + // Otherewise, use the default path. if (io.Platform.isLinux) { return DynamicLibrary.open('libhub.so'); } else if (io.Platform.isAndroid) { diff --git a/flutter_ffi_plugin/lib/src/load_web.dart b/flutter_ffi_plugin/lib/src/load_web.dart index d54ba4cfb..759492a26 100644 --- a/flutter_ffi_plugin/lib/src/load_web.dart +++ b/flutter_ffi_plugin/lib/src/load_web.dart @@ -4,11 +4,17 @@ import 'dart:js' as js; import 'dart:html'; import 'dart:async'; +String? jsLibPath; + // When Dart performs hot restart, // the `rinf` object is already defined // as a global JavaScript variable. final wasAlreadyLoaded = js.context.hasProperty("rinf"); +void setJsLibPath(String? path) { + jsLibPath = path; +} + Future loadJsFile() async { if (wasAlreadyLoaded) { return; @@ -17,10 +23,13 @@ Future loadJsFile() async { final loadCompleter = Completer(); js.context['completeRinfLoad'] = loadCompleter.complete; + // Use the default JavaScript path unless provided. + final path = jsLibPath ?? "/pkg/hub.js"; + final scriptElement = ScriptElement(); scriptElement.type = "module"; scriptElement.innerHtml = ''' -import init, * as wasmBindings from "/pkg/hub.js"; +import init, * as wasmBindings from "$path"; await init(); window.rinf = { ...wasmBindings }; completeRinfLoad(); From 5f30cb92018c8b1a4bf59ccbd4b1d13854667d0a Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Sat, 1 Jun 2024 10:26:16 +0900 Subject: [PATCH 2/2] Update docs --- .../docs/frequently-asked-questions.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/documentation/docs/frequently-asked-questions.md b/documentation/docs/frequently-asked-questions.md index 4d18af4c7..d64be28e8 100644 --- a/documentation/docs/frequently-asked-questions.md +++ b/documentation/docs/frequently-asked-questions.md @@ -308,3 +308,25 @@ These links might be a help: - https://kazlauskas.me/entries/writing-proper-buildrs-scripts - https://github.com/RustAudio/rodio/issues/404 - https://github.com/breez/c-breez/issues/553 + +### How do I set the path to a compiled dynamic library? + +You might want to run your app on embedded devices. However, you may encounter this error when running your app on a non-major platform: + +``` +Failed to load dynamic library 'libhub.so': libhub.so: cannot open shared object file: No such file or directory +``` + +In this case, you can specify a path that points to the compiled Rust library. Simply provide a string path to your dynamic library file. + +```dart title="lib/main.dart" +import './messages/generated.dart'; + +async void main() { + await initializeRust(compiledLibPath: "/path/to/library/libhub.so"); + ... +} +... +``` + +This provided path will be used for finding dynamic library files on native platforms with Dart's `DynamicLibrary.open([compiledLibPath])`, and for loading the JavaScript module on the web with `import init, * as wasmBindings from "[compiledLibPath]"`.