symbols in static library sometimes got linked into executable, sometimes not - c++

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.

Related

Force construction of a global object

Here’s the code:
struct S
{
S()
{
__debugbreak();
}
};
static const S g_s;
Obviously, I want some code to run at startup.
This only works for some source files, that have symbols referenced by outside code. For source files in a static library that don’t have any symbols referenced from outside, looks like the compiler or linker drop the complete compilation unit, so the global object is not constructed.
Is there a way to force construction of static objects, or otherwise force running of the code at startup?
I’ve double checked compilation settings for these source files, they are identical, and they are in the same static library project.
The static library is used by a DLL. Global objects are expected to be constructed before DLL_PROCESS_ATTACH call.
You will need to link "everything" from this library using linker options such as
-Wl--whole-archive -lmylib -Wl--no-whole-archive (gcc)
or
/INCLUDE symbol (vc)
or
/WHOLEARCHIVE:mylib (vc)
However relying on dynamic initialization stage and / or making assumptions about state of global objects during program startup / dll loading makes your program doomed. So you should consider explicit initialization instead.

C++ static variable in .lib does not initialize

I have static library (.lib) in VS2010 and am linking it to my test project.
The lib has a factory that I create using the below MACRO:
#define REGISTER_FACTORY(mType, my_class) \
class Factory##my_class : public CAbstractFactory\
{\
public:\
Factory##my_class() : CAbstractFactory(mType){}\
CBaseClass *Create()\
{ return new my_class(); }\
};\
static Factory##my_class StaticFactory##my_class;
What is supposed to happen is that in the CAbstractFactory the new factory gets registered by mtype. But when I check the factory the factory does not exist.
It works fine when I use a DLL instead of a .lib. My guess is that the linker does not include the static variable as it is not referenced or the static variable was not even included in the library.
How can I force the linker to include all objects from the static library in my .exe.
I use the macro like this:
// Register factory that can create CMyObject with ID=100
REGISTER_FACTORY(100, CMyObject);
class CMyObject
{
};
The CAbstractFactory looks like this:
class CAbstractFactory {
CAbstractFactory(int id) {
CFactory::instance().add(id, this);
}
}
Then some where else in the code, my main .exe I use:
CBaseClass *pObject = CFactory::instance().Create(100);
This will then give my a new CMyObject. The idea is that I have many different kind object and I have a database containing the id specifying the kind of objects I need.
100 is just an example.
So indeed, I do not reference anything from the .lib directly but I want to be able to create the objects using my factory
The CFactory class is a simple class that keeps a register (in a map) of all the CAbstractFactory classes and delegates the create method to the correct factory.
CFactory &CFactory::Instance()
{
static CFactory instance;
return instance;
}
The main problem lies in the fact that I do not reference anything from the .lib as it is all done through the CFactory. It works if I make it a DLL and make sure I add some reference to this DLL to make sure it is loaded. But for a .lib, I even added a dummy function to make sure I have at least one reference that doesn't include the rest of the code.
I had a similar problem and solved it by setting the lib project as a dependency of the main app project and then setting 'Link Library Dependencies' and 'Use Library Dependency Inputs' to Yes for the main project.
Update:
Recently I discovered that Visual Studio 2015 now supports a /WHOLEARCHIVE linker flag. I can't find it through the linker options, but you can add it as an additional command line option. It works similar to the GCC flag -whole-archive and you add it to your target linker flags (not to the static lib flags).
For example, specify /WHOLEARCHIVE:lib_name as an additional linker command line option and it will include all symbols from that lib. You can do this more than one lib as well.
If you use this /WHOLEARCHIVE:lib_name you no longer need the 'Link Library Dependencies' and 'Use Library Dependency Inputs' set to Yes. This is perfect for solutions generated through CMAKE. See a related answer here: https://stackoverflow.com/a/42083877/1151329
static defines an object with internal linkage --> if it's not used internally in the same translation unit, it can be optimized out. Remove the static from your instantiation for the object to have external linkage - Factory##my_class StaticFactory##my_class;

Statically linked libraries not running code inside to setup static variables

In a c++ project I am working on, I have a simple c++ file that needs to run some code at the beginning of the program execution. This file is linked into a static library, which is then linked into the main program.
I have similar code in other files running fine, that looks something like:
bool ____nonexistent_value = executeAction();
However, it does not work inside this file unless I make use of a function implemented in this file. It does work if the library is compiled as a shared library. I'd prefer to link this statically as the library is only a convenience as the file is in a different directory.
Update (Solution):
For now creating shared instead of static libraries makes everything work. Later I will look into getting everything linking with static libraries. Thanks for everyone's help!
If no symbol is referenced in that particular file then the file will not be included by the linker. You have two options:
Remove the file from library and include it (object or source file) directly in the command line for compilation/linking. Then the file should be included in executable.
Have a symbol in a file which you reference from from other files (for example the one with main() definition), this should "pull" the file during linking.
I'm not sure if there's a way to guarantee such static allocation in a static library, but you can always make it explicit. Provide an init function for your library that will be called from main to setup everything you need. This way you don't have to worry about linkers omitting code that's apparently unused, etc.
There's no guaranteed order for static initialization. You want to be very careful with this!

Not all symbols of an DLL-exported class is exported (VS9)

I'm building a DLL from a group of static libraries and I'm having a problem where only parts of classes are exported.
What I'm doing is declaring all symbols I want to export with a preprocessor definition like:
#if defined(MYPROJ_BUILD_DLL)
//Build as a DLL
# define MY_API __declspec(dllexport)
#elif defined(MYPROJ_USE_DLL)
//Use as a DLL
# define MY_API __declspec(dllimport)
#else
//Build or use as a static lib
# define MY_API
#endif
For example:
class MY_API Foo{
...
}
I then build static library with MYPROJ_BUILD_DLL & MYPROJ_USE_DLL undefined causing a static library to be built.
In another build I create a DLL from these static libraries. So I define MYPROJ_BUILD_DLL causing all symbols I want to export to be attributed with __declspec(dllexport) (this is done by including all static library headers in the DLL-project source file).
Edit:
Note on unrefenced symbols: Linker options Keep Unreferenced Data (/OPT:NOREF) and Do Not Remove Redundant COMDATs (/OPT:NOICF) is set so that no unreferenced symbols will be removed.
Ok, so now to the problem. When I use this new DLL I get unresolved externals because not all symbols of a class is exported. For example in a class like this:
class MY_API Foo{
public:
Foo(char const* );
int bar();
private:
Foo( char const*, char const* );
};
Only Foo::Foo( char const*, char const*); and int Foo::bar(); is exported. How can that be? I can understand if the entire class was missing, due to e.g. I forgot to include the header in the DLL-build. But it's only partial missing.
Also, say if Foo::Foo( char const*) was not implemented; then the DLL build would have unresolved external errors. But the build is fine (I also double checked for declarations without implementation).
Note: The combined size of the static libraries I'm combining is in the region of 30MB, and the resulting DLL is 1.2MB.
I'm using Visual Studio 9.0 (2008) to build everything. And Depends to check for exported symbols.
Edit:
For the ones who wonder why I don't just build a DLL from each of the static libraries: I can't because they cross-reference each other (that's why I need to group them together in one a single DLL). I know, it's horrible I can't really understand the logic behind it.
Remember that when you link against a static LIB, by default the linker is only pulling in the functions, classes, and data that the client (which in this case is your DLL) actually references.
So what happens is this:
You build your static LIB, and that's fine. This LIB is 100% valid.
You now build your static DLL around the original binary LIB. It pulls in only the stuff that it actually references. It doesn't pull in the entire class definition which is what it needs to do. This DLL, though it builds, is invalid.
A client then uses the DLL, and expects to see a complete binary definition for the exported class, because that's what the client sees in the accompanying header file.
However the class has only been partially imported, and this is why you're getting those link errors.
To fix:
If you're able to, don't build your DLL off your static LIB. Build your DLL off the original source code. And build your static LIB off the original source code.
Otherwise you can possibly fiddle with linker settings but I strongly recommend option 1 above. Note that OPT:NOREF won't work here as OPT:NOREF has no effect on static LIBs.
What wont't fix it:
High-level linker tweaks like OPT:NOREF, anything involving COMDATs, etc. If you want those functions present, you have to make sure they're referenced, either by referencing them, or by telling the linker explicitly, "hey, this Symbol X is referenced".
As a side note:
Anytime I build a DLL or LIB, I build both a DLL and a LIB, using exactly the technique you're using. Having a single code base that can generate either a DLL or a LIB by toggling a setting is ideal. But building a DLL off of a (binary) static LIB when you own the source code for both... I'm having a hard time imagining when such a scenario would be necessary.
The problem is surely that you use the already-built static .lib in your DLL project. That cannot work, you have to rebuild the .lib so that the functions get the __declspec(dllexport) declarator and will be exported by the linker.
At that point, it just isn't all that useful anymore to create the DLL compatible version of the .lib in the first place. Just create two projects, one that creates the static .lib, another that creates the DLL. Technically it is possible to still use the static .lib in your DLL project but you'll have to export the functions with a .def file. That can be high maintenance if the library has a lot of exports.
This is probably years too late, but OP's complaint was that a private method (the destructor) was not exported from a dllexport'd class. Isn't that normal? No external user is allowed to call a private method.

static Member access linker problems

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();
//...//
};