因无法解析的外部符号错误而感到困惑
-
20-09-2019 - |
题
我正在尝试使用 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)。
之后它就干净了。