Our project is a VS2008 based project using Boost and Qt heavily. However, today we have a new linking problem that doesn't make any sense.
What is happening is that during the link
For program A, our static library Foobar is finding links to 5 of the 8 member functions.
For program FoobarUnitTest, everything from Foobar links and runs fine.
For program B, our library Foobar2 is a DLL. During the link, it finds all of the member functions except for the constructor and destructor.
When I say the linker finds some of the member functions, what I did was link with /VERBOSE option on. I then went and examined the resulting buildlog.htm file and I could see where the linker was finding some of the functions from the libraries. Linker error is `"error LNK2019: unresolved external"
Also, the same thing happens in 32bit or 64bit - debug or release mode.
Any suggestions as to where to look?
Hard to give any meaningful advice for such a nebulous question but here are a couple things to check out. The linker reports "unresolved externals" when the header says there's a function named "x::y()" but it can't find that function in the lib file. Keep in mind that this assumes you have in fact implemented the functions in question. Ultimately however, whatever the problem ends up being, it will be some morphing of "you told me there's a function named x::y(), but then you didn't implement a functon named x::y()."
So, step zero is make sure you actually have implemented these functions. OK, lets assume you have.
Step 1 is make sure you are declspec(__dllexport)ing the functions in the library's implementation, and declspec(__dllimport)ing the functions on the client side. I use macros for this:
MyFancyLib.h:
#ifndef MYLIB_API
# define MYLIB_API (declspec(__dllimport))
#endif
MYLIB_API void DoIt();
MyFancyLib.CPP:
// this should be moved to stdafx.h or something sufficiently low-level
#define MYLIB_API (declspec(__dllexport))
MYLIB_API void DoIt()
{
// magic happens
}
Step 2: Make sure you've really named things properly in the implementation. One of my most common mistakes is to declare a member function of a class or namespace, say namespace Foo { void DoIt(); };, and then forget to fully-qualify the class or namespace in the implementation. If you never call the function in your implementation, the linker may never look for it.
MyLib.h:
namespace lib
{
MILIB_API void DoIt();
};
MyLib.cpp:
MYLIB_API void DoIt()
{
// magic happens
};
This will generate an unresolved external. The CPP should look like this:
MyLibCorrect.cpp:
MYLIB_API void mylib::DoIt()
{
// magic
}
Step 3: Make sure you're linking to everything you need to link to. This might seem more like step-0 or step-1, but assuming you've linked to everything you think you need, this step can be hard. Look through the names the linker is complaing about, do some undecoration of them and search your library's code for the implementation of those functions. You may find they are exported from a project other than the one you think they're exported from.
Related
I am developing a static library A with a mix of Objective C and C++ in Xcode, I run into the need to "weak link" another static library and Let's call it B. A calls some methods defined in B. The idea is that if B is not linked/provided, A will not throw any undefined symbols error.
I know that in Objective C you can do that and in code I can rely on run time methods such as NSClassFromString or [someObject Class] to check if a certain function is present/available from another static library, but I don't know if I can achieve that in one of my .cpp source file. Please advise and thank you!
I created a very simple sample project for illustration purpose:
Library A:
Core_ObjC.h, this is the header that will be exposed
#import <Foundation/Foundation.h>
#interface Core_Objc : NSObject
-(int) calculate;
#end
Core_ObjC.mm
#import "Core_ObjC.h"
#include "Core_CPP.h"
#implementation Core_Objc
-(int) calculate{
return calculate_Core();//Call into cpp here
}
#end
Core_CPP.cpp
#include "Core_CPP.h"
#include "NonCore_CPP.h"
int calculate_Core(){
return calculate_NonCore();//Call into another cpp here but it's defined in Library B
}
Library B:
NonCore_CPP.cpp
#include "NonCore_CPP.h"
int calculate_NonCore(){
return 100;
}
If I link both libraries in a sample app, the app will compile fine. However, when I link only A from the sample app, I will encounter error like:
Undefined symbols for architecture arm64:
"calculate_NonCore()", referenced from:
calculate_Core() in CoreFramework(Core_CPP.o)
The error does make sense to me because B will have the missing definition, but I am just looking for a solution that the compilation won't complain when there is only A.
So, weak linking works at the C function level as well. For details, see Apple's documentation but basically, the symbol needs to be declared using __attribute__((weak_import)), as follows
extern int MyFunction() __attribute__((weak_import));
extern int MyVariable __attribute__((weak_import));
and then you can check if its address is zero to check if it was found during link time, using e.g. if (MyFunction != NULL) or if (&MyVariable != NULL).
Your title mentions static libraries. Note that static libraries are just collections of object files, so you either link the library or you don't; there's no weak linking a static library, because by definition, it's present at build time. Or not. If you want runtime behaviour, use a dynamic library. (dylib)
The above should actually cover the example you have given: you'll just need to provide alternative code for when calculate_NonCore is unavailable, as you can't call it without crashing the program. (Makes sense, it's missing)
You mention C++ too, although your code doesn't make any obvious use of it. C++ makes this a little more complicated because of its mangled names; additionally, classes themselves don't have any linkage, so you can't test for presence of a class. The compiler seems to allow applying the weak_import attribute to member functions, static member variables, etc. but I'm not sure to what extent the NULL checks will work. Free functions should certainly not be an issue - treat them like C functions - and I'd guess that static members are probably a good candidate because you can easily take their address.
I'd probably try to avoid calling into any code that makes use of any part of a class that might not be there, and set things up such that you can simply check for the presence of a "canary" static member variable or function, which, if present, you can conclude that the whole class is present.
I am currently working on a project with some old poorly documented code, and am trying to navigate my way through the various .h files that they have provided complete documentation on the use of all of the functions contained (the definitions are held in .lib and .dll files). One of the .h files has functions the are not only declared, but defined with either simple return statements or empty statements as such
class DLL ExampleLibraryClass {
public:
int exampleGetValue() {return 0;}
void exampleSetValue(Type val) {;}
void exampleActionFxn() {;}
};
These would be functions that I expect to return current variable states or perform certain actions, which is why this puzzles me.
Additionally:
I have used Dependency Walker and found that each function does have a matching definition in a dll.
The Keyword DLL has been defined with
#ifndef _PWSDLL_
# define _PWSDLL_
# define WINCALL _stdcall
# ifdef _USRDLL
# define DLL __declspec(dllexport)
# else
# define DLL __declspec(dllimport)
# endif
#endif
_USRDLL is not defined and therefore DLL is defined as __declspec(dllimport)
My question revolves less about the apparent effect of the empty definitions (which do nothing I suppose, and have already been discussed on SO) and more about why the .h file has been written this way and how to utilize the file. Is this a common or known practice? Will the linker still look for definitions to the function in my linked libraries? Are there other pieces of code that I should look for for more clues? Or perhaps in the broadest sense, how should I respond to this?
Many thanks, and please let me know if you need more information to address this, I am unsure what exactly is important in this matter.
EDIT: Added forgotten return types in example code.
EDIT: Added note about DLL definition.
One scenario where you put this code to some use would be to override the functions. These functions hold some default code and could be overridden later.
This question might be similar to
DLL Exports: not all my functions are exported
but as it was not fully answered there, I have to ask again. Also my case is because of the use of templates and exporting the whole classes slightly different.
Used environment: VS2008, cl9.0.
I have created a dll-project and added about 40 files (each class a file), mainly headers, because a lot of the classes are templates. An example of the heritage would be:
// Class1.h
template<class TYPE>
class TInt
{
// Some member functions here
// Also a function bool IsValid() const;
};
// Implementation of template here in the header
// Class2.h
#ifndef DllExpImpM
#define DllExpImpM __declspec(dllimport)
#endif
class DllExpImpM CInt : public TInt<double>
{
// Some member functions here
};
// Class2.cpp
// Some includes, including "stdafx.h", which sets DllExpImpM
// to __declspec(dllexport)
template class DllExpImpM TInt<double>;
// Implemenation of CInt
So far, it worked fine as long as I used the debug (compile) option. I was able the use the dll project from other projects.
But if the dll projekt is compiled as release (which works fine), I cannot use it from other projects, because the compiler complains that are some missing functions, e.g. that IsValid() in TInt. I used the dependency walker to check it, and indeed, the compiler is right! The member function IsValid() was not exported, along with another function and with a constructor und the destructor. All other member functions of TInt are exported, I can see them using the dependency walker, I can use them from other projects. This also happens in a similar way with one other class.
I then compared the debug dll and the release dll using the dependency walker and winmerge. They are almost identical, just that the release dll is missing a few functions (about 3 %).
I have no idea what is wrong. I know that I do not have a lot information (the whole information is much too big and I yet could not find a simple example that does not work) and to me all sounds a little bit weird. But perhaps anyone out there once had the same problem. I appreciate every idea very much.
Thank you!
If it works for debug, but not release, then you need to identify what is different. My first guess would be that a #define macro or an equivalent /D macro us not getting defined or is getting defined wrongly.
Maybe DllExpImpM or maybe something else.
If not a macro, then what else changes between builds?
Here are some things I found when I ran into this.
I had the same issue, but taking off the /GL parameter didn't make any difference.
My first test was creating a very simple funcion - void test () - and trying to export it. That didn't work until I got rid of the whole output directory (x64 in my case) and rebuilt it all. It would guess that some intermediate file was messing my compilation, anyway, I didn't investigate it further.
But there was still one function that wouldn't be exported. I took some time to realize the declaration in the .h file wasn't matching exatly the signature in the .cpp file! I was missing a parameter in the .h file... I don't know why it was even compiling, anyway, fixing that allowed the function to be exported.
I have two modules, each with own class and with own object. Each module is compiled to a DLL. I want to make a "cross-DLL" method call, having pointer to the object of another class, but linker doesn't allow to do this (MSVC++ 2008).
More specifically:
there is calledModule.cpp, that has calledClass, and object of this class (calledObject); class has calledMethod, which I want to call; module is compiled to DLL and becomes (surprise!) calledLib.dll.
there is callingModule.cpp, that has callingClass; among other things, the class has the attribute, which is a pointer to the calledObject; module is compiled to DLL callingLib.dll; the pointer on calledObject is set in the constructor.
I'm able to compile the whole code. The trouble comes when the linker starts. I'm getting the following:
moduleCalling.obj : error LNK2001: unresolved external symbol "public: void __thiscall classCalled::methodCalled ..."
I don't use any declspec things, so nothing is exported from the calledLib.dll.
The method that I'm calling (methodCalled) is present in the implementation, its prototype is correctly declared in header. The classCalled is a "basic" class, not inherited from anything.
Moreover, the whole project compiles and working correctly, when I declare methodCalled as a virtual...
I have troubles understanding, why I can't call the method of the object in a "normal" way from another DLL? Why declaring it as a "virtual" helps? Anyone knows? I have some guesses, but expert answer will help a lot to understand this stuff.
P.S.: I'm using MSVC++ 2008.
Thanks!
Update: adding code snippet, which reflects, how the code looks like.
// part of calledLib.dll
// moduleCalled.h
class classCalled {
public:
int methodCalled() { return 1 };
};
// ---------------------------------------------------------------
// part of callingLib.dll
// moduleCalling.h
#include "moduleCalled.h"
class classCalling {
public:
classCalled* ref;
void justSomeMethod();
};
// ---------------------
// moduleCalling.cpp
#include "moduleCalling.h"
void classCalling::justSomeMethod() {
ref = new classCalled();
int a = ref->methodCalled(); // <--- this is not allowed by linker,
// unless methodCalled is made virtual.
}
Linker links pieces of code from various modules. If you have a call from one module to another, linker has to know in which other module the function you're invoking is implemented and substitute the call by the real address. This is a very rough picture, but it's enough to understand what is going on.
In your case the linker has to know that your function is located in calledLib.dll. Therefore you have to link with something that refers to calledLib.dll. This something is called an import library. It's name should be calledLib.lib. In order to generate it you either should write a .def file, but it's difficult for class methods, since class methods names used by linker look very different from what they look like in your C++ code. Or you can use declspecs. It will generate the proper calledLib.lib, which you will have to link with your callingLib.dll.
I am a little out of my depth here, I'll be honest.
I am doing some rather curious experimentation, having pre-main functions register my classes in a factory, through anonymous namespaces. Until recently, adding the following to a class definition (.cpp) would do the trick.
namespace { int x = Register<classType>(className); }
This would be wrapped in a macro and 'Register' would pass the type and name off to my factory.
This worked fine and every class that included this macro was getting registered, until I went to move the code into a static library. Now, since the classes are only referenced by the factory, it looks like they're being omitted from the build - my 'Register' functions are no longer being called and so my factory is empty.
I have managed to fix this by moving all my macros into the constructor of a manager object, but I noticed that as soon as I referenced them there, the macros in the .cpp files started getting called again. I guessed because now the classes are actually being referenced by something.
However, I don't really want to do it this way and I can't seem to find a non-committal way of referencing the classes in the constructor (e.g class ClassToRegister;) which includes them in the build, so that my register macros will get called.
Firstly, does this make sense?
Secondly, any advice on how I can force these TUs to compile so that the anonymous namespaces 'kick in' at runtime?
It appears this is part and parcel of using static libraries; unused code will not make it through without linker voodoo.
A static library is a bunch of object files you give the linker saying "hey, find here what I didn't define elsewhere". So if a given object file in the library doesn't fill a dependency, you won't be able to include it in your program without relying on other features of the linker (for instance some linkers have a way to include all the object files of static libraries instead of only the one who fill dependencies).
Most likely you are a victim of aggressive optimisation, but with a reason : since you do not use objects in a nameless namespace, the compiler removes them.
You could try to get around like this :
namespace foo
{
namespace{
MACRO_TO_DEFINE_VARIABLE( MyClass ); // define a variable named registrationObj
};
MyClass::MyClass()
{
(void)registrationObj;
}
}