构建故障排除

此页面收集了一些已知的构建错误并介绍了如何修复它们。

如果您有其他提示,请提交带有建议的 PR。

所有平台

常见留言

虽然在下面您会找到一些关于在 BinaryBuilder 中构建包时发现的常见问题的提示,但请记住,如果在构建过程中出现问题,没有修复它的灵丹妙药:您需要了解问题所在。大多数时候,这是一个反复试验的问题。最好的建议是访问构建环境并仔细阅读构建系统生成的日志文件:构建系统在屏幕上打印误导性错误消息的情况并不少见,而实际问题可能完全不同(例如“不能找到库 XYZ ”,而问题是他们运行查找库 XYZ 的命令,但由于不相关的原因而失败,例如检查中使用了错误的编译器标志)。了解构建系统正在做什么也将非常有用。

欢迎向 Yggdrasil 提出未能成功构建的配方的 PR,或在 [JuliaLang Slack] 的“#binarybuilder”频道中寻求帮助](https://julialang.org/slack/)。有人可能会在他们有空的时候帮助你,比如志愿者提供的任何支持。

如何检索正在进行的构建脚本

如果基于向导的构建在第一个平台目标之后失败,向导可能偶尔会退出而无法恢复(因为唯一的恢复模式是重试失败的平台)。在这种情况下,可以使用以下步骤检索上次构建状态和正在进行的构建脚本:

state = BinaryBuilder.Wizard.load_wizard_state() # select 'resume'
BinaryBuilder.Wizard.print_build_tarballs(stdout, state)

然后可以根据需要编辑构建脚本——例如禁用失败的平台——并直接使用 julia build_tarballs.jl --debug --verbose 重新运行(参见手动构建文档) 调试和完成无需从头开始。

找不到依赖的头文件

有时构建系统找不到依赖项的头文件,即使它们已正确安装。发生这种情况时,您必须指明 C/C++ 预处理器文件的位置。

例如,如果项目使用 Autotools,您可以设置 CPPFLAGS 环境变量:

export CPPFLAGS="-I${includedir}"
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nprocs}
make install

作为例子,参见 Cairo 的构建脚本。

相反,如果项目使用 CMake,您将需要使用不同的环境变量,因为 CMake 会忽略 CPPFLAGS。如果找不到头文件的编译器是C编译器,则需要将路径添加到 CFLAGS 变量(例如,CFLAGS="-I${includedir}"),如果这是一个 C++ 版本,你必须设置 CXXFLAGS 变量(例如,CXXFLAGS="-I${includedir}")。

找不到依赖库

就像在上面的部分中一样,构建系统可能无法找到依赖项的库,即使它们安装在正确的位置,即 ${libdir} 目录中。在这些情况下,您必须通过传递选项 -L${libdir} 来通知链接器库的位置。如何做到这一点的细节取决于所使用的特定构建系统。

对于基于 Autotools 和 CMake 的构建,您可以设置 LDFLAGS 环境变量:

export LDFLAGS="-L${libdir}"
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nprocs}
make install

作为例子,参见 libwebp 构建脚本(在这种情况下,只有在为 FreeBSD 构建时才需要) .

旧的 Autoconf 帮助脚本

使用 Autoconf 的软件包带有一些帮助脚本——比如 config.subconfig.guess —— 上游开发人员需要保持最新以便获得最新的改进。一些软件包提供了这些脚本的非常旧的副本,例如会导致不知道 Musl C 库。在这种情况下,在运行 ./configure 之后你可能会得到类似这样的错误

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

BinaryBuilder 环境提供实用程序 update_configure_scripts 来自动更新这些脚本,在执行 ./configure 之前调用它:

update_configure_scripts
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nproc}
make install

使用旧的 GCC 版本构建一个库,该库具有使用较新的 GCC 版本构建的依赖项

build_tarballs 函数的关键字参数 preferred_gcc_version 允许您在需要时选择更新的编译器来构建库。纯 C 库具有良好的兼容性,因此使用较新编译器构建的库应该能够在使用较旧 GCC 版本的系统上运行而不会出现问题。但是,请记住,BinaryBuilder.jl 中的每个 GCC 版本都捆绑了特定版本的 binutils——它提供了 ld 链接器——请参阅此表

ld 非常挑剔,该工具的给定版本不喜欢与被链接较新版本的库进行链接:这意味着如果您使用 GCC v6 构建库,则需要构建所有库 GCC >= v6 取决于它。如果你不这样做,你会得到这样一个神秘的错误:

/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

解决方案是至少使用依赖项使用的最大 GCC 版本构建下游库:

build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; preferred_gcc_version=v"8")

例如,FFMPEG 必须使用 GCC v8 构建 因为 LibVPX 需要 GCC v8

一般来说,我们会尝试使用尽可能旧的 GCC 版本(v4.8.5 是当前可用的最旧版本)来构建,以获得最大的兼容性。

运行外部可执行文件

BinaryBuilder 提供的构建环境是 x86_64-linux-musl,它可以运行以下平台的可执行文件:x86_64-linux-muslx86_64-linux-gnui686-linux-gnu `。对于所有其他平台,如果构建系统尝试运行外部可执行文件,您将收到错误消息,通常类似于

./foreign.exe: line 1: ELF��
                       @@xG@8@@@@@@���@�@@����A�A����A�A���@�@: not found
./foreign.exe: line 1: syntax error: unexpected end of file (expecting ")")

这是交叉编译时最糟糕的情况之一,并且没有简单的解决方案。您必须查看构建过程以查看是否可以跳过运行可执行文件(例如,参见 Yggdrasil#351), 或者用别的东西代替。如果可执行文件是仅编译时实用程序,请尝试使用本机编译器构建它(例如,请参阅 Yggdrasil#351 中用于构建本机 mkdefs 的补丁)

Musl Linux

posix_memalign 定义错误

为 Musl 平台编译有时会失败并显示错误消息

/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);
     ^

这是由于旧版本的 GCC 中针对此 libc 的错误,请参阅 BinaryBuilder.jl#387 了解更多详细信息。

有两种选择可以解决此问题:

  • 通过使用 build_tarballs(...; preferred_gcc_version=v"6") 需要 GCC 6。在某些情况下,这可能是最简单的选择。作为例子,参见 Yggdrasil#3974

  • 如果使用旧版本的 GCC 对于更广泛的兼容性很重要,您可以应用 此补丁 到构建工具链。作为例子,参见 ZeroMQ 的配方。

PowerPC Linux

未构建共享库

有时候 powerpc64le-linux-gnu 的共享库编译成功后没有建好,审计失败,因为只编译了静态库。如果构建使用 Autotools,这很可能会发生,因为 configure 脚本是使用非常旧版本的 Autotools 生成的,它不知道如何为该系统构建共享库。这里的技巧是使用 autoreconf 重新生成 configure 脚本:

autoreconf -vi
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nproc}
make install

作为例子,参见 Giflib 的构建器。如果您需要重新生成 configure,您可能需要运行 update_configure_scripts 以使其他平台也能正常工作。

FreeBSD

undefined reference to `backtrace_symbols'

如果因为以下错误导致编译失败

undefined reference to `backtrace_symbols'
undefined reference to `backtrace'

那么你需要链接到 execinfo

if [[ "${target}" == *-freebsd* ]]; then
    export LDFLAGS="-lexecinfo"
fi
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nprocs}
make install

例子参见 Yggdrasil#354Yggdrasil#982

undefined reference to `environ'

此问题是由 -Wl,--no-undefined 标志引起的。如果未定义的引用一起出现,删除此标志也可以解决上述回溯问题。

Windows

由于未定义的符号,Libtool 拒绝构建共享库

在为 Windows 构建时,有时 libtool 会因为未定义的符号而拒绝构建共享库。发生这种情况时,编译成功但 BinaryBuilder 的审计无法找到预期的 LibraryProduct

在编译日志中,您通常可以找到类似的消息

libtool: warning: undefined symbols not allowed in i686-w64-mingw32 shared libraries; building static only

或者

libtool: error: can't build i686-w64-mingw32 shared library unless -no-undefined is specified

在这些情况下,您必须将 -no-undefined 选项传递给链接器,如第二条消息明确建议的那样。

正确的修复需要将 -no-undefined 标志添加到 Makefile.am 文件中相应 libtool 存档的 LDFLAGS。作为解决方案的例子,参考 CALCEPHERFAlibsharp2

修补 Makefile.am 文件的一种快速的替代方法是仅将 LDFLAGS=-no-undefined 传递给 make

FLAGS=()
if [[ "${target}" == *-mingw* ]]; then
    FLAGS+=(LDFLAGS="-no-undefined")
fi
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nprocs} "${FLAGS[@]}"
make install

请注意,在 ./configure 之前设置 LDFLAGS=-no-undefined 会使此操作失败,因为它会运行类似 cc -no-undefined conftest.c 的命令,这会扰乱编译器)。例子参见 Yggdrasil#170Yggdrasil#354

Libtool 拒绝构建共享库,因为 -lmingw32 不是真实文件

如果您看到类似以下的错误:

[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

这是 autoconf 的 ACF77LIBRARYLDFLAGS(或 ACFCLIBRARYLDFLAGS)宏中的错误。已提交补丁以修复此上游。

同时,您可以删除这些宏。它们通常不是必需的。

苹果系统

CMake 抛出 “No known for CXX compiler”

例如,错误消息如下:

CMake Error in CMakeLists.txt:
  No known features for CXX compiler

  "Clang"

  version 12.0.0.

此问题是由于未设置 CMake 策略 CMP0025 引起的。该策略仅影响 AppleClang 的 CompilerId,但它还有关闭上游 clang 的特征检测的效果(这是我们正在使用的)作用在 CMake 3.18 之前的 CMake 版本。在项目定义之前(或获取 CMake 的更新版本),将

cmake_policy(SET CMP0025 NEW)

添加在 CMakeLists.txt 的最顶部。