查看源代码 在 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_TARGET
、CC
、CXX
、AR
和 RANLIB
会设置为它们各自的包装器,并且目录 $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.exe
或 otp_win64_27.exe
的文件,即 $ERL_TOP/release/win32
。
让我们更详细地了解一下
$ ./otp_build configure
- 这将运行新生成的 configure 脚本,并使用选项使 configure 正常运行。目标计算机类型显然是win32
,因此许多 configure 脚本会识别此不常用的目标名称并相应地执行操作。CC 变量还使编译器成为cc.sh
,它包装了 MSVC++,因此所有关于 C 编译器的 configure 测试都会运行正确的编译器。Windows 上不需要许多测试,但我们认为最好还是运行整个 configure。$ ./otp_build boot -a
- 这将使用引导目录(随源代码一起提供,$ERL_TOP/bootstrap
)来构建完整的 OTP 系统。完成后,您可以在源代码树中运行 erl;只需键入$ERL_TOP/bin/erl
,您就应该看到提示符。$ ./otp_build release -a
- 从源代码树构建商业发行树。默认情况下将其放置在$ERL_TOP/release/win32
中。您可以将任何目录作为参数,但如果您也要构建自解压安装程序,则它实际上并不重要。$ ./otp_build installer_win32
- 创建自解压安装程序可执行文件。可执行文件otp_win32_27.exe
或otp_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。