Fake non-crosscompiled build while cross-compiling

If I cross-compile a program, the hash will be different from the hash one would get from a non-cross compiled binary. While this is great to ensure reproducibility, it is not great for end users that do not care if the software was compiled natively or cross-compiled. For instance, if in a given channel, programA is natively compiled, and programB is not, the user cannot simply write environment.systemPackages = [ programA programB]. Worse, the closure size will basically be twice as big since the user will get libraries that are cross-compiled and libraries that are natively compiled.

So my question is: is it possible (theoretically and/or practically) to fake a natively compiled binary while cross-compiling it? I can imagine a quite rude way of proceeding, like get the hash somehash of the natively compiled binary, and manually link /nix/store/somehash-programB to the path of the cross-compiled binary, but there are two drawbacks:

  1. I’m not sure how to do that in a “safe” way, i.e. without corrupting the nix store… and I’m not 100% sure it will work, notably for libraries
  2. this seems like quite dirty, maybe there is a more organized way to do it?
  3. the program will still be linked to the cross-compiled libs I guess. Would it be possible then to recursively do the same trick on all cross-compiled libs (seems really dirty), or, maybe, to replace all links by automatically applying the same trick as system.replaceRuntimeDependencies to use the native libraries?

One application I have in mind would be to create a Hydra server on x86_64, that can transparently compile for aarch64 say, while having greater speed than binfmt.

I believe it differs significantly, making it too difficult to achieve transparency. Say, shebangs in developer scripts. Those are meant to be run on the build machine. So those scripts will need to differ not in just hashes but also in contents (refer to different interpreter and other binaries). But I don’t do cross really, so perhaps someone can help you better.

Uhm, thanks for your answer. But once a package is built, the $out package should not refer anymore to any code that runs on the build machine right?

Well there might still be some scripts necessary for building rev-deps.

… sounds like you want to fake all deps to cross then fake the output to native?

I guess if you want to try and see how it goes, you could experiment with a personal binary cache that does in-place path rewriting on cross-compiled stuff (both for deps and self-refs) then pretends this is a legal subsitute content for the native-compiled output path? Please share the results if you do, I am curious now.

2 Likes