Always run Process in Library's build.rs

This one is tricky and I am not sure if it is really possible:

I have a git repository that contains a workspace of multiple binary crates and a library crate. The library has a build.rs script that determines the git version from git describe and fills an environment variable. The library also has a get_version() function that just returns the &'static str returned by env!().

Now this does not always work correctly, because the git describe string sometimes changes without the library being rebuilt. What would be the correct way to achieve what I am trying to do? I just want a static version string that is always updated, when the git describe output changes.

You can use println!("cargo:rerun-if-changed=some_path"); for each file read by git describe. This seems to be .git/HEAD and the file that you get when adding .git before the part after the : in .git/HEAD. For example .git/refs/heads/master.

1 Like

That is a great idea, but now it gets even more tricky: I use the --dirty flag of git describe to find out if the produced binary is created with a clean working directory (and I can reproduce it from git) or was just a working version with an undefined source state.

For a dirty working directory neither my head nor the branches head file is changed. Probably I need something that runs every time while building? I am not entirely sure if this is a clever thing to do, but having the up-to-date git describe string with the dirty flag seems really useful to me.

When entering or exiting dirty state either the source has to change, or the the current commit has to change.

That would be true if I only had one crate. But the library, that returns the version string, might not have had a source change, while the binary crate did.

Now the version string is returned as non-dirty, while the binary cannot be reproduced correctly from the git source.

You could mark all files of your project as cargo:rerun-if-changed. New files don't cause git describe to include -dirty.

That seems possible. But there are a lot of files in my project.

At the moment I prefer having a library crate that is always rebuilt and only determines the version string. But I did not find a way to force a crate to always be rebuilt.

Even better would be if I had a macro that is runs git describe at compile time in the binary crate. This would mean, that only the changed crate needs to be linked again. However I am not sure if this is possible at all...

Proc macros currently have no way to say that they need to rerun when a certain file changed or must always rerun. Even when it did, rerunning the proc macro, would always require recompilation of the whole crate.

If a dependency is rebuilt (the library in this case) all dependents (the binaries in this case) need to be rebuilt too, not just relinked. It is currently not possible to skip ahead to linking. This is the case even when the dependency compiles to an identical file as cargo currently uses mtime instead of the file content.