Search code examples
compilationrustmacrosenvironment-variablesrust-proc-macros

Can proc macros determine the target of the invoking compilation?


Procedural macros live in their own crates, which are compiled for the development machine (so that they can be executed when crates that use them are compiled). Any conditional compilation directives within the procedural macro crates will accordingly be based on their compilation environment, rather than that of the invoking crate.

Of course, such macros could expand to tokens that include conditional compilation directives that will then be evaluated in the context of the invoking crate's compilation—however, this is not always possible or desirable.

Where one wishes for the expanded tokens themselves to be some function of the invoking crate's compilation environment, there is a need for the macro to determine that environment during its run-time (which is of course the invoking crate's compilation-time). Clearly a perfect use-case for the std::env module.

However, rustc doesn't set any environment variables; and Cargo sets only a limited few. In particular, some key information (like target architecture/operating system etc) is not present at all.

I appreciate that a build script in the invoking crate could set environment variables for the macro then to read, but this places an unsatisfactory burden on the invoking crate author.

Is there any way that a proc macro author can obtain runtime information about the invoking crate's compilation environment (target architecture and operating system being of most interest to me)?


Solution

  • I've somewhat inelegantly solved this by recursing into a second proc macro invocation, where the first invocation adds #[cfg_attr] attributes with literal boolean parameters that can then be accessed within the second invocation:

    #[cfg_attr(all(target_os = "linux"), my_macro(linux = true ))]
    #[cfg_attr(not(target_os = "linux"), my_macro(linux = false))]
    // ...
    

    A hack, but it works.