Build Troubleshooting
This page collects some known build errors and trick how to fix them.
If you have additional tips, please submit a PR with suggestions.
All platforms
General comments
While below you will find some tips about common problems found when building packages in BinaryBuilder, keep in mind that if something fails during the build, there is not a magic recipe to fix it: you will need to understand what the problem is. Most of the time it's a matter of trial-and-error. The best recommendation is to access the build environment and carefully read the log files generated by the build systems: it is not uncommon that build systems would only print to screen misleading error messages, and the actual problem is completely different (e.g. "library XYZ can't be found", when the problem instead is that the command they run to look for library XYZ fails for unrelated reasons, for example for a wrong compiler flag used in the check). Having an understanding of what the build system is doing would also be extremely useful.
You are welcome to open a pull request to Yggdrasil with a non-working build recipe, or ask for help in the #binarybuilder
channel in the JuliaLang Slack. Someone will likely help you out if and when they are available, like for any support provided by volunteers.
How to retrieve in-progress build script
If the Wizard-based build fails after the first platform target, the Wizard may occasionally exit without resumability (because the only resume mode is to retry the failed platform). In this situation, the last build state and in-progress build script may be retrieved using the following steps:
state = BinaryBuilder.Wizard.load_wizard_state() # select 'resume'
BinaryBuilder.Wizard.print_build_tarballs(stdout, state)
The build script may then be edited as appropriate – for example to disable the failing platform – and rerun directly with julia build_tarballs.jl --debug --verbose
(see manual build documentation) to debug and complete without starting from scratch.
Header files of the dependencies can't be found
Sometimes the build system can't find the header files of the dependencies, even if they're properly installed. When this happens, you have to inform the C/C++ preprocessor where the files are.
For example, if the project uses Autotools you can set the CPPFLAGS
environment variable:
export CPPFLAGS="-I${includedir}"
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nprocs}
make install
See for example Cairo build script.
If instead the project uses CMake you'll need to use a different environment variable, since CMake ignores CPPFLAGS
. If the compiler that can't find the header file is the C one, you need to add the path to the CFLAGS
variable (e.g., CFLAGS="-I${includedir}"
), in case it's the C++ one you have to set the CXXFLAGS
variable (e.g., CXXFLAGS="-I${includedir}"
).
Libraries of the dependencies can't be found
Like in the section above, it may happen that the build system fails to find the libraries of the dependencies, even when they're installed to the right place, i.e. in the ${libdir}
directory. In these cases, you have to inform the linker where the libraries are by passing the option -L${libdir}
. The details of how to do that depend on the specific build system in use.
For Autotools- and CMake-based builds, you can the set the LDFLAGS
environment variable:
export LDFLAGS="-L${libdir}"
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nprocs}
make install
See for example libwebp build script (in this case this was needed only when building for FreeBSD).
Old Autoconf helper scripts
Packages using Autoconf come with some helper scripts – like config.sub
and config.guess
– that the upstream developers need to keep up-to-date in order to get the latest improvements. Some packages ship very old copies of these scripts, that for example don't know about the Musl C library. In that case, after running ./configure
you may get an error like
checking build system type... Invalid configuration `x86_64-linux-musl': system `musl' not recognized
configure: error: /bin/sh ./config.sub x86_64-linux-musl failed
The BinaryBuilder
environment provides the utility update_configure_scripts
to automatically update these scripts, call it before ./configure
:
update_configure_scripts
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nproc}
make install
Building with an old GCC version a library that has dependencies built with newer GCC versions
The keyword argument preferred_gcc_version
to the build_tarballs
function allows you to select a newer compiler to build a library, if needed. Pure C libraries have good compatibility so that a library built with a newer compiler should be able to run on a system using an older GCC version without problems. However, keep in mind that each GCC version in BinaryBuilder.jl
comes bundled with a specific version of binutils – which provides the ld
linker – see this table.
ld
is quite picky and a given version of this tool doesn't like to link a library linked with a newer version: this means that if you build a library with, say, GCC v6, you'll need to build all libraries depending on it with GCC >= v6. If you fail to do so, you'll get a cryptic error like this:
/opt/x86_64-linux-gnu/bin/../lib/gcc/x86_64-linux-gnu/4.8.5/../../../../x86_64-linux-gnu/bin/ld: /workspace/destdir/lib/libvpx.a(vp8_cx_iface.c.o): unrecognized relocation (0x2a) in section `.text'
/opt/x86_64-linux-gnu/bin/../lib/gcc/x86_64-linux-gnu/4.8.5/../../../../x86_64-linux-gnu/bin/ld: final link failed: Bad value
The solution is to build the downstream libraries with at least the maximum of the GCC versions used by the dependencies:
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; preferred_gcc_version=v"8")
For instance, FFMPEG has to be built with GCC v8 because LibVPX requires GCC v8.
Generally speaking, we try to build with the as old as possible version of GCC (v4.8.5 being the oldest one currently available), for maximum compatibility.
Running foreign executables
The build environment provided by BinaryBuilder
is a x86_64-linux-musl
, and it can run executables for the following platforms: x86_64-linux-musl
, x86_64-linux-gnu
, i686-linux-gnu
. For all other platforms, if the build system tries to run a foreign executable you'll get an error, usually something like
./foreign.exe: line 1: ELF��
@@xG@8@@@@@@���@�@@����A�A����A�A���@�@: not found
./foreign.exe: line 1: syntax error: unexpected end of file (expecting ")")
This is one of worst cases when cross-compiling, and there isn't a simple solution. You have to look into the build process to see if running the executable can be skipped (see for example the patch to not run dot
in Yggdrasil#351), or replaced by something else. If the executable is a compile-time only utility, try to build it with the native compiler (see for example the patch to build a native mkdefs
in Yggdrasil#351)
Musl Linux
Error in definition of posix_memalign
Compiling for Musl platforms can sometimes fail with the error message
/opt/x86_64-linux-musl/x86_64-linux-musl/sys-root/usr/include/stdlib.h:99:5: error: from previous declaration ‘int posix_memalign(void**, size_t, size_t)’
int posix_memalign (void **, size_t, size_t);
^
This is due to a bug in older versions of GCC targeting this libc, see BinaryBuilder.jl#387 for more details. There are two options to solve this issue:
- require GCC 6 by using
build_tarballs(...; preferred_gcc_version=v"6")
. This may be the simplest option in some cases. See for example Yggdrasil#3974 - if using older versions of GCC is important for wider compatibility, you can apply this patch to the build toolchain. See for example ZeroMQ recipe.
PowerPC Linux
Shared library not built
Sometimes the shared library for powerpc64le-linux-gnu
is not built after a successful compilation, and audit fails because only the static library has been compiled. If the build uses Autotools, this most likely happens because the configure
script was generated with a very old version of Autotools, which didn't know how to build shared libraries for this system. The trick here is to regenerate the configure
script with autoreconf
:
autoreconf -vi
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nproc}
make install
See for example the builder for Giflib. If you need to regenerate configure
, you'll probably need to run update_configure_scripts
to make other platforms work as well.
FreeBSD
undefined reference to `backtrace_symbols'
If compilation fails because of the following errors
undefined reference to `backtrace_symbols'
undefined reference to `backtrace'
then you need to link to execinfo
:
if [[ "${target}" == *-freebsd* ]]; then
export LDFLAGS="-lexecinfo"
fi
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nprocs}
make install
See for example Yggdrasil#354 and Yggdrasil#982.
undefined reference to `environ'
This problem is caused by the -Wl,--no-undefined
flag. Removing this flag may also fix the above problem with backtrace, if the undefined references appear together.
Windows
Libtool refuses to build shared library because of undefined symbols
When building for Windows, sometimes libtool refuses to build the shared library because of undefined symbols. When this happens, compilation is successful but BinaryBuilder's audit can't find the expected LibraryProduct
s.
In the log of compilation you can usually find messages like
libtool: warning: undefined symbols not allowed in i686-w64-mingw32 shared libraries; building static only
or
libtool: error: can't build i686-w64-mingw32 shared library unless -no-undefined is specified
In these cases you have to pass the -no-undefined
option to the linker, as explicitly suggested by the second message.
A proper fix requires to add the -no-undefined
flag to the LDFLAGS
of the corresponding libtool archive in the Makefile.am
file. For example, this is done in CALCEPH
, ERFA
, and libsharp2
.
A quick and dirty alternative to patching the Makefile.am
file is to pass LDFLAGS=-no-undefined
only to make
:
FLAGS=()
if [[ "${target}" == *-mingw* ]]; then
FLAGS+=(LDFLAGS="-no-undefined")
fi
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nprocs} "${FLAGS[@]}"
make install
Note that setting LDFLAGS=-no-undefined
before ./configure
would make this fail because it would run a command like cc -no-undefined conftest.c
, which upsets the compiler). See for example Yggdrasil#170, Yggdrasil#354.
Libtool refuses to build shared library because '-lmingw32' is not a real file
If you see errors like:
[14:12:52] *** Warning: linker path does not have real file for library -lmingw32.
[14:12:52] *** I have the capability to make that library automatically link in when
[14:12:52] *** you link to this library. But I can only do this if you have a
[14:12:52] *** shared version of the library, which you do not appear to have
[14:12:52] *** because I did check the linker path looking for a file starting
[14:12:52] *** with libmingw32 and none of the candidates passed a file format test
[14:12:52] *** using a file magic. Last file checked: /opt/x86_64-w64-mingw32/x86_64-w64-mingw32/sys-root/lib/libmingw32.a
This is a bug in autoconf's ACF77LIBRARYLDFLAGS (or ACFCLIBRARYLDFLAGS) macro. A patch has been submitted to fix this upstream. In the meantime, you may be able to remove these macros. They are often not required.
macOS
CMake complains "No known for CXX compiler"
E.g. error messages like:
CMake Error in CMakeLists.txt:
No known features for CXX compiler
"Clang"
version 12.0.0.
This issue is caused by not setting CMake policy CMP0025. This policy is supposed to only affect the CompilerId for AppleClang, but it also has the effect of turning off feature detection for upstream clang (which is what we're using here) on CMake versions prior to CMake 3.18. Add
cmake_policy(SET CMP0025 NEW)
At the very top of your CMakeLists.txt, before the project definition (or get an updated version of CMake).