Wrap entry point

I need to develop a SDK that takes care of setting up some details for a software. The details are for allowing, for example, mapping URLs such as app-storage://app-private-file.bin to C:/Users/Foo/AppData/Roaming/com.qux.foo-app/app-private-file.bin.

The developer's software should be a regular Cargo project and I want to keep the entry point as being src/main.rs, however I need to wrap it with another entry point, kinda like this:

src/_flxentry.rs:

mod main;

fn main() {
    // setup some details here
    ...
    main::main();
}

But there's clearly one problem: the name main should conflict. I've not even tested it, but quite sure it won't work. Is there a better way to do this?

It'd also be nice if I could hide this entry point _flxentry.rs from src and still have IDE integration working.

I've forgot I could also try:

src/main.rs

mod _flxentry;

fn main() {
    _flxentry::setup();
}

However is there a way to be more discrete?

You could copy tokio's approach and create an attribute macro (e.g. #[flx::main]) which does the setup before calling the user's main().

#[flx::main]
fn main() {
  // user code
}

// would expand to

fn main() {
  fn main() { /* user code */ }

  // setup

  main()
}
1 Like

Interesting... So I tried this:

f/Cargo.toml

[package]
name = "f"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[lib]
proc-macro = true

f/src/lib.rs

use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
    println!("Hi!");
    TokenStream::new()
}

demo/Cargo.toml

[package]
name = "demo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
f = { path = "../f", version = "0.1.0" }

demo/src/main.rs

#[f::main]
pub fn main() {
    println!("Hello, world!");
}

I get:

   Compiling demo v0.1.0 (C:\Users\matheus-pc\Documents\foo-rs-p\demo)
Hi!
error[E0601]: `main` function not found in crate `demo`
 --> src\main.rs:4:2
  |
4 | }
  |  ^ consider adding a `main` function to `src\main.rs`

For more information about this error, try `rustc --explain E0601`.
error: could not compile `demo` due to previous error

Any idea?

Well your f::main proc-macro just returns an empty stream of tokens (TokenStream::new()), so it effectively deletes anything with a #[f::main] annotation. Hence why the compiler complains about a missing main.

You need to return a new token stream which contains the item that was passed to it.

You can also use the cargo expand sub-command to see what your macros expand to.