views:

225

answers:

2

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?

+2  A: 

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.

Tyler McHenry
There is no object file or library. All I have are header files. The instructions I'm going by do not link with any libs.
David Brown
Header files do not contain variables or code. They contain only declarations. There is absolutely nothing you can do with "just header files". Either your instructions are wrong, or you are misunderstanding them.
Tyler McHenry
I just noticed that the word Driver keeps appearing. Are you trying to build a Windows device driver? If so, the symbol may be in the Windows kernel, and someone who knows more about writing Windows drivers can comment on how to accomplish what you want.
Tyler McHenry
So how can the TWinDynDriverCallbacks struct appear in another source file if it's "declared" in the same file it's being used in?
David Brown
Also, it's not a windows driver. It's an Erlang port driver (basically a DLL that gets called from an Erlang program).
David Brown
*Declarations* mean "this is a name for something that will appear in this program". *Definitions* mean "please allocate memory (for a variable) or generate code (for a function) at this point in the program and assign this name to it." Any given symbol can have as many declarations as you want, so long as they all agree on what the types involved are. A symbol can have only one definition, because its memory (or code) can exist in only one place in the executable. Declarations are used to tell the compiler about symbols you are using that come from files other than the one you are compiling.
Tyler McHenry
Thanks for explaining it. I didn't look far enough into the code. WinDynDriverCallbacks gets defined when DRIVER_INIT is called, which I'm not doing since this isn't a real port driver. So I just defined it myself and everything works.
David Brown
A: 

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.

1800 INFORMATION
I have absolutely no idea why that works, but it sure does. Why is it that every single Erlang port driver I can find doesn't need to use this?
David Brown
They must be doing something equivalent - or they are not making use of that symbol so the linker does not need to have a definition
1800 INFORMATION
There may be a .lib file that you need to link against that contains the definition, for example - it may be part of the SDK you are using
1800 INFORMATION
I guess I won't think too much into it. At least it works now. Thanks!
David Brown