相同的代码和相同的编译器可以在不同的机器上生成不同的二进制文件吗?

问题描述

Nixos binary caches 的想法促使我考虑这个问题。

在 nix 中,每个编译的二进制文件都与一个散列键相关联,该键是从散列所有依赖项和构建脚本中获得的,即 nix 中的“派生”。无论如何,这是我的理解。

但是在不同的机器上编译时,相同的派生不能导致不同的二进制文件吗? 如果机器 A 的处理器与机器 B 的处理器的指令集略有不同,并且编译器考虑了这种不同的指令集,那么在机器 A 上编译推导产生的二进制文件是否与在机器 A 上编译推导产生的二进制文件有区别?机器B?如果是这样,那么不同的二进制文件就不能具有相同的派生和因此具有相同的 nix 哈希值吗?

在具有不同指令集的机器上构建的相同推导是否总是产生相同的二进制文件

解决方法

这取决于编译器的实现和传递给它的选项。例如,默认情况下 GCC 似乎并不关注当前处理器的细节,除非您指定 -march=native-mtune=native

所以是的,如果您使用这些标志或具有这些标志的默认行为的编译器,您将在具有不同 CPU 型号的机器上获得不同的输出。

构建也可能由于其他原因而无法重现,例如不当使用时钟值或随机值,甚至是线程以非确定性交错模式访问的计数器。

Nix 确实提供了一个沙箱,可以去除一些熵源;主要是可能存在于机器上的假定不相关的软件。出于实际原因,它不会删除所有这些来源。

出于这些原因,即使使用 Nix 进行包装,也必须考虑可重复性;不是它完全解决的。

我将引用菜单“实现确定性构建 " 来自 https://reproducible-builds.org/docs/ 并尽我所知用 Nix 的效果对其进行注释。不要在这方面引用我。

  • SOURCE_DATE_EPOCH:已解决;由 Nixpkgs 设置
  • 确定性构建系统:部分解决; Nixpkgs 可能包含补丁
  • 不稳定输入可能会消失:如果您将源上传到(二进制)缓存,则可以使用 Nix 解决。 Hercules CI 做到了这一点。
  • 输入的稳定顺序:大部分已解决。 Nix 语言保留源代码顺序并对属性进行排序。
  • 值初始化:Nix 未解决的低级问题
  • 版本信息:未解决;时钟可在沙箱中访问
  • 时间戳:同上
  • 时区:由沙箱解决
  • 语言环境:通过沙盒解决
  • 归档元数据:未解决
  • 输出的稳定顺序:使用沙箱无法解决的随机性
  • 随机性:相同
  • 构建路径:部分; linux 使用 /build; macOS 可能因安装方法而异
  • 系统映像:从以前的项目中提取元素的广泛问题
  • JVM:相同