When I have an abstract base class foo, defined in libX.a
class foo {
virtual void bar() = 0;
};
... and a derived class foo_impl, defined in libY.a
class foo_impl : public foo {
void bar() { /* do something */ }
};
... and use both libraries to link a program -lX -lY
int main() {
foo* my_foo = receive_a_foo_from_somewhere();
my_foo->bar();
}
Then
how can I force the linker to actually link the symbol referring to foo_impl::bar()?
does objdump -t program list foo_impl::bar() when it is correctly linked?
EDIT: to clarify, I am using linux with gcc or clang
EDIT 2: had missed virtual for bar()
EDIT 4: I apologize for missing clarity. The question should have been "how can I force the linker to actually include foo_impl::bar() in the executable so it can be resolved at runtime?"
Since the bar method is defined as virtual, there is no need of static linking. The linking will be done dynamically at runtime based on the object type to which the *my_foo refers to. Regardless of whether it's defined in libX.a or libY.a.
Answer to you question how to force the linker to link the symbol referring to foo_impl::bar()?
You can't force the linker to link to particular implementation. The linking will happen based on which object address you got from receive_a_foo_from_somewhere().
Obviously the implementation should be linked to your exe. If it is not available it will definitely fail. But you can't force linker to link particular implementation,
It appears there are at least two ways to get the linker to include foo_impl::bar() functionality in the executable:
With gcc, one can use -Wl,--whole-archive to link an entire static library - no matter what.
As Captain Obvlious pointed out, when foo_impl is used in the program, it's virtual functions are tagged as having been used and are thus included in the executable. This could also be an otherwise useless static dummy foo_impl object.
Related
I have a static library which is generated from many cpp files on linux using g++. one header file contains a class which implements factory pattern
pseudo code in the header file as below
class Factory
{
public:
static Factory& instance();
Base * create(const std::string& name);
template<class T>
void register_class(const std::string& name);
}
template <class T>
class FactoryRegister
{
public:
FactoryRegister(const std::string& name)
{
Factory::instance().register_class<T>(name);
}
}
cpp file for Factory has the implementations. in another cpp file Derive.cpp, there is a class that I want to register into Factory. and I defined a global variable to do this. code as below
FactoryRegister<Derive> g_register_derive("derive");
all these files are compiled into one static library and is linked to one executable.
my understanding is that as the g_register_derive is not referenced by any code, it shouldn't be linked into the executable unless whole-archive option is provided.
the strange part is that if I put g_register_derive in Derive.cpp, it's true that this symbol is not linked into the executable. but if I put g_register_derive in Factory.cpp, it got linked into executable.
I used nm to verify the result, and there is also a line of code calls Factory::instance().create("Derive") which can also be used to check if g_register_derive is linked or not.
and of course if I provided whole-archive option, g_register_derive will always be linked into the executable.
See the Stackoverflow tag wiki about static-libraries
to understand linkage with static libraries, especially the fact that by default, an object file libx.a(p.o) in a static library is extracted and linked into a program only if the linker needs it.
If the linker needs to link an archive member libx.a(p.o) in order to
resolve some prior reference to a symbol foo that is defined in that object file,
then the definition of any other symbol bar that is also defined in libx.a(p.o)
is also linked into the program - because it is part of that object file - whether
bar is referenced by the program or not.
So, if you define g_register_derive in source file p.cpp which is compiled
to p.o and archived as libx.a(p.o), and your application needs to link
libx.a(p.o) for any reason, then by default1 g_register_derive becomes
defined in your program.
If you move the definition of g_register_derive to
q.cpp, which is compiled and archived as libx.a(q.o), and your application
does not need to link libx.a(q.o) for any reason, then g_register_derive
is not defined in your program.
[1] With non-default compilation and linkage options, you can remove definitions
of unused symbols from your program. See How to remove unused C/C++ symbols with GCC and ld? and the accepted answer.
Say, there is a third-party library that has the following in a header file:
foo.h:
namespace tpl {
template <class T, class Enable = void>
struct foo {
static void bar(T const&) {
// Default implementation...
};
};
}
In the interface of my own library, I'm supposed to provide partial specialization of this foo for my own type(s). So, let's say I have:
xxx.h:
# include <foo.h>
namespace ml {
struct ML_GLOBAL xxx {
// Whatever...
};
}
namespace tpl {
template <>
struct ML_GLOBAL foo<::ml::xxx> {
static void bar(::ml::xxx const&);
};
}
where ML_GLOBAL is a compiler-specific visibility attribute to ensure that the symbols are available for dynamic linkage (that is by default my build system hides all of the symbols in the produced shared library).
Now, I don't want to disclose my implementation of bar, so I employ explicit template instantiation:
xxx.cpp:
# include "xxx.h"
namespace tpl {
void foo<::ml::xxx>::bar(::ml::xxx const&) {
// My implementation...
}
extern template struct foo<::ml::xxx>;
}
When the time comes to actually use this tpl::foo<::ml::xxx>::bar function in some consumer application (where my shared library is linked as well), I get the undefined reference error to the tpl::foo<::ml::xxx, void>::bar symbol. And indeed, running nm -CD on the produced shared library shows no trace of tpl::foo<::ml::xxx, void> symbol.
What I've tried so far, were different combinations on where to put ML_GLOBAL (e.g. on explicit template instantiation itself, about what GCC clearly complains unlike Clang) and with/without the second template argument void.
The question is whether this is related to the fact that the original definition has no visibility attribute (ML_GLOBAL) attached by virtue of coming from a third-party library or did I actually miss something here? If I didn't miss anything, then am I really forced to expose my implementation in such a scenario ? [... *cough* looks more like a compiler deficiency to be honest *cough* ...]
It turned out to be a false alarm. Nevertheless, this catch took me a couple of hours to finally remember why this symbol might be invisible to consumers. It's really trivial but I feel like posting it here for future visitors who happen to have the same setup. Basically, if you use either a linker script [1] or a (pure) version script [2] (specified with the --version-script linker option), then don't forget to set global visibility for those tpl::foo* third-party-based symbols (or whichever they are in your case). In my case, I originally had the following:
{
global:
extern "C++" {
ml::*;
typeinfo*for?ml::*;
vtable*for?ml::*;
};
local:
extern "C++" {
*;
};
};
what I clearly had to change to
{
global:
extern "C++" {
tpl::foo*;
ml::*;
typeinfo*for?ml::*;
vtable*for?ml::*;
};
local:
extern "C++" {
*;
};
};
in order to link everything properly and get the expected result.
Hope this helps and regards.
BONUS
A curious reader could ask though, "Why the hell are you combining explicit visibility attributes and a linker/version script to control visibility of symbols when there are already the -fvisibility=hidden and -fvisibility-inlines-hidden options which are supposed to do just that?".
The answer is that they of course do, and I indeed do use them to build my shared libraries. However, there is one catch. It is a common practice to link some internal libraries (privately) used by your shared library statically (into that library), primarily in order to completely conceal such dependencies (keep in mind, though, that header files accompanying your shared library should also be properly designed to implement this). The benefits are clear: clean and controllable ABI and reduced compile times for shared library consumers.
Take for example, Boost, as the most widespread candidate for such a use case. Encapsulating all of the heavily templated code from Boost privately into your shared library and eliminating any Boost symbols from the ABI will greatly reduce interface pollution and compile times of your shared library consumers, not including the fact that your software components will also look professionally developed.
Anyway, to the point, it turns out that unless those static libraries that you want to link into your shared library were themselves also built with the -fvisibility=hidden and -fvisibility-inlines-hidden options (what would be a ridiculous expectation as nobody is going to distribute static libraries with hidden interface symbols by default as it defeats their purpose), their symbols will inevitably still be visible (for instance, through nm -CD <shared-library>) regardless of the fact that you're building the shared library itself with those options. That is, in this case, you have two options to resolve it:
Manually rebuild those static libraries (your shared library dependencies) with the -fvisibility=hidden and -fvisibility-inlines-hidden options, what is clearly not always possible/practical given their potential third-party origin.
Use linker/version script (like it is done above) to supply at link time in order to instruct linker to forcefully export/hide proper symbols from your shared library.
Let's say I have libA.so with version 1.1 and 1.2, both have the same symbols defined.
what happens if myApp need a symbol from libA but mistakenly linked both versions:
ld -o myApp -Lpath -lA_1_1 -lA_1_2
Am I right it will use symbols from the first one as long as it can find it?
Am I right it will use symbols from the first one as long as it can find it?
Yes, in general. And that might not be what you want.
If a function foo() in libA_1_2 calls another public function in the library, bar(), then it will use the symbol from libA_1_1, which might do the wrong thing (for example if v1.2 of the library was changed so that foo() expects bar() to deallocate some memory, but the v1.1 version of bar() doesn't do that).
I am getting following runtime error.
anyfile.cpp (60) : E_FATAL : Could not
start process libprocbase_so.so
(/opt/company/processes/sharedbase_so.so:
undefined symbol:
_ZTV16CResourceManager)
I found that meaning of _ZTV16CResourceManager is virtual table of Resource Manager,
Any idea why it is coming? how to solve it?
The problem is that while loading the dynamic libraries (sharedbase_so.so) it has not been able to resolve the symbol. Try to locate in what library (if any) the symbol is defined and ensure that ld can load it (add it to the path). If it is not present in any dynamic library, go back to the object files and try to determine where it is and why it did not make it to the binary.
A common situation where this can be an issue is with classes that are mostly defined inlined, like:
struct test {
virtual void foo() {}
//virtual void bar();
};
If the line with bar is commented out, then the compiler will generate the vtable as a weak symbol in all translation units that include it. If bar is uncommented, the compiler will not generate the vtable in each translation unit, but only in the translation unit that defines test::bar. Make sure that even if you do not use test::bar, the object file gets linked in the library.
Where did you declare the class ResourceManager ?
It seems that this library is not loaded - when you use runtime linking, you have to load all dependencies by hand in the correct order.
gph is a singleton class with no getInstance method
class gph
{
public:
static void newfun();
static void newfun1();
//...//
private:
gph();
};
This class gets build into a static library
Now I have a Dll from where I need to access the static function . So class A is a part of a Dll
I have a C++ member function say
void A:: fun()
{
gph::newfun() ; //accessing a static function : gives linker errors
}
On the other hand if I make fun() as static it doesnt give me any linker errors . But I do not want to make fun() as static
Most of what I work on deals with statically linked libraries, so this answer may not apply, but may clue you in to the problem. So based on that and what I'm looking at right now, my first thought would be to check that in the dll you're building, you've included the static library.
An unresolved symbol usually means that either the signature doesn't match or you're not including the necessary library. It varies from compiler to compiler, but most make you specify the library directory (sometimes denoted by -L in a command line) and the actual library to be linked in (sometimes denoted by -l).
Since I don't use DLL's that much, my understanding of them is similar to building an executable. If you use dynamic linking when you build, the path of the libraries you are linking to are embedded in your executable, so your executable size is smaller, but is dependent on the library path they are linked to on not moving.
So when you're building your DLL, make sure you've compiled the cpp for class gph and created a static library for it. Then when you use it in class A, you include the header and link in the library.
I think it is the calling convention issue.
Please try the following code:
class gph
{
public:
static void __cdecl newfun();
//...//
};