Demonstration
Reproduction repo: https://gitlab.com/sampointon/crate2nix-cross-missing-override
Try building the various derivations in the default.nix attrset.
Analysis
Somewhere, the defaultCrateOverrides I'm passing to buildRustCrate.override is getting eaten and the correctness-critical env var is hence not getting set.
cross fails to compile while crossInline does, demonstrating that it's a bug in crate2nix and not buildRustCrate. native builds, suggesting cross compilation must be involved somehow.
I have narrowed the problematic code down to the else branch in buildRustCrateForPkgsFuncOverridden. Swapping out that conditional expression entirely for buildRustCratesForPkgs fixes the observed problem.
This makes sense: when buildRustCrate is re-overridden, the new defaultCrateOverrides supplied by crate2nix isn't merged with the previous one I'd supplied but rather straight up replaced.
What I don't understand:
- Why does
crateOverrides not evaluate as equal to pkgs.defaultCrateOverrides, only when cross-compiling? If I'm following things correctly, crateOverrides is also sourced unmodified from pkgs.defaultCrateOverrides. Is this some deep cross-compilation magic in Nixpkgs?
- Isn't that
else branch with the override broken even if the weird non-equality is solved? Stomping on the user's supplied default crate overrides seems like the sort of thing that will always lead to trouble, even if the re-overriding is needed for whatever reason.
- I don't actually understand what purpose re-overriding here is serving at all or why it's behind a guard. If the guard evaluates to true, wouldn't re-overriding be a no-op and be safe? If the user wants overrides, can't they do it by overriding
buildRustCrates function and pass it as the buildRustCratesForPkgs parameter? But I'm mostly only looking at the generated Cargo.nix in the minimiser reproducer repo, so it's possible there's a reason it exists in cases the reproducer isn't tickling.
If I'm not meant to be overriding buildRustCrate but rather passing defaultCrateOverrides to crate2nix, then the docs have led me astray.
Possible workaround
Not overriding defaultCrateOverrides on buildRustCrate, but rather passing that as a parameter to Cargo.nix.
This fixed the minimised reproducer, but, in my real code, I'm now running in to some cross-related trouble and I'm going to have to figure out if the workaround is bad or my code's just buggy.
Fixing
Two immediate ideas:
- instead of checking
crateOverrides against pkgs.defaultCrateOverrides, use a sentinel value to detect if crateOverrides has changed. This does not resolve the mystery of why it's not equal iff cross, and leaves the issue of stomping on the user's defaultCrateOverrides.
- crate2nix can forget all about
defaultCrateOverrides and rely on users overriding buildRustCrate appropriately if they want that functionality. But this may not work if there're other reasons for performing overrides than the user's request. Also, compatibility will need some thought.
There are probably other solutions if you actually understand the problem space the code is solving (unlike me).
If the workaround turns out to be good, then I probably won't submit a PR: the resulting code isn't even a hack. The remaining problem would be the docs and the footgun for the unwary.
Demonstration
Reproduction repo: https://gitlab.com/sampointon/crate2nix-cross-missing-override
Try building the various derivations in the
default.nixattrset.Analysis
Somewhere, the
defaultCrateOverridesI'm passing tobuildRustCrate.overrideis getting eaten and the correctness-critical env var is hence not getting set.crossfails to compile whilecrossInlinedoes, demonstrating that it's a bug in crate2nix and not buildRustCrate.nativebuilds, suggesting cross compilation must be involved somehow.I have narrowed the problematic code down to the
elsebranch inbuildRustCrateForPkgsFuncOverridden. Swapping out that conditional expression entirely forbuildRustCratesForPkgsfixes the observed problem.This makes sense: when
buildRustCrateis re-overridden, the newdefaultCrateOverridessupplied by crate2nix isn't merged with the previous one I'd supplied but rather straight up replaced.What I don't understand:
crateOverridesnot evaluate as equal topkgs.defaultCrateOverrides, only when cross-compiling? If I'm following things correctly,crateOverridesis also sourced unmodified frompkgs.defaultCrateOverrides. Is this some deep cross-compilation magic in Nixpkgs?elsebranch with the override broken even if the weird non-equality is solved? Stomping on the user's supplied default crate overrides seems like the sort of thing that will always lead to trouble, even if the re-overriding is needed for whatever reason.buildRustCratesfunction and pass it as thebuildRustCratesForPkgsparameter? But I'm mostly only looking at the generatedCargo.nixin the minimiser reproducer repo, so it's possible there's a reason it exists in cases the reproducer isn't tickling.If I'm not meant to be overriding
buildRustCratebut rather passingdefaultCrateOverridesto crate2nix, then the docs have led me astray.Possible workaround
Not overriding
defaultCrateOverridesonbuildRustCrate, but rather passing that as a parameter toCargo.nix.This fixed the minimised reproducer, but, in my real code, I'm now running in to some cross-related trouble and I'm going to have to figure out if the workaround is bad or my code's just buggy.
Fixing
Two immediate ideas:
crateOverridesagainstpkgs.defaultCrateOverrides, use a sentinel value to detect ifcrateOverrideshas changed. This does not resolve the mystery of why it's not equal iff cross, and leaves the issue of stomping on the user'sdefaultCrateOverrides.defaultCrateOverridesand rely on users overridingbuildRustCrateappropriately if they want that functionality. But this may not work if there're other reasons for performing overrides than the user's request. Also, compatibility will need some thought.There are probably other solutions if you actually understand the problem space the code is solving (unlike me).
If the workaround turns out to be good, then I probably won't submit a PR: the resulting code isn't even a hack. The remaining problem would be the docs and the footgun for the unwary.