Why should simplelog's dependencies be introduced when its paris feature is enabled?

[dependencies]
simplelog = { version = "0.11", features = ["paris"]}
# these following dependencies have to be introduced
log = "0.4"
paris = "1.5" 
// A demo that actually doesn't need apis from log or paris 
fn main() {
    simplelog::TermLogger::init(simplelog::LevelFilter::Debug,
                                simplelog::Config::default(),
                                simplelog::TerminalMode::Mixed,
                                simplelog::ColorChoice::Auto).expect("Failed to start simplelog");

    simplelog::info!("I can write <b>bold</b> text or use tags to <red>color it</>");
}

If log and paris are not introduced in my crate, an error occurs:

error[E0433]: failed to resolve: use of undeclared crate or module `log`
 --> src/main.rs:7:5
  |
7 |     simplelog::info!("I can write <b>bold</b> text or use tags to <red>color it</>");
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared crate or module `log`
  |
  = note: this error originates in the macro `simplelog::info` (in Nightly builds, run with -Z macro-backtrace for more info)

P.S. I know the scope rule of declarative macro is subtle, but here I'm confused.
The code, which is related to this post, in simplelog crate may be here.
Any explanation is appreciated!

You can find the info macro here

Since declarative macros effectively just replace the macro call with some code, writing

simplelog::info!("I can write <b>bold</b> text or use tags to <red>color it</>");

is the same as writing

log::info!("{}", paris::formatter::colorize_string(format!("I can write <b>bold</b> text or use tags to <red>color it</>")));

Since the resulting code tries to use both the log and paris crates, they need to be in your Cargo.toml. I think simplelog should instead re-export both log and paris in the crate root and write the macro like this

#[macro_export]
macro_rules! info {
    ($($args:tt)+) => {
        $crate::log::info!("{}", $crate::paris::formatter::colorize_string(format!($($args)*)));
    };
}

This way, it would instead be expanded to

simplelog::log::info!("{}", simplelog::paris::formatter::colorize_string(format!("I can write <b>bold</b> text or use tags to <red>color it</>")));

and since you already depend on simplelog, you wouldn't have to worry about the internals of the macro.

(edit: actually, the last code example should read ::simplelog::log and ::simplelog::paris, the leading :: makes it a canonical path, which just makes sure that it is resolved to the simplelog dependency and not any other thing named simplelog that may happen to be in scope)

2 Likes

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.