0

I've read many of the answers on SO regarding unresolved externals, but only one seemed close to my situation (Unresolved external symbol for some function calls but not all), but the answers don't help.

Here's my situation: I'm using VS 2015 and compiling a .dll that uses several static libraries. (All the libraries are part of my VS 'project' - meaning I'm in control of all the code - I'm not using libraries from other sources yet).

By the way, I'm using the term "library" pretty loosely here. These are all C++ 'projects' in my VS 'solution' that create static libs, but they're mostly meant for code organization. They're not meant to be used in other projects or by other coding groups.

I have a global function that can be called in the library code. The declaration is in a header file that I #include where I want to use the function (the header file uses both #pragma once, and #ifndef guards). The definition is in the .dll code.

Here's what I don't understand: If I use the global function in some of the classes defined in my libraries, I'll get an unresolved external error. But, I can comment out the line, and the the .dll will compile, link, with other places in the code, from the same "library", successfully using the global function, called in the same manner. I run the code with a simple console app and the places that use the global function do indeed get appropriate returns from it. So, the global function does get resolved correctly.

From what I've read about 'unresolved external' errors, it seemed to me that either the linker should be able to resolve a reference, or not. If not, then shouldn't any of the calls to the global function result in an unresolved external, and keep the code from linking?

I feel like I'm missing something fundamental here. I'm not quite sure how go about trying to solve this. Instinct says to compare the code where it works (global function call doesn't cause linker errors) with where it doesn't. But, I can't see a difference from a linking perspective. All of the files that use the global function have to include the header with the function declaration, which they do (or the compiler would complain).

Any ideas, suggestions or insights are welcome. If you made it this far, well, thanks for your time!

Just in case the actual error might be helpful, here it is:

WindogEngineLibd.lib(ColumnFinder.obj) :
error LNK2019: unresolved external symbol "class IUserPreferences & __cdecl global_user_prefs::GetUserPreferences(void)" (?GetUserPreferences@global_user_prefs@@YAAEAVIUserPreferences@@XZ) referenced in function "public: class std::vector<struct std::pair<class std::weak_ptr<class CDataColumn const >,class std::weak_ptr<class CDataColumn const > >,class std::allocator<struct std::pair<class std::weak_ptr<class CDataColumn const >,class std::weak_ptr<class CDataColumn const > > > > __cdecl CColumnFinder::EvaluateDualExpressions(class CColumnExpression,class CColumnExpression)const " (?EvaluateDualExpressions@CColumnFinder@@QEBA?AV?$vector@U?$pair@V?$weak_ptr@$$CBVCDataColumn@@@std@@V12@@std@@V?$allocator@U?$pair@V?$weak_ptr@$$CBVCDataColumn@@@std@@V12@@std@@@2@@std@@VCColumnExpression@@0@Z)

Edit 1

I'm going to add some pseudo code to (hopefully) make my situation more clear.

FileA.h in static lib 1 (the header file I include where needed)

float GlobalFunction();

FileB.cpp in static lib 2 (.cpp file for one class that uses GlobalFunction)

#include FileA.h;

float ClassWidget::UseGlobalValue()
{
    return GlobalFunction() * 2.0f; // no problem with this line
}

FileC.cpp in static lib 2 (.cpp file for another class that tries to use GlobalFunction, in the same library as ClassWidget)

#include FileA.h;

float ClassThingy::TryToUseGlobalValue()
{
    return GlobalFunction() * -1.0f; // uncommenting this line will cause link error
}

In the .dll project, I include the same header file:

FileDll.h

#include FileA.h;

And then define the function:

FileDll.cpp

float GlobalFunction()
{
    return 2.0f;
}

If I comment out the definition of 'GlobalFunction' in FileDll.cpp, then all of the calls to 'GlobalFunction' cause unresolved external errors when I compile the .dll. With it there, all of the errors are resolved (including the one in ClassThingy).

When I try to use my .dll in a console app, the call to GlobalFunction in ClassThingy causes a link error, while the call in ClassWidget does not.

I'm pretty certain this has to do with way the .dll is getting linked, but I can't figure out how. If I create a console app that uses the static libs directly, and have it define 'GlobalFunction' - everything is fine, no link errors. If the console app were my goal, I'd just do that. But, the .dll is my goal - the console apps are just for testing.

I looked into using the 'extern' keyword, but from what I can tell, that's superfluous for file scoped functions.

Thanks again for any help, insight.

  • 1
    Suggestion: Look for different compile options between the modules that link successfully and those that don't. – Carey Gregory Jun 23 '17 at 23:54
  • Does library link order matter for the MS linker? (The documentation I found suggests not.) – aschepler Jun 23 '17 at 23:57
  • @Carey Gregory, thanks for your suggestion. The different calls to the global function come from different classes in the same library. So, I think that means they are in the same 'module', right? At least, I wouldn't know how to set different compile options between them. – user3074363 Jun 24 '17 at 11:01
  • What I mean is make sure the compile options for source files that call the functions *and* the functions themselves are all identical, or at least compatible. – Carey Gregory Jun 24 '17 at 15:16
  • ClassThingy should be baked into the DLL and never produce a link error. Since it was linked when you created the DLL. So it is *not* baked, probably because it appears in a .h file that the client code also #includes. A detail that isn't visible in the question at all. Now there's trouble, you probably forgot to export GlobalFunction. Get somewhere by partitioning the code better, decide what you are going to export and minimize the footprint. And beware that you almost always need __declspec(dllexport) to export a class, a .def file can't cut it. – Hans Passant Jun 25 '17 at 12:58
  • @Hans - Thank you. I will pursue this and post what I figure out. I think you just saved me a lot of time! – user3074363 Jun 25 '17 at 21:34
  • @Hans Yup, you did save me a lot of time. Thanks, I appreciate your insight. You were basically correct about the class being included in a .h file that the client also included. If you would like credit for an answer [doesn't look like you **need** any more credit, ;-)], I'll be happy to accept your comment as an answer. – user3074363 Jun 26 '17 at 11:42

0 Answers0