From 0786d303001567a73d02605e5e4089f33a720a73 Mon Sep 17 00:00:00 2001 From: xkeyC <3334969096@qq.com> Date: Sat, 4 Nov 2023 22:55:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=95=E5=85=A5=20Rust=20\\TODO=20=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20rust=20=E5=AE=9E=E7=8E=B0=E7=9A=84=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + lib/common/rust/bridge_definitions.dart | 34 +++ lib/common/rust/bridge_generated.dart | 282 ++++++++++++++++++++++++ lib/common/rust/ffi.dart | 23 ++ lib/main.dart | 4 + pubspec.yaml | 7 + rust/src/api.rs | 63 ++++++ rust/src/bridge_generated.io.rs | 46 ++++ rust/src/bridge_generated.io.rs.bk | 43 ++++ rust/src/bridge_generated.rs | 124 +++++++++++ rust/src/lib.rs | 2 + update_rsut.bat | 2 + windows/CMakeLists.txt | 2 +- windows/rust.cmake | 21 ++ 14 files changed, 654 insertions(+), 1 deletion(-) create mode 100644 lib/common/rust/bridge_definitions.dart create mode 100644 lib/common/rust/bridge_generated.dart create mode 100644 lib/common/rust/ffi.dart create mode 100644 rust/src/api.rs create mode 100644 rust/src/bridge_generated.io.rs create mode 100644 rust/src/bridge_generated.io.rs.bk create mode 100644 rust/src/bridge_generated.rs create mode 100644 rust/src/lib.rs create mode 100644 update_rsut.bat create mode 100644 windows/rust.cmake diff --git a/.gitignore b/.gitignore index 489faea..18f5bc9 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ app.*.map.json /android/app/profile /android/app/release /pubspec.lock +/rust/target/ +/rust/Cargo.lock diff --git a/lib/common/rust/bridge_definitions.dart b/lib/common/rust/bridge_definitions.dart new file mode 100644 index 0000000..d5ba786 --- /dev/null +++ b/lib/common/rust/bridge_definitions.dart @@ -0,0 +1,34 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.82.3. +// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const + +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; + +abstract class Rust { + Future platform({dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kPlatformConstMeta; + + Future add({required int left, required int right, dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kAddConstMeta; + + Future rustReleaseMode({dynamic hint}); + + FlutterRustBridgeTaskConstMeta get kRustReleaseModeConstMeta; +} + +enum Platform { + Unknown, + Android, + Ios, + Windows, + Unix, + MacIntel, + MacApple, + Wasm, +} diff --git a/lib/common/rust/bridge_generated.dart b/lib/common/rust/bridge_generated.dart new file mode 100644 index 0000000..4391c92 --- /dev/null +++ b/lib/common/rust/bridge_generated.dart @@ -0,0 +1,282 @@ +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.82.3. +// ignore_for_file: non_constant_identifier_names, unused_element, duplicate_ignore, directives_ordering, curly_braces_in_flow_control_structures, unnecessary_lambdas, slash_for_doc_comments, prefer_const_literals_to_create_immutables, implicit_dynamic_list_literal, duplicate_import, unused_import, unnecessary_import, prefer_single_quotes, prefer_const_constructors, use_super_parameters, always_use_package_imports, annotate_overrides, invalid_use_of_protected_member, constant_identifier_names, invalid_use_of_internal_member, prefer_is_empty, unnecessary_const + +import "bridge_definitions.dart"; +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; + +import 'dart:convert'; +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge.dart'; +import 'package:uuid/uuid.dart'; + +import 'dart:ffi' as ffi; + +class RustImpl implements Rust { + final RustPlatform _platform; + factory RustImpl(ExternalLibrary dylib) => RustImpl.raw(RustPlatform(dylib)); + + /// Only valid on web/WASM platforms. + factory RustImpl.wasm(FutureOr module) => + RustImpl(module as ExternalLibrary); + RustImpl.raw(this._platform); + Future platform({dynamic hint}) { + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_platform(port_), + parseSuccessData: _wire2api_platform, + parseErrorData: null, + constMeta: kPlatformConstMeta, + argValues: [], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kPlatformConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "platform", + argNames: [], + ); + + Future add({required int left, required int right, dynamic hint}) { + var arg0 = api2wire_usize(left); + var arg1 = api2wire_usize(right); + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_add(port_, arg0, arg1), + parseSuccessData: _wire2api_usize, + parseErrorData: null, + constMeta: kAddConstMeta, + argValues: [left, right], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kAddConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "add", + argNames: ["left", "right"], + ); + + Future rustReleaseMode({dynamic hint}) { + return _platform.executeNormal(FlutterRustBridgeTask( + callFfi: (port_) => _platform.inner.wire_rust_release_mode(port_), + parseSuccessData: _wire2api_bool, + parseErrorData: null, + constMeta: kRustReleaseModeConstMeta, + argValues: [], + hint: hint, + )); + } + + FlutterRustBridgeTaskConstMeta get kRustReleaseModeConstMeta => + const FlutterRustBridgeTaskConstMeta( + debugName: "rust_release_mode", + argNames: [], + ); + + void dispose() { + _platform.dispose(); + } +// Section: wire2api + + bool _wire2api_bool(dynamic raw) { + return raw as bool; + } + + int _wire2api_i32(dynamic raw) { + return raw as int; + } + + Platform _wire2api_platform(dynamic raw) { + return Platform.values[raw as int]; + } + + int _wire2api_usize(dynamic raw) { + return castInt(raw); + } +} + +// Section: api2wire + +@protected +int api2wire_usize(int raw) { + return raw; +} +// Section: finalizer + +class RustPlatform extends FlutterRustBridgeBase { + RustPlatform(ffi.DynamicLibrary dylib) : super(RustWire(dylib)); + +// Section: api2wire + +// Section: finalizer + +// Section: api_fill_to_wire +} + +// ignore_for_file: camel_case_types, non_constant_identifier_names, avoid_positional_boolean_parameters, annotate_overrides, constant_identifier_names + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint + +/// generated by flutter_rust_bridge +class RustWire implements FlutterRustBridgeWireBase { + @internal + late final dartApi = DartApiDl(init_frb_dart_api_dl); + + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + RustWire(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup; + + /// The symbols are looked up with [lookup]. + RustWire.fromLookup( + ffi.Pointer Function(String symbolName) + lookup) + : _lookup = lookup; + + void store_dart_post_cobject( + DartPostCObjectFnType ptr, + ) { + return _store_dart_post_cobject( + ptr, + ); + } + + late final _store_dart_post_cobjectPtr = + _lookup>( + 'store_dart_post_cobject'); + late final _store_dart_post_cobject = _store_dart_post_cobjectPtr + .asFunction(); + + Object get_dart_object( + int ptr, + ) { + return _get_dart_object( + ptr, + ); + } + + late final _get_dart_objectPtr = + _lookup>( + 'get_dart_object'); + late final _get_dart_object = + _get_dart_objectPtr.asFunction(); + + void drop_dart_object( + int ptr, + ) { + return _drop_dart_object( + ptr, + ); + } + + late final _drop_dart_objectPtr = + _lookup>( + 'drop_dart_object'); + late final _drop_dart_object = + _drop_dart_objectPtr.asFunction(); + + int new_dart_opaque( + Object handle, + ) { + return _new_dart_opaque( + handle, + ); + } + + late final _new_dart_opaquePtr = + _lookup>( + 'new_dart_opaque'); + late final _new_dart_opaque = + _new_dart_opaquePtr.asFunction(); + + int init_frb_dart_api_dl( + ffi.Pointer obj, + ) { + return _init_frb_dart_api_dl( + obj, + ); + } + + late final _init_frb_dart_api_dlPtr = + _lookup)>>( + 'init_frb_dart_api_dl'); + late final _init_frb_dart_api_dl = _init_frb_dart_api_dlPtr + .asFunction)>(); + + void wire_platform( + int port_, + ) { + return _wire_platform( + port_, + ); + } + + late final _wire_platformPtr = + _lookup>( + 'wire_platform'); + late final _wire_platform = + _wire_platformPtr.asFunction(); + + void wire_add( + int port_, + int left, + int right, + ) { + return _wire_add( + port_, + left, + right, + ); + } + + late final _wire_addPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Int64, ffi.UintPtr, ffi.UintPtr)>>('wire_add'); + late final _wire_add = + _wire_addPtr.asFunction(); + + void wire_rust_release_mode( + int port_, + ) { + return _wire_rust_release_mode( + port_, + ); + } + + late final _wire_rust_release_modePtr = + _lookup>( + 'wire_rust_release_mode'); + late final _wire_rust_release_mode = + _wire_rust_release_modePtr.asFunction(); + + void free_WireSyncReturn( + WireSyncReturn ptr, + ) { + return _free_WireSyncReturn( + ptr, + ); + } + + late final _free_WireSyncReturnPtr = + _lookup>( + 'free_WireSyncReturn'); + late final _free_WireSyncReturn = + _free_WireSyncReturnPtr.asFunction(); +} + +final class _Dart_Handle extends ffi.Opaque {} + +typedef DartPostCObjectFnType = ffi.Pointer< + ffi.NativeFunction< + ffi.Bool Function(DartPort port_id, ffi.Pointer message)>>; +typedef DartPort = ffi.Int64; diff --git a/lib/common/rust/ffi.dart b/lib/common/rust/ffi.dart new file mode 100644 index 0000000..7bc8d8a --- /dev/null +++ b/lib/common/rust/ffi.dart @@ -0,0 +1,23 @@ +// This file initializes the dynamic library and connects it with the stub +// generated by flutter_rust_bridge_codegen. + +import 'dart:ffi'; + +import 'bridge_generated.dart'; +import 'bridge_definitions.dart'; +export 'bridge_definitions.dart'; + +// Re-export the bridge so it is only necessary to import this file. +export 'bridge_generated.dart'; +import 'dart:io' as io; + + +const _base = 'rust'; + +// On MacOS, the dynamic library is not bundled with the binary, +// but rather directly **linked** against the binary. +final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so'; + +final Rust rustFii = RustImpl(io.Platform.isIOS || io.Platform.isMacOS + ? DynamicLibrary.executable() + : DynamicLibrary.open(_dylib)); diff --git a/lib/main.dart b/lib/main.dart index e5e9caa..5fd6261 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:starcitizen_doctor/base/ui_model.dart'; import 'package:starcitizen_doctor/common/conf.dart'; +import 'package:starcitizen_doctor/common/rust/ffi.dart'; import 'package:starcitizen_doctor/ui/index_ui_model.dart'; import 'package:window_manager/window_manager.dart'; @@ -9,6 +10,9 @@ import 'global_ui_model.dart'; import 'ui/index_ui.dart'; void main(List args) async { + + dPrint("rust ffi ${await rustFii.platform()}"); + if (runWebViewTitleBarWidget(args, backgroundColor: const Color.fromRGBO(19, 36, 49, 1), builder: _defaultWebviewTitleBar)) { diff --git a/pubspec.yaml b/pubspec.yaml index 95c3307..8dba17c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -53,6 +53,10 @@ dependencies: uuid: ^4.1.0 flutter_tilt: ^2.0.10 card_swiper: ^3.0.1 + ffi: ^2.1.0 + flutter_rust_bridge: ^1.82.3 + freezed_annotation: ^2.4.1 + meta: ^1.9.1 dev_dependencies: flutter_test: @@ -65,6 +69,9 @@ dev_dependencies: # rules and activating additional ones. flutter_lints: ^3.0.0 msix: ^3.16.4 + ffigen: ^9.0.1 + build_runner: ^2.4.6 + freezed: ^2.4.5 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/rust/src/api.rs b/rust/src/api.rs new file mode 100644 index 0000000..d39e2a9 --- /dev/null +++ b/rust/src/api.rs @@ -0,0 +1,63 @@ +// This is the entry point of your Rust library. +// When adding new code to your project, note that only items used +// here will be transformed to their Dart equivalents. + +// A plain enum without any fields. This is similar to Dart- or C-style enums. +// flutter_rust_bridge is capable of generating code for enums with fields +// (@freezed classes in Dart and tagged unions in C). +pub enum Platform { + Unknown, + Android, + Ios, + Windows, + Unix, + MacIntel, + MacApple, + Wasm, +} + +// A function definition in Rust. Similar to Dart, the return type must always be named +// and is never inferred. +pub fn platform() -> Platform { + // This is a macro, a special expression that expands into code. In Rust, all macros + // end with an exclamation mark and can be invoked with all kinds of brackets (parentheses, + // brackets and curly braces). However, certain conventions exist, for example the + // vector macro is almost always invoked as vec![..]. + // + // The cfg!() macro returns a boolean value based on the current compiler configuration. + // When attached to expressions (#[cfg(..)] form), they show or hide the expression at compile time. + // Here, however, they evaluate to runtime values, which may or may not be optimized out + // by the compiler. A variety of configurations are demonstrated here which cover most of + // the modern oeprating systems. Try running the Flutter application on different machines + // and see if it matches your expected OS. + // + // Furthermore, in Rust, the last expression in a function is the return value and does + // not have the trailing semicolon. This entire if-else chain forms a single expression. + if cfg!(windows) { + Platform::Windows + } else if cfg!(target_os = "android") { + Platform::Android + } else if cfg!(target_os = "ios") { + Platform::Ios + } else if cfg!(all(target_os = "macos", target_arch = "aarch64")) { + Platform::MacApple + } else if cfg!(target_os = "macos") { + Platform::MacIntel + } else if cfg!(target_family = "wasm") { + Platform::Wasm + } else if cfg!(unix) { + Platform::Unix + } else { + Platform::Unknown + } +} + +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +// The convention for Rust identifiers is the snake_case, +// and they are automatically converted to camelCase on the Dart side. +pub fn rust_release_mode() -> bool { + cfg!(not(debug_assertions)) +} \ No newline at end of file diff --git a/rust/src/bridge_generated.io.rs b/rust/src/bridge_generated.io.rs new file mode 100644 index 0000000..f89e5e0 --- /dev/null +++ b/rust/src/bridge_generated.io.rs @@ -0,0 +1,46 @@ +use super::*; +// Section: wire functions + +#[no_mangle] +pub extern "C" fn wire_platform(port_: i64) { + wire_platform_impl(port_) +} + +#[no_mangle] +pub extern "C" fn wire_add(port_: i64, left: usize, right: usize) { + wire_add_impl(port_, left, right) +} + +#[no_mangle] +pub extern "C" fn wire_rust_release_mode(port_: i64) { + wire_rust_release_mode_impl(port_) +} + +// Section: allocate functions + +// Section: related functions + +// Section: impl Wire2Api + +// Section: wire structs + +// Section: impl NewWithNullPtr + +pub trait NewWithNullPtr { + fn new_with_null_ptr() -> Self; +} + +impl NewWithNullPtr for *mut T { + fn new_with_null_ptr() -> Self { + std::ptr::null_mut() + } +} + +// Section: sync execution mode utility + +#[no_mangle] +pub extern "C" fn free_WireSyncReturn(ptr: support::WireSyncReturn) { + unsafe { + let _ = support::box_from_leak_ptr(ptr); + }; +} diff --git a/rust/src/bridge_generated.io.rs.bk b/rust/src/bridge_generated.io.rs.bk new file mode 100644 index 0000000..d704f0e --- /dev/null +++ b/rust/src/bridge_generated.io.rs.bk @@ -0,0 +1,43 @@ +use super::*; +// Section: wire functions + + + #[no_mangle] + pub extern "C" fn wire_add(port_: i64,left: usize,right: usize) { + wire_add_impl(port_,left,right) + } + +// Section: allocate functions + + +// Section: related functions + + +// Section: impl Wire2Api + + +// Section: wire structs + + + +// Section: impl NewWithNullPtr + +pub trait NewWithNullPtr { + fn new_with_null_ptr() -> Self; + } + + impl NewWithNullPtr for *mut T { + fn new_with_null_ptr() -> Self { + std::ptr::null_mut() + } + } + + +// Section: sync execution mode utility + + + #[no_mangle] + pub extern "C" fn free_WireSyncReturn(ptr: support::WireSyncReturn) { + unsafe { let _ = support::box_from_leak_ptr(ptr); }; + } + \ No newline at end of file diff --git a/rust/src/bridge_generated.rs b/rust/src/bridge_generated.rs new file mode 100644 index 0000000..bd8921b --- /dev/null +++ b/rust/src/bridge_generated.rs @@ -0,0 +1,124 @@ +#![allow( + non_camel_case_types, + unused, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + clippy::double_parens, + non_snake_case, + clippy::too_many_arguments +)] +// AUTO GENERATED FILE, DO NOT EDIT. +// Generated by `flutter_rust_bridge`@ 1.82.3. + +use crate::api::*; +use core::panic::UnwindSafe; +use flutter_rust_bridge::rust2dart::IntoIntoDart; +use flutter_rust_bridge::*; +use std::ffi::c_void; +use std::sync::Arc; + +// Section: imports + +// Section: wire functions + +fn wire_platform_impl(port_: MessagePort) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, Platform, _>( + WrapInfo { + debug_name: "platform", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || move |task_callback| Result::<_, ()>::Ok(platform()), + ) +} +fn wire_add_impl( + port_: MessagePort, + left: impl Wire2Api + UnwindSafe, + right: impl Wire2Api + UnwindSafe, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, usize, _>( + WrapInfo { + debug_name: "add", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || { + let api_left = left.wire2api(); + let api_right = right.wire2api(); + move |task_callback| Result::<_, ()>::Ok(add(api_left, api_right)) + }, + ) +} +fn wire_rust_release_mode_impl(port_: MessagePort) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap::<_, _, _, bool, _>( + WrapInfo { + debug_name: "rust_release_mode", + port: Some(port_), + mode: FfiCallMode::Normal, + }, + move || move |task_callback| Result::<_, ()>::Ok(rust_release_mode()), + ) +} +// Section: wrapper structs + +// Section: static checks + +// Section: allocate functions + +// Section: related functions + +// Section: impl Wire2Api + +pub trait Wire2Api { + fn wire2api(self) -> T; +} + +impl Wire2Api> for *mut S +where + *mut S: Wire2Api, +{ + fn wire2api(self) -> Option { + (!self.is_null()).then(|| self.wire2api()) + } +} +impl Wire2Api for usize { + fn wire2api(self) -> usize { + self + } +} +// Section: impl IntoDart + +impl support::IntoDart for Platform { + fn into_dart(self) -> support::DartAbi { + match self { + Self::Unknown => 0, + Self::Android => 1, + Self::Ios => 2, + Self::Windows => 3, + Self::Unix => 4, + Self::MacIntel => 5, + Self::MacApple => 6, + Self::Wasm => 7, + } + .into_dart() + } +} +impl support::IntoDartExceptPrimitive for Platform {} +impl rust2dart::IntoIntoDart for Platform { + fn into_into_dart(self) -> Self { + self + } +} + +// Section: executor + +support::lazy_static! { + pub static ref FLUTTER_RUST_BRIDGE_HANDLER: support::DefaultHandler = Default::default(); +} + +#[cfg(not(target_family = "wasm"))] +#[path = "bridge_generated.io.rs"] +mod io; +#[cfg(not(target_family = "wasm"))] +pub use io::*; diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 0000000..bde602f --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,2 @@ +mod api; +mod bridge_generated; /* AUTO INJECTED BY flutter_rust_bridge. This line may not be accurate, and you can change it according to your needs. */ diff --git a/update_rsut.bat b/update_rsut.bat new file mode 100644 index 0000000..9bf3f64 --- /dev/null +++ b/update_rsut.bat @@ -0,0 +1,2 @@ +flutter_rust_bridge_codegen --rust-input rust\src\api.rs --dart-output .\lib\common\rust\bridge_generated.dart --dart-decl-output .\lib\common\rust\bridge_definitions.dart +dart run build_runner build \ No newline at end of file diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index a646c42..49b97ef 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -56,7 +56,7 @@ add_subdirectory("runner") # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) - +include(./rust.cmake) # === Installation === # Support files are copied into place next to the executable, so that it can diff --git a/windows/rust.cmake b/windows/rust.cmake new file mode 100644 index 0000000..4931b35 --- /dev/null +++ b/windows/rust.cmake @@ -0,0 +1,21 @@ +# We include Corrosion inline here, but ideally in a project with +# many dependencies we would need to install Corrosion on the system. +# See instructions on https://github.com/AndrewGaspar/corrosion#cmake-install +# Once done, uncomment this line: +# find_package(Corrosion REQUIRED) + +include(FetchContent) + +FetchContent_Declare( + Corrosion + GIT_REPOSITORY https://github.com/AndrewGaspar/corrosion.git + GIT_TAG origin/master # Optionally specify a version tag or branch here +) + +FetchContent_MakeAvailable(Corrosion) + +corrosion_import_crate(MANIFEST_PATH ../rust/Cargo.toml IMPORTED_CRATES imported_crates) +target_link_libraries(${BINARY_NAME} PRIVATE ${imported_crates}) +foreach(imported_crate ${imported_crates}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) +endforeach() \ No newline at end of file