fzyzcjy / flutter_rust_bridge

Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple.
https://fzyzcjy.github.io/flutter_rust_bridge/
MIT License
4.17k stars 289 forks source link

How to debug rust code? #2055

Closed hilpara closed 1 month ago

hilpara commented 3 months ago

I do want to debug the rust code at the same time when the flutter app runs. I have two instances of vscode running and in one I start the flutter/dart debugging. After it has started, I attach the second vscode with lldb to the process. The problem I have is, that when the breakpoint hits, the debugger shows: Stop reason: signal SIGPROF and it is not possible to debug the code. As an example I'm using the gallery (Mandelbrot) and set the breakpoint to pub async fn mandelbrot in mandelbrot_related.rs

My launch.json

 {
            "type": "lldb",
            "request": "attach",
            "pid": "${command:pickProcess}",
            "name": "Debug Rust",
  }

Is it not possible to debug the rust code at the same time or am I doing something wrong?

welcome[bot] commented 3 months ago

Hi! Thanks for opening your first issue here! :smile:

fzyzcjy commented 3 months ago

Hi, IIRC rust code can be debugged. If you are using the default template, the library flutter-rust-bridge uses to compile Rust within Flutter is https://github.com/irondash/cargokit. Therefore, I guess it would be great to ask there.

fzyzcjy commented 3 months ago

In addition, Larpoux mentioned in https://github.com/fzyzcjy/flutter_rust_bridge/issues/1990#issuecomment-2151794089 that he successfully debugged Rust code. Thus cc @Larpoux in case he has some suggestions

Larpoux commented 3 months ago

Yes, I am able to debug the rust code under iOS. I did many tries and failing before my success. Unfortunately I don’t remember well what I did to success. Here what I remember:

On iOS I am able to set breakpoints, run instructions steps by step, and display variables values. Do not hesitate to ask if you have specific questions. I will try to remember what I did.

Larpoux commented 3 months ago

oh! I also add in Cargo.toml :

[profile.dev]
debug = true
strip = false
opt-level = 0

It is possible that it is not necessary. But actually I am not sure that FRB is linked with the Debug built of my crate.

Larpoux commented 3 months ago

Note : Things are not yet perfect. Actually I can put breakpoints, run step by step, show variables in up functions (not a method) but I cannot put breakpoints on a method. I can break correctly on the following function :

pub fn greet(name: String) -> String 
{
        log(Level::Trace, "boubou", "hello I am a log from Rust");
        t!("titi");
        format!("Hello, {name}!")
}

but I can't on this method new() :

#[no_mangle]
impl MediaElement
{
        /// The constructor
        #[frb(sync)]
        #[no_mangle]
        pub fn new(path: String) -> MediaElement
        {
                MediaElement
                {
                        my_media_element: Mutex::new(XMediaElement::new(path).unwrap())
                }
        }
}

There is space for improvement ...

patmuk commented 3 months ago

Maybe my approach helps: I set up another rust project, which exposes a CLI, which calls the rust code I am using in the flutter app. I mainly do that for faster turnarounds, so that I can work on the app logic over a CLI before I implement the UI in Flutter. Depending on for what you are using Rust it might not suit your needs ... if so, check out my sample project. (Apologies for spamming with my project ... I truly hope that this helps!)

Larpoux commented 3 months ago

NO!!!! You are not spamming us. We need to share our experiences. Definitely.

BTW: The problems that I had to put breakpoints under Xcode was not because the code was with methods, but because I could not break on a constructor (I am very new on Rust). I will post other informations when I will have some.

patmuk commented 3 months ago

@Larpoux Great, thanks!

fzyzcjy commented 3 months ago

@Larpoux Btw, my two cents for debugging (not sure whether I have discussed this before): Another way may be doing a lot of printing. For example, we may add many lines like log::info!("variable a has value: {a:?}, blah blah") and look at the output to see what is going on.

As for the breakpoints - have you tried #[inline(never)] on the function? Just a random thought, but maybe the inlining confuses the debugger.

hilpara commented 3 months ago

oh! I also add in Cargo.toml :

[profile.dev]
debug = true
strip = false
opt-level = 0

It is possible that it is not necessary. But actually I am not sure that FRB is linked with the Debug built of my crate.

Unfortunately that didn't change anything, as I was already building rust in debug mode

hilpara commented 3 months ago

@Larpoux Btw, my two cents for debugging (not sure whether I have discussed this before): Another way may be doing a lot of printing. For example, we may add many lines like log::info!("variable a has value: {a:?}, blah blah") and look at the output to see what is going on.

As for the breakpoints - have you tried #[inline(never)] on the function? Just a random thought, but maybe the inlining confuses the debugger.

Also this didn't change anything.

hilpara commented 3 months ago

Maybe my approach helps: I set up another rust project, which exposes a CLI, which calls the rust code I am using in the flutter app. I mainly do that for faster turnarounds, so that I can work on the app logic over a CLI before I implement the UI in Flutter. Depending on for what you are using Rust it might not suit your needs ... if so, check out my sample project. (Apologies for spamming with my project ... I truly hope that this helps!)

I think, this is the best way at the moment. It is just more work to make two "GUIs".

hilpara commented 3 months ago

Hi, IIRC rust code can be debugged. If you are using the default template, the library flutter-rust-bridge uses to compile Rust within Flutter is https://github.com/irondash/cargokit. Therefore, I guess it would be great to ask there.

I didn't get any answer from the cargokit

fzyzcjy commented 3 months ago

I personally seldomly use debugger so may not be able to help here. Another brainstorm is, maybe ask on Rust forums to see whether someone has experiences about this?

fzyzcjy commented 3 months ago

I tried it a bit, mainly follow @hilpara's steps (e.g. create launch.json), and seem to successfully get debugger to work as below (e.g. "Variables" section looks correct, "Step Over" button also works). I will try to provide detailed steps for easier reproduction. Seldom use VSCode and debugger, so please correct me if I am wrong!

image

code

In the frb_example/flutter_for_create folder, on branch feat/12375.

https://github.com/fzyzcjy/flutter_rust_bridge/compare/master...feat/12375

detail:

In rust/.vscode/launch.json, write

```json { "version": "0.2.0", "configurations": [ { "type": "lldb", "request": "attach", "pid": "${command:pickProcess}", "name": "Hello Debug Rust" } ] } ```

In simple.rs, modify the greet into:

```rust #[flutter_rust_bridge::frb(sync)] pub fn greet(name: String) -> String { greet_inner(name) } #[no_mangle] #[inline(never)] pub fn greet_inner(name: String) -> String { let a = name.len(); let b = a * a + a; format!("Hello, {name}! a={a} b={b}") } ```

NOTE: I find that it does not work without inline-never and/or no-mangle (not checked which works though)

In main.dart, modify as below to ensure Rust code is code periodically:

```dart import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_via_create/src/rust/api/simple.dart'; import 'package:flutter_via_create/src/rust/frb_generated.dart'; Future main() async { await RustLib.init(); runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { @override void initState() { super.initState(); Timer.periodic(const Duration(seconds: 3), (_) { print('Call rust: ${greet(name: "Tom")}'); }); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('flutter_rust_bridge quickstart')), body: Center( child: Text('Action: Call Rust `greet("Tom")`\nResult: `${greet(name: "Tom")}`'), ), ), ); } } ```

steps

step 0: open ide

Open two VSCodes:

  1. VSCode a: on the flutter app folder
  2. VSCode b: on the rust/ folder

step 1: create files

modify code like mentioned above

step 2: install

VSCode hint me it does not know "type:lldb", and thus I go to plugin market, and install "CodeLLDB" plugin.

step 3: run flutter

In "VSCode a", use F5 to "start debugging" the Flutter app. I chose the target "MacOS". Then the Flutter app window appears on my mac.

step 4: put breakpoints, and attach debugger

In "VSCode b", click to breakpoints on some lines of the greet_inner function. Then, F5 to start the debugger. It will ask which process to attach, choose the flutter one.

Then it seems to work for me.

fzyzcjy commented 1 month ago

Close since this seems to be solved and also is referred by doc https://cjycode.com/flutter_rust_bridge/guides/how-to/debug. But feel free to reopen or create new issues if seeing any issues!

github-actions[bot] commented 1 month ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new issue.