Repro steps:
1) Create build.rs and make appropriate entry in Cargo.toml
2) Have build.rs conditionally generate a file src/foo.rs (eg generate file if it doesn't exist, or generate file if mtime is older than its configuration)
3) cargo build --verbose (should run build script, generate file, and build foo.rs)
4) cargo build --verbose again. This time, I would expect it to be a noop, but it rebuilds foo.rs
5) cargo build --verbose again. This time it's a noop as expected.
I am running into this issue because I am compiling a .proto file into a protobuf rs file during the build.rs phase.
Ah yeah Cargo doesn't work well if files are generated into the source directory (due to its mtime checking). In that sense this is expected behavior.
Instead though it's intended that build scripts generate files into $OUT_DIR and then they're included in the normal Rust source via:
include!(concat!(env!("OUT_DIR"), "/foo.rs"));
Would that work for this use case?
It will work, but it's a little inconvenient because reading the generated code is generally useful. This just makes it a little trickier to locate.
Yeah that's true, although Cargo otherwise has no way to distinguish between build-script-generated files and normal Rust files (unless you configure ignore in Cargo.toml I believe)
Would it be possible to re-stat the mtime after running the build script? The issue here is that the build script generates a file (updating its mtime). Then during compile phase, cargo persists the old mtime, but compiles the new file.
Eg:
build.rs (generates foo.rs from foo.proto)
proto/
- foo.proto
src/
- foo.rs
If we update foo.proto to foo'.proto, cargo will compile the new foo'.rs, but persist the mtime from foo.rs
When you build a second time, the build script can recognize that foo.proto is up to date, but cargo thinks that foo'.rs needs to be recompiled since it's checking against the old mtime.
If you build a third time, things are fine.
We could do that I think, but I believe it'd break the case where if a file is edited normally during a build that it'd trigger a rebuild later (which has been asked for before). Cargo would have to differentiate from a file being generated/edited by a build script or a file edited during a build.
I have the same problem and use case (compiling a proto in build.rs). Unfortunately include!(concat!(env!("OUT_DIR"), "/foo.rs")); does not work for me due to https://github.com/rust-lang/rfcs/issues/752. I found mod_path which works, but since it is a compiler plugin it limits me to unstable which is not acceptable for the project I work on.
For now I am stumped on this. I work around the issue by checking in the manually generated .rs files next to the .proto files, which is suboptimal.
@nipunn1313, did you find an acceptable solution for yourself?
@alexcrichton Can you advise on another work around that would allow me to codegen the .rs file on build?
@SirVer you may be able to get by with cargo:rerun-if-changed output perhaps? Other than include! though I don't know how to include files from OUT_DIR
We ended up putting the .proto in a proto/ directory next to src/. The
double compile isn't too bad.
--Nipunn
On Thu, Dec 8, 2016 at 4:13 PM Alex Crichton notifications@github.com
wrote:
@SirVer https://github.com/SirVer you may be able to get by with
cargo:rerun-if-changed output perhaps? Other than include! though I don't
know how to include files from OUT_DIR—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/rust-lang/cargo/issues/3076#issuecomment-265895289,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABPXo3mZrNT_UxIf-fPacovQnI9irab0ks5rGJ0ugaJpZM4J2hf9
.
@alexcrichton Thanks. I will wait for some conclusion to https://github.com/rust-lang/rfcs/issues/752 and regenerate the code manually for now then.
@nipunn1313 Can I see this code somewhere? Would be interesting to see how you solved it.