There are a plethora of gotchas when it comes to binary compilation and distribution that must be appropriately addressed, or the binaries will only work on certain machines and not others. Here is an incomplete list of things that
BinaryBuilder.jl takes care of for you:
- Uniform compiler interface
No need to worry about invoking compilers through weird names; just run
gcc within the proper environment and you'll get the appropriate cross-compiler. Triplet-prefixed names (such as
x86_64-linux-gnu-gcc) are, of course, also available, and the same version of
gfortran is used across all platforms.
On Linux platforms that use
glibc as the C runtime library (at the time of writing, this is the great majority of most desktop and server distros), it is necessary to compile code against a version of
glibc that is older than any glibc version it will be run on. E.g. if your code is compiled against
glibc v2.5, it will run on
glibc v2.6, but it will not run on
glibc v2.4. Therefore, to maximize compatibility, all code should be compiled against as old a version of
glibc as possible.
When compiling FORTRAN code, the
gfortran compiler has broken ABI compatibility in the 6.X -> 7.X transition, and the 7.X -> 8.X transition. This means that code built with
gfortran 6.X cannot be linked against code built with
gfortran 7.X. We therefore compile all
gfortran code against multiple different
gfortran versions, then at runtime decide which to download based upon the currently running process' existing linkage.
When switching from the
cxx03 standard to
cxx11 in GCC 5, the internal layout of
std::string objects changed. This causes incompatibility between C++ code passing strings back and forth across the public interface if they are not built with the same C++ string ABI. We therefore detect when
std::string objects are being passed around, and warn that you need to build two different versions, one with
cxx03-style strings (doable by setting
-D_GLIBCXX_USE_CXX11_ABI=0 for newer GCC versions) and one with
- Library Dependencies
A large source of problems in binary distribution is improper library linkage. When building a binary object that depends upon another binary object, some operating systems (such as macOS) bake the absolute path to the dependee library into the dependent, whereas others rely on the library being present within a default search path.
BinaryBuilder.jl takes care of this by automatically discovering these errors and fixing them by using the
RUNPATH semantics of whichever platform it is targeting. Note that this is technically a build system error, and although we will fix it automatically, it will raise a nice yellow warning during build prefix audit time.
- Embedded absolute paths
Similar to library dependencies, plain files (and even symlinks) can have the absolute location of files embedded within them.
BinaryBuilder.jl will automatically transform symlinks to files within the build prefix to be the equivalent relative path, and will alert you if any files within the prefix contain absolute paths to the build prefix within them. While the latter cannot be automatically fixed, it may help in tracking down problems with the software later on.
- Instruction Set Differences
When compiling for architectures that have evolved over time (such as
x86_64), it is important to target the correct instruction set, otherwise a binary may contain instructions that will run on the computer it was compiled on, but will fail rather ungracefully when run on a machine that does not have as new a processor.
BinaryBuilder.jl will automatically disassemble every built binary object and inspect the instructions used, warning the user if a binary is found that does not conform to the agreed-upon minimum instruction set architecture. It will also notice if the binary contains a
cpuid instruction, which is a good sign that the binary is aware of this issue and will internally switch itself to use only available instructions.