如何实现 Erlang Driver 作为默认高效实现

How to implement Erlang Driver As Default efficient Implementation

Erlang Run-Time 系统 (ERTS) 有一些用 C 语言编写的 drivers,用于与 OS 交互或访问 low-level 资源,在据我所知,ERTS 在启动时编译这些 drivers 以准备从 Erlang 代码加载,driver inet_drv.c 是这些 drivers 之一,它用于处理网络任务,例如创建套接字和侦听或接受新的传入连接。

我想手动测试这个 driver 以获得 ERTS 默认行为的一般视图,并了解如何在未来有效地实现 drivers,我跟踪了 Erlang 手册参考实现 driver 说:首先通过 OS C 语言编译器编写和编译 driver,然后使用 erl_ddll 从 erlang 代码加载 driver模块,最后 link 由衍生的 Erlang 进程 driver,所以这非常简单易行。

所以我用 driver inet_drv.c 尝试了这些步骤,我搜索了它并尝试用 Clang 编译器编译它,它是 FreeBSD 系统的默认 C 编译器:

cc inet_drv.c

之后出现错误,指出文件 erl_driver.h 未定义,此 header 文件在 driver 的代码中用作包含文件(#include<erl_driver.h>) 所以我搜索它并使用 -I 选项将它的目录路径添加到 cc 命令,让编译器搜索该目录中包含的文件,然后我重新编译它:

cc inet_drv.c -I/usr/ports.... 

在那之后,有另一个未定义的文件,所以我做了 5 或 6 次同样的事情,最后,我为包含的文件添加了所有需要的路径,结果是这个命令:

cc inet_drv.c

-I/usr/ports/lang/erlang/work/otp-OTP-21.3.8.18/erts/emulator/beam

-I/usr/local/lib/erlang/usr/include

-I/usr/ports/lang/erlang/work/otp-OTP-21.3.8.18/erts/emulator/sys/unix

-I/usr/ports/lang/erlang/work/otp-OTP-21.3.8.18/erts/include/internal

-I/usr/ports/lang/erlang/work/otp-OTP-21.3.8.18/erts/emulator/sys/common

-I/usr/ports/lang/erlang/work/stage/usr/local/lib/erlang/erts-10.3.5.14/include/internal

我对 result:13 错误和 7 个警告感到惊讶,shell 输出以及错误和警告描述在下面的 link 中。 我的问题是:为什么会出现这些错误?我做错了什么?

由于这个 driver 可以完美地响应 ERTS 网络任务,因此它由 ERTS 编译而没有错误,ERTS 应该使用默认为 Clang 的 OS C 语言编译器,并且应该像我一样添加包含的 headers 文件,那么为什么当我尝试这样做时这不起作用?

https://ibb.co/bbtFHZ7

https://ibb.co/sF8QsDx

https://ibb.co/Lh9cDCH

https://ibb.co/W5Gcj7g

要事第一:

In my knowledge the ERTS compile these drivers at boot time

不,ERTS 不编译驱动程序。 inet_drv.c 被编译为 Erlang/OTP 的一部分并链接到 beam.smp 二进制文件。

inet_drv 不是典型的驱动程序。引用文档的 How to Implement a Driver 部分:

A driver can be dynamically loaded, as a shared library (known as a DLL on Windows), or statically loaded, linked with the emulator when it is compiled and linked. Only dynamically loaded drivers are described here, statically linked drivers are beyond the scope of this section.

inet_drv 是一个静态加载的驱动程序,因此不需要用 erl_ddll.

加载

关于编译错误。当你 运行 make 时,所有编译器参数都会自动为你添加,所以如果你需要手动调用编译器,最好只检查 make 生成的命令行并从那里开始。让我们看看the build log for the Debian Erlang package。搜索 inet_drv 我们得到这个命令行(添加了换行符):

x86_64-linux-gnu-gcc -Werror=undef -Werror=implicit -Werror=return-type  -fno-common \
  -g -O2 -fno-strict-aliasing -I/<<PKGBUILDDIR>>/erts/x86_64-pc-linux-gnu    -D_GNU_SOURCE \
  -DHAVE_CONFIG_H -Wall -Wstrict-prototypes -Wpointer-arith -Wmissing-prototypes \
  -Wdeclaration-after-statement -DUSE_THREADS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS \
  -D_POSIX_THREAD_SAFE_FUNCTIONS   -DBEAMASM=1 -DLIBSCTP=libsctp.so.1 \
  -Ix86_64-pc-linux-gnu/opt/jit -Ibeam -Isys/unix -Isys/common -Ix86_64-pc-linux-gnu \
  -Ipcre -I../include -I../include/x86_64-pc-linux-gnu -I../include/internal \
  -I../include/internal/x86_64-pc-linux-gnu -Ibeam/jit -Ibeam/jit/x86 -Idrivers/common \
  -Idrivers/unix -c \
  drivers/common/inet_drv.c -o obj/x86_64-pc-linux-gnu/opt/jit/inet_drv.o

由于您是在 FreeBSD 上构建的,所以其中一些会有所不同,但原则是成立的 - 大多数时候您只想 运行 make 而不是直接调用编译器, 但如果你需要调用编译器,那么从 make 为你生成的命令行开始会容易得多。