Search code examples
rustrust-proc-macros

Is there a way to get the file and the module path of where a procedural macro is attached at compile-time?


I'm looking for the equivalent of file!() & module_path!() in a procedural macro context.

For example, the following doesn't work:

file.rs:

#[some_attribute]
const A: bool = true;

macro.rs:

#[proc_macro_attribute]
pub fn some_attribute(attr: TokenStream, input: TokenStream) -> TokenStream {
    println!("{}", file!());

    input
}

This prints macro.rs which makes sense, but what I want is file.rs. Is there a way to achieve this? Is there also a similar way for module_path!()?

A requirement of this is that has to happen at compile-time.

I'm trying to create a file in the OUT_DIR containing constant values where the attribute is added with the module and the file that they are in.


Solution

  • I had the same problem and found out that Rust added a new experimential API to Rust macros (#54725) which allows exactly what you want:

    #![feature(proc_macro_span)]
    
    #[proc_macro]
    pub(crate) fn do_something(item: TokenStream) -> TokenStream {
        let span = Span::call_site();
        let source = span.source_file();
        format!("println!(r#\"Path: {}\"#)", source.path().to_str().unwrap())
            .parse()
            .unwrap()
    }
    
    use my_macro_crate::*;
    
    fn main() {
        println!("Hello, world!");
        do_something!();
    }
    

    Will output:

    Hello, world!
    Path: src\main.rs
    

    Important

    Apart from this API being experimential, the path might not be a real OS path. This can be the case if the Span was generated by a macro. Visit the documentation here.