我正在尝试用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);
}
的build.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是定义的声明。
可能导致链接器错误的是什么?
答案 0 :(得分:2)
不,它没有定义(至少在你引用的内容中)。它被宣布了。 “extern”关键字表示“此符号的定义出现在另一个编译单元(源文件)中。”您需要链接到通过编译定义该符号的源文件生成的目标文件(或库)。
答案 1 :(得分:1)
在C或C ++中“声明”某些内容与“定义”内容之间存在细微差别。当您声明它时,它会告诉编译器某个符号将在其他地方定义 - 这可以允许代码使用该符号而无需查看实际定义。您仍然需要在链接的代码中的某处定义符号,否则您将收到您看到的错误消息。
例如,这是符号WinDynDriverCallbacks
:
extern TWinDynDriverCallbacks WinDynDriverCallbacks;
您的代码具有此声明 - 它允许使用该符号的代码成功编译(但不能链接)。
您需要在某处添加定义:
TWinDynDriverCallbacks WinDynDriverCallbacks;
定义必须放在某处的源代码文件中(通常不在头文件中)。这告诉编译器在该对象的目标代码中分配空间,并允许程序成功链接。
答案 2 :(得分:1)
我在Windows上构建NIF时遇到了类似的问题。未解析的外部符号_WinDynNifCallbacks。事实证明这是由ERL_NIF_INIT宏定义的,在我的情况下,整个宏需要包含在一个extern C块中。
即失败
extern "C" ERL_NIF_INIT(...)
虽然成功了
extern "C"
{
ERL_NIF_INIT(...)
}
我强烈怀疑这个问题是由于同样的问题,但是使用了erlang端口驱动程序的DRIVER_INIT宏。
答案 3 :(得分:0)
Driver_Init是声明“TWinDynDriverCallbacks WinDynDriverCallbacks”的主循环;但它在driver_init的多行定义中正确声明。你不应该把它包装在extern“c”中。
因为这个线程在尝试设置我的准系统erlang端口驱动程序时出现了大约一百万次,我会在这里说。我正在编写Joe Armstrong的编程erlang书,第12章接口技术。使用erl5.9和vs2010。
本书中的代码在example1_lib.c中有遗漏和错误。虽然错误很可能是由于书的年龄与erlang版本的变化有关。
需要在example1_lib.c的最顶部设置(#define WIN32 ),否则erlang默认为所有Linux选项。
需要在example_drv_output中将(int bufflen)更改为(ErlDrvSizeT bufflen)。
之后它变得干净了。