dtolnay/proc-macro-hack

Build fails with can't find crate for `proc_macro` on musl target

golddranks opened this issue · 11 comments

When targeting musl (nightly-2017-02-13, but the stable 1.15.1 fails too.), I'm encountering the following error:

Compiling proc-macro-hack v0.3.0
error[E0463]: can't find crate for `proc_macro`
 --> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro-hack-0.3.0/src/lib.rs:1:1
  |
1 | extern crate proc_macro;
  | ^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate

error: aborting due to previous error

error: Could not compile `proc-macro-hack`.

Here is a dockerized test: https://github.com/golddranks/proc_macro_test (run with docker build .)

I don't know much about musl but based on macros 1.1 implementation details it doesn't sound like procedural macro crates can be statically linked. It should still be possible to use a dynamically linked proc macro crate's macros from within a statically linked other crate - if not, file a Cargo issue.

So it seems that on musl target, "normal" derive marcos as introduced in the book work without a hitch, but proc-macro-hack fails. The reason seems to be that on musl target it can't find the proc_macro crate unless the crate using it is also marked [lib] proc-macro = true.

I think the problem is, indeed in static and dynamical linking, but actually the proc macro part seems to work fine, and the problem is the statically linked part that still links to proc_macro.

The reason why proc_macro is linked from proc-macro-hack seems to be because of these lines TokenStream is mentioned:

            pub fn $func(input: $crate::TokenStream) -> $crate::TokenStream {

Is importing TokenStream a necessity here?

I'm going to also file an issue to the Rust repo about the inability to link to proc_macro.

Okay, the reason seems to be that proc_macro is currently always dynamically linked, so it's incompatible linking it with a binary built for the musl target.

This makes proc-macro-hack incompatible with musl unless either the dependency to proc macro in the declaration crate can be gotten rid of, or unless rustc starts supporting linking proc_macro statically.

I released 0.3.2 with a fix. Try it out with:

proc-macro-hack = { version = "0.3.2", default-features = false }

Your crate is responsible for providing ::proc_macro:

extern crate proc_macro;

#[macro_use]
extern crate proc_macro_hack;

proc_macro_expr_impl! {
    /* ... */
}

Tried with the binary_macros crate (newest commit on master), but the following error occurs:

error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
 --> src/lib.rs:9:1
  |
9 | proc_macro_expr_decl!(base2! => base2_impl);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: this error originates in a macro outside of the current crate

error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
 --> src/lib.rs:9:1
  |
9 | proc_macro_expr_decl!(base2! => base2_impl);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: this error originates in a macro outside of the current crate

That looks like the error from rust-lang/rust#39889. You need to use stable 1.15 or beta 1.16 at least until tomorrow's nightly is out. See the note in the readme.

Oops, that's right! This was an unrelated error. Reporting back in a sec.

@dtolnay: Thanks, this works.

For future reference: for the default features to be omitted, every crate linking to proc-macro-hack must set default-features = false, so this might be a bit fragile solution, but it works for me, at least.

@alexcrichton made a point which made me think that not referencing proc_macro, (like it now does without default features) is the "proper" way to do this. Not that it matters too much if this crate is just a hacky stop-gap solution, just a pointer.