I'm trying to write some macros that work in nostd environment as well as in std environment. In order to do so I have this kind of code in proc macro crate:
#[cfg(not(feature = "alloc"))]
{
quote!(err.message = Some(::std::borrow::Cow::from(#m));)
}
#[cfg(feature = "alloc")]
{
quote!(err.message = Some(::alloc::borrow::Cow::from(#m));)
}
This correctly produces the code that uses alloc when alloc feature is enabled, but the compiler complains
error[E0433]: failed to resolve: could not find `alloc` in the list of imported crates
Of course the reason is that the macro expansion is missing
extern crate alloc;
But adding that is a problem. Since it's a procedural derive macro, the extern crate will be added on each derive call. How can I refer to an extern crate in macro expansion? Using $crate does not seem to work inside quote!.
You can wrap the expansion in a block, then you can define alloc multiple times.
Another common practice for proc macros that need auxiliary types is to create a crate that provides them, and reexport the macro from it. E.g. create mycrate and mycrate-macros. Then you can get rid of the whole alloc feature if you only need alloc-accessible types, like:
#![no_std]
extern crate alloc;
#[doc(inline)]
pub use mycrate_macros::my_macro;
#[doc(hidden)]
pub use alloc:borrow::Cow;
Then in the macro refer to ::my_crate::Cow.
Related
So I want to have some modules defined in lib.rs but not make them public but only available for use within the project.
in my lib.rs, if I have the definition as this:
pub mod args;
in my main.rs, I can use the args modules this way:
use my_lib::args::Cli;
where my_lib is defined in Cargo.tml as
[lib]
name = "my_lib"
path = "src/lib.rs"
but I don't want pub mod args;. I tried changing to pub(crate) mod args; but this leads to compilation error that the args module cannot be found.
How do I make a module like args defined in lib.rs available without have to give it the most permissive visibility?
Since Rust separates the library lib.rs and binary main.rs into separate crates there is no simple way to include things that are in lib.rs and not pub from main.rs.
I suggest you follow the way of big crates (serde comes to mind) and add a pub mod __private; which conveys the meaning. You can additionaly annotate it with #[doc(hidden)] to hide it from the documentation making it even more obvious.
I had some extern "C" functions in my Rust library; then I decided to split the library up into a bunch of crates and make one workspace crate that just re-exports everything from its members. However, now that I have done this, the symbols for these extern "C" functions are missing from the generated .so file. How can I fix this?
I tried re-exporting the extern "C" functions individually; this did not work. I also tried setting crate-type = ["cdylib"] on the crate containing the functions, and this didn't work either.
According to this GitHub issue, the behaviour I'm seeing is a bug and there doesn't seem to be any known solution besides wrapping the functions that I want to re-export.
I just added actix_rt in Cargo.toml and didn't declare it at the first line with the use keyword. Then I could use it in the code. I know some frequently used functions are included in the prelude of Rust, but I had no idea 3rd party libraries could do the some thing. Can I create a crate like that?
Any one could tell me why or give me some tips or some reference links? I'd appreciate it.
[dependencies]
actix-rt = "0.2.5"
actix-web = "1.0.8"
use std::io;
fn main() -> io::Result<()> {
let sys = actix_rt::System::new("basic");
sys.run()
}
In the Rust 2018 Edition, extern crate is no longer required. Putting a crate as a dependency allows it to be accessed as a module. There's nothing you need to do to make your crate accessible like this.
This is very different from the standard library prelude, which uses all the items in the prelude implicitly (with use std::prelude::v1::*;). With extern crate or adding an external crate as a dependency, the types, functions and traits have to be qualified. In your example, you have to use actix_rt::System::new("basic") rather than simply System::new("basic"). Compare this to std::prelude::v1::Option, which can be used as Option<T> without any prefix.
I have a crate foo_sys. In Rust 2015 I used extern crate foo_sys as foo for convenience, but in Rust 2018 extern crate isn't needed anymore and I don't want to use it only for aliasing. When dropping extern crate, I get
error[E0463]: can't find crate for foo
This can be achieved with the rename-dependency Cargo feature, available in Rust 1.31. With this feature, it's possible to provide a package attribute to the dependencies:
The rename-dependency feature allows you to import a dependency with a different name from the source. This can be useful in a few scenarios:
Depending on crates with the same name from different registries.
Depending on multiple versions of a crate.
Avoid needing extern crate foo as bar in Rust source.
Instead of writing
[dependencies]
foo_sys = "0.2"
the package key can be added to the dependency in Cargo.toml:
[dependencies]
foo = { package = "foo_sys", version = "0.2" }
WARNING: Cargo prior to Rust 1.26.0 may download the wrong dependency when using this feature!
The idiomatic solution is to rename the crate in Cargo.toml. See the answer by Tim Diekmann for more information about that.
But if you don't want to use Cargo.toml renaming for some reason, you can still use the old syntax. It's soft-deprecated, but not removed. So this still works:
extern crate foo_sys as foo;
(Playground example)
I'm trying to pass my whole crate to a procedural macro.
I've tried putting this code on top of my lib.rs:
#![my_macro]
#![feature(proc_macro)]
extern crate my_macro;
use my_macro::{my_macro};
and failed: error: cannot find attribute macro 'my_macro' in this scope
I've tried also putting the macro invocation below the use clause:
#![feature(proc_macro)]
extern crate my_macro;
use mock_macro::{my_macro};
#![my_macro]
but failed as well: error: an inner attribute is not permitted in this context
Is it possible to do it? (I know syn has a function for parsing a whole crate)
This is possible as of Rust 1.25.0-nightly as long as you enable feature(extern_absolute_paths) and use an absolute path for your attribute macro.
#![::my_crate::my_macro]
#![feature(extern_absolute_paths, proc_macro)]
The issue of attribute macros invoked at the crate root is being tracked in rust-lang/rust#41430. We expect to remove the limitation that the attribute must be specified with an absolute path as the implementation of RFC 2126 proceeds further. You may run into other limitations too, in particular attempting to inject functions into the crate from a crate-level procedural macro currently crashes the compiler.