I'm trying to figure out how to compile multi-file crates in Rust, but I keep getting a compile error.
I have the file I want to import into the crate thing.rs:
mod asdf {
pub enum stuff {
One,
Two,
Three
}
}
And my crate file test.rc:
mod thing;
use thing::asdf::*;
fn main(){
}
When I run rust build test.rc I get:
test.rc:3:0: 3:19 error: `use` and `extern mod` declarations must precede items
test.rc:3 use thing::asdf::*;
^~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
There's obviously something simple about how modules, crates and use work that I'm just not getting. My understanding was that mod something; for files in the same directory or extern mod something; for libraries on the library path caused the object file to be linked. Then use would allow you to import parts of the module into the current file, function or module. This seems to work for stuff in the core library.
This is with version 0.6 of the rust compiler.
You just need to put the use at the top of the file:
use thing::asdf::*;
mod thing;
fn main() {}
This looks very strange, but
It's what the error message says (anything that you can put at the top level that is not use or extern mod is an "item", including mods), and
It's how Rust name resolution works. use is always relative to the top of the crate, and the whole crate is loaded before name resolution happens, so use thing::asdf::*; makes rustc look for thing as a submodule of the crate (which it finds), and then asdf as a submodule of that, etc.
To illustrate this last point better (and demonstrate the two special names in use, super and self, which import directly from the parent and current module respectively):
// crate.rs
pub mod foo {
// use bar::baz; // (an error, there is no bar at the top level)
use foo::bar::baz; // (fine)
// use self::bar::baz; // (also fine)
pub mod bar {
use super::qux; // equivalent to
// use foo::qux;
pub mod baz {}
}
pub mod qux {}
}
fn main() {}
(Also, tangentially, the .rc file extension no longer has any special meaning to any Rust tools (including in 0.6), and is deprecated, e.g. all the .rc files in the compiler source tree were recently renamed to .rs.)
Related
Recently, I started to learn rust. I'm currently at section 7.4 (bringing paths into scope). Tried hard, but I can't understand the purpose of self::some_sort_of_identifier in rust. Would you please explain what is the difference between use self::module_name::function_name and use module_name::function_name? I tried both and they both worked as expected in the example below:
mod my_mod {
pub fn func() {
print!("I'm here!");
}
}
use my_mod::func;
fn main() {
func();
}
Running this program, as expected, I can see this statement printed into the terminal:
I'm here
And this program here gives me exactly the same results and the rust compiler doesn't complain about anything:
mod my_mod {
pub fn func() {
print!("I'm here!");
}
}
use self::my_mod::func;
fn main() {
func();
}
So, is self:: useless in rust? Why should I even use self::my_mod::my_function(); when I can directly call it like so: my_mod::my_function();.
Are there any cases in which they might defer?
For your use-case, it's mainly a relict from the 2015 rust edition.
In this edition the following code would not compile:
use my_mod::func;
mod my_mod {
use my_mod2::func2;
pub fn func() {
func2();
}
mod my_mod2 {
pub fn func2() {
print!("I'm here!");
}
}
}
fn main() {
func();
}
The compiler complains:
error[E0432]: unresolved import my_mod2
--> src\main.rs:4:9
|
| use my_mod2::func2;
| ^^^^^^^ help: a similar path exists: self::my_mod2
Why did it change? You can see the note about the path and module system changes here.
Rust 2018 simplifies and unifies path handling compared to Rust 2015. In Rust
2015, paths work differently in use declarations than they do
elsewhere. In particular, paths in use declarations would always start
from the crate root, while paths in other code implicitly started from
the current scope. Those differences didn't have any effect in the
top-level module, which meant that everything would seem
straightforward until working on a project large enough to have
submodules.
In Rust 2018, paths in use declarations and in other code work the
same way, both in the top-level module and in any submodule. You can
use a relative path from the current scope, a path starting from an
external crate name, or a path starting with crate, super, or self.
The blog post Anchored and Uniform Paths from the language team also underlines this
The uniformity is a really big advantage, and the specific feature we’re changing -
no longer having to use self:: - is something I know is a big
stumbling block for new users and a big annoyance for advanced users
(I’m always having to edit and recompile because I tried to import
from a submodule without using self).
The keyword itself however is still useful in use statments to refer to the current module in the path itself. Like
use std::io::{self, Read};
being the same as
use std::io;
use std::io::Read;
I have a small Rust project, and would like the simplicity of a flat module system, combined with the modularity of separate files. In essence, I would like this program:
src/main.rs
fn print_hello_world() {
println!("Hello, world!");
}
fn main() {
print_hello_world();
}
to be structured akin to this:
src/print_hello_world.rs
pub fn print_hello_world() {
println!("Hello, world!");
}
src/main.rs
use crate::print_hello_world; // Error: no `print_hello_world` in the root
fn main() {
print_hello_world();
}
Note that there is only a single module in this pseudo project; the crate root module. No child modules exists. Is it possible to structure my project like this? If yes, how?
Solution attempts
It is easy to get this file structure by having this:
src/main.rs
mod print_hello_world;
use print_hello_world::print_hello_world;
fn main() {
print_hello_world();
}
but this does not give me the desired module structure since it introduces a child module.
I have tried finding the answer to this question myself by studying various authorative texts on this matter, most notably relevant parts of
The Rust Book
The Rust Reference
The rustc book
My conclusion so far is that what I am asking is not possible; that there is no way to use code from other files without introducing child modules. But there is always the hope that I am missing something.
This is possible, but unidiomatic and not recommended, since it results in bad code isolation. Making changes in one file is likely to introduce compilation errors in other files. If you still want to do it, you can use the include!() macro, like this:
src/main.rs
include!("print_hello_world.rs");
fn main() {
print_hello_world();
}
I'm writing a Rust library (generated from cargo) with unit tests.
I'd like to use the extern crate maplit in my unit tests to be able to use JavaScript-like hashmap literals. I don't want to use maplit in my library code.
maplit provides a macro that apparently must be activated using #[macro_use]. The only way I've been able to get this all working is to place this at the top of lib.rs:
#[cfg(test)] #[macro_use] extern crate maplit;
// my crate-specific stuff
At this point I realized I don't know what exactly #[cfg(test)] does. I'm using it in my tests. These are included with library code, as per the convention, like so:
// some library code
#[cfg(test)]
mod test {
use super::*;
// tests here
}
I had thought that the line #[cfg(test)] was marking what follows until the end of the file (or block?) as only applicable to the test configuration.
If so, then putting this directive at the top of lib.rs seems like a problem. Won't my entire library be dropped when I compile a distribution?
I've tried to find documentation on what exactly #[cfg(test)] does, but to no avail.
#[....]
The above is a Rust Attribute which is like an annotation in other languages. For example; in Java we have #Annotation(....) for methods and classes. Unlike annotation the rust attribute can be an expression that follows the attribute syntax.
#[cfg(....)]
The above is a compiler configuration attribute. The cfg() is one of many built-in attributes.
#[cfg(test)]
The above tells the Rust compiler that the following code should only be compiled when the test configuration is active. You can have other configuration attributes like debug, windows or features.
#[cfg(test)] #[macro_use] extern crate maplit;
Is the same as
#[cfg(test)]
#[macro_use]
extern crate maplit;
Which tells the Rust compiler to only compile the next line if the test configuration is active, and the next line tells Rust to only use macros from the following crate.
If so, then putting this directive at the top of lib.rs seems like a problem. Won't my entire library be dropped when I compile a distribution?
The #[cfg(...)] attribute only applies the compiler condition upon the thing it is attached to.
When you place the attribute at the top of the file followed by a space. The attribute is attached to the current module or crate.
As shown here from the documentation example, the crate_type is applied to the entire file:
// General metadata applied to the enclosing module or crate.
#![crate_type = "lib"]
// A function marked as a unit test
#[test]
fn test_foo() {
/* ... */
}
// A conditionally-compiled module
#[cfg(target_os = "linux")]
mod bar {
/* ... */
}
// A lint attribute used to suppress a warning/error
#[allow(non_camel_case_types)]
type int8_t = i8;
// Inner attribute applies to the entire function.
fn some_unused_variables() {
#![allow(unused_variables)]
let x = ();
let y = ();
let z = ();
}
struct SemanticDirection;
fn main() {}
warning: struct is never used: `SemanticDirection`
--> src/main.rs:1:1
|
1 | struct SemanticDirection;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(dead_code)] on by default
I will turn these warnings back on for anything serious, but I am just tinkering with the language and this is driving me bats.
I tried adding #[allow(dead_code)] to my code, but that did not work.
You can either:
Add an allow attribute on a struct, module, function, etc.:
#[allow(dead_code)]
struct SemanticDirection;
Add a crate-level allow attribute; notice the !:
#![allow(dead_code)]
Pass it to rustc:
rustc -A dead_code main.rs
Pass it using cargo via the RUSTFLAGS environment variable:
RUSTFLAGS="$RUSTFLAGS -A dead_code" cargo build
Another way to disable this warning is to prefix the identifier by _:
struct _UnusedStruct {
_unused_field: i32,
}
fn main() {
let _unused_variable = 10;
}
This can be useful, for instance, with an SDL window:
let _window = video_subsystem.window("Rust SDL2 demo", 800, 600);
Prefixing with an underscore is different from using a lone underscore as the name. Doing the following will immediately destroy the window, which is unlikely to be the intended behavior.
let _ = video_subsystem.window("Rust SDL2 demo", 800, 600);
Put these two lines on the top of the file.
#![allow(dead_code)]
#![allow(unused_variables)]
Making the code public also stops the warnings; you'll need to make the enclosing mod's public too.
This makes sense when you're writing a library: your code is "unused" internally because it's intended to be used by client code.
also as an addition: rust provides four levels of lints (allow, warn, deny, forbid).
https://doc.rust-lang.org/rustc/lints/levels.html#lint-levels
For unused functions, you should make the function public, but watch out. If the struct isn't public, then you'll still get the error as in here:
//this should be public also
struct A{
A{}
}
impl A {
pub fn new() -> A {
}
}
Or if you don't want it to be public, you should put #[allow(unused)]
Directly way to just put the following in the head of the file
#![allow(dead_code, unused_variables)]
The dead_code lint detects unused, unexported items.
The unused_variables lint detects variables which are not used in any way.
More simple way is to put the following in the head of the file
#![allow(unused)]
Ref: rust lint list
You can always disable unused variables/functions by adding an (_) to the variable name, like so:
let _variable = vec![0; 10];
You can add the #[allow(dead_code)] attribute to the struct definition like so:
#[allow(dead_code)]
struct SemanticDirection;
Or you can disable the warning for the entire file by adding the attribute at the top of the file, like so:
#![allow(dead_code)]
struct SemanticDirection;
But these attributes only work if you have the dead_code lint enabled. By default, the dead_code lint is enabled in Rust, but you can disable it by adding the following to the top of your code:
#![deny(dead_code)]
This will disable the dead_code lint for the entire file.
It's generally a good idea to keep the dead_code lint enabled, as it can help you catch mistakes in your code and ensure that you are not introducing unnecessary code into your project. However, it can be annoying when you are just experimenting and trying out different things, so it's understandable if you want to disable it in those cases.
At the top of *.rs file:
#![allow(unused)] // FIXME
using features
#[cfg(feature = "dead_code")]
note: "dead_code" can be replaced by any word.
I'm trying to write some debugging helper macros. So I create a crate to hold all of them, and referred to the crate externally using phase(plugin):
#[cfg(test)]
#[phase(plugin)]
extern crate debugging;
That successfully exports the macros into the crate.
However, for some of these tools I wanted to invoke functions from the crate, for example:
#[macro_export]
macro_rules! trace(
{$($arg:tt)*} => {
{
extern crate debug;
let s = ::macros::logger(); // <---- This!
let _ = s.write_line(format_args!(::std::fmt::format, $($arg)*).as_slice());
}
};
)
Using a global namespace, ie. ::macros::logger works if the macro is placed into macros.rs and imported from the crate root of a crate.
However, what I'm trying to achieve here is the same thing when the macro has to invoke a call from its own crate.
If the macro expanded correctly, I believe:
let s = ::crate_name::logger();
Would be the way to do it, but the crate with the macro cannot refer to itself by name in this way. It generates errors like:
src/macros.rs:52:15: 52:20 error: failed to resolve. Maybe a missing `extern crate debugging`?
src/macros.rs:52 let s = ::debugging::logger();
^~~~~
src/macros.rs:49:1: 56:2 note: in expansion of trace!
src/file.rs:26:11: 26:29 note: expansion site
...and finally just so we're completely clear about what I'm trying to do:
crate debugging:
lib.rs
fn logger()
macros.rs
macro_rules! trace(...) // <--- Trying to figure out what to put here...
crate foo:
lib.rs
#[phase(plugin)] extern crate debugging;
fn test_thing() {
trace!("{}", ...); // <--- So debugging::logger() is invoked here
}
So, is there some way to do this from a macro?
For now, the correct thing to do is use an absolute path like that and then do some reexports in the original crate so that path resolves.
I.e. in lib.rs put
mod debugging {
pub use logger;
}
which reexports the top level function logger as debugging::logger. There is work being done that makes this saner, e.g. $crate which expands to name of the crate from which the macro came (when used externally), or to nothing (when used internally); this isn't necessarily the final design, but it is improving.
For anyone else who finds this, it's worth noting that you cannot use from a crate marked with phase plugin. To import the symbols locally (as per the accepted answer), you need to do this:
#[cfg(test)]
mod debug {
#[phase(plugin)]
extern crate debugging;
extern crate debugging;
pub use self::debugging::debug;
}
Notice the double extern crate debugging, because typically you wouldn't want to export a syntax extension module as part of the code.