Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid global ffigen #605

Merged
merged 31 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
12c869f
:hammer: update just lint to format rust code altogether
Roms1383 Aug 1, 2022
ef84ec4
:arrow_up: add ffi and ffigen dependencies to examples
Roms1383 Aug 1, 2022
26de1f3
:recycle: use local dependencies instead of global
Roms1383 Aug 1, 2022
666b799
:green_heart: remove ffigen as a global dependency from CI
Roms1383 Aug 1, 2022
69b74b9
:art: lint code
Roms1383 Aug 1, 2022
fa0e943
:truck: move redundant code from commands to utils
Roms1383 Aug 1, 2022
185d469
:hammer: update just check to run clippy in frb_codegen altogether
Roms1383 Aug 1, 2022
4488c38
:recycle: refactor ensure dependencies methods
Roms1383 Aug 1, 2022
9c242b3
:recycle: parse dart root only once
Roms1383 Aug 1, 2022
b6a8c8e
:recycle: add dart root or default
Roms1383 Aug 1, 2022
e90a486
:art: lint and fix clippy warnings
Roms1383 Aug 1, 2022
f8f968b
:recycle: refactor, improve naming
Roms1383 Aug 1, 2022
374de6b
:art: simplify code
Roms1383 Aug 1, 2022
92b60ba
:fire: remove version req comparison
Roms1383 Aug 1, 2022
9b9ec7d
:pencil2: remove unecessary fully qualified syntax
Roms1383 Aug 1, 2022
e6ec7da
:memo: update install docs
Roms1383 Aug 1, 2022
fe86a45
Merge branch 'master' into chore/avoid-global-ffigen
Roms1383 Aug 2, 2022
310c89d
:green_heart: add flutter setup action
Roms1383 Aug 2, 2022
6c31eea
:art: fix clippy warning
Roms1383 Aug 2, 2022
4e79ebe
:green_heart: add install deps step
Roms1383 Aug 2, 2022
63603f4
:memo: reuse parts of the docs and fix mardown lint warnings
Roms1383 Aug 2, 2022
9525d5c
Update deps.md
fzyzcjy Aug 2, 2022
98f3a19
Merge branch 'fzyzcjy:master' into chore/avoid-global-ffigen
Roms1383 Aug 3, 2022
c8575ce
:green_heart: remove unused install step
Roms1383 Aug 3, 2022
15d6e46
:fire: remove unused markdown file
Roms1383 Aug 3, 2022
ef86e5b
:pencil2: fix doc wording
Roms1383 Aug 3, 2022
f6b6366
:recycle: refactor pattern matching into condition
Roms1383 Aug 3, 2022
94c11a4
:recycle: reuse impl method
Roms1383 Aug 3, 2022
d56544d
:recycle: add version method to package version
Roms1383 Aug 3, 2022
01ee615
:rewind: remove install deps in CI
Roms1383 Aug 3, 2022
c09c62e
:green_heart: install deps in CI
Roms1383 Aug 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ jobs:

- uses: dart-lang/setup-dart@v1

- name: Install ffigen
run: dart pub global activate ffigen ^6.0.1

- name: Install dart dependencies (single block)
working-directory: ./frb_example/pure_dart/dart
run: dart pub get
Expand Down Expand Up @@ -335,8 +332,6 @@ jobs:
- uses: actions/checkout@v2

- uses: dart-lang/setup-dart@v1
- name: Install ffigen
run: dart pub global activate ffigen ^6.0.1
- name: Install llvm dependency (Linux)
run: sudo apt update && sudo apt-get install -y libclang-dev
- name: Build codegen
Expand Down Expand Up @@ -403,8 +398,6 @@ jobs:
components: rustfmt, clippy

- uses: dart-lang/setup-dart@v1
- name: Install ffigen
run: dart pub global activate ffigen ^6.0.1
- name: Install llvm dependency (Linux)
run: sudo apt update && sudo apt-get install -y libclang-dev

Expand Down Expand Up @@ -563,18 +556,29 @@ jobs:
runs-on: ${{ matrix.os.image }}

steps:
- uses: subosito/flutter-action@v2
with:
channel: "stable"

- uses: actions/checkout@v2

- uses: dart-lang/setup-dart@v1

- name: Install dart global dependency
run: dart pub global activate ffigen ^6.0.1

# needed by `ffigen`, see https://github.com/dart-lang/ffigen#installing-llvm
- name: Install llvm dependency (Linux)
if: ${{ matrix.os.family == 'linux' }}
run: sudo apt update && sudo apt-get install -y libclang-dev

- name: Install dart dependencies (single block)
fzyzcjy marked this conversation as resolved.
Show resolved Hide resolved
working-directory: ./frb_example/pure_dart/dart
run: dart pub get

- name: Install dart dependencies (multi blocks)
working-directory: ./frb_example/pure_dart_multi/dart
run: dart pub get

- name: Install Flutter dependencies
working-directory: ./frb_example/with_flutter
run: flutter pub get

# NOTE in windows, need "\\" instead of "/"
- name: Run codegen to pure_dart example (non-windows)
if: ${{ matrix.os.family != 'windows' }}
Expand Down
12 changes: 4 additions & 8 deletions .github/workflows/post_release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ jobs:

- uses: dart-lang/setup-dart@v1

- name: Install ffigen
run: dart pub global activate ffigen ^6.0.1

- name: Install dart dependencies (single block)
working-directory: ./frb_example/pure_dart/dart
run: dart pub get
Expand Down Expand Up @@ -171,16 +168,15 @@ jobs:
runs-on: ${{ matrix.os.image }}

steps:
- uses: subosito/flutter-action@v2
with:
channel: "stable"

- uses: actions/checkout@v2

- name: Install released version of codegen
run: cargo install flutter_rust_bridge_codegen

- uses: dart-lang/setup-dart@v1

- name: Install dart global dependency
run: dart pub global activate ffigen ^6.0.1

# needed by `ffigen`, see https://github.com/dart-lang/ffigen#installing-llvm
- name: Install llvm dependency (Linux)
if: ${{ matrix.os.family == 'linux' }}
Expand Down
33 changes: 22 additions & 11 deletions book/src/integrate/deps.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,31 @@ These depdencies are required only in build-time:

- [`flutter_rust_bridge_codegen`](https://lib.rs/crates/flutter_rust_bridge_codegen), the core codegen for Rust-Dart glue code
- [`ffigen`](https://pub.dev/packages/ffigen), to generate Dart code from C headers
- [`cargo-xcode`](https://lib.rs/crates/cargo-xcode), to generate Xcode projects for iOS and MacOS
- A working installation of LLVM, see [Installing LLVM](https://pub.dev/packages/ffigen#installing-llvm)
- A working installation of LLVM, see [Installing LLVM](https://pub.dev/packages/ffigen#installing-llvm), used by `ffigen`
- (Optional) [`cargo-xcode`](https://lib.rs/crates/cargo-xcode), if you want to generate Xcode projects for iOS and MacOS

An easy way to install most of these dependencies is to run:

```bash
cargo install flutter_rust_bridge_codegen
dart pub global activate ffigen
# if building for iOS or MacOS
cargo install cargo-xcode
```
- dart project

```bash
cargo install flutter_rust_bridge_codegen
dart pub add --dev ffigen && dart pub add ffi
# if building for iOS or MacOS
cargo install cargo-xcode
```

- flutter project

```bash
cargo install flutter_rust_bridge_codegen
flutter pub add --dev ffigen && flutter pub add ffi
# if building for iOS or MacOS
cargo install cargo-xcode
```

Alternatively, each of these dependencies may provide prebuilt binaries. Check with
your package manager and review them individually.

## Dart dependencies

Expand Down Expand Up @@ -51,6 +65,3 @@ Add these lines to `Cargo.toml`:
+flutter_rust_bridge = "1"
```

> **Note** \
> If you wish to return a `Result`, keep in mind that this library can only run codegen
> for [`anyhow::Result`](https://docs.rs/anyhow/latest/anyhow/type.Result.html).
11 changes: 0 additions & 11 deletions book/src/setup_codegen.md

This file was deleted.

17 changes: 1 addition & 16 deletions book/src/template/generate_install.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
# Installing codegen

First, you will need the following programs, preferably visible from your path:

- [`flutter_rust_bridge_codegen`](https://lib.rs/crates/flutter_rust_bridge_codegen), the core codegen for Rust-Dart glue code
- [`ffigen`](https://pub.dev/packages/ffigen), to generate Dart code from C headers
- [`just`](https://github.com/casey/just), a modern command runner alternative to Make
- A working installation of LLVM, see [Installing LLVM](https://pub.dev/packages/ffigen#installing-llvm)

An easy way to install the first three dependencies is to run these commands:

```shell
cargo install flutter_rust_bridge_codegen just
dart pub global activate ffigen
```

Alternatively, each of these dependencies may provide prebuilt binaries. Check with
your package manager and review them individually.
More informations in the [Installing dependencies](../integrate/deps.md) section.
12 changes: 2 additions & 10 deletions book/src/tutorial_with_flutter.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

In this tutorial, let us draw a [Mandelbrot set](https://en.wikipedia.org/wiki/Mandelbrot_set) (a well-known infinite-resolution "image" generated by a simple math formula). The image is plotted in Flutter UI, generated by Rust algorithm, and communicated via this library.

<!-- markdownlint-disable MD033 -->
<details>
<summary>(Click to see: What is a Mandelbrot set)</summary>

Expand All @@ -27,16 +28,7 @@ git clone https://github.com/fzyzcjy/flutter_rust_bridge && cd flutter_rust_brid

This step is optional, since I have generated the source code already (in quickstart). Even if you do it, you should not see anything changed.

Firstly, you may need to install dependencies of this library:

* Install `ffigen`: `dart pub global activate ffigen`, and [install LLVM](https://pub.dev/packages/ffigen#installing-llvm) which is required by `ffigen`.
* Install the codegen program: `cargo install flutter_rust_bridge_codegen` (or other probably faster methods described [here](quickstart.md)).

Then, run the code generator:

```shell
flutter_rust_bridge_codegen --rust-input frb_example/with_flutter/rust/src/api.rs --dart-output frb_example/with_flutter/lib/bridge_generated.dart --c-output frb_example/with_flutter/ios/Runner/bridge_generated.h
```
As soon as you make any modification to `api.rs`, you need to run codegen again. More informations about requirements for code generation can be seen in the [Installing dependencies](integrate/deps.md) section.

## Run app

Expand Down
140 changes: 42 additions & 98 deletions frb_codegen/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use std::collections::HashMap;
use std::fmt::Write;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;

use crate::error::{Error, Result};
use crate::utils::PackageManager;
use crate::utils::{ensure_dependencies, guess_toolchain, DartToolchain};
use log::{debug, info, warn};
use serde::Deserialize;

#[must_use]
fn call_shell(cmd: &str) -> Output {
Expand All @@ -18,11 +17,32 @@ fn call_shell(cmd: &str) -> Output {
execute_command("sh", &["-c", cmd], None)
}

pub fn ensure_tools_available() -> Result {
let output = call_shell("dart pub global list");
let output = String::from_utf8_lossy(&output.stdout);
if !output.contains("ffigen") {
return Err(Error::MissingExe(String::from("ffigen")));
pub fn ensure_tools_available(dart_root: &str) -> Result {
let toolchain = guess_toolchain(dart_root).unwrap();
if toolchain == DartToolchain::Dart && !call_shell("dart --version").status.success() {
return Err(Error::MissingExe("dart".to_string()));
} else if toolchain == DartToolchain::Flutter
&& !call_shell("flutter --version").status.success()
{
return Err(Error::MissingExe("flutter".to_string()));
}

let ffi = ensure_dependencies(dart_root, "ffi", PackageManager::Dependencies).unwrap();
if ffi.is_none() {
return Err(Error::MissingDep {
name: "ffi".into(),
context: PackageManager::Dependencies,
version: "^2.0.1".into(),
});
}
Roms1383 marked this conversation as resolved.
Show resolved Hide resolved

let ffigen = ensure_dependencies(dart_root, "ffigen", PackageManager::DevDependencies).unwrap();
if ffigen.is_none() {
return Err(Error::MissingDep {
name: "ffigen".into(),
context: PackageManager::DevDependencies,
version: "^6.0.1".into(),
});
}

Ok(())
Expand All @@ -39,7 +59,10 @@ pub(crate) struct BindgenRustToDartArg<'a> {
pub llvm_compiler_opts: &'a str,
}

pub(crate) fn bindgen_rust_to_dart(arg: BindgenRustToDartArg) -> anyhow::Result<()> {
pub(crate) fn bindgen_rust_to_dart(
arg: BindgenRustToDartArg,
dart_root: &str,
) -> anyhow::Result<()> {
cbindgen(
arg.rust_crate_dir,
arg.c_output_path,
Expand All @@ -52,6 +75,7 @@ pub(crate) fn bindgen_rust_to_dart(arg: BindgenRustToDartArg) -> anyhow::Result<
arg.dart_class_name,
arg.llvm_install_path,
arg.llvm_compiler_opts,
dart_root,
)
}

Expand Down Expand Up @@ -161,6 +185,7 @@ fn ffigen(
dart_class_name: &str,
llvm_path: &[String],
llvm_compiler_opts: &str,
dart_root: &str,
) -> anyhow::Result<()> {
debug!(
"execute ffigen c_path={} dart_path={} llvm_path={:?}",
Expand Down Expand Up @@ -208,9 +233,15 @@ fn ffigen(
std::io::Write::write_all(&mut config_file, config.as_bytes())?;
debug!("ffigen config_file: {:?}", config_file);

// NOTE please install ffigen globally first: `dart pub global activate ffigen`
let cmd = format!(
"{} run",
guess_toolchain(dart_root).unwrap().as_run_command()
);
let res = call_shell(&format!(
"dart pub global run ffigen --config \"{}\"",
"cd {}{}{} ffigen --config \"{}\"",
dart_root,
if cfg!(windows) { "; " } else { " && " },
cmd,
config_file.path().to_string_lossy()
));
if !res.status.success() {
Expand Down Expand Up @@ -280,90 +311,3 @@ pub fn build_runner(dart_root: &str) -> Result {
}
Ok(())
}

fn guess_toolchain(dart_root: &str) -> anyhow::Result<DartToolchain> {
debug!("Guessing toolchain the runner is run into");
let lock_file = PathBuf::from(dart_root).join("pubspec.lock");
if !lock_file.exists() {
return Err(anyhow::Error::msg(format!(
"missing pubspec.lock in {}",
dart_root
)));
}
let lock_file = std::fs::read_to_string(lock_file)
.map_err(|_| anyhow::Error::msg(format!("unable to read pubspec.lock in {}", dart_root)))?;
let lock_file: PubspecLock = serde_yaml::from_str(&lock_file).map_err(|_| {
anyhow::Error::msg(format!("unable to parse pubspec.lock in {}", dart_root))
})?;
if lock_file.packages.contains_key("flutter") {
return Ok(DartToolchain::Flutter);
}
Ok(DartToolchain::Dart)
}

#[derive(Debug, PartialEq)]
enum DartToolchain {
Dart,
Flutter,
}

impl DartToolchain {
fn as_run_command(&self) -> &'static str {
match self {
DartToolchain::Dart => "dart",
DartToolchain::Flutter => "flutter pub",
}
}
}

#[derive(Debug, Deserialize)]
struct PubspecLock {
pub packages: HashMap<String, serde_yaml::Value>,
}

#[cfg(test)]
mod tests {
use std::path::{Path, PathBuf};

use crate::commands::{guess_toolchain, DartToolchain};
use lazy_static::lazy_static;

lazy_static! {
static ref FRB_EXAMPLES_FOLDER: PathBuf = {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("frb_example")
};
}

fn guess_toolchain_base(path: &Path, expect_toolchain: DartToolchain) {
let toolchain = guess_toolchain(&path.to_string_lossy()).expect(&format!(
"can get toolchain from {}",
path.to_string_lossy()
));
assert_eq!(toolchain, expect_toolchain);
}

#[test]
fn guess_dart_toolchain() {
guess_toolchain_base(
FRB_EXAMPLES_FOLDER.join("pure_dart").join("dart").as_path(),
DartToolchain::Dart,
);
guess_toolchain_base(
FRB_EXAMPLES_FOLDER
.join("pure_dart_multi")
.join("dart")
.as_path(),
DartToolchain::Dart,
);
}

#[test]
fn guess_flutter_toolchain() {
guess_toolchain_base(
FRB_EXAMPLES_FOLDER.join("with_flutter").as_path(),
DartToolchain::Flutter,
);
}
}
Loading