Question

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?

Was it helpful?

Solution

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:

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.

OTHER TIPS

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.

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

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top