对未解析的外部符号错误感到困惑

Confused by Unresolved external symbol error

提问人:David Brown 提问时间:8/28/2009 最后编辑:David Brown 更新时间:2/15/2013 访问量:1729

问:

我正在尝试使用 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 链接器 链接器错误 cl.exe 未解决外部

评论


答:

2赞 Tyler McHenry 8/28/2009 #1

不,它没有定义(至少在你引用的内容中)。它被宣布。“extern”关键字表示“此符号的定义出现在另一个编译单元(源文件)中”。您需要与通过编译定义该符号的源文件生成的对象文件(或库)进行链接。

评论

0赞 David Brown 8/28/2009
没有对象文件或库。我所拥有的只是头文件。我正在使用的说明不与任何库链接。
0赞 Tyler McHenry 8/28/2009
头文件不包含变量或代码。它们仅包含声明。“只是头文件”绝对无能为力。要么你的指示是错误的,要么是你误解了它们。
0赞 Tyler McHenry 8/28/2009
我刚刚注意到司机这个词不断出现。您是否正在尝试构建 Windows 设备驱动程序?如果是这样,则该符号可能位于 Windows 内核中,并且对编写 Windows 驱动程序有更多了解的人可以评论如何完成您想要的任务。
0赞 David Brown 8/28/2009
那么,如果 TWinDynDriverCallbacks 结构在使用它的同一文件中“声明”,它如何出现在另一个源文件中呢?
0赞 David Brown 8/28/2009
此外,它不是 Windows 驱动程序。它是一个 Erlang 端口驱动程序(基本上是从 Erlang 程序调用的 DLL)。
1赞 1800 INFORMATION 8/28/2009 #2

在 C 或 C++ 中“声明”某物和“定义”它之间存在微妙的区别。当你声明它时,它会告诉编译器某个符号将在其他地方定义 - 这可以允许代码使用该符号,而无需查看实际定义。您仍然必须在链接的代码中的某个位置定义符号,否则您将收到您看到的错误消息。

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

extern TWinDynDriverCallbacks WinDynDriverCallbacks;

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

您需要在某处添加定义:

TWinDynDriverCallbacks WinDynDriverCallbacks;

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

评论

0赞 David Brown 8/28/2009
我完全不知道为什么会这样,但确实如此。为什么我能找到的每个 Erlang 移植驱动程序都不需要使用它?
0赞 1800 INFORMATION 8/28/2009
他们必须做一些等效的事情 - 或者他们没有使用该符号,因此链接器不需要有定义
0赞 1800 INFORMATION 8/28/2009
例如,您可能需要链接到包含定义的 .lib 文件,它可能是您正在使用的 SDK 的一部分
0赞 David Brown 8/28/2009
我想我不会想太多。至少它现在有效。谢谢!
1赞 Gary 12/22/2011 #3

我在 Windows 上构建 NIF 时遇到了一个非常相似的问题。未解析的外部符号_WinDynNifCallbacks。事实证明,这是由 ERL_NIF_INIT 宏定义的,在我的情况下,整个宏需要包含在外部 C 块中。

即这失败了

extern "C" ERL_NIF_INIT(...)

虽然这成功了

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

我强烈怀疑这个问题是由于相同的问题造成的,但与 erlang 端口驱动程序的 DRIVER_INIT 宏有关。

0赞 jason 2/15/2013 #4

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

在那之后,它变得干净了。