Procedural macros and dependencies

  1. crate foo_derive provides a derive macro

  2. crate foo_derive depends on crate_apple

  3. crate bar uses foo_derive

Question: Does bar now need crate_apple as a dependency ?

Yes => From what I can see via cargo tree this seems to be the situation.

Argument for no: At runtime, bar does not need foo_derive (or crate_apple); bar only needs foo_derive during the compile process. Therefore, shouldn't it be thrown away ?

Rust executables don't require any dependencies at runtime [1]. There's a few different categories of dependencies that cargo recognizes:

  • Normal dependencies: these are your standard dependencies that provide some code for you to use
  • Dev dependencies: dependencies included when running cargo test
  • Build dependencies: dependencies included when building a build script
  • Procedural macros: each proc macro crate is compiled as its own executable, then saved, and rustc will use them to expand your code at compile time

Importantly, build dependencies and proc macros are compiled for the host instead of the target.

It's up to you how you want to define "dependency", but in objective terms: since proc macro crates are distributed by source, your example would end up with anyone compiling bar to download and compile the source of crate_apple.

There is a new proposal to allow distributing proc macros as wasm modules, which would let you use them without needing to compile them or their dependencies. There's still a lot of technical work to be done before that would happen, though.

  1. unless you depend on some external libraries like OpenSSL, but this is separate from cargo/rust dependencies ↩ī¸Ž


Sorry, I was very imprecise with my usage of 'dependency' above. Let me try to rephrase the question.


Are the contents of crate_apple linked into the output binary of crate bar ?

From reading cargo tree, my intuition says yes. However, a more precise reasoning seems to suggest:

  1. We need to build foo_derive into a binary during compile time

  2. We need to run said binary when bar uses the derive macro

  3. However, there is no need to link the contents of foo_derive into the binary output of bar.

Question: In the binary output of crate bar, are the contents of crate apple linked in ?


The only thing proc macros do is convert some syntax to some other syntax.


If you need a tool that tells you about all your runtime dependencies specifically, you can use cargo-depgraph, which by default generates a graph of only runtime deps. cargo tree can do this, see message below.

Though something being a runtime dependency doesn't actually mean that any symbols from it end up in your binary, for example for macro_rules!-only crates this is always the case, or the crate could only contain generic symbols that are never instantiated for your binary, or the compiler / linker could discard all the symbols from it because they're ultimately found to be unused.

It is also possible to list only "run time" dependencies with

cargo tree -e normal

Even without the option, cargo tree will mark build dependencies, but this will hide them entirely.


In Rust, when crate bar uses a proc-macro provided by foo_derive, it indirectly relies on the dependencies of foo_derive, such as crate_apple, during the compile process. This means that bar requires these dependencies to be available during compilation, even though it doesn't need them at runtime.

Here's a breakdown:

  1. crate bar depends on foo_derive for the proc macro.
  2. foo_derive depends on crate_apple.
  3. When you compile bar, the proc macro from foo_derive is executed as part of the compilation process. This means that foo_derive, including its dependencies (including crate_apple), must be available at compile time.

Nice, I didn't know about this flag! Seems like the right invocation for no-host-dependencies including proc macros is -e normal,no-proc-macro.

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.