Hi!
I'm working on integrating nix into cargo, see libnix cargo-nix-backend for what I already did.
My current quest is to support faster builds but I struggle a lot with .fingerprint and the way nix evaluates builds. I can build a complete rust project from on nix build command, I love this very much as nix then does so much of the heavy lifting.
The fingerprint concept in the legacy cargo backend works because it uses the dep-info from the last build and in nix I don't have such a concept at all.
options
As a result there are a few options:
- rework the dep-info file-list scanner so it runs once per project and not as it is now per unit
- only for the interactive speedup: split the nix toolchain into many different parts and make cargo the scheduler and keep the already working toolchain for deployments where only the nix files are delivered
1. dep-info scanner per project
I looked into GitHub - dcchut/cargo-files: List all source files in a cargo crate. as a start. But what I actually want is:
- from on mkDerivation with all the src
- generate file-list(s) per unit
- support macros
- support features like cfg (which are on a per-unit basis)
And all of this in one mkDerivation, so I'd need to create a set of unit configurations which are then executed once. The result will be fed into the src filter for the other units. A unit is taken from the cargo nomenclature: smallest possible set of files which can be compiled.
Not sure if that is feasible as it would mean to replicate the rustc effort of creating a dep-info per unit in a separate tool.
Please think like a nix toolchain developer: In case we have a list, which is sorted as an input, we could exactly know what to recompile. If the list changes, recompile but if the list is the same but the file changed, recompile also as the list means that the src input is serialized into a NAR and this has a hash which is used to match the previous build.
This is an issue in the current toolchain I've created: With changing one line in the source code, for building cargo with the nix backend, currently means copying the source code 8 times, parsing & compiling it 8 times where sometimes 2 compiles: cargo(lib) and cargo(bin) would have sufficed.
Here an example:
[nixos@nixos:~/cargo]$ touch src/cargo/lib.rs
[nixos@nixos:~/cargo]$ time CARGO_BACKEND=nix ./cargo build
❄❄❄ snowflake edition ❄❄❄
Using 'nix' backend to build crates
Compiling cargo
Compiling cargo
Compiling cargo-credential
Compiling cargo-platform
Compiling cargo-util
Compiling crates-io
Compiling cargo-util-schemas
Compiling rustfix
Compiling cargo-credential-libsecret
Compiling cargo
...
real 0m48.824s
user 0m14.409s
sys 0m5.242s
2. rework toolchain
As a last resort I would split the toolchain and hand over store paths as inputs to mkDerivations. I don't like this idea so much because it would mean there is now two toolchains to support in the nix backend; a) the interatcive one and b) the complete one which can be shipped into nixpkgs and such. There is other reasons to not like this either, like the dep file discussion: Proposal: make cargo output dep-info
summary
If you have ideas on how to make 1.) work, please teach me!
@alexcrichton ideas?
