查看源代码 在 Windows 上构建 Erlang/OTP

简介

本节介绍如何在 Windows 上构建 Erlang 虚拟机和 OTP 库。请注意,如果用户没有 Microsoft 的开发工具和/或不想安装 WSL,Windows 二进制版本仍然是首选替代方案。您可以从 https://erlang.org.cn/downloads 下载二进制版本。

这些说明适用于支持 WSL.1(适用于 Linux 的 Windows 子系统 v.1)并使用 Ubuntu 18.04 版本的 Windows 10(v.1809 及更高版本)。

所描述的过程使用 WSL 作为构建环境。您在 WSL 中运行 bash shell,并使用 gnu configure/make 等来进行构建。然而,虚拟机 C 源代码主要使用 Microsoft Visual C++™ 编译,从而生成一个本地 Windows 二进制文件。这与我们用于构建预构建二进制文件的过程相同。为什么我们使用 VC++ 而不是 gcc,在常见问题解答部分会进一步解释。

这些说明适用于 32 位和 64 位 Windows。请注意,即使您构建的是 64 位版本的 Erlang,大多数目录和文件仍然被命名为 win32。然而,也存在一些 win64 的命名。例如,64 位 Windows 版本 Erlang 的安装文件是 otp_win64_27.exe

如果您对环境和构建系统感到满意,并且拥有所有必要的工具,那么您就有很好的机会使 Erlang/OTP 的 Windows 版本更好。请将任何建议或补丁提交到我们的 git 项目,以便它们能够进入 Erlang 的下一个版本。如果对构建系统(如 makefiles 等)进行更改,请记住,相同的 makefiles 也用于 Unix,因此您的更改不会破坏其他平台。这对于 C 代码也同样适用;系统特定代码主要位于 $ERL_TOP/erts/emulator/sys/win32$ERL_TOP/erts/etc/win32 目录中。$ERL_TOP/erts/emulator/beam 目录用于通用代码。

简短版本

在以下章节中,我们尽可能地描述了所需工具的安装。一旦安装了这些工具,构建就非常容易了。我们还尝试使这些说明对于 Unix 经验有限的人来说易于理解。对于某些 Windows 用户来说,WSL 是一个全新的环境,因此仔细解释环境变量等似乎是必要的。

以下是为经验丰富且不耐烦的人准备的简短说明:

  • 获取并安装完整的 WSL 环境

  • 安装 Visual Studio 2019

  • 获取并安装 Windows JDK-8

  • 获取并安装 Windows NSIS 3.05 或更高版本(已尝试并可用的 3.05 版本)

  • 获取、构建并安装 OpenSSL v1.1.1d 或更高版本(已尝试并可用的 1.1.1d 版本),并使用静态库。

  • 获取、构建并安装 wxWidgets-3.2.2.1 或更高版本(已尝试并可用的该版本),并使用静态库。

  • 获取 Erlang 源代码发行版(来自 https://erlang.org.cn/download.html),并使用 tar 将其解压到 Windows 磁盘,例如:/mnt/c/src/

  • 安装 mingw-gcc 和 make:sudo apt update && sudo apt install g++-mingw-w64 gcc-mingw-w64 make

  • $ cd UNPACK_DIR

  • 修改 PATH 和其他环境变量,以便所有这些工具都可以从 bash shell 运行。仍然位于 $ERL_TOP 中,发出以下命令(对于 32 位 Windows,请从第一行删除 x64,并将最后一行中的 otp_win64_27 更改为 otp_win32_27

    $ eval `./otp_build env_win32 x64`
    $ ./otp_build configure
    $ ./otp_build boot -a
    $ ./otp_build release -a
    $ ./otp_build installer_win32
    $ release/win32/otp_win64_27 /S
    

瞧!开始 -> 程序 -> Erlang OTP 27 -> Erlang 启动 Erlang Windows shell。

您需要的工具及其环境

您需要一些工具才能在 Windows 上构建 Erlang/OTP。最值得注意的是,您需要 WSL(使用 ubuntu)、Visual Studio 和 Microsoft 的 Windows SDK,但您可能还需要 Java 编译器、NSIS 安装系统、OpenSSL 和 wxWidgets。以下是一些有关不同工具的信息

  • WSL:在 Windows 10 中安装 WSL 和 Ubuntu https://docs.microsoft.com/zh-cn/windows/wsl/install-win10

    我们已经使用 WSL-1 进行了测试,WSL-2 尚不可用,并且在构建 Erlang/OTP 时可能不是首选,因为访问 Windows 磁盘的速度(目前)在 WSL-2 中较慢。

  • Visual Studio 2019 从以下网址下载并运行安装程序:http://visualstudio.microsoft.com/downloads 将 C++ 和 SDK 包安装到默认安装目录。

  • Java JDK 8 或更高版本(可选)如果您不关心 Java,可以跳过此步骤。结果是不会构建 jinterface。

    我们的 Java 代码(jinterface,ic)在 Windows 上使用 JDK 8 进行了测试。获取 Windows 版本并安装它,JRE 不够。

    URL:http://www.oracle.com/java/technologies/javase-downloads.html

    将 javac 添加到您的路径环境中,在我的情况下这意味着

    PATH="/mnt/c/Program\ Files/Java/jdk1.8.0_241/bin:$PATH

    不需要 CLASSPATH 或任何其他内容。在 bash 提示符中键入 javac.exe,您应该会看到可用 Java 选项的列表。

  • Nullsoft NSIS 安装程序系统(可选)您需要它来构建自安装包。

    从以下网址下载并运行安装程序:URL:http://nsis.sourceforge.net/download

    将 'makensis.exe' 添加到您的路径环境

    PATH="/mnt/c/Program\ Files/NSIS/Bin:$PATH

    在 bash 提示符中键入 which makensis.exe,您应该会看到该程序的路径。

  • OpenSSL(可选)您需要它来构建 crypto、ssh 和 ssl 库。

    我们建议使用 v1.1.1d 或更高版本。这里有预构建的可用二进制文件,您可以直接下载并安装:URL:http://wiki.openssl.org/index.php/Binaries

    安装到 C:/OpenSSL-Win64(或 C:/OpenSSL-Win32

  • wxWidgets(可选)您需要它来构建 wx,以便在调试器和观察器中使用 GUI。

    我们建议使用 v3.2.2.1 或更高版本。解压到 c:/opt/local64/pgm/wxWidgets-3.2.2.1

    如果在 c:/opt/local64/pgm/wxWidgets-3.2.2.1/include/wx/msw/setup.h 中未启用 wxUSE_POSTSCRIPT,请启用它。

    我们建议为 wxWebView 启用 wxUSE_WEBVIEW_EDGE。

    • 下载 nuget 包 'Microsoft.Web.WebView2'(0.9.488 或更高版本)
    • 将包(它是一个 zip 存档)解压到 wxWidgets/3rdparty/webview2(解压后,您应该有 3rdparty/webview2/build/native/include/WebView2.h 文件)
    • c:/opt/local64/pgm/wxWidgets-3.2.2.1/include/wx/msw/setup.h 中启用 wxUSE_WEBVIEW_EDGE

    使用以下命令构建

    C:\...\> cd c:\opt\local64\pgm\wxWidgets-3.2.2.1\build\msw
    C:\...\> nmake TARGET_CPU=amd64 BUILD=release SHARED=0 DIR_SUFFIX_CPU= -f makefile.vc

    对于 32 位版本构建,请删除 TARGET_CPU=amd64

  • 获取 Erlang 源代码发行版(来自 https://erlang.org.cn/download.html)。与 Unix 平台相同。最好使用 tar 解压源代码 tar.gz(tar zxf otp_src_27.tar.gz)到 Windows 磁盘上的某个位置,/mnt/c/path/to/otp_src

    注意:源代码必须在 Windows 磁盘上,这一点很重要。

    设置环境变量 ERL_TOP 以指向源代码发行版的根目录。假设我位于 /mnt/c/src 并解压了 otp_src_27.tar.gz,然后我在 .profile 中添加以下内容

    ERL_TOP=/mnt/c/src/otp_src_27
    export ERL_TOP

Shell 环境

path 变量现在应该包含 javac.exe 和 makensis.exe 的 Windows 路径。

使用以下命令设置环境

$ export PATH
$ cd /mnt/c/path/to/otp_src/
$ eval `./otp_build env_win32 x64`

这将设置其他环境变量。

这将完成环境的最终设置,此后构建应该很容易。您可以运行 ./otp_build env_win32 而不使用 eval,只是为了查看它做了什么,并查看它设置的环境是否正常。如果可能,路径会清除空格(改为使用 DOS 风格的短名称),变量 OVERRIDE_TARGETCCCXXARRANLIB 会设置为它们各自的包装器,并且目录 $ERL_TOP/erts/etc/win32/wsl_tools/vc$ERL_TOP/erts/etc/win32/wsl_tools 会首先添加到 PATH 中。

现在您可以通过在 shell 中键入 type erlc 来检查您拥有哪个 erlc。它应该位于 $ERL_TOP/erts/etc/win32/wsl_tools 中。

运行 cl.exe 应该会打印 Microsoft 编译器使用消息。

所需的编译器环境变量是通过 otp_build 中的 erts/etc/win32/wsl_tools/SetupWSLcross.bat 设置的。它包含一些硬编码的路径,如果您的安装路径不同,则可以将其添加到该文件中。

构建和安装

使用 otp_build 脚本构建最容易

$ ./otp_build configure <optional configure options>
$ ./otp_build boot -a
$ ./otp_build release -a <installation directory>
$ ./otp_build installer_win32 <installation directory> # optional

现在,您将在 <安装目录> 中获得一个名为 otp_win32_27.exeotp_win64_27.exe 的文件,即 $ERL_TOP/release/win32

让我们更详细地了解一下

  1. $ ./otp_build configure - 这将运行新生成的 configure 脚本,并使用选项使 configure 正常运行。目标计算机类型显然是 win32,因此许多 configure 脚本会识别此不常用的目标名称并相应地执行操作。CC 变量还使编译器成为 cc.sh,它包装了 MSVC++,因此所有关于 C 编译器的 configure 测试都会运行正确的编译器。Windows 上不需要许多测试,但我们认为最好还是运行整个 configure。

  2. $ ./otp_build boot -a - 这将使用引导目录(随源代码一起提供,$ERL_TOP/bootstrap)来构建完整的 OTP 系统。完成后,您可以在源代码树中运行 erl;只需键入 $ERL_TOP/bin/erl,您就应该看到提示符。

  3. $ ./otp_build release -a - 从源代码树构建商业发行树。默认情况下将其放置在 $ERL_TOP/release/win32 中。您可以将任何目录作为参数,但如果您也要构建自解压安装程序,则它实际上并不重要。

  4. $ ./otp_build installer_win32 - 创建自解压安装程序可执行文件。可执行文件 otp_win32_27.exeotp_win64_27.exe 将被放置在上一步创建的发布版本的顶层目录中。如果没有指定发布目录,则假定发布版本已构建到 $ERL_TOP/release/win32,这也是安装程序可执行文件放置的位置。如果您为发布版本指定了其他目录(例如 ./otp_build release -a /tmp/erl_release),则您需要在此处提供相同的参数(例如 ./otp_build installer_win32 /tmp/erl_release)。您需要安装完整的 NSIS 并且 makensis.exe 在您的路径中才能使其正常工作。创建安装程序后,您可以运行它以常规方式安装 Erlang/OTP,只需运行可执行文件并按照安装向导中的步骤操作即可。要在安装中获取所有默认设置而无需任何提问,您可以像下面这样使用参数 /S(大写 S)运行可执行文件:

    $ cd $ERL_TOP
    $ release/win32/otp_win32_27 /S
    ...
    

    $ cd $ERL_TOP
    $ release/win32/otp_win64_27 /S
    ...
    

    稍后,Erlang/OTP-27 将安装在 C:\Program Files\erl%ERTS-VSN%\ 中,并在菜单中带有快捷方式等。

开发

系统构建完成后,您可能想要对其进行更改。在某个方便的目录中拥有一个测试版本可能很有用,但您也可以从源代码树中运行 Erlang。目标 local_setup 使程序 $ERL_TOP/bin/erl.exe 可用,并且它还使用源代码树中的所有 OTP 库。

如果您修改了模拟器,则可以通过位于 $ERL_TOP/erts/emulator 中并执行简单的操作来构建模拟器可执行文件

$ make opt

请注意,在 Windows 上构建任何内容之前,您需要在特定 shell 中运行 (cd $ERL_TOP && eval `./otp_build env_win32`)。在执行 make opt 后,您可以通过运行 $ERL_TOP/bin/erl 来测试您的结果。如果您想将结果复制到发布目录(例如 /tmp/erl_release),您可以这样做(仍然在 $ERL_TOP/erts/emulator 中)

$ make TESTROOT=/tmp/erl_release release

这将复制模拟器可执行文件。

要进行模拟器的调试构建,您需要重新编译 beam.dll(实际的运行时系统)和 erlexec.dll。像这样操作

$ cd $ERL_TOP
$ rm bin/win32/erlexec.dll
$ cd erts/emulator
$ make debug
$ cd ../etc
$ make debug

有时

$ cd $ERL_TOP
$ make local_setup

现在当您运行 $ERL_TOP/erl.exe 时,您应该拥有一个调试编译的模拟器,如果您在 erlang shell 中执行以下操作,您将会看到:

1> erlang:system_info(system_version).

如果返回的字符串包含 [debug],则表示您得到了一个调试编译的模拟器。

要修改 erlang 库,您只需在特定的“applications”目录中执行 make opt,例如

$ cd $ERL_TOP/lib/stdlib
$ make opt

甚至在源代码目录中...

$ cd $ERL_TOP/lib/stdlib/src
$ make opt

请注意,在执行此操作时,您应该在路径中拥有一个全新的 Erlang,最好是您在上一步中构建的纯 27 版本。您也可以在重新构建特定库之前将 $ERL_TOP/bootstrap/bin 添加到您的 PATH 中。这将为您提供一个足够好的 Erlang 系统来编译任何 OTP erlang 代码。正确设置路径有点棘手。您仍然需要在路径中将 $ERL_TOP/erts/etc/win32/wsl_tools/vc$ERL_TOP/erts/etc/win32/wsl_tools 放在 实际的模拟器之前。使用引导编译器的路径的典型设置是

$ export PATH=$ERL_TOP/erts/etc/win32/wsl_tools/vc\
:$ERL_TOP/erts/etc/win32/wsl_tools:$ERL_TOP/bootstrap/bin:$PATH

这应该可以轻松地重新构建任何库...

如果您想将新构建的库(应用程序)复制到发布区域,您可以像复制模拟器一样操作

$ cd $ERL_TOP/lib/stdlib
$ make TESTROOT=/tmp/erlang_release release

记住

  • Windows 特定的 C 代码位于 $ERL_TOP/erts/emulator/sys/win32$ERL_TOP/erts/emulator/drivers/win32$ERL_TOP/erts/etc/win32 中。

  • Windows 特定的 erlang 代码应该有条件地使用,并在运行时测试主机操作系统,每个平台应该分发完全相同的 beam 文件!因此,请编写如下代码:

    case os:type() of
        {win32,_} ->
            do_windows_specific();
        Other ->
            do_fallback_or_exit()
    end,

这基本上就是您开始工作所需的一切。

常见问题解答

  • 问:那么,现在我可以在 Windows 上使用 GCC 构建 Erlang 了吗?

    答:不,很遗憾不能。您仍然需要 Microsoft 的 Visual C++。一个 Bourne shell 脚本(cc.sh)包装了 Visual C++ 编译器,并从 WSL 环境中运行它。构建 Erlang 所需的所有其他工具都是免费软件/开源的,但 C 编译器不是。

  • 问:那你们为什么不摆脱 VC++ 呢,你们这帮 ******?

    答:嗯,部分原因是它是一个很好的编译器 - 真的!实际上,在 R11 后期版本中,可以使用 mingw 而不是 visual C++ 进行构建(您可能会在一些脚本和目录中看到它的残留)。不幸的是,Windows 的 SMP 版本的开发破坏了 mingw 构建,我们选择专注于 VC++ 构建,因为 VC++ 版本的性能要好得多。mingw 构建可能会重新出现,但是只要 VC++ 提供更好的性能,商业版本将是 VC++ 版本。

  • 问:哈哈,我看到了,你明明说不用 GCC,结果你用了!

    答:好吧,我承认,其中一个文件是使用 MinGW 的 GCC 编译的,然后使用一个小的 C hack 将生成的对象代码转换为 MS VC++ 兼容的 coff。这是因为那个特定的文件 beam_emu.c 可以从使用 GCC 的 labels-as-values 扩展中获得极大的好处,这可以将模拟器性能提高高达 50%。但这很遗憾(尚未)意味着所有 OTP 都可以使用 GCC 编译。该特定源代码不执行任何系统特定的操作,并且实际上是为了适应在 Windows 上使用 GCC 编译它的事实。

  • 问:那么现在某个地方有一个 MS VC++ 项目文件,我可以使用漂亮的 VC++ GUI 构建 OTP 了吗?

    答:不,永远不会。保持项目文件最新,并从 VC++ GUI 中执行构成 OTP 构建的所有步骤的麻烦根本不值得,甚至可能是不可能的。Erlang/OTP 的 VC++ 项目文件永远不会出现。

  • 问:那么这一切是如何工作的呢?

    答:WSL/Ubuntu 是环境,它几乎就像您在 Windows 内部拥有一个虚拟的 Unix 机器。Configure 在给定特定参数的情况下,会创建 makefile,这些 makefile 由环境的 gnu-make 用于构建系统。但是,大多数实际的编译器等都不是 WSL 工具,因此我们编写了一些包装器(Bourne-shell 脚本),这些包装器位于 $ERL_TOP/etc/win32/wsl_tools 中。它们都将 Unix 环境中常见的参数和开关转换为适合本机 Windows 工具的参数和开关。最值得注意的是路径,在 WSL 中,路径是类似 Unix 的路径,带有“正斜杠”(/)且没有驱动器盘符。WSL 特定命令 wslpath 用于 WSL 环境中的大多数路径转换。幸运的是,大多数编译器都接受正斜杠而不是反斜杠作为路径分隔符,但是仍然需要正确获取驱动器盘符等。包装器脚本不是通用的,例如,cc.sh 不会理解并转换每个可能的 gcc 选项,并将正确的选项传递给 cl.exe。原则是,这些脚本足够强大,可以构建 Erlang/OTP,仅此而已。它们可能需要扩展以应对 Erlang 开发期间的变化,这也是我们将其制作成 shell 脚本而不是 Perl 脚本的原因之一。我们认为它们更容易理解和更改。

    $ERL_TOP 中,有一个名为 otp_build 的脚本。该脚本处理向 configure/make 提供所有正确参数的麻烦,并帮助您设置正确的环境变量,以便在 WSL 下使用 Erlang 源代码。

  • 问:我可以构建一个看起来与商业版本完全相同的东西吗?

    答:是的,我们使用完全相同的构建过程。

  • 问:那么你们使用哪个版本的 WSL 和其他工具?

    答:我们使用 WSL 1 和 Ubuntu 18.04。我们用于 27 的 GCC 版本是 7.3-win32。我们使用了 Visual Studio 2019、Sun 的 JDK 1.8.0_241、NSIS 3.05、Win32 OpenSSL 1.1.1d 和 wxWidgets-3.1.3。