由未解决的外部符号错误困惑

时间:2009-08-27 21:19:30

标签: c linker linker-errors cl.exe unresolved-external

我正在尝试用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是定义的声明。

可能导致链接器错误的是什么?

4 个答案:

答案 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)。

之后它变得干净了。