What the 'life cycle' of a proc-macro could be?

I'm currently working on a macro for writting R plugins faster.

Currently, these things are needed:

  1. Like other normal proc-macro, perform token switchings.
  2. After compile end, save meta informations obtained from the prevoius step.
  3. Write R wrappers.
  4. Decide whether adding a #![no_std] attribute.

Currently, 4. might be done with #![proc_macro], but since the proc macro will read things such as #[prelude_import] and yield warnings, thus I am just planning to write a 'read' macro and a 'done' macro, read for functions and 'done' located at the end of the file, exporting meta informations.

and here comes the question: are proc macros executing in order?

#[read]
fn foo(){}
mod bar{
    #[read]
    fn bar(){}
}
mod baz{
    #[read]
    fn baz(){}
}
done!{}
// for rextendr, here would be
// i_forgot_the_name!{
//     fn foo;
//     mod bar; // I'm not sure whether it is the correct grammar for rextendr
//     fn bar;
//     mod baz;
//     fn baz;
//}
// this could generate a slice `const META: &[Meta]=&[("foo\0".as_ptr() as *const c_char, foo as *const c_void, 0),(...),...,(ptr::null(),ptr::null(),0)]` //the tuple is named and has #[repr(C)], I omit the name

Is there some feature that could ensure done is executed after all the #[read] finishes?

Should I writting a multi-threading logic to prevent potential data racing in proc_macro?

What's more, is there a safe folder that could always write to? Currently proc_macro is not safe(since it could read and write everywhere) Will there some directory that proc_macro could always output to?


(Sorry for so much trouble in these days.)

In rust code is mostly read from top to bottom, and executed the same way. This does not take into account things like multithreading, which provide an exception to that.

However, macros of any kind are ultimately just textual substitutions early in the compile process, which means that in a real sense macros just do what their use site expansions do. No more, no less. That also implies that macros have no power other than syntactic abstraction i.e. making the relevant input stand out in a short piece of code rather than being lost in a possibly large swath of code (which would correspond to some expansion of a macro).

In other words, if your macro, when expanded, only does deterministic things, the macro itself when expanded to that code will do the same. I particular a macro by itself cannot introduce any changes to execution order.

That would require one of :

  1. Putting #[read] above done!() in every source file, which would be a footgun as it would be easy to forget.
  2. making your macros unsandboxable by having them e.g. write to the file system, or some other persistsble data shared between the 2. Doing this would work today but might break your project in the future, if proc macros are actually sandboxed.
  3. Tossing it all into one big macro. Not recommended either, as that would just obfuscate whatever needs to happen between #[read] and done!().

Ultimately macros of any kind as they exist today were not designed for this purpose.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.