简体   繁体   English

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

[英]Confused by Unresolved external symbol error

I'm trying to build a wrapper library with VC++'s compiler. 我正在尝试用VC ++的编译器构建一个包装器库。

ErlDriver.c 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 运行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 ErlDriver.obj:错误LNK2019:函数__driver_output中引用的未解析的外部符号_WinDynDriverCallbacks

erl_win_dyn_driver.h (included in erl_driver.h ) 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)

So, as you can see, WinDynDriverCallbacks is defined declared. 因此,正如您所看到的,WinDynDriverCallbacks已 定义 为声明。

What could be causing the linker error, then? 那可能导致链接器错误的原因是什么?

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)." “extern”关键字表示“此符号的定义出现在另一个编译单元(源文件)中。” You need to be linking with the object file (or library) produced from compiling the source file that defines that symbol. 您需要链接到通过编译定义该符号的源文件生成的目标文件(或库)。

There is a subtle difference between "declaring" something and "defining" it in C or C++. “声明”某些东西与用C或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 : 例如,这是符号WinDynDriverCallbacks的声明:

extern TWinDynDriverCallbacks 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: 您需要在某处添加定义:

TWinDynDriverCallbacks WinDynDriverCallbacks;

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. 这告诉编译器在该对象的目标代码中分配空间,并允许程序成功链接。

I got a very similar problem building a NIF on Windows. 我在Windows上构建NIF时遇到了类似的问题。 Unresolved external symbol _WinDynNifCallbacks. 未解析的外部符号_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. 事实证明这是由ERL_NIF_INIT宏定义的,在我的情况下,整个宏需要包含在extern C块中。

ie this failed 即失败了

extern "C" ERL_NIF_INIT(...)

while this succeeded 虽然这成功了

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

I strongly suspect this problem is due to the same issue but with the DRIVER_INIT macro for an erlang port driver. 我强烈怀疑这个问题是由于同样的问题,但是对于erlang端口驱动程序使用DRIVER_INIT宏。

Driver_Init is the main loop that declares "TWinDynDriverCallbacks WinDynDriverCallbacks;" Driver_Init是声明“TWinDynDriverCallbacks WinDynDriverCallbacks;”的主循环。 but it's properly declared in the multiple line define for driver_init. 但它在driver_init的多行定义中正确声明。 You shouldn't need to wrap it in extern "c". 你不应该把它包装在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. 因为这个线程在尝试设置我的准系统erlang端口驱动程序时出现了大约一百万次,我会在这里说。 I am working out of Joe Armstrong's programming erlang book, chapter 12 interfacing techniques. 我正在编写Joe Armstrong的编程erlang书,第12章接口​​技术。 Using erl5.9 and vs2010. 使用erl5.9和vs2010。

The code in the book had a omission and a error in example1_lib.c. 书中的代码在example1_lib.c中有遗漏和错误。 Though the error is most likely due to the age of the book versus erlang version changes. 虽然错误很可能是由于书的年龄与erlang版本的变化。

Needed to set (#define WIN32 ) at the very top of example1_lib.c otherwise erlang defaulted to all the Linux options. 需要在example1_lib.c的最顶部设置(#define WIN32 ),否则erlang默认为所有Linux选项。

Second needed to change (int bufflen) to (ErlDrvSizeT bufflen) in example_drv_output. 第二个需要在example_drv_output中将(int bufflen)更改为(ErlDrvSizeT bufflen)。

After that it built clean. 之后,它建立了干净。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM