Skip to content

Inappropriate re-override of buildRustCrate while cross compiling #404

@sepointon

Description

@sepointon

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions