因无法解析的外部符号错误而感到困惑
我正在尝试使用 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_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 是 已定义已声明。
那么什么可能导致链接器错误呢?
I'm trying to build a wrapper library with VC++'s compiler.
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
When I attempt to build this, I get the following linker error:
ErlDriver.obj : error LNK2019: unresolved external symbol _WinDynDriverCallbacks referenced in function __driver_output
erl_win_dyn_driver.h (included in 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)
So, as you can see, WinDynDriverCallbacks is defined declared.
What could be causing the linker error, then?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不,它没有定义(至少在你引用的内容中)。已宣布。 “extern”关键字的意思是“该符号的定义出现在另一个编译单元(源文件)中”。您需要链接通过编译定义该符号的源文件而生成的目标文件(或库)。
No, it's not defined (at least in what you quoted). It's declared. The "extern" keyword means "the definition for this symbol appears in another compilation unit (source file)." You need to be linking with the object file (or library) produced from compiling the source file that defines that symbol.
在 C 或 C++ 中“声明”某些东西和“定义”它之间存在细微的区别。当您声明它时,它告诉编译器某个符号将在其他地方定义 - 这可以允许代码使用该符号而无需查看实际定义。您仍然必须在链接的代码中的某个位置定义符号,否则您将收到所看到的错误消息。
例如,这是符号
WinDynDriverCallbacks
的声明:您的代码具有此声明 - 它允许使用该符号的代码成功编译(但不能链接)。
您需要在某处添加定义:
定义必须进入源代码文件中的某处(通常不在头文件中)。这告诉编译器在目标代码中为该对象分配空间,并允许程序成功链接。
There is a subtle difference between "declaring" something and "defining" it in C or C++. When you declare it, it tells the compiler that a certain symbol will be defined somewhere else - this can allow the code to use that symbol without needing to see the actual definition. You still have to define the symbol somewhere in the code that is linked in, or else you will get the error message you are seeing.
For example, this is a declaration of the symbol
WinDynDriverCallbacks
:Your code has this declaration - it allows the code that uses the symbol to successfully compile (but not link).
You need to add a definition somewhere:
The definition must go into a source code file somewhere (not generally in a header file). This tells the compiler to allocate space in the object code for that object and allows the program to link successfully.
我在 Windows 上构建 NIF 时遇到了非常类似的问题。无法解析的外部符号 _WinDynNifCallbacks。事实证明,这是由 ERL_NIF_INIT 宏定义的,在我的例子中,整个宏需要包含在 extern C 块中。
也就是说,这失败了,
而这成功了,
我强烈怀疑这个问题是由于同样的问题造成的,但使用了erlang端口驱动程序的DRIVER_INIT宏。
I got a very similar problem building a NIF on Windows. Unresolved external symbol _WinDynNifCallbacks. Turns out this is defined by the ERL_NIF_INIT macro and in my case the entire macro needed to be enclosed in a extern C block.
ie this failed
while this succeeded
I strongly suspect this problem is due to the same issue but with the DRIVER_INIT macro for an erlang port driver.
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)。
之后它就干净了。
Driver_Init is the main loop that declares "TWinDynDriverCallbacks WinDynDriverCallbacks;" but it's properly declared in the multiple line define for driver_init. You shouldn't need to wrap it in extern "c".
since this thread came up about a million times while trying to setup my barebones erlang port driver i will say this here. I am working out of Joe Armstrong's programming erlang book, chapter 12 interfacing techniques. Using erl5.9 and vs2010.
The code in the book had a omission and a error in example1_lib.c. Though the error is most likely due to the age of the book versus erlang version changes.
Needed to set (#define WIN32) at the very top of example1_lib.c otherwise erlang defaulted to all the Linux options.
Second needed to change (int bufflen) to (ErlDrvSizeT bufflen) in example_drv_output.
After that it built clean.