我正在尝试使用 VC++ 的编译器构建一个包装库。

ErlDriver.c

#define __WIN32__
#define DLL_EXPORT __declspec(dllexport)

#include "erl_driver.h"

DLL_EXPORT int _driver_output(ErlDrvPort port, char *buf, int len) {
    return driver_output(port, buf, len);
}

构建.bat

cl /I%ERL_DRIVER_H% /LD /MD ErlDriver.c

当我尝试构建它时,出现以下链接器错误:

ErlDriver.obj:错误LNK2019:函数 __driver_output 中引用的未解析的外部符号 _WinDynDriverCallbacks

erl_win_dyn_driver.h (包括在 erl_driver.h)

typedef struct {
    WDD_FTYPE(driver_output) *driver_output;
    // a ton more of those
} TWinDynDriverCallbacks;

extern TWinDynDriverCallbacks WinDynDriverCallbacks;

#define driver_output (WinDynDriverCallbacks.driver_output)

因此,如您所见,WinDynDriverCallbacks 是 定义的 宣布。

那么什么可能导致链接器错误呢?

有帮助吗?

解决方案

有是“声明”的东西,在C或C“定义”它++之间细微的差别。当你声明它,它告诉某一个符号将被其他地方所定义的编译器 - 这可以让代码使用该符号,而不需要看到实际的定义。你仍然需要在链接代码中的某处定义符号,否则你会得到你所看到的错误消息。

例如,这是符号WinDynDriverCallbacks的声明:

extern TWinDynDriverCallbacks WinDynDriverCallbacks;

您的代码有该声明 - 它允许使用符号成功地编译代码(但不是链接)

您需要的地方添加一个定义:

TWinDynDriverCallbacks WinDynDriverCallbacks;

定义必须进入一个源代码文件某处(未通常在头文件中)。这告诉编译器在该对象的对象代码分配空间并允许程序成功链接。

其他提示

没有,这不是(至少在你引用的)定义。它的声明。所述“外部”关键字的意思是“用于此符号的定义出现在另一个编译单元(源文件)”。您需要与从编译,它定义了符号的源文件生成的目标文件(或文库)来链接。

我有一个非常类似的问题在Windows上建立一个NIF。解析的外部符号_WinDynNifCallbacks。原来这是由ERL_NIF_INIT宏观和在我的情况下需要被包围在外部C块整个宏定义。

即,该失败

extern "C" ERL_NIF_INIT(...)

而这成功

extern "C"
{
   ERL_NIF_INIT(...)
}

我强烈怀疑这个问题是由于同样的问题,但与DRIVER_INIT宏一个Erlang端口驱动程序。

Driver_init是声明“ TwindyndriverCallbacks WindyndriverCallbacks的主要循环;”但是在多行定义driver_init中正确声明了它。您不需要将其包装在 extern "c" 中。

因为这个线程在尝试设置我的准系统 erlang 端口驱动程序时出现了大约一百万次,所以我会在这里说这一点。我正在研究 Joe Armstrong 的 erlang 编程书籍,第 12 章接口技术。使用erl5.9和vs2010。

书中的代码在example1_lib.c中有遗漏和错误。尽管该错误很可能是由于本书的年龄与 erlang 版本的变化所致。

需要设置(#define WIN32)位于 example1_lib.c 的最顶部,否则 erlang 默认为所有 Linux 选项。

其次需要将 example_drv_output 中的 (int bufflen) 更改为 (ErlDrvSizeT bufflen)。

之后它就干净了。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top