17

I'm using watch with cargo, in order to quickly see compile time errors. However, cargo build will only show errors when building the first time.

$ cargo build
Compiling clayman v0.0.1
src/core_math/vector.rs:8:5: 13:6 warning: method is never used: `New`, #[warn(dead_code)] on by default
src/core_math/vector.rs:8     pub fn New(x: i32, y: i32) -> Vector {
src/core_math/vector.rs:9         Vector {
src/core_math/vector.rs:10             x: x,
src/core_math/vector.rs:11             y: y
src/core_math/vector.rs:12         }
src/core_math/vector.rs:13     }
src/core_math/vector.rs:8:5: 13:6 warning: method `New` should have a snake case name such as `new`, #[warn(non_snake_case)] on by default
src/core_math/vector.rs:8     pub fn New(x: i32, y: i32) -> Vector {
src/core_math/vector.rs:9         Vector {
src/core_math/vector.rs:10             x: x,
src/core_math/vector.rs:11             y: y
src/core_math/vector.rs:12         }
src/core_math/vector.rs:13     }
src/main.rs:28:9: 28:10 warning: unused variable: `v`, #[warn(unused_variables)] on by default
src/main.rs:28     let v: vector::Vector;
                   ^
$ cargo build
$

Which means I only get to see the warnings for a few seconds before watch gives me a clear screen.

Is there any way to make cargo build always give me the warnings?

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
MartinHaTh
  • 1,417
  • 1
  • 13
  • 25

5 Answers5

5

As of Rust 1.40, Cargo will cache the compiler messages. This means that even if the code doesn't need to be compiled again, the previous warnings will be printed out.

Rust 1.40

% cargo build
   Compiling warnings v0.1.0 (/private/tmp/warnings)
warning: unused variable: `a`
 --> src/main.rs:2:9
  |
2 |     let a = 42;
  |         ^ help: consider prefixing with an underscore: `_a`
  |
  = note: `#[warn(unused_variables)]` on by default

    Finished dev [unoptimized + debuginfo] target(s) in 1.58s

% cargo build
warning: unused variable: `a`
 --> src/main.rs:2:9
  |
2 |     let a = 42;
  |         ^ help: consider prefixing with an underscore: `_a`
  |
  = note: `#[warn(unused_variables)]` on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.00s

Rust 1.39

% cargo build
   Compiling warnings v0.1.0 (/private/tmp/warnings)
warning: unused variable: `a`
 --> src/main.rs:2:9
  |
2 |     let a = 42;
  |         ^ help: consider prefixing with an underscore: `_a`
  |
  = note: `#[warn(unused_variables)]` on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.42s

% cargo build
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
4

Warnings only happen when Rust recompiles your files; however it caches as much as possible and if something hasn't changed it will happily skip an useless compile. There's currently no option in Cargo to force rebuild.

A quick and dirty solution, but easy to setup, is to touch your source files so that Cargo believes they changed:

$ cd /path/to/project/root
$ ls
Cargo.lock Cargo.toml src        target
$ cargo build
     Compiling abc v0.1.0 (file:///private/tmp/b/abc)
  src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default
  src/main.rs:2     let x: u8 = 123;
                        ^
$ cargo build
$ touch $(find src)
$ cargo build
     Compiling abc v0.1.0 (file:///private/tmp/b/abc)
  src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default
  src/main.rs:2     let x: u8 = 123;
                        ^

Another solution, maybe better, would be to clean off the target directory containing binary artifacts, with cargo clean:

$ cargo build
   Compiling abc v0.1.0 (file:///private/tmp/b/abc)
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default
src/main.rs:2     let x: u8 = 123;
                      ^
$ cargo build
$ cargo clean
$ cargo build
   Compiling abc v0.1.0 (file:///private/tmp/b/abc)
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default
src/main.rs:2     let x: u8 = 123;
                      ^

It has the advantage of not triggering Vim "file changed!" warnings and is also runnable anywhere within the project dir, not just the root.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
mdup
  • 7,889
  • 3
  • 32
  • 34
  • I tried this now, and it works -- however, since we're modifying the files, vim is complaining each time I save (because 'the file has been modified'!) – MartinHaTh Jun 29 '15 at 21:11
  • Ouch -- going down the quick-and-dirty road, try `:set autoread` – mdup Jun 29 '15 at 21:20
  • See edit: I propose to use `cargo clean` as an alternative. – mdup Jun 29 '15 at 21:31
  • It might require a bit of extra work to make it work with `watch`, though. – mdup Jun 29 '15 at 21:34
  • This works, but I'm having a few dependencies, including sdl2, so compile time is about 30 sec. – MartinHaTh Jun 30 '15 at 15:03
  • However, It did work pretty good to simply `touch` _one_ file - the whole project is still compiled, and all errors show. – MartinHaTh Jun 30 '15 at 15:18
  • I noticed that currently (using stable or nightly, on Windows), the first part of this answer is wrong. Touching does not bring back clippy diagnostics. Even changing contents such that previously reported line numbers are off, doesn't motivate clippy to repeat. Apparently it strongly adheres to "Listen carefully, I shall say this only once". `cargo clean` is the only option. – Stein Oct 12 '19 at 19:35
1

This is another variant of the touch pattern described in mdups answer.

Use this command to check for type errors and display all warnings every run, even when no code change has occurred:

touch src/my_tra_la_la.rs && clear && clear && cargo check

The clear && clear && part is mostly irrelevant to this answer but it's a mandatory part of every build command for me, to avoid having the new output visually merge with output from the previous run.

It requires two things, first mod my_tra_la_la; in main.rs, or in lib.rs if it's a library.

The second part is optional but I think it's nice to add some documentation to this special source file, src/my_tra_la_la.rs:

//! The only purpose of this file is to act as a target for the `touch` command
//! in order to force recompilation of this otherwise meaningless file and in
//! turn to force rustc to display warnings, every time.
//!
//! touch src/my_tra_la_la.rs && clear && clear && cargo check
//!
//! Mmm...my ding ding dong

The whole point of a dedicated touch file like this is to avoid the need to ever have it open in your code editor and avoid popups and warnings like "file changed!" while working.

arkod
  • 1,973
  • 1
  • 20
  • 20
0

A solution, albeit temporarily, was to touch a file I rarely edit. This way, I'm avoiding the this file has been changed problem, and also don't need to clean the whole project all the time.

In addition, I managed to get colors in as well (cargo doesn't have a --color option), by not using watch at all, but by simply running the following script:

#!/bin/sh
while :
do
    script -qc "cargo build" /dev/null > .tmp
    clear
    cat .tmp
    sleep 2 # or whatever
    touch src/somefile.rs
done

The reason I'm writing and reading to .tmp is to make all the output appear at one (rustc outputs as it runs)

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
-3

I've run into this before. I use:

cargo check
rjloura
  • 554
  • 4
  • 6
  • 2
    `cargo check` does not solve this problem. Two back-to-back runs of `cargo check` (without changes to the source of the crate) will not report warnings on the second invocation. – Shepmaster Apr 11 '19 at 19:00
  • This was wrong when it was posted, but works now! The bug (or, whatever, undesired feature) has been fixed! `cargo check` and `cargo clippy` cache warnings :tada: – Richard Rast May 05 '20 at 18:23