Skip to content

Conversation

@alvaro-cuesta
Copy link
Contributor

Cargo build scipts should not modify any files outside of OUT_DIR. Both Stockfish and Fairy-Stockfish Makefiles generate output files in their src folders, which was making the build non-idempotent. To fix this, a copy of the repository is created in OUT_DIR and the compilation is performed there.

This is not only a theoretical concern: this was actually failing when using rust-analyzer with a separate targetDir, since the normal and the analyzer builds can run in parallel, modifying files in the source folder concurrently and making each other fail.

Copy link
Member

@niklasf niklasf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

build.rs Outdated
archive.into_inner().unwrap().finish().unwrap();

// Clean up copied source trees to save space in target directory
fs::remove_dir_all(&*STOCKFISH_OUT_PATH).unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this force the .nnue files to be redownloaded for each build?

Copy link
Contributor Author

@alvaro-cuesta alvaro-cuesta Oct 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Those lines only remove the copied folders in the output, and build outputs are not shared across builds.

If you mean between Stockfish targets, these are only cleaned at the end of build.rs, so only the first target will download the .nnues.

But if you mean between runs of build.rs, since this PR forces the submodules not to change on build (by Cargo's build scripts contract) .nnues will always be downloaded per build.rs run unless they're somehow already there in the submodule folder (e.g if you ran make net in the submodule manually).

Note

They will only be redownloaded when build.rs itself is run (i.e. only if any of the cargo:rerun-if-* triggers), not for each build of fishnet itself!

Unfortunately we cannot prime the submodules with make net in build.rs due to the build.rs contact, since side-effects outside of OUT_DIR can break builds in subtle ways even if they're idempotent. As a real-world scenario: I'm planning to split fishnet into binary and library which would put fishnet code in Cargo's cache folder (when used as a library) which is supposed to be immutable.

🤔 I'm not sure if there's an easy way to fix this without manually managing a cache for the .nnues that's persisted across builds. Is this a deal breaker?

Copy link
Contributor Author

@alvaro-cuesta alvaro-cuesta Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@niklasf after investigating this a bit further:

Turns out I was wrong and OUT_DIR's hash changes less often than I thought, so deleting the NNUEs was indeed causing a lot of unnecessary downloads.

Added a700a90 which basically backups the eval files before the submodules are overwritten in OUT_DIR.

Note that the backup is still scoped to OUT_DIR, which means it will download the eval files on changes to build profile, settings, compiler version, etc... Seems like the best we can do without a dedicated cache outside of OUT_DIR.

What do you think?

(Also: rebased on master.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I'll check it out later this week.

@niklasf
Copy link
Member

niklasf commented Oct 5, 2025

(Now skipping the signpath test job that cannot succeed on pull requests: b7e0c1f)

alvaro-cuesta and others added 2 commits October 7, 2025 19:47
Cargo build scipts [should not modify any files outside of `OUT_DIR`](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script).
Both Stockfish and Fairy-Stockfish `Makefile`s generate output files in
their `src` folders, which was making the build non-idempotent. To fix
this, a copy of the repository is created in `OUT_DIR` and the
compilation is performed there.

This is not only a theoretical concern: this was actually failing when
using rust-analyzer with a separate `targetDir`, since the normal and
the analyzer builds can run in parallel, modifying files in the source
folder concurrently and making each other fail.
Co-authored-by: Niklas Fiekas <niklas.fiekas@backscattering.de>
@alvaro-cuesta alvaro-cuesta force-pushed the fix/idempotent-build-rs branch from 886469d to e59b47b Compare October 7, 2025 17:48
This avoids hitting the network on subsequent `build.rs` runs.

Note that the backup is still scoped to `OUT_DIR`, which means it will
download the eval files on changes to build profile, settings, compiler
version, etc...

Seems like the best we can do without a dedicated cache directory.
@alvaro-cuesta alvaro-cuesta force-pushed the fix/idempotent-build-rs branch from e59b47b to a700a90 Compare October 7, 2025 18:33
@niklasf niklasf merged commit f383cb8 into lichess-org:master Oct 8, 2025
7 checks passed
alvaro-cuesta added a commit to alvaro-cuesta/fishnet that referenced this pull request Oct 9, 2025
Submodules need to be initialized before building on a fresh repo. There
is an error message indicating this, but lichess-org#278 introduced a bug where the
warning is not shown anymore.

The root cause is that submodules are (empty) directories even if not
yet initialized so checking if "submodule" is a directory always passes.
Instead it should check "submodule/src", which should only exist if the
submodule has been initialized.
alvaro-cuesta added a commit to alvaro-cuesta/fishnet that referenced this pull request Oct 9, 2025
Submodules need to be initialized before building on a fresh repo. There
is an error message indicating this, but lichess-org#278 introduced a bug where the
warning is not shown anymore.

The root cause is that submodules are (empty) directories even if not
yet initialized so checking if "submodule" is a directory always passes.
Instead it should check "submodule/src", which should only exist if the
submodule has been initialized.
@alvaro-cuesta alvaro-cuesta deleted the fix/idempotent-build-rs branch October 9, 2025 18:09
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.

2 participants