棘手的陷阱

在二进制编译和分发时,存在大量问题需进行适当处理,否则二进制文件只能在某些机器上运行。以下是 BinaryBuilder.jl 自动为您处理的事情(不完整列表):

  • 统一的编译器接口

不用担心通过奇怪的名字调用编译器;只需在适当的环境中运行 gcc,您就会得到适当的交叉编译器。三元组前缀后的名称(例如 x86_64-linux-gnu-gcc)也可以用,并且所有平台都使用相同版本的 gccg++gfortran

  • glibc 版本控制

在使用 glibc 作为 C 运行库的 Linux 平台上(在撰写本文时,这是绝大多数桌面和服务器发行版的情况),有必要针对比起将要运行的 glibc 版本更 的版本编译代码。例如,如果您的代码是针对 glibc v2.5 编译的,它将在 glibc v2.6 上运行,但不会在 glibc v2.4 上运行。因此,为了最大限度地提高兼容性,所有代码都应尽可能针对旧版本的 glibc 进行编译。

  • gfortran 版本控制

编译 FORTRAN 代码时,gfortran 编译器破坏了 6.X -> 7.X 转换和 7.X -> 8.X 转换中的 ABI 兼容性。这意味着使用 gfortran 6.X 构建的代码不能与使用 gfortran 7.X 构建的代码链接。因此,我们针对多个不同的 gfortran 版本编译所有 gfortran 代码,然后在运行时根据当前运行进程的已有链接决定下载哪个。

  • cxx11 字符串 ABI

在 GCC 5 中从 cxx03 标准切换到 cxx11 时,std::string 对象的内部布局发生了变化。如果 C++ 代码不是使用相同的 C++ 字符串 ABI 构建的,这会导致在公共接口上来回传递字符串的 C++ 代码之间不兼容。因此,我们检测 std::string 对象何时被传递,并警告您需要构建两个不同版本,一个是具有 cxx03 样式的字符串(通过为较新的 GCC 版本设置 -D_GLIBCXX_USE_CXX11_ABI=0 来实现),另一个是带有 cxx11 风格的字符串。

  • 库依赖

二进制分发中的一大问题是不正确的库链接。在构建依赖于另一个二进制对象的二进制对象时,一些操作系统(例如 macOS)将依赖库的绝对路径加入到依赖项中,而其他操作系统依赖默认搜索路径中的库。 BinaryBuilder.jl 通过自动发现这些错误并用目标平台的 RPATH/RUNPATH 语义来修复这个问题。请注意,这在技术上是一个构建系统错误,虽然我们会自动修复它,但它会在构建前缀审核期间发出一个温和的黄色警告。

  • 嵌入式绝对路径

与库依赖项类似,普通文件(甚至符号链接)可以在其中嵌入文件的绝对位置。 BinaryBuilder.jl 会自动将构建前缀目录内文件的符号链接转换为等效的相对路径,如果前缀内的任何文件包含指向构建前缀的绝对路径,则会提醒您。虽然后者不能自动修复,但它可能有助于以后跟踪软件问题。

  • 指令集差异

在编译随时间发展的体系结构(例如 x86_64 )时,确定正确的指令集为目标很重要,否则二进制文件可能包含将在编译所在计算机上运行的指令,但在没有新处理器的机器上运行出现异常错误。 BinaryBuilder.jl 将自动反汇编每个构建的二进制对象并检查所使用的指令,如果发现二进制文件不符合商定的最小指令集架构,则会警告用户。它还会注意到二进制文件是否包含 cpuid 指令,这表明二进制文件意识到此问题并将在内部切换为仅使用可用指令,是个好的迹象。