Problems when compiling to Rust
alfonsogarciacaro opened this issue ยท 7 comments
Hi @delneg! Thanks a lot integrating Fable with Tauri, this looks really interesting! In this tweet you mention that you also tried to compile to Rust (the code is in fable4-rust
branch in this repo) but faced some problems.
Would it be possible to quickly summarize the issues? I'm sure that @ncave and @alexswan10k will be happy to hear your feedback and maybe they know how to fix/work around :)
Hello @alfonsogarciacaro ,
Well first of all it's Fable version in .config/dotnet-tools.json
.
I had to switch between Fable 4.0.0-snake-island-alpha-021 and Fable 3.7.18 because Feliz requires Fable 3 or it won't compile. I don't know if there's any way to use specific dotnet tool for specific projects though.
Secondly, I've had much trouble with getting a global function (maybe it's called 'crate-level function', I don't remember)
I need it for build.rs
which is a special file used to build the project:
fn main() {
tauri_build::build()
}
The other issue with that file is that if it's the last file in fsproj, other file (src/main.rs) gets 'mod'-ed into it, which is a no-go because it's a build file:
#[path = "./src/main.rs"]
mod module_e43b409d;
Also, I didn't understand how to get
#![cfg_attr(all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows")]
to appear at the very top.
Note that it's not #[cfg_attr(
but a #![cfg_attr(
Another very important issue is I don't know how to get &str
, because it's what #[tauri::command]
expects - it doesn't work with any type of Rc
(and definitely not Lrc<str>
that fsharp string
compiles into.
I've read Fable.Core.Rust source code, read through tests
in Fable repo, even searched in issues & pull requests - but didn't find any examples of that.
[<ByRef>]
or inref<string>
that I've found didn't work, they just produced &Lrc<str>
.
Also, I didn't understand how get get my functions compile into regular functions without a module, they always seem to be showed into some pub mod Main
or pub mod Build
, and that doesn't work for binaries because I want to have my own pub fn main() {
, not the one that Fable generates from [<Entrypoint>]
.
Anyway, I'm not an expert in neither F# nor Rust and I didn't write too much code using Fable Rust so far, so maybe those issues have some pretty easy solutions.
I hope that I've outlined them correctly and it's possible to get if not exactly the same but close to the existing Rust code to be generated by Fable.
- Currently you can't do
#![cfg_attr
at file level, but you can do#[cfg_attr
at file module level, which is the same:
[<Fable.Core.Rust.OuterAttr("cfg_attr", [| "all(not(debug_assertions), target_os = \"windows\")"; "windows_subsystem = \"windows\"" |])>]
module MyModule
- We are still considering whether to change the string type representation to lower the impedance with interop code. In the mean time, Rust interop is still a work in progress, but you can emit the code you need, for example:
open Fable.Core
open Fable.Core.Rust
[<Erase; Emit("String")>]
type String = interface end
[<Erase; Emit("&str")>]
type StrRef = interface end
[<Emit("$0.as_ref()")>]
let asRef x = nativeOnly
[<OuterAttr("tauri::command")>]
let my_custom_command (invoke_message: String): StrRef = asRef invoke_message
This is just an example how to emit types and funcs, not actual code, so don't read too much into it.
Also, we don't have any serialization support yet, so perhaps for now the whole command layer needs to be in native Rust and transform the command payload before calling into your F# code.
- Yes, there are no global functions in F#, everything is in a module.
I want to have my own pub fn main() { , not the one that Fable generates from
[<Entrypoint>]
.
All that the generated main does is to call the F# main, passing the arguments, that's it.
So you can just put your F# code in the F# main, like you normally do.
Or, you can always have your own Rust main.rs/lib.rs/build.rs
top level file that does whatever you need to do and then calls into the rest of the code.
I think @ncave covered my thoughts really, but I just wanted to quickly summarize a couple of things
How to get various commonly used strings from an Lrc<str>
in Rust:
let s:&str = string("3.14").as_ref();
let s2:String = s.to_string();
You can also do this using emit as ncave pointed out. We will probably be able to standardize the interop story better down the road.
As to your question about integrating with existing libraries, the way I have been experimenting with personally is to actually keep all of the F# generated code in a separate crate, and assemble the F# code with Rust libraries in a consuming root crate. By doing this you do not need to work around any F# generation limitations when trying to interop, although this is definitely a scenario that would be nice to have working well too.
Another point of interest - you can pull in rust files into the compilation process in F# using
importAll "./ExtInteropTests.rs"
We have examples of this in the Fable Rust tests.
At some point I hope to be able to post an example but not quite there yet, sorry.
Hello and thank you for your answers.
I've played around and pushed a somewhat practical version here c7b77c2
However, right now I guess it doesn't make much sense to force yourself to write tauri code in F#, because it's very hard to define commands without serde.
I've left build.rs & main.rs "as is" and added a separate file "commands.fs" to define Tauri commands.
Although, it's still not usable for development because of Feliz.HookAttribute incompatibility with Fable 4 currently
./fable_modules/Feliz.1.68.0/React.fs(1,1): error EXCEPTION: Plugin Feliz.HookAttribute expects v3.0 but currently running Fable v4.0.0-snake-island-alpha-021
Anyway, even if it's not practical it's a fun experiment
FWIW, the inner attributes were fixed and will work as expected in the next released version.
@delneg I've published alpha-023 which includes latest Rust fixes if you want to give it a new try ๐ This version should be also compatible with Feliz so you can use it to replace Fable 3 (please let us know if you find any regression). You just need to install the latest Feliz plugins with:
dotnet add package Feliz.CompilerPlugins --version 2.0.0-prerelease-001
@delneg I've published alpha-023 which includes latest Rust fixes if you want to give it a new try ๐ This version should be also compatible with Feliz so you can use it to replace Fable 3 (please let us know if you find any regression). You just need to install the latest Feliz plugins with:
dotnet add package Feliz.CompilerPlugins --version 2.0.0-prerelease-001
@alfonsogarciacaro Yes, after updating it looks like it works, tauri dev
works fine for me locally