Skip to content

Commit

Permalink
Merge pull request #1567 from fzyzcjy/feat/1459
Browse files Browse the repository at this point in the history
Let `flutter_rust_bridge create/integrate` support customizing rust crate name and directory
  • Loading branch information
fzyzcjy authored Jan 1, 2024
2 parents ea2cc2e + b21994e commit c006efe
Show file tree
Hide file tree
Showing 29 changed files with 160 additions and 78 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "rust_lib"
name = "REPLACE_ME_RUST_CRATE_NAME"
version = "0.1.0"
edition = "2018"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl<T> NewWithNullPtr for *mut T {
}

#[no_mangle]
pub extern "C" fn frbgen_REPLACE_ME_PACKAGE_NAME_dart_fn_deliver_output(
pub extern "C" fn frbgen_REPLACE_ME_DART_PACKAGE_NAME_dart_fn_deliver_output(
call_id: i32,
ptr_: *mut u8,
rust_vec_len_: i32,
Expand All @@ -52,14 +52,14 @@ pub extern "C" fn frbgen_REPLACE_ME_PACKAGE_NAME_dart_fn_deliver_output(
}

#[no_mangle]
pub extern "C" fn frbgen_REPLACE_ME_PACKAGE_NAME_wire_greet(
pub extern "C" fn frbgen_REPLACE_ME_DART_PACKAGE_NAME_wire_greet(
name: *mut wire_cst_list_prim_u_8,
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
wire_greet_impl(name)
}

#[no_mangle]
pub extern "C" fn frbgen_REPLACE_ME_PACKAGE_NAME_cst_new_list_prim_u_8(
pub extern "C" fn frbgen_REPLACE_ME_DART_PACKAGE_NAME_cst_new_list_prim_u_8(
len: i32,
) -> *mut wire_cst_list_prim_u_8 {
let ans = wire_cst_list_prim_u_8 {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rust_input: rust/src/api/**/*.rs
rust_input: REPLACE_ME_RUST_CRATE_DIR/src/api/**/*.rs
dart_output: lib/src/rust
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:REPLACE_ME_PACKAGE_NAME/main.dart';
import 'package:REPLACE_ME_PACKAGE_NAME/src/rust/frb_generated.dart';
import 'package:REPLACE_ME_DART_PACKAGE_NAME/main.dart';
import 'package:REPLACE_ME_DART_PACKAGE_NAME/src/rust/frb_generated.dart';
import 'package:integration_test/integration_test.dart';

void main() {
Expand Down
4 changes: 2 additions & 2 deletions frb_codegen/assets/integration_template/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:REPLACE_ME_PACKAGE_NAME/src/rust/api/simple.dart';
import 'package:REPLACE_ME_PACKAGE_NAME/src/rust/frb_generated.dart';
import 'package:REPLACE_ME_DART_PACKAGE_NAME/src/rust/api/simple.dart';
import 'package:REPLACE_ME_DART_PACKAGE_NAME/src/rust/frb_generated.dart';

Future<void> main() async {
await RustLib.init();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {

static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig(
stem: 'rust_lib',
stem: 'REPLACE_ME_RUST_CRATE_NAME',
ioDirectory: 'rust/target/release/',
webPrefix: 'pkg/',
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class RustLibWire implements BaseWire {
ffi.NativeFunction<
ffi.Void Function(
ffi.Int32, ffi.Pointer<ffi.Uint8>, ffi.Int32, ffi.Int32)>>(
'frbgen_REPLACE_ME_PACKAGE_NAME_dart_fn_deliver_output');
'frbgen_REPLACE_ME_DART_PACKAGE_NAME_dart_fn_deliver_output');
late final _dart_fn_deliver_output = _dart_fn_deliver_outputPtr
.asFunction<void Function(int, ffi.Pointer<ffi.Uint8>, int, int)>();

Expand All @@ -146,7 +146,7 @@ class RustLibWire implements BaseWire {
ffi.NativeFunction<
WireSyncRust2DartDco Function(
ffi.Pointer<wire_cst_list_prim_u_8>)>>(
'frbgen_REPLACE_ME_PACKAGE_NAME_wire_greet');
'frbgen_REPLACE_ME_DART_PACKAGE_NAME_wire_greet');
late final _wire_greet = _wire_greetPtr.asFunction<
WireSyncRust2DartDco Function(ffi.Pointer<wire_cst_list_prim_u_8>)>();

Expand All @@ -161,7 +161,7 @@ class RustLibWire implements BaseWire {
late final _cst_new_list_prim_u_8Ptr = _lookup<
ffi.NativeFunction<
ffi.Pointer<wire_cst_list_prim_u_8> Function(ffi.Int32)>>(
'frbgen_REPLACE_ME_PACKAGE_NAME_cst_new_list_prim_u_8');
'frbgen_REPLACE_ME_DART_PACKAGE_NAME_cst_new_list_prim_u_8');
late final _cst_new_list_prim_u_8 = _cst_new_list_prim_u_8Ptr
.asFunction<ffi.Pointer<wire_cst_list_prim_u_8> Function(int)>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ android {

apply from: "../cargokit/gradle/plugin.gradle"
cargokit {
manifestDir = "../../rust"
libname = "rust_lib"
manifestDir = "../../REPLACE_ME_RUST_CRATE_DIR"
libname = "REPLACE_ME_RUST_CRATE_NAME"
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ A new Flutter FFI plugin project.
s.script_phase = {
:name => 'Build Rust library',
# First argument is relative path to the `rust` folder, second is name of rust library
:script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib',
:script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../REPLACE_ME_RUST_CRATE_DIR REPLACE_ME_RUST_CRATE_NAME',
:execution_position => :before_compile,
:input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'],
# Let XCode know that the static library referenced in -force_load below is
# created by this build step.
:output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib.a"],
:output_files => ["${BUILT_PRODUCTS_DIR}/libREPLACE_ME_RUST_CRATE_NAME.a"],
}
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
# Flutter.framework does not contain a i386 slice.
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib.a',
'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/libREPLACE_ME_RUST_CRATE_NAME.a',
}
end
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set(PROJECT_NAME "rust_builder")
project(${PROJECT_NAME} LANGUAGES CXX)

include("../cargokit/cmake/cargokit.cmake")
apply_cargokit(${PROJECT_NAME} ../../rust rust_lib "")
apply_cargokit(${PROJECT_NAME} ../../REPLACE_ME_RUST_CRATE_DIR REPLACE_ME_RUST_CRATE_NAME "")

# List of absolute paths to libraries that should be bundled with the plugin.
# This list could contain prebuilt libraries, or libraries created by an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ A new Flutter FFI plugin project.
s.script_phase = {
:name => 'Build Rust library',
# First argument is relative path to the `rust` folder, second is name of rust library
:script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../rust rust_lib',
:script => 'sh "$PODS_TARGET_SRCROOT/../cargokit/build_pod.sh" ../../REPLACE_ME_RUST_CRATE_DIR REPLACE_ME_RUST_CRATE_NAME',
:execution_position => :before_compile,
:input_files => ['${BUILT_PRODUCTS_DIR}/cargokit_phony'],
# Let XCode know that the static library referenced in -force_load below is
# created by this build step.
:output_files => ["${BUILT_PRODUCTS_DIR}/librust_lib.a"],
:output_files => ["${BUILT_PRODUCTS_DIR}/libREPLACE_ME_RUST_CRATE_NAME.a"],
}
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
# Flutter.framework does not contain a i386 slice.
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/librust_lib.a',
'OTHER_LDFLAGS' => '-force_load ${BUILT_PRODUCTS_DIR}/libREPLACE_ME_RUST_CRATE_NAME.a',
}
end
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ set(PROJECT_NAME "rust_builder")
project(${PROJECT_NAME} LANGUAGES CXX)

include("../cargokit/cmake/cargokit.cmake")
apply_cargokit(${PROJECT_NAME} ../../../../../../rust rust_lib "")
apply_cargokit(${PROJECT_NAME} ../../../../../../REPLACE_ME_RUST_CRATE_DIR REPLACE_ME_RUST_CRATE_NAME "")

# List of absolute paths to libraries that should be bundled with the plugin.
# This list could contain prebuilt libraries, or libraries created by an
Expand Down
8 changes: 8 additions & 0 deletions frb_codegen/src/binary/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ pub(crate) struct IntegrateCommandArgs {

#[derive(Debug, Args)]
pub(crate) struct CreateOrIntegrateCommandCommonArgs {
/// The name of the generated Rust crate
#[arg(long)]
pub rust_crate_name: Option<String>,

/// The directory of the generated Rust crate
#[arg(long)]
pub rust_crate_dir: Option<String>,

/// Use local version instead of the release version
#[arg(long, hide = true)]
pub local: bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::codegen::polisher::internal_config::PolisherInternalConfig;
use crate::codegen::preparer::internal_config::PreparerInternalConfig;
use crate::codegen::{Config, ConfigDumpContent};
use crate::library::commands::cargo_metadata::execute_cargo_metadata;
use crate::utils::dart_repository::get_package_name;
use crate::utils::dart_repository::get_dart_package_name;
use crate::utils::path_utils::{
canonicalize_with_error_message, find_dart_package_dir, find_rust_crate_dir, glob_path,
path_to_string,
Expand Down Expand Up @@ -169,7 +169,7 @@ fn parse_dump_contents(config: &Config) -> Vec<ConfigDumpContent> {
}

fn compute_c_symbol_prefix(dart_root: &Path) -> Result<String> {
let package_name = get_package_name(dart_root)?;
let package_name = get_dart_package_name(dart_root)?;
Ok(format!("frbgen_{package_name}_"))
}

Expand Down
23 changes: 18 additions & 5 deletions frb_codegen/src/library/integration/creator.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
use crate::integration::integrator;
use crate::integration::integrator::IntegrateConfig;
use crate::library::commands::flutter::flutter_create;
use log::{debug, info};
use std::path::Path;
use std::{env, fs};

pub struct CreateConfig {
pub name: String,
pub enable_local_dependency: bool,
pub rust_crate_name: String,
pub rust_crate_dir: String,
}

/// Create a new Flutter + Rust project.
pub fn create(name: &str, enable_local_dependency: bool) -> anyhow::Result<()> {
debug!("create name={name}");
pub fn create(config: CreateConfig) -> anyhow::Result<()> {
debug!("create name={}", config.name);

flutter_create(name)?;
flutter_create(&config.name)?;

let dart_root = env::current_dir()?.join(name);
let dart_root = env::current_dir()?.join(&config.name);
env::set_current_dir(&dart_root)?;

remove_unnecessary_files(&dart_root)?;

info!("Step: Inject flutter_rust_bridge related code");
integrator::integrate(true, enable_local_dependency)
integrator::integrate(IntegrateConfig {
enable_integration_test: true,
enable_local_dependency: config.enable_local_dependency,
rust_crate_name: config.rust_crate_name,
rust_crate_dir: config.rust_crate_dir,
})
}

// the function signature is not covered while the whole body is covered - looks like a bug in coverage tool
Expand Down
91 changes: 63 additions & 28 deletions frb_codegen/src/library/integration/integrator.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::integration::utils::extract_dir_and_modify;
use crate::library::commands::flutter::flutter_pub_add;
use crate::library::commands::format_dart::format_dart;
use crate::utils::dart_repository::get_package_name;
use crate::utils::path_utils::find_dart_package_dir;
use crate::utils::dart_repository::get_dart_package_name;
use crate::utils::path_utils::{find_dart_package_dir, path_to_string};
use anyhow::Result;
use include_dir::{include_dir, Dir};
use itertools::Itertools;
Expand All @@ -14,13 +14,20 @@ use std::{env, fs};
static INTEGRATION_TEMPLATE_DIR: Dir<'_> =
include_dir!("$CARGO_MANIFEST_DIR/assets/integration_template");

pub struct IntegrateConfig {
pub enable_integration_test: bool,
pub enable_local_dependency: bool,
pub rust_crate_name: String,
pub rust_crate_dir: String,
}

/// Integrate Rust into existing Flutter project.
// ref: https://matejknopp.com/post/flutter_plugin_in_rust_with_no_prebuilt_binaries/
pub fn integrate(enable_integration_test: bool, enable_local_dependency: bool) -> Result<()> {
pub fn integrate(config: IntegrateConfig) -> Result<()> {
let dart_root = find_dart_package_dir(&env::current_dir()?)?;
debug!("integrate dart_root={dart_root:?}");

let package_name = get_package_name(&dart_root)?;
let dart_package_name = get_dart_package_name(&dart_root)?;

extract_dir_and_modify(
&INTEGRATION_TEMPLATE_DIR,
Expand All @@ -30,16 +37,21 @@ pub fn integrate(enable_integration_test: bool, enable_local_dependency: bool) -
path,
src_raw,
existing_content,
&package_name,
enable_local_dependency,
&dart_package_name,
&config.rust_crate_name,
&config.rust_crate_dir,
config.enable_local_dependency,
)
},
&|path| filter_file(path, enable_integration_test),
&|path| filter_file(path, config.enable_integration_test),
)?;

modify_permissions(&dart_root)?;

pub_add_dependencies(enable_integration_test, enable_local_dependency)?;
pub_add_dependencies(
config.enable_integration_test,
config.enable_local_dependency,
)?;

format_dart(&[dart_root], 80)?;

Expand Down Expand Up @@ -73,17 +85,20 @@ fn modify_file(
path_raw: &Path,
src_raw: &[u8],
existing_content: Option<Vec<u8>>,
package_name: &str,
dart_package_name: &str,
rust_crate_name: &str,
rust_crate_dir: &str,
enable_local_dependency: bool,
) -> Option<(PathBuf, Vec<u8>)> {
let src = replace_file_content(src_raw, package_name, enable_local_dependency);
let replace_content_config = ReplaceContentConfig {
dart_package_name,
rust_crate_name,
rust_crate_dir,
enable_local_dependency,
};
let src = replace_file_content(src_raw, &replace_content_config);

let path =
if (path_raw.extension().unwrap_or_default().to_str()).unwrap_or_default() == "template" {
path_raw.with_extension("")
} else {
path_raw.to_owned()
};
let path = compute_effective_path(path_raw, &replace_content_config);

if let Some(existing_content) = existing_content {
if path.file_name() == Some(OsStr::new("main.dart")) {
Expand Down Expand Up @@ -118,23 +133,43 @@ fn modify_file(
Some((path, src))
}

fn replace_file_content(raw: &[u8], package_name: &str, enable_local_dependency: bool) -> Vec<u8> {
fn compute_effective_path(path: &Path, config: &ReplaceContentConfig) -> PathBuf {
let mut path = path.to_owned();
if (path.extension().unwrap_or_default().to_str()).unwrap_or_default() == "template" {
path = path.with_extension("")
}
path = replace_string_content(&path_to_string(&path).unwrap(), config).into();
path
}

fn replace_file_content(raw: &[u8], config: &ReplaceContentConfig) -> Vec<u8> {
match String::from_utf8(raw.to_owned()) {
Ok(raw_str) => raw_str
.replace("REPLACE_ME_PACKAGE_NAME", package_name)
.replace(
"REPLACE_ME_RUST_FRB_DEPENDENCY",
&if enable_local_dependency {
r#"{ path = "../../../frb_rust" }"#.to_owned()
} else {
format!(r#""={}""#, env!("CARGO_PKG_VERSION"))
},
)
.into_bytes(),
Ok(raw_str) => replace_string_content(&raw_str, config).into_bytes(),
Err(e) => e.into_bytes(),
}
}

struct ReplaceContentConfig<'a> {
dart_package_name: &'a str,
rust_crate_name: &'a str,
rust_crate_dir: &'a str,
enable_local_dependency: bool,
}

fn replace_string_content(raw: &str, config: &ReplaceContentConfig) -> String {
raw.replace("REPLACE_ME_DART_PACKAGE_NAME", config.dart_package_name)
.replace("REPLACE_ME_RUST_CRATE_NAME", config.rust_crate_name)
.replace("REPLACE_ME_RUST_CRATE_DIR", config.rust_crate_dir)
.replace(
"REPLACE_ME_RUST_FRB_DEPENDENCY",
&if config.enable_local_dependency {
r#"{ path = "../../../frb_rust" }"#.to_owned()
} else {
format!(r#""={}""#, env!("CARGO_PKG_VERSION"))
},
)
}

fn filter_file(path: &Path, enable_integration_test: bool) -> bool {
if path.iter().contains(&OsStr::new("cargokit")) {
return ![".git", ".github", "docs", "test"].contains(&file_name(path));
Expand Down
4 changes: 2 additions & 2 deletions frb_codegen/src/library/integration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ mod creator;
mod integrator;
mod utils;

pub use creator::create;
pub use integrator::integrate;
pub use creator::{create, CreateConfig};
pub use integrator::{integrate, IntegrateConfig};
Loading

0 comments on commit c006efe

Please sign in to comment.