Compile-time plugins: Re-purposing Cargo `[patch]` and proc-macros

The Cargo github repo points here, so I've migrated the following from the user-forum:

I've been experimenting with how a compile-time plugin system might work in Rust. Indeed, with some rough edges, I have something functional - the roughness comes about when trying to have a [patch.cargo-io] interact with package renaming in the [dependencies] stanza. However, I am uncertain if I have correctly inferred that this is the blessed way to do this in Rust?

Specifically I'd like library users to replace the (default) implementation of an proc-macro-attribute with their implementation. The library functions are decorated with the proc-macro-attributes, in this way users are able to customize the library behavior (at compile-time). In case it matters the plugins alter tracing behavior.

There are some very good blog posts describing how to setup run-time plugins. But less on the compile-time plugins idea.

As best I can tell a compile-time plugin 'setup' would use proc-macros and the Cargo [patch] stanza in the user application Cargo.toml (or .cargo/config.toml ).

My doubt is due to the fact that the documentation (below) dealing with the use of [patch] , has four scenarios all dealing with development and shorter lived activities, and doesn't mention the ability to provide library users with compile-time plugins that can alter the library subsequent run-time behavior (with caveats):

https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html

Are proc-macros+ [patch] the correct way to do this or is there some other Rust pattern better suited?

I mean, this would work, but it's very much not an intended use of the feature.

Assuming this is the tracing crate, the normal way to handle this would be to have a tracing feature to enable tracing, and then just put the appropriate tracing metadata into the sink with appropriate tracing Level. Note that tracing already supports setting a compile-time minimum reporting level, and spans/records which don't meet that requirement are not even compiled into the binary.

The tracing team cares quite a lot about making tracing/observability not any more expensive than it needs to be, and even when events are filtered out at runtime, the cost to do so is very minimal (especially if said cost is amortized across multiple times through the code).

That was my impression, and concern. It would be more functional if the [dependencies] package functionality wasn't going to throw errors in the future.... and a few other things. But MVP compile-time plugins seem feasible right now.

Anyway, I'm still wondering, should this be an intended use feature? Welcome any suggestions about how to advance on that front, and with who to engage?

Agreed. The issue here is the library users are developers who have different, and strong, opinions on the data traced, field names etc., etc.. Further, because this is a library, finding the agreed set will, I fear, be nigh impossible.

I'm hoping to propose the current code (the plugin API if you like) as a compile-time plugin system with some an optional default that can be settled/agreed on over time - without blocking a user who wants to go ahead now, or who wants to do something different.