Skip to content

cpp_build: emit rerun-if-changed for every parsed source file - #118

Open
0xull wants to merge 1 commit into
mystor:masterfrom
0xull:cpp-build-rerun-if-changed
Open

0xull wants to merge 1 commit into
mystor:masterfrom
0xull:cpp-build-rerun-if-changed

Conversation

@0xull

@0xull 0xull commented Nov 7, 2026 •

Copy link
Copy Markdown

fixes #115, related to #84.

since cc 1.0.74 (rust-lang/cc-rs@019603a), cc::Build prints cargo:rerun-if-env-changed lines by default. once a build script prints any rerun-if line, cargo stops rerunning it when other files in the package change (cargo docs), so an edited or new cpp! macro is never extracted again, and the build fails with "This cpp! macro is not found in the library's rust-cpp metadata" until cargo clean.

with this change the parser records every file it reads, and Config::build prints a cargo:rerun-if-changed line for each one. modules turned off with #[cfg(feature = ...)] aren't listed, because the parser never reads them and cargo reruns the build script anyway when features change. a file is recorded before it's read, so fixing a file that failed to parse also reruns the build script. the paths stay relative, which cargo resolves from the package root, and the lines use cargo: rather than cargo:: to keep the 1.71 msrv. nothing is printed after cargo_metadata(false), as the XXX comment in that method asked for, and cc prints no rerun-if lines in that case either, so cargo's default rescan still applies. the docs for cargo_metadata, From<cc::Build> and the build script section of the cpp crate now explain this.

to reproduce, take a crate whose build.rs only calls cpp_build::build("src/lib.rs"), run cargo test, change the cpp! block in src/value.rs from return 1; to return 2;, and run cargo test again without cargo clean. with cpp_build 0.5.12 the second run fails with the metadata error. with this branch it passes, and the build script prints:

cargo:rerun-if-changed=src/lib.rs
cargo:rerun-if-changed=src/value.rs

i also checked these cases with scratch crates, building twice without cargo clean:

case 0.5.12 this branch
edit an existing cpp! macro fails passes
add the first cpp! macro to a module that had none fails passes
add a new module with a cpp! macro fails passes
enable a feature that adds a module, then edit it fails passes
fix a syntax error in a module and change its cpp! macro fails passes
workspace member, built from the workspace root fails passes
crate root at the package root, build("lib.rs") fails passes
cargo_metadata(false) with hand-written link lines passes passes
rebuild with no changes, or after editing a non-source file no rerun no rerun

test_source_files checks the recorded files for each module layout the parser follows, which are an adjacent foo.rs, foo/mod.rs, a file module declared inside an inline module, #[path], and a feature-disabled module.

there are a few things this doesn't cover. headers included from cpp! macros and files added with Config::file() still don't rerun the build script, the same as now, because only the compiler knows which headers it opened, so i'd like to handle them in a separate pr using the compiler's dependency output. with cc 1.0.73 or older, cargo's default rescan used to pick up header edits, and these lines turn that rescan off, which newer cc versions already do. a cc::Build passed through From with cargo_metadata(false) already set can't be detected, so the docs ask for Config::cargo_metadata(false) as well. the build script, and so the C++ compile, now reruns on every edit to a parsed file, which is how it behaved before cc 1.0.74. a build script that rewrites one of the parsed files on every run will now rerun on every build, because cargo sees that file as newer each time. the build script can avoid this by only writing the file when its contents actually change.

your comment on #115 mentions an option. cargo_metadata(false) turns this off, but if you'd rather have a separate Config method, i can add one.

(for context, i ran into this while working on the rust foundation's overloading-macros experiment, which uses cpp (rustfoundation/overloading-macros#61). we worked around it there by adding a rerun-if-changed line to its build script (rustfoundation/overloading-macros#63), and a reviewer there suggested working on a fix upstream here.)

Signed-off-by: Ikeh Chukwuka <mrikehchukwuka@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cpp! fails with "not found in metadata"

1 participant