查看源代码 交叉编译 Erlang/OTP

简介

本文档描述了如何交叉编译 Erlang/OTP-27。在尝试交叉编译 Erlang/OTP 之前,建议您阅读完整文档。但是,在阅读本文档之前,您应该阅读构建和安装 Erlang/OTP,其中介绍了 Erlang/OTP 的一般构建和安装过程。

在下面的文本中,$ERL_TOP 是 Erlang/OTP 源代码树中的顶级目录。

otp_build 与 configure/make

构建 Erlang/OTP 可以通过使用 $ERL_TOP/otp_build 脚本,或者直接调用 $ERL_TOP/configuremake 来完成。使用 otp_build 构建更容易,因为它涉及的步骤更少,但是 otp_build 构建过程不如 configure/make 构建过程灵活。请注意,otp_build configure 将生成与 configure 默认生成的配置不同的默认配置。例如,目前 --disable-dynamic-ssl-lib 被添加到 configure 命令行参数中,除非显式传递了 --enable-dynamic-ssl-libotp_build configure 使用的默认值可能会随时更改,恕不另行通知。

交叉配置

$ERL_TOP/xcomp/erl-xcomp.conf.template 文件包含所有可用的交叉配置变量,可以在创建交叉编译配置时用作模板。所有交叉配置变量也在本文档末尾列出。有关工作交叉配置的示例,请参阅 $ERL_TOP/xcomp/erl-xcomp-TileraMDE2.0-tilepro.conf 文件和 $ERL_TOP/xcomp/erl-xcomp-x86_64-saf-linux-gnu.conf 文件。如果变量的默认行为令人满意,则无需设置该变量。但是,当使用默认值时,configure 脚本将发出警告。设置变量后,将不会发出警告。

可以使用 --xcomp-conf 命令行参数将交叉配置文件传递给 otp_build configure。请注意,configure 不接受此命令行参数。当直接使用 configure 脚本时,请使用 <VARIABLE>=<VALUE> 语法将配置变量作为参数传递给 configure。变量也可以作为环境变量传递给 configure。但是,如果您在环境中传递配置,请确保在调用 make 之前取消设置所有这些环境变量;否则,环境变量可能会在某些应用程序或某些应用程序的部分中设置 make 变量,并且您最终可能会得到一个配置错误的构建。

哪些可以交叉编译?

除了 wx 应用程序之外,所有 Erlang/OTP 应用程序都可以交叉编译。目前,交叉编译时会自动禁用 wx 驱动程序的构建。

兼容性

构建系统,包括使用的交叉编译配置变量,可能会在不事先通知的情况下进行不向后兼容的更改。当前的交叉构建系统已在交叉编译某些 Linux/GNU 系统时进行了测试,但在其他平台上仅进行了部分测试。

补丁

请以与此系统一致的方式提交任何用于交叉编译的补丁。欢迎所有输入,因为我们只有非常有限的交叉编译环境可用于测试。如果需要新的配置变量,请将其添加到 $ERL_TOP/xcomp/erl-xcomp.conf.template,并在 configure.in 中使用它。可能需要更新的其他文件是

  • $ERL_TOP/xcomp/erl-xcomp-vars.sh
  • $ERL_TOP/erl-build-tool-vars.sh
  • $ERL_TOP/erts/aclocal.m4
  • $ERL_TOP/xcomp/README.md
  • $ERL_TOP/xcomp/erl-xcomp-*.conf

请注意,这可能不是需要更新的文件的完整列表。

有关如何提交补丁的常规信息,请访问:http://wiki.github.com/erlang/otp/submitting-patches

构建和安装过程

我们将首先介绍人们可能最熟悉的 configure/make 构建过程。

直接使用 configure/make 构建

将目录更改为 Erlang/OTP 源代码树的顶级目录。

$ cd $ERL_TOP

为了编译 Erlang 代码,必须构建一个小的 Erlang 引导系统,或者必须在 $PATH 中提供与正在构建的版本相同的 Erlang/OTP 系统。目标系统的 Erlang/OTP 将使用此 Erlang 系统以及提供的交叉编译工具进行构建。

如果您想使用 $PATH 中兼容的 Erlang/OTP 系统进行构建,请跳至 交叉构建系统

构建引导系统

$ ./configure --enable-bootstrap-only
$ make

对于 configure 而言,--enable-bootstrap-only 参数不是绝对必要的,但会加快速度。它将仅在引导所需的应用程序中运行 configure,并将禁用引导系统不需要的许多内容。如果您在没有 --enable-boostrap-only 的情况下运行 configure,则还必须运行 make bootstrap;否则,将构建整个系统。

交叉构建系统

$ ./configure --host=<HOST> --build=<BUILD> [Other Config Args]
$ make

<HOST> 是您为其构建的主机/目标系统。它不必是完整的 CPU-VENDOR-OS 三元组,但可以是。完整的规范化 CPU-VENDOR-OS 三元组将通过执行 $ERL_TOP/make/autoconf/config.sub <HOST> 创建。如果 config.sub 失败,则您需要更具体。

<BUILD> 应等于您在其上构建的系统的 CPU-VENDOR-OS 三元组。如果您执行 $ERL_TOP/make/autoconf/config.guess,则在大多数情况下,它将打印您要用于此的三元组。

使用不同的 <HOST><BUILD> 值将触发交叉编译。请注意,如果 <HOST><BUILD> 不同,则 <HOST><BUILD> 的规范化值也必须不同。如果它们不同,则配置将失败。

使用 <VARIABLE>=<VALUE> 语法将交叉编译变量作为命令行参数传递给 configure

注意

直接调用 configure 时,您不能使用 --xcomp-conf 参数传递配置文件。 --xcomp-conf 参数只能传递给 otp_build configure

make 将验证构建时使用的 Erlang/OTP 系统是否与正在构建的系统版本相同,如果不是,则会失败。但是,即使使用了错误的 Erlang/OTP 系统,也可以强制进行交叉编译,但不建议这样做。通过以下方式调用 makemake ERL_XCOMP_FORCE_DIFFERENT_OTP=yes

警告

调用 make ERL_XCOMP_FORCE_DIFFERENT_OTP=yes 可能会失败,静默地生成次优代码或静默地生成错误代码。

安装

您可以使用 configure 确定的路径安装,或手动安装

使用 configure 确定的路径安装
$ make install DESTDIR=<TEMPORARY_PREFIX>

make install 将安装到执行 configure 时指定的位置。指定安装位置的 configure 参数例如:--prefix--exec-prefix--libdir--bindir 等。默认情况下,它将安装在 /usr/local 下。您通常不希望将交叉构建安装在构建机器上的 /usr/local 下。使用 DESTDIR 将导致安装路径以 $DESTDIR 为前缀。这样就可以在构建机器上安装和打包安装,而不必将安装放置在与目标机器上应该执行的目录相同的构建机器上。

make install 完成后,将目录更改为 $DESTDIR,打包系统,将其移动到目标机器,然后解压缩。请注意,安装仅在目标机器上由 configure 确定的位置工作。

手动安装
$ make release RELEASE_ROOT=<RELEASE_DIR>

make release 会将您为目标机器构建的内容复制到 <RELEASE_DIR>Install 脚本将不会运行。默认情况下,<RELEASE_DIR> 的内容最终会位于 /usr/local/lib/erlang 中。

安装 Erlang/OTP 时使用的 Install 脚本需要常见的 Unix 工具(例如 sed)出现在您的 $PATH 中。如果您的目标系统没有此类工具,则需要在打包 Erlang/OTP 之前在构建机器上运行 Install 脚本。Install 脚本目前应在它所在的目录(顶级目录)中按如下方式调用

$ ./Install [-cross] [-minimal|-sasl] <ERL_ROOT>

其中

  • -minimal 创建一个启动最少数量的应用程序的安装,即仅启动 kernelstdlib。最小系统通常足够,并且是 make install 使用的系统。
  • -sasl 创建一个也启动 sasl 应用程序的安装。
  • -cross 用于交叉编译。通知安装脚本它在构建机器上运行。
  • <ERL_ROOT> - 运行时要使用的 Erlang 安装的绝对路径。这通常与当前工作目录相同,但不必如此。它可以遵循文件系统中到同一目录的任何其他路径。

如果既没有传递 -minimal,也没有传递 -sasl 作为参数,系统将提示您。

现在您可以执行以下操作之一

  • 确定安装应位于目标机器上的位置,在构建机器上运行 Install 脚本,然后打包已安装的安装。安装只需要在目标机器上的正确位置解压缩

    $ cd <RELEASE_DIR>
    $ ./Install -cross [-minimal|-sasl] <ABSOLUTE_INSTALL_DIR_ON_TARGET>
    

  • 打包 <RELEASE_DIR> 中的安装,将其放置在目标机器上的任何位置,然后在目标机器上运行 Install 脚本

    $ cd <ABSOLUTE_INSTALL_DIR_ON_TARGET>
    $ ./Install [-minimal|-sasl] <ABSOLUTE_INSTALL_DIR_ON_TARGET>
    

使用 otp_build 脚本构建

$ cd $ERL_TOP

$ ./otp_build configure --xcomp-conf=<FILE> [Other Config Args]

或者

$ ./otp_build configure --host=<HOST> --build=<BUILD> [Other Config Args]

如果你的交叉编译配置在一个文件中,可以使用命令行参数 --xcomp-conf=<FILE> 来传递它。如果没有,则使用 --host=<HOST>--build=<BUILD> 以及命令行上的 <VARIABLE>=<VALUE> 语法来传递配置变量(与 交叉构建系统 中相同)。注意,<HOST><BUILD> 必须以某种方式传递;可以通过在配置文件中使用 erl_xcomp_host=<HOST>erl_xcomp_build=<BUILD>,或者使用命令行参数 --host=<HOST>--build=<BUILD>

otp_build configure 将配置构建机器上的引导系统和交叉主机系统。

$ ./otp_build boot -a

otp_build boot -a 将首先为构建机器构建一个引导系统,然后进行系统的交叉构建。

$ ./otp_build release -a <RELEASE_DIR>

otp_build release -a 的作用与 [手动安装] 中的 make release 相同,在此之后你必须在主机或目标上执行 手动 ./Install

构建和安装文档

在系统交叉构建完成后,你可以像在本地构建系统后一样构建和安装文档。请参阅 如何构建文档 部分,该部分位于 构建和安装 Erlang/OTP 文档中,了解如何构建文档的信息。

测试交叉编译的系统

Erlang 自带的一些测试使用本机代码进行测试。这意味着在交叉编译 Erlang 时,你还必须交叉编译测试套件,以便在目标主机上运行测试。要做到这一点,你首先必须像往常一样发布测试。

$ make release_tests

$ ./otp_build tests

测试将发布到 $ERL_TOP/release/tests 中。发布测试后,你必须在构建机器上安装测试。你需要提供与在 使用 otp_build 脚本构建 中向 ./otp_build 提供的相同的 xcomp 文件。

$ cd $ERL_TOP/release/tests/test_server/
$ $ERL_TOP/bootstrap/bin/erl -eval 'ts:install([{xcomp,"<FILE>"}])' -s ts compile_testcases -s init stop

当测试用例被编译时,你应该会看到大量的输出。完成后,你应该将整个 $ERL_TOP/release/tests 文件夹复制到交叉主机系统。

然后进入交叉主机系统,设置 Erlang 安装使其位于你的 $PATH 中。然后进入之前是 $ERL_TOP/release/tests/test_server 的位置,并执行以下命令。

$ erl -s ts install -s ts run all_tests -s init stop

配置应该被跳过,所有测试应该都能够通过。有关如何使用 ts 的更多详细信息,请运行 erl -s ts help -s init stop

当前使用的配置变量

请注意,你不能在交叉编译配置文件中定义任意变量。只有下面列出的变量才能保证在所有 configure 脚本的整个执行过程中可见。其他变量需要定义为 configure 的参数或在环境中导出。

仅用于 otp_build 的变量

本节中的变量仅在使用 $ERL_TOP/otp_build configure 配置 Erlang/OTP 进行交叉编译时使用。

注意

如果你直接使用 configure 脚本进行配置,这些变量目前不起任何作用。

  • erl_xcomp_build - 使用的构建系统。此值将作为 --build=$erl_xcomp_build 参数传递给 configure 脚本。它不必是一个完整的 CPU-VENDOR-OS 三元组,但可以是。完整的 CPU-VENDOR-OS 三元组将由 $ERL_TOP/make/autoconf/config.sub $erl_xcomp_build 创建。如果设置为 guess,则将使用 $ERL_TOP/make/autoconf/config.guess 猜测构建系统。

  • erl_xcomp_host - 要为其构建的交叉主机/目标系统。此值将作为 --host=$erl_xcomp_host 参数传递给 configure 脚本。它不必是一个完整的 CPU-VENDOR-OS 三元组,但可以是。完整的 CPU-VENDOR-OS 三元组将由 $ERL_TOP/make/autoconf/config.sub $erl_xcomp_host 创建。

  • erl_xcomp_configure_flags - 传递给 configure 脚本的额外配置标志。

交叉编译器和其他工具

如果交叉编译工具以 <HOST>- 为前缀,你可能不需要设置这些变量(其中 <HOST> 是作为 --host=<HOST> 参数传递给 configure 的值)。编译器和其他工具可以通过作为命令行参数传递给 configure 的变量、xcomp 文件或环境变量来识别。有关更多信息,请参阅 configure 检查的重要变量 部分,该部分位于 构建和安装 Erlang/OTP 中。

交叉系统根位置

  • erl_xcomp_sysroot - 交叉编译环境的系统根目录的绝对路径。目前,cryptoodbcsshssl 应用程序需要系统根目录。如果未设置系统根目录,将跳过这些应用程序。系统根目录可能也需要用于其他事情。如果出现这种情况且未设置系统根目录,configure 将会失败并要求你设置它。

  • erl_xcomp_isysroot - 交叉编译环境的包含文件的系统根目录的绝对路径。如果未设置,此值默认为 $erl_xcomp_sysroot,也就是说,仅当包含文件的系统根目录路径与系统根目录路径不同时才设置此值。

可选功能和错误测试

在交叉编译时,这些测试不能(总是)自动完成。你通常不需要设置这些变量。

警告

错误地设置这些变量可能会导致难以检测的运行时错误。如果你需要更改这些值,请务必确保这些值是正确的。

注意

其中一些值将覆盖 configure 执行的测试结果,而一些值将在 configure 确定它无法找出结果之前不会使用。

当使用默认值时,configure 脚本将发出警告。当变量已设置时,将不会发出警告。

  • erl_xcomp_after_morecore_hook - yes|no。默认为 no。如果为 yes,则目标系统必须具有一个可工作的 __after_morecore_hook,可用于跟踪使用的 malloc() 实现的核心内存使用情况。这目前仅用于不受支持的功能。

  • erl_xcomp_bigendian - yes|no。无默认值。如果为 yes,则目标系统必须为大端。如果为 no,则为小端。这通常可以自动检测,但并非总是如此。如果未自动检测到,除非设置此变量,否则 configure 将失败。由于未使用默认值,configure 将尝试自动找出此值。

  • erl_xcomp_double_middle - yes|no。默认为 no。如果为 yes,则目标系统必须具有“中间端”格式的双精度浮点数。如果为 no,则具有“常规”字节序。

  • erl_xcomp_clock_gettime_cpu_time - yes|no。默认为 no。如果为 yes,则目标系统必须具有一个可工作的 clock_gettime() 实现,可用于检索进程 CPU 时间。

  • erl_xcomp_getaddrinfo - yes|no。默认为 no。如果为 yes,则目标系统必须具有一个可工作的 getaddrinfo() 实现,可以处理 IPv4 和 IPv6。

  • erl_xcomp_gethrvtime_procfs_ioctl - yes|no。默认为 no。如果为 yes,则目标系统必须具有一个可工作的 gethrvtime() 实现,并且与 procfs ioctl() 一起使用。

  • erl_xcomp_dlsym_brk_wrappers - yes|no。默认为 no。如果为 yes,则目标系统必须具有一个可工作的 dlsym(RTLD_NEXT, <S>) 实现,可以用于正在使用的 malloc() 实现中的 brksbrk 符号,从而跟踪 malloc() 实现的核心内存使用情况。这目前仅用于不受支持的功能。

  • erl_xcomp_kqueue - yes|no。默认为 no。如果为 yes,则目标系统必须具有一个可工作的 kqueue() 实现,该实现返回一个可供 poll() 和/或 select() 使用的文件描述符。如果为 no 并且目标系统没有 epoll()/dev/poll,则内核轮询功能将被禁用。

  • erl_xcomp_linux_clock_gettime_correction - yes|no。在 Linux 上默认为 yes;否则为 no。如果为 yes,则目标系统上的 clock_gettime(CLOCK_MONOTONIC, _) 必须工作。建议在内核版本低于 2.6 的 Linux 系统上将此变量设置为 no

  • erl_xcomp_linux_nptl - yes|no。在 Linux 上默认为 yes;否则为 no。如果为 yes,则目标系统必须具有 NPTL(本机 POSIX 线程库)。较旧的 Linux 系统使用 LinuxThreads 而不是 NPTL(Linux 内核版本通常低于 2.6)。

  • erl_xcomp_linux_usable_sigaltstack - yes|no。在 Linux 上默认为 yes;否则为 no。如果为 yes,则目标系统上必须可以使用 sigaltstack()。Linux 内核版本低于 2.4 上的 sigaltstack() 已损坏。

  • erl_xcomp_linux_usable_sigusrx - yes|no。默认为 yes。如果为 yes,则 ERTS 必须可以使用 SIGUSR1SIGUSR2 信号。旧的 LinuxThreads 线程库(Linux 内核版本通常低于 2.2)使用了这些信号,并使 ERTS 无法使用它们。

  • erl_xcomp_poll - yes|no。在 Darwin/MacOSX 上默认为 no;否则默认为 yes。如果为 yes,目标系统必须有一个可以处理设备的 poll() 实现。如果为 no,将使用 select() 代替 poll()

  • erl_xcomp_putenv_copy - yes|no。默认为 no。如果为 yes,目标系统必须有一个 putenv() 实现,该实现存储键/值对的副本。

  • erl_xcomp_reliable_fpe - yes|no。默认为 no。如果为 yes,目标系统必须具有可靠的浮点异常处理。

  • erl_xcomp_posix_memalign - yes|no。如果存在 posix_memalign 系统调用,则默认为 yes;否则默认为 no。如果为 yes,目标系统必须有一个 posix_memalign 实现,该实现接受大于页大小的对齐。

  • erl_xcomp_code_model_small - yes|no。默认为 no。如果为 yes,目标系统必须将 beam.smp 可执行文件放置在内存的低 2GB 区域。也就是说,它不应该使用位置无关的可执行文件。